@djangocfg/seo 2.1.50 → 2.1.52

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.
@@ -363,6 +363,22 @@ async function analyzeRobotsTxt(siteUrl) {
363
363
  }
364
364
  analysis.exists = true;
365
365
  analysis.content = await response.text();
366
+ if (analysis.content.includes("content-signal") || analysis.content.includes("Content-Signal") || analysis.content.includes("ai-input") || analysis.content.includes("ai-train")) {
367
+ analysis.issues.push({
368
+ id: "cloudflare-managed-robots",
369
+ url: robotsUrl,
370
+ category: "technical",
371
+ severity: "warning",
372
+ title: "Cloudflare managed robots.txt detected",
373
+ description: `Your robots.txt is being overwritten by Cloudflare's "Content Signals Policy". Your app/robots.ts file is not being served.`,
374
+ recommendation: 'Disable in Cloudflare Dashboard: Security \u2192 Settings \u2192 "Manage your robots.txt" \u2192 Set to "Off".',
375
+ detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
376
+ metadata: {
377
+ cloudflareFeature: "Managed robots.txt",
378
+ docsUrl: "https://developers.cloudflare.com/bots/additional-configurations/managed-robots-txt/"
379
+ }
380
+ });
381
+ }
366
382
  const robots = robotsParser(robotsUrl, analysis.content);
367
383
  analysis.sitemaps = robots.getSitemaps();
368
384
  if (analysis.sitemaps.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/crawler/crawler.ts","../../src/crawler/robots-parser.ts","../../src/crawler/sitemap-validator.ts"],"names":["hash","consola","load"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @djangocfg/seo - Site Crawler\n * Internal site crawler for SEO analysis\n */\n\nimport { load } from 'cheerio';\nimport pLimit from 'p-limit';\nimport consola from 'consola';\nimport type { CrawlResult, CrawlerConfig, SeoIssue } from '../types/index.js';\n\nconst DEFAULT_CONFIG: Required<CrawlerConfig> = {\n maxPages: 100,\n maxDepth: 3,\n concurrency: 5,\n timeout: 30000,\n userAgent: 'DjangoCFG-SEO-Crawler/1.0 (+https://djangocfg.com/bot)',\n respectRobotsTxt: true,\n includePatterns: [],\n excludePatterns: [\n '/api/',\n '/admin/',\n '/_next/',\n '/static/',\n '.pdf',\n '.jpg',\n '.png',\n '.gif',\n '.svg',\n '.css',\n '.js',\n ],\n};\n\nexport class SiteCrawler {\n private config: Required<CrawlerConfig>;\n private baseUrl: URL;\n private visited = new Set<string>();\n private queue: Array<{ url: string; depth: number }> = [];\n private results: CrawlResult[] = [];\n private limit: ReturnType<typeof pLimit>;\n\n constructor(siteUrl: string, config?: CrawlerConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.baseUrl = new URL(siteUrl);\n this.limit = pLimit(this.config.concurrency);\n }\n\n /**\n * Start crawling the site\n */\n async crawl(): Promise<CrawlResult[]> {\n consola.info(`Starting crawl of ${this.baseUrl.origin}`);\n consola.info(`Config: maxPages=${this.config.maxPages}, maxDepth=${this.config.maxDepth}`);\n\n this.queue.push({ url: this.baseUrl.href, depth: 0 });\n\n while (this.queue.length > 0 && this.results.length < this.config.maxPages) {\n const batch = this.queue.splice(0, this.config.concurrency);\n\n const promises = batch.map(({ url, depth }) =>\n this.limit(() => this.crawlPage(url, depth))\n );\n\n await Promise.all(promises);\n }\n\n consola.success(`Crawl complete. Crawled ${this.results.length} pages.`);\n return this.results;\n }\n\n /**\n * Crawl a single page\n */\n private async crawlPage(url: string, depth: number): Promise<void> {\n const normalizedUrl = this.normalizeUrl(url);\n\n if (this.visited.has(normalizedUrl)) return;\n if (this.shouldExclude(normalizedUrl)) return;\n\n this.visited.add(normalizedUrl);\n\n const startTime = Date.now();\n const result: CrawlResult = {\n url: normalizedUrl,\n statusCode: 0,\n links: { internal: [], external: [] },\n images: [],\n loadTime: 0,\n errors: [],\n warnings: [],\n crawledAt: new Date().toISOString(),\n };\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(normalizedUrl, {\n headers: {\n 'User-Agent': this.config.userAgent,\n Accept: 'text/html,application/xhtml+xml',\n },\n signal: controller.signal,\n redirect: 'follow',\n });\n\n // TTFB = time from request start to first response headers\n result.ttfb = Date.now() - startTime;\n\n clearTimeout(timeoutId);\n\n result.statusCode = response.status;\n result.contentType = response.headers.get('content-type') || undefined;\n result.contentLength = Number(response.headers.get('content-length')) || undefined;\n\n if (response.ok && result.contentType?.includes('text/html')) {\n const html = await response.text();\n this.parseHtml(html, result, normalizedUrl, depth);\n } else if (!response.ok) {\n result.errors.push(`HTTP ${response.status}: ${response.statusText}`);\n }\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n result.errors.push('Request timeout');\n } else {\n result.errors.push(error.message);\n }\n }\n }\n\n result.loadTime = Date.now() - startTime;\n this.results.push(result);\n\n consola.debug(`Crawled: ${normalizedUrl} (${result.statusCode}) - ${result.loadTime}ms`);\n }\n\n /**\n * Parse HTML and extract SEO-relevant data\n */\n private parseHtml(html: string, result: CrawlResult, pageUrl: string, depth: number): void {\n const $ = load(html);\n\n // Title\n result.title = $('title').first().text().trim() || undefined;\n if (!result.title) {\n result.warnings.push('Missing title tag');\n } else if (result.title.length > 60) {\n result.warnings.push(`Title too long (${result.title.length} chars, recommended: <60)`);\n }\n\n // Meta description\n result.metaDescription =\n $('meta[name=\"description\"]').attr('content')?.trim() || undefined;\n if (!result.metaDescription) {\n result.warnings.push('Missing meta description');\n } else if (result.metaDescription.length > 160) {\n result.warnings.push(\n `Meta description too long (${result.metaDescription.length} chars, recommended: <160)`\n );\n }\n\n // Meta robots\n result.metaRobots = $('meta[name=\"robots\"]').attr('content')?.trim() || undefined;\n const xRobots = $('meta[http-equiv=\"X-Robots-Tag\"]').attr('content')?.trim();\n if (xRobots) {\n result.metaRobots = result.metaRobots ? `${result.metaRobots}, ${xRobots}` : xRobots;\n }\n\n // Canonical\n result.canonicalUrl = $('link[rel=\"canonical\"]').attr('href')?.trim() || undefined;\n if (!result.canonicalUrl) {\n result.warnings.push('Missing canonical tag');\n }\n\n // Headings\n result.h1 = $('h1')\n .map((_, el) => $(el).text().trim())\n .get();\n result.h2 = $('h2')\n .map((_, el) => $(el).text().trim())\n .get();\n\n if (result.h1.length === 0) {\n result.warnings.push('Missing H1 tag');\n } else if (result.h1.length > 1) {\n result.warnings.push(`Multiple H1 tags (${result.h1.length})`);\n }\n\n // Links\n $('a[href]').each((_, el) => {\n const href = $(el).attr('href');\n if (!href) return;\n\n try {\n const linkUrl = new URL(href, pageUrl);\n\n if (linkUrl.hostname === this.baseUrl.hostname) {\n const internalUrl = this.normalizeUrl(linkUrl.href);\n result.links.internal.push(internalUrl);\n\n // Add to crawl queue\n if (depth < this.config.maxDepth && !this.visited.has(internalUrl)) {\n this.queue.push({ url: internalUrl, depth: depth + 1 });\n }\n } else {\n result.links.external.push(linkUrl.href);\n }\n } catch {\n // Invalid URL, skip\n }\n });\n\n // Images\n $('img').each((_, el) => {\n const src = $(el).attr('src');\n const alt = $(el).attr('alt');\n\n if (src) {\n result.images.push({\n src,\n alt,\n hasAlt: alt !== undefined && alt.trim().length > 0,\n });\n }\n });\n\n const imagesWithoutAlt = result.images.filter((img) => !img.hasAlt);\n if (imagesWithoutAlt.length > 0) {\n result.warnings.push(`${imagesWithoutAlt.length} images without alt text`);\n }\n }\n\n /**\n * Normalize URL for deduplication\n */\n private normalizeUrl(url: string): string {\n try {\n const parsed = new URL(url, this.baseUrl.href);\n // Remove trailing slash, hash, and sort query params\n parsed.hash = '';\n let pathname = parsed.pathname;\n if (pathname.endsWith('/') && pathname !== '/') {\n pathname = pathname.slice(0, -1);\n }\n parsed.pathname = pathname;\n return parsed.href;\n } catch {\n return url;\n }\n }\n\n /**\n * Check if URL should be excluded\n */\n private shouldExclude(url: string): boolean {\n // Check include patterns first\n if (this.config.includePatterns.length > 0) {\n const included = this.config.includePatterns.some((pattern) =>\n url.includes(pattern)\n );\n if (!included) return true;\n }\n\n // Check exclude patterns\n return this.config.excludePatterns.some((pattern) => url.includes(pattern));\n }\n}\n\n/**\n * Analyze crawl results for SEO issues\n */\nexport function analyzeCrawlResults(results: CrawlResult[]): SeoIssue[] {\n const issues: SeoIssue[] = [];\n\n for (const result of results) {\n // HTTP errors\n if (result.statusCode >= 400) {\n issues.push({\n id: `http-error-${hash(result.url)}`,\n url: result.url,\n category: 'technical',\n severity: result.statusCode >= 500 ? 'critical' : 'error',\n title: `HTTP ${result.statusCode} error`,\n description: `Page returns ${result.statusCode} status code.`,\n recommendation:\n result.statusCode === 404\n ? 'Either restore the content or set up a redirect.'\n : 'Fix the server error and ensure the page is accessible.',\n detectedAt: result.crawledAt,\n metadata: { statusCode: result.statusCode },\n });\n }\n\n // Missing title\n if (!result.title && result.statusCode === 200) {\n issues.push({\n id: `missing-title-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'error',\n title: 'Missing title tag',\n description: 'This page does not have a title tag.',\n recommendation: 'Add a unique, descriptive title tag (50-60 characters).',\n detectedAt: result.crawledAt,\n });\n }\n\n // Missing meta description\n if (!result.metaDescription && result.statusCode === 200) {\n issues.push({\n id: `missing-meta-desc-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'warning',\n title: 'Missing meta description',\n description: 'This page does not have a meta description.',\n recommendation: 'Add a unique meta description (120-160 characters).',\n detectedAt: result.crawledAt,\n });\n }\n\n // Missing H1\n if (result.h1 && result.h1.length === 0 && result.statusCode === 200) {\n issues.push({\n id: `missing-h1-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'warning',\n title: 'Missing H1 heading',\n description: 'This page does not have an H1 heading.',\n recommendation: 'Add a single H1 heading that describes the page content.',\n detectedAt: result.crawledAt,\n });\n }\n\n // Multiple H1s\n if (result.h1 && result.h1.length > 1) {\n issues.push({\n id: `multiple-h1-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'warning',\n title: 'Multiple H1 headings',\n description: `This page has ${result.h1.length} H1 headings.`,\n recommendation: 'Use only one H1 heading per page.',\n detectedAt: result.crawledAt,\n metadata: { h1Count: result.h1.length },\n });\n }\n\n // Images without alt\n const imagesWithoutAlt = result.images.filter((img) => !img.hasAlt);\n if (imagesWithoutAlt.length > 0) {\n issues.push({\n id: `images-no-alt-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'info',\n title: 'Images without alt text',\n description: `${imagesWithoutAlt.length} images are missing alt text.`,\n recommendation: 'Add descriptive alt text to all images for accessibility and SEO.',\n detectedAt: result.crawledAt,\n metadata: { count: imagesWithoutAlt.length },\n });\n }\n\n // Slow load time (> 3s)\n if (result.loadTime > 3000) {\n issues.push({\n id: `slow-page-${hash(result.url)}`,\n url: result.url,\n category: 'performance',\n severity: result.loadTime > 5000 ? 'error' : 'warning',\n title: 'Slow page load time',\n description: `Page took ${result.loadTime}ms to load.`,\n recommendation: 'Optimize page load time. Target under 3 seconds.',\n detectedAt: result.crawledAt,\n metadata: { loadTime: result.loadTime },\n });\n }\n\n // Slow TTFB (> 800ms)\n if (result.ttfb && result.ttfb > 800) {\n issues.push({\n id: `slow-ttfb-${hash(result.url)}`,\n url: result.url,\n category: 'performance',\n severity: result.ttfb > 1500 ? 'error' : 'warning',\n title: 'Slow Time to First Byte',\n description: `TTFB is ${result.ttfb}ms. Server responded slowly.`,\n recommendation: 'Optimize server response. Target TTFB under 800ms. Consider CDN, caching, or server upgrades.',\n detectedAt: result.crawledAt,\n metadata: { ttfb: result.ttfb },\n });\n }\n\n // Noindex check\n if (result.metaRobots?.includes('noindex')) {\n issues.push({\n id: `noindex-${hash(result.url)}`,\n url: result.url,\n category: 'indexing',\n severity: 'info',\n title: 'Page marked as noindex',\n description: 'This page has a noindex directive.',\n recommendation: 'Verify this is intentional. Remove noindex if the page should be indexed.',\n detectedAt: result.crawledAt,\n metadata: { metaRobots: result.metaRobots },\n });\n }\n }\n\n return issues;\n}\n\nfunction hash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n","/**\n * @djangocfg/seo - Robots.txt Parser\n * Parse and analyze robots.txt files\n */\n\nimport robotsParser from 'robots-parser';\nimport consola from 'consola';\nimport type { SeoIssue } from '../types/index.js';\n\nexport interface RobotsAnalysis {\n exists: boolean;\n content?: string;\n sitemaps: string[];\n allowedPaths: string[];\n disallowedPaths: string[];\n crawlDelay?: number;\n issues: SeoIssue[];\n}\n\n/**\n * Fetch and parse robots.txt for a site\n */\nexport async function analyzeRobotsTxt(siteUrl: string): Promise<RobotsAnalysis> {\n const robotsUrl = new URL('/robots.txt', siteUrl).href;\n\n const analysis: RobotsAnalysis = {\n exists: false,\n sitemaps: [],\n allowedPaths: [],\n disallowedPaths: [],\n issues: [],\n };\n\n try {\n const response = await fetch(robotsUrl);\n\n if (!response.ok) {\n analysis.issues.push({\n id: 'missing-robots-txt',\n url: robotsUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Missing robots.txt',\n description: `No robots.txt file found (HTTP ${response.status}).`,\n recommendation: 'Create a robots.txt file to control crawler access.',\n detectedAt: new Date().toISOString(),\n });\n return analysis;\n }\n\n analysis.exists = true;\n analysis.content = await response.text();\n\n // Parse robots.txt\n const robots = robotsParser(robotsUrl, analysis.content);\n\n // Extract sitemaps\n analysis.sitemaps = robots.getSitemaps();\n\n if (analysis.sitemaps.length === 0) {\n analysis.issues.push({\n id: 'no-sitemap-in-robots',\n url: robotsUrl,\n category: 'technical',\n severity: 'info',\n title: 'No sitemap in robots.txt',\n description: 'No sitemap URL is declared in robots.txt.',\n recommendation: 'Add a Sitemap directive pointing to your XML sitemap.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n // Parse rules (simplified extraction)\n const lines = analysis.content.split('\\n');\n let currentUserAgent = '*';\n\n for (const line of lines) {\n const trimmed = line.trim().toLowerCase();\n\n if (trimmed.startsWith('user-agent:')) {\n currentUserAgent = trimmed.replace('user-agent:', '').trim();\n } else if (trimmed.startsWith('disallow:')) {\n const path = line.trim().replace(/disallow:/i, '').trim();\n if (path) {\n analysis.disallowedPaths.push(path);\n }\n } else if (trimmed.startsWith('allow:')) {\n const path = line.trim().replace(/allow:/i, '').trim();\n if (path) {\n analysis.allowedPaths.push(path);\n }\n } else if (trimmed.startsWith('crawl-delay:')) {\n const delay = parseInt(trimmed.replace('crawl-delay:', '').trim(), 10);\n if (!isNaN(delay)) {\n analysis.crawlDelay = delay;\n }\n }\n }\n\n // Check for blocking important paths\n const importantPaths = ['/', '/sitemap.xml'];\n for (const path of importantPaths) {\n if (!robots.isAllowed(new URL(path, siteUrl).href, 'Googlebot')) {\n analysis.issues.push({\n id: `blocked-important-path-${path.replace(/\\//g, '-')}`,\n url: siteUrl,\n category: 'crawling',\n severity: 'error',\n title: `Important path blocked: ${path}`,\n description: `The path ${path} is blocked in robots.txt.`,\n recommendation: `Ensure ${path} is accessible to search engines.`,\n detectedAt: new Date().toISOString(),\n metadata: { path },\n });\n }\n }\n\n // Check for excessively restrictive rules\n if (analysis.disallowedPaths.includes('/')) {\n analysis.issues.push({\n id: 'all-blocked',\n url: robotsUrl,\n category: 'crawling',\n severity: 'critical',\n title: 'Entire site blocked',\n description: 'robots.txt blocks access to the entire site (Disallow: /).',\n recommendation: 'Remove or modify this rule if you want your site to be indexed.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n consola.debug(`Analyzed robots.txt: ${analysis.disallowedPaths.length} disallow rules`);\n } catch (error) {\n consola.error('Failed to fetch robots.txt:', error);\n analysis.issues.push({\n id: 'robots-txt-error',\n url: robotsUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Failed to fetch robots.txt',\n description: `Error fetching robots.txt: ${error instanceof Error ? error.message : 'Unknown error'}`,\n recommendation: 'Ensure robots.txt is accessible.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n return analysis;\n}\n\n/**\n * Check if a URL is allowed by robots.txt\n */\nexport async function isUrlAllowed(\n siteUrl: string,\n url: string,\n userAgent = 'Googlebot'\n): Promise<boolean> {\n const robotsUrl = new URL('/robots.txt', siteUrl).href;\n\n try {\n const response = await fetch(robotsUrl);\n if (!response.ok) return true; // No robots.txt = allow all\n\n const content = await response.text();\n const robots = robotsParser(robotsUrl, content);\n\n return robots.isAllowed(url, userAgent) ?? true;\n } catch {\n return true; // Error fetching = allow\n }\n}\n","/**\n * @djangocfg/seo - Sitemap Validator\n * Validate XML sitemaps\n */\n\nimport { load } from 'cheerio';\nimport consola from 'consola';\nimport type { SeoIssue } from '../types/index.js';\n\nexport interface SitemapAnalysis {\n url: string;\n exists: boolean;\n type: 'sitemap' | 'sitemap-index' | 'unknown';\n urls: string[];\n childSitemaps: string[];\n lastmod?: string;\n issues: SeoIssue[];\n}\n\n/**\n * Analyze a sitemap URL\n */\nexport async function analyzeSitemap(sitemapUrl: string): Promise<SitemapAnalysis> {\n const analysis: SitemapAnalysis = {\n url: sitemapUrl,\n exists: false,\n type: 'unknown',\n urls: [],\n childSitemaps: [],\n issues: [],\n };\n\n try {\n const response = await fetch(sitemapUrl, {\n headers: {\n Accept: 'application/xml, text/xml, */*',\n },\n });\n\n if (!response.ok) {\n analysis.issues.push({\n id: `sitemap-not-found-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Sitemap not accessible',\n description: `Sitemap returned HTTP ${response.status}.`,\n recommendation: 'Ensure the sitemap URL is correct and accessible.',\n detectedAt: new Date().toISOString(),\n metadata: { statusCode: response.status },\n });\n return analysis;\n }\n\n analysis.exists = true;\n const content = await response.text();\n\n // Check content type\n const contentType = response.headers.get('content-type') || '';\n if (!contentType.includes('xml') && !content.trim().startsWith('<?xml')) {\n analysis.issues.push({\n id: `sitemap-not-xml-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Sitemap is not XML',\n description: 'The sitemap does not have an XML content type.',\n recommendation: 'Ensure sitemap is served with Content-Type: application/xml.',\n detectedAt: new Date().toISOString(),\n metadata: { contentType },\n });\n }\n\n // Parse XML\n const $ = load(content, { xmlMode: true });\n\n // Check if it's a sitemap index\n const sitemapIndex = $('sitemapindex');\n if (sitemapIndex.length > 0) {\n analysis.type = 'sitemap-index';\n\n $('sitemap').each((_, el) => {\n const loc = $('loc', el).text().trim();\n if (loc) {\n analysis.childSitemaps.push(loc);\n }\n });\n\n consola.debug(`Sitemap index contains ${analysis.childSitemaps.length} sitemaps`);\n } else {\n analysis.type = 'sitemap';\n\n $('url').each((_, el) => {\n const loc = $('loc', el).text().trim();\n if (loc) {\n analysis.urls.push(loc);\n }\n });\n\n const lastmod = $('url lastmod').first().text().trim();\n if (lastmod) {\n analysis.lastmod = lastmod;\n }\n\n consola.debug(`Sitemap contains ${analysis.urls.length} URLs`);\n }\n\n // Validate sitemap content\n if (analysis.type === 'sitemap' && analysis.urls.length === 0) {\n analysis.issues.push({\n id: `sitemap-empty-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Sitemap is empty',\n description: 'The sitemap contains no URLs.',\n recommendation: 'Add URLs to your sitemap or remove it if not needed.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n // Check for too many URLs (Google limit is 50,000)\n if (analysis.urls.length > 50000) {\n analysis.issues.push({\n id: `sitemap-too-large-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Sitemap exceeds URL limit',\n description: `Sitemap contains ${analysis.urls.length} URLs. Maximum is 50,000.`,\n recommendation: 'Split the sitemap into multiple files using a sitemap index.',\n detectedAt: new Date().toISOString(),\n metadata: { urlCount: analysis.urls.length },\n });\n }\n\n // Check file size (Google limit is 50MB uncompressed)\n const sizeInMB = new Blob([content]).size / (1024 * 1024);\n if (sizeInMB > 50) {\n analysis.issues.push({\n id: `sitemap-too-large-size-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Sitemap exceeds size limit',\n description: `Sitemap is ${sizeInMB.toFixed(2)}MB. Maximum is 50MB.`,\n recommendation: 'Split the sitemap or compress it.',\n detectedAt: new Date().toISOString(),\n metadata: { sizeMB: sizeInMB },\n });\n }\n } catch (error) {\n consola.error('Failed to analyze sitemap:', error);\n analysis.issues.push({\n id: `sitemap-error-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Failed to parse sitemap',\n description: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,\n recommendation: 'Check sitemap validity using Google Search Console.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n return analysis;\n}\n\n/**\n * Recursively analyze a sitemap and all its children\n */\nexport async function analyzeAllSitemaps(\n sitemapUrl: string,\n maxDepth = 3\n): Promise<SitemapAnalysis[]> {\n const results: SitemapAnalysis[] = [];\n const visited = new Set<string>();\n\n async function analyze(url: string, depth: number): Promise<void> {\n if (depth > maxDepth || visited.has(url)) return;\n visited.add(url);\n\n const analysis = await analyzeSitemap(url);\n results.push(analysis);\n\n // Recursively analyze child sitemaps\n for (const childUrl of analysis.childSitemaps) {\n await analyze(childUrl, depth + 1);\n }\n }\n\n await analyze(sitemapUrl, 0);\n return results;\n}\n\nfunction hash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n"]}
1
+ {"version":3,"sources":["../../src/crawler/crawler.ts","../../src/crawler/robots-parser.ts","../../src/crawler/sitemap-validator.ts"],"names":["hash","consola","load"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @djangocfg/seo - Site Crawler\n * Internal site crawler for SEO analysis\n */\n\nimport { load } from 'cheerio';\nimport pLimit from 'p-limit';\nimport consola from 'consola';\nimport type { CrawlResult, CrawlerConfig, SeoIssue } from '../types/index.js';\n\nconst DEFAULT_CONFIG: Required<CrawlerConfig> = {\n maxPages: 100,\n maxDepth: 3,\n concurrency: 5,\n timeout: 30000,\n userAgent: 'DjangoCFG-SEO-Crawler/1.0 (+https://djangocfg.com/bot)',\n respectRobotsTxt: true,\n includePatterns: [],\n excludePatterns: [\n '/api/',\n '/admin/',\n '/_next/',\n '/static/',\n '.pdf',\n '.jpg',\n '.png',\n '.gif',\n '.svg',\n '.css',\n '.js',\n ],\n};\n\nexport class SiteCrawler {\n private config: Required<CrawlerConfig>;\n private baseUrl: URL;\n private visited = new Set<string>();\n private queue: Array<{ url: string; depth: number }> = [];\n private results: CrawlResult[] = [];\n private limit: ReturnType<typeof pLimit>;\n\n constructor(siteUrl: string, config?: CrawlerConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.baseUrl = new URL(siteUrl);\n this.limit = pLimit(this.config.concurrency);\n }\n\n /**\n * Start crawling the site\n */\n async crawl(): Promise<CrawlResult[]> {\n consola.info(`Starting crawl of ${this.baseUrl.origin}`);\n consola.info(`Config: maxPages=${this.config.maxPages}, maxDepth=${this.config.maxDepth}`);\n\n this.queue.push({ url: this.baseUrl.href, depth: 0 });\n\n while (this.queue.length > 0 && this.results.length < this.config.maxPages) {\n const batch = this.queue.splice(0, this.config.concurrency);\n\n const promises = batch.map(({ url, depth }) =>\n this.limit(() => this.crawlPage(url, depth))\n );\n\n await Promise.all(promises);\n }\n\n consola.success(`Crawl complete. Crawled ${this.results.length} pages.`);\n return this.results;\n }\n\n /**\n * Crawl a single page\n */\n private async crawlPage(url: string, depth: number): Promise<void> {\n const normalizedUrl = this.normalizeUrl(url);\n\n if (this.visited.has(normalizedUrl)) return;\n if (this.shouldExclude(normalizedUrl)) return;\n\n this.visited.add(normalizedUrl);\n\n const startTime = Date.now();\n const result: CrawlResult = {\n url: normalizedUrl,\n statusCode: 0,\n links: { internal: [], external: [] },\n images: [],\n loadTime: 0,\n errors: [],\n warnings: [],\n crawledAt: new Date().toISOString(),\n };\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(normalizedUrl, {\n headers: {\n 'User-Agent': this.config.userAgent,\n Accept: 'text/html,application/xhtml+xml',\n },\n signal: controller.signal,\n redirect: 'follow',\n });\n\n // TTFB = time from request start to first response headers\n result.ttfb = Date.now() - startTime;\n\n clearTimeout(timeoutId);\n\n result.statusCode = response.status;\n result.contentType = response.headers.get('content-type') || undefined;\n result.contentLength = Number(response.headers.get('content-length')) || undefined;\n\n if (response.ok && result.contentType?.includes('text/html')) {\n const html = await response.text();\n this.parseHtml(html, result, normalizedUrl, depth);\n } else if (!response.ok) {\n result.errors.push(`HTTP ${response.status}: ${response.statusText}`);\n }\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n result.errors.push('Request timeout');\n } else {\n result.errors.push(error.message);\n }\n }\n }\n\n result.loadTime = Date.now() - startTime;\n this.results.push(result);\n\n consola.debug(`Crawled: ${normalizedUrl} (${result.statusCode}) - ${result.loadTime}ms`);\n }\n\n /**\n * Parse HTML and extract SEO-relevant data\n */\n private parseHtml(html: string, result: CrawlResult, pageUrl: string, depth: number): void {\n const $ = load(html);\n\n // Title\n result.title = $('title').first().text().trim() || undefined;\n if (!result.title) {\n result.warnings.push('Missing title tag');\n } else if (result.title.length > 60) {\n result.warnings.push(`Title too long (${result.title.length} chars, recommended: <60)`);\n }\n\n // Meta description\n result.metaDescription =\n $('meta[name=\"description\"]').attr('content')?.trim() || undefined;\n if (!result.metaDescription) {\n result.warnings.push('Missing meta description');\n } else if (result.metaDescription.length > 160) {\n result.warnings.push(\n `Meta description too long (${result.metaDescription.length} chars, recommended: <160)`\n );\n }\n\n // Meta robots\n result.metaRobots = $('meta[name=\"robots\"]').attr('content')?.trim() || undefined;\n const xRobots = $('meta[http-equiv=\"X-Robots-Tag\"]').attr('content')?.trim();\n if (xRobots) {\n result.metaRobots = result.metaRobots ? `${result.metaRobots}, ${xRobots}` : xRobots;\n }\n\n // Canonical\n result.canonicalUrl = $('link[rel=\"canonical\"]').attr('href')?.trim() || undefined;\n if (!result.canonicalUrl) {\n result.warnings.push('Missing canonical tag');\n }\n\n // Headings\n result.h1 = $('h1')\n .map((_, el) => $(el).text().trim())\n .get();\n result.h2 = $('h2')\n .map((_, el) => $(el).text().trim())\n .get();\n\n if (result.h1.length === 0) {\n result.warnings.push('Missing H1 tag');\n } else if (result.h1.length > 1) {\n result.warnings.push(`Multiple H1 tags (${result.h1.length})`);\n }\n\n // Links\n $('a[href]').each((_, el) => {\n const href = $(el).attr('href');\n if (!href) return;\n\n try {\n const linkUrl = new URL(href, pageUrl);\n\n if (linkUrl.hostname === this.baseUrl.hostname) {\n const internalUrl = this.normalizeUrl(linkUrl.href);\n result.links.internal.push(internalUrl);\n\n // Add to crawl queue\n if (depth < this.config.maxDepth && !this.visited.has(internalUrl)) {\n this.queue.push({ url: internalUrl, depth: depth + 1 });\n }\n } else {\n result.links.external.push(linkUrl.href);\n }\n } catch {\n // Invalid URL, skip\n }\n });\n\n // Images\n $('img').each((_, el) => {\n const src = $(el).attr('src');\n const alt = $(el).attr('alt');\n\n if (src) {\n result.images.push({\n src,\n alt,\n hasAlt: alt !== undefined && alt.trim().length > 0,\n });\n }\n });\n\n const imagesWithoutAlt = result.images.filter((img) => !img.hasAlt);\n if (imagesWithoutAlt.length > 0) {\n result.warnings.push(`${imagesWithoutAlt.length} images without alt text`);\n }\n }\n\n /**\n * Normalize URL for deduplication\n */\n private normalizeUrl(url: string): string {\n try {\n const parsed = new URL(url, this.baseUrl.href);\n // Remove trailing slash, hash, and sort query params\n parsed.hash = '';\n let pathname = parsed.pathname;\n if (pathname.endsWith('/') && pathname !== '/') {\n pathname = pathname.slice(0, -1);\n }\n parsed.pathname = pathname;\n return parsed.href;\n } catch {\n return url;\n }\n }\n\n /**\n * Check if URL should be excluded\n */\n private shouldExclude(url: string): boolean {\n // Check include patterns first\n if (this.config.includePatterns.length > 0) {\n const included = this.config.includePatterns.some((pattern) =>\n url.includes(pattern)\n );\n if (!included) return true;\n }\n\n // Check exclude patterns\n return this.config.excludePatterns.some((pattern) => url.includes(pattern));\n }\n}\n\n/**\n * Analyze crawl results for SEO issues\n */\nexport function analyzeCrawlResults(results: CrawlResult[]): SeoIssue[] {\n const issues: SeoIssue[] = [];\n\n for (const result of results) {\n // HTTP errors\n if (result.statusCode >= 400) {\n issues.push({\n id: `http-error-${hash(result.url)}`,\n url: result.url,\n category: 'technical',\n severity: result.statusCode >= 500 ? 'critical' : 'error',\n title: `HTTP ${result.statusCode} error`,\n description: `Page returns ${result.statusCode} status code.`,\n recommendation:\n result.statusCode === 404\n ? 'Either restore the content or set up a redirect.'\n : 'Fix the server error and ensure the page is accessible.',\n detectedAt: result.crawledAt,\n metadata: { statusCode: result.statusCode },\n });\n }\n\n // Missing title\n if (!result.title && result.statusCode === 200) {\n issues.push({\n id: `missing-title-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'error',\n title: 'Missing title tag',\n description: 'This page does not have a title tag.',\n recommendation: 'Add a unique, descriptive title tag (50-60 characters).',\n detectedAt: result.crawledAt,\n });\n }\n\n // Missing meta description\n if (!result.metaDescription && result.statusCode === 200) {\n issues.push({\n id: `missing-meta-desc-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'warning',\n title: 'Missing meta description',\n description: 'This page does not have a meta description.',\n recommendation: 'Add a unique meta description (120-160 characters).',\n detectedAt: result.crawledAt,\n });\n }\n\n // Missing H1\n if (result.h1 && result.h1.length === 0 && result.statusCode === 200) {\n issues.push({\n id: `missing-h1-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'warning',\n title: 'Missing H1 heading',\n description: 'This page does not have an H1 heading.',\n recommendation: 'Add a single H1 heading that describes the page content.',\n detectedAt: result.crawledAt,\n });\n }\n\n // Multiple H1s\n if (result.h1 && result.h1.length > 1) {\n issues.push({\n id: `multiple-h1-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'warning',\n title: 'Multiple H1 headings',\n description: `This page has ${result.h1.length} H1 headings.`,\n recommendation: 'Use only one H1 heading per page.',\n detectedAt: result.crawledAt,\n metadata: { h1Count: result.h1.length },\n });\n }\n\n // Images without alt\n const imagesWithoutAlt = result.images.filter((img) => !img.hasAlt);\n if (imagesWithoutAlt.length > 0) {\n issues.push({\n id: `images-no-alt-${hash(result.url)}`,\n url: result.url,\n category: 'content',\n severity: 'info',\n title: 'Images without alt text',\n description: `${imagesWithoutAlt.length} images are missing alt text.`,\n recommendation: 'Add descriptive alt text to all images for accessibility and SEO.',\n detectedAt: result.crawledAt,\n metadata: { count: imagesWithoutAlt.length },\n });\n }\n\n // Slow load time (> 3s)\n if (result.loadTime > 3000) {\n issues.push({\n id: `slow-page-${hash(result.url)}`,\n url: result.url,\n category: 'performance',\n severity: result.loadTime > 5000 ? 'error' : 'warning',\n title: 'Slow page load time',\n description: `Page took ${result.loadTime}ms to load.`,\n recommendation: 'Optimize page load time. Target under 3 seconds.',\n detectedAt: result.crawledAt,\n metadata: { loadTime: result.loadTime },\n });\n }\n\n // Slow TTFB (> 800ms)\n if (result.ttfb && result.ttfb > 800) {\n issues.push({\n id: `slow-ttfb-${hash(result.url)}`,\n url: result.url,\n category: 'performance',\n severity: result.ttfb > 1500 ? 'error' : 'warning',\n title: 'Slow Time to First Byte',\n description: `TTFB is ${result.ttfb}ms. Server responded slowly.`,\n recommendation: 'Optimize server response. Target TTFB under 800ms. Consider CDN, caching, or server upgrades.',\n detectedAt: result.crawledAt,\n metadata: { ttfb: result.ttfb },\n });\n }\n\n // Noindex check\n if (result.metaRobots?.includes('noindex')) {\n issues.push({\n id: `noindex-${hash(result.url)}`,\n url: result.url,\n category: 'indexing',\n severity: 'info',\n title: 'Page marked as noindex',\n description: 'This page has a noindex directive.',\n recommendation: 'Verify this is intentional. Remove noindex if the page should be indexed.',\n detectedAt: result.crawledAt,\n metadata: { metaRobots: result.metaRobots },\n });\n }\n }\n\n return issues;\n}\n\nfunction hash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n","/**\n * @djangocfg/seo - Robots.txt Parser\n * Parse and analyze robots.txt files\n */\n\nimport robotsParser from 'robots-parser';\nimport consola from 'consola';\nimport type { SeoIssue } from '../types/index.js';\n\nexport interface RobotsAnalysis {\n exists: boolean;\n content?: string;\n sitemaps: string[];\n allowedPaths: string[];\n disallowedPaths: string[];\n crawlDelay?: number;\n issues: SeoIssue[];\n}\n\n/**\n * Fetch and parse robots.txt for a site\n */\nexport async function analyzeRobotsTxt(siteUrl: string): Promise<RobotsAnalysis> {\n const robotsUrl = new URL('/robots.txt', siteUrl).href;\n\n const analysis: RobotsAnalysis = {\n exists: false,\n sitemaps: [],\n allowedPaths: [],\n disallowedPaths: [],\n issues: [],\n };\n\n try {\n const response = await fetch(robotsUrl);\n\n if (!response.ok) {\n analysis.issues.push({\n id: 'missing-robots-txt',\n url: robotsUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Missing robots.txt',\n description: `No robots.txt file found (HTTP ${response.status}).`,\n recommendation: 'Create a robots.txt file to control crawler access.',\n detectedAt: new Date().toISOString(),\n });\n return analysis;\n }\n\n analysis.exists = true;\n analysis.content = await response.text();\n\n // Check for Cloudflare managed robots.txt override\n if (\n analysis.content.includes('content-signal') ||\n analysis.content.includes('Content-Signal') ||\n analysis.content.includes('ai-input') ||\n analysis.content.includes('ai-train')\n ) {\n analysis.issues.push({\n id: 'cloudflare-managed-robots',\n url: robotsUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Cloudflare managed robots.txt detected',\n description:\n 'Your robots.txt is being overwritten by Cloudflare\\'s \"Content Signals Policy\". ' +\n 'Your app/robots.ts file is not being served.',\n recommendation:\n 'Disable in Cloudflare Dashboard: Security → Settings → \"Manage your robots.txt\" → Set to \"Off\".',\n detectedAt: new Date().toISOString(),\n metadata: {\n cloudflareFeature: 'Managed robots.txt',\n docsUrl: 'https://developers.cloudflare.com/bots/additional-configurations/managed-robots-txt/',\n },\n });\n }\n\n // Parse robots.txt\n const robots = robotsParser(robotsUrl, analysis.content);\n\n // Extract sitemaps\n analysis.sitemaps = robots.getSitemaps();\n\n if (analysis.sitemaps.length === 0) {\n analysis.issues.push({\n id: 'no-sitemap-in-robots',\n url: robotsUrl,\n category: 'technical',\n severity: 'info',\n title: 'No sitemap in robots.txt',\n description: 'No sitemap URL is declared in robots.txt.',\n recommendation: 'Add a Sitemap directive pointing to your XML sitemap.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n // Parse rules (simplified extraction)\n const lines = analysis.content.split('\\n');\n let currentUserAgent = '*';\n\n for (const line of lines) {\n const trimmed = line.trim().toLowerCase();\n\n if (trimmed.startsWith('user-agent:')) {\n currentUserAgent = trimmed.replace('user-agent:', '').trim();\n } else if (trimmed.startsWith('disallow:')) {\n const path = line.trim().replace(/disallow:/i, '').trim();\n if (path) {\n analysis.disallowedPaths.push(path);\n }\n } else if (trimmed.startsWith('allow:')) {\n const path = line.trim().replace(/allow:/i, '').trim();\n if (path) {\n analysis.allowedPaths.push(path);\n }\n } else if (trimmed.startsWith('crawl-delay:')) {\n const delay = parseInt(trimmed.replace('crawl-delay:', '').trim(), 10);\n if (!isNaN(delay)) {\n analysis.crawlDelay = delay;\n }\n }\n }\n\n // Check for blocking important paths\n const importantPaths = ['/', '/sitemap.xml'];\n for (const path of importantPaths) {\n if (!robots.isAllowed(new URL(path, siteUrl).href, 'Googlebot')) {\n analysis.issues.push({\n id: `blocked-important-path-${path.replace(/\\//g, '-')}`,\n url: siteUrl,\n category: 'crawling',\n severity: 'error',\n title: `Important path blocked: ${path}`,\n description: `The path ${path} is blocked in robots.txt.`,\n recommendation: `Ensure ${path} is accessible to search engines.`,\n detectedAt: new Date().toISOString(),\n metadata: { path },\n });\n }\n }\n\n // Check for excessively restrictive rules\n if (analysis.disallowedPaths.includes('/')) {\n analysis.issues.push({\n id: 'all-blocked',\n url: robotsUrl,\n category: 'crawling',\n severity: 'critical',\n title: 'Entire site blocked',\n description: 'robots.txt blocks access to the entire site (Disallow: /).',\n recommendation: 'Remove or modify this rule if you want your site to be indexed.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n consola.debug(`Analyzed robots.txt: ${analysis.disallowedPaths.length} disallow rules`);\n } catch (error) {\n consola.error('Failed to fetch robots.txt:', error);\n analysis.issues.push({\n id: 'robots-txt-error',\n url: robotsUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Failed to fetch robots.txt',\n description: `Error fetching robots.txt: ${error instanceof Error ? error.message : 'Unknown error'}`,\n recommendation: 'Ensure robots.txt is accessible.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n return analysis;\n}\n\n/**\n * Check if a URL is allowed by robots.txt\n */\nexport async function isUrlAllowed(\n siteUrl: string,\n url: string,\n userAgent = 'Googlebot'\n): Promise<boolean> {\n const robotsUrl = new URL('/robots.txt', siteUrl).href;\n\n try {\n const response = await fetch(robotsUrl);\n if (!response.ok) return true; // No robots.txt = allow all\n\n const content = await response.text();\n const robots = robotsParser(robotsUrl, content);\n\n return robots.isAllowed(url, userAgent) ?? true;\n } catch {\n return true; // Error fetching = allow\n }\n}\n","/**\n * @djangocfg/seo - Sitemap Validator\n * Validate XML sitemaps\n */\n\nimport { load } from 'cheerio';\nimport consola from 'consola';\nimport type { SeoIssue } from '../types/index.js';\n\nexport interface SitemapAnalysis {\n url: string;\n exists: boolean;\n type: 'sitemap' | 'sitemap-index' | 'unknown';\n urls: string[];\n childSitemaps: string[];\n lastmod?: string;\n issues: SeoIssue[];\n}\n\n/**\n * Analyze a sitemap URL\n */\nexport async function analyzeSitemap(sitemapUrl: string): Promise<SitemapAnalysis> {\n const analysis: SitemapAnalysis = {\n url: sitemapUrl,\n exists: false,\n type: 'unknown',\n urls: [],\n childSitemaps: [],\n issues: [],\n };\n\n try {\n const response = await fetch(sitemapUrl, {\n headers: {\n Accept: 'application/xml, text/xml, */*',\n },\n });\n\n if (!response.ok) {\n analysis.issues.push({\n id: `sitemap-not-found-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Sitemap not accessible',\n description: `Sitemap returned HTTP ${response.status}.`,\n recommendation: 'Ensure the sitemap URL is correct and accessible.',\n detectedAt: new Date().toISOString(),\n metadata: { statusCode: response.status },\n });\n return analysis;\n }\n\n analysis.exists = true;\n const content = await response.text();\n\n // Check content type\n const contentType = response.headers.get('content-type') || '';\n if (!contentType.includes('xml') && !content.trim().startsWith('<?xml')) {\n analysis.issues.push({\n id: `sitemap-not-xml-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Sitemap is not XML',\n description: 'The sitemap does not have an XML content type.',\n recommendation: 'Ensure sitemap is served with Content-Type: application/xml.',\n detectedAt: new Date().toISOString(),\n metadata: { contentType },\n });\n }\n\n // Parse XML\n const $ = load(content, { xmlMode: true });\n\n // Check if it's a sitemap index\n const sitemapIndex = $('sitemapindex');\n if (sitemapIndex.length > 0) {\n analysis.type = 'sitemap-index';\n\n $('sitemap').each((_, el) => {\n const loc = $('loc', el).text().trim();\n if (loc) {\n analysis.childSitemaps.push(loc);\n }\n });\n\n consola.debug(`Sitemap index contains ${analysis.childSitemaps.length} sitemaps`);\n } else {\n analysis.type = 'sitemap';\n\n $('url').each((_, el) => {\n const loc = $('loc', el).text().trim();\n if (loc) {\n analysis.urls.push(loc);\n }\n });\n\n const lastmod = $('url lastmod').first().text().trim();\n if (lastmod) {\n analysis.lastmod = lastmod;\n }\n\n consola.debug(`Sitemap contains ${analysis.urls.length} URLs`);\n }\n\n // Validate sitemap content\n if (analysis.type === 'sitemap' && analysis.urls.length === 0) {\n analysis.issues.push({\n id: `sitemap-empty-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'warning',\n title: 'Sitemap is empty',\n description: 'The sitemap contains no URLs.',\n recommendation: 'Add URLs to your sitemap or remove it if not needed.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n // Check for too many URLs (Google limit is 50,000)\n if (analysis.urls.length > 50000) {\n analysis.issues.push({\n id: `sitemap-too-large-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Sitemap exceeds URL limit',\n description: `Sitemap contains ${analysis.urls.length} URLs. Maximum is 50,000.`,\n recommendation: 'Split the sitemap into multiple files using a sitemap index.',\n detectedAt: new Date().toISOString(),\n metadata: { urlCount: analysis.urls.length },\n });\n }\n\n // Check file size (Google limit is 50MB uncompressed)\n const sizeInMB = new Blob([content]).size / (1024 * 1024);\n if (sizeInMB > 50) {\n analysis.issues.push({\n id: `sitemap-too-large-size-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Sitemap exceeds size limit',\n description: `Sitemap is ${sizeInMB.toFixed(2)}MB. Maximum is 50MB.`,\n recommendation: 'Split the sitemap or compress it.',\n detectedAt: new Date().toISOString(),\n metadata: { sizeMB: sizeInMB },\n });\n }\n } catch (error) {\n consola.error('Failed to analyze sitemap:', error);\n analysis.issues.push({\n id: `sitemap-error-${hash(sitemapUrl)}`,\n url: sitemapUrl,\n category: 'technical',\n severity: 'error',\n title: 'Failed to parse sitemap',\n description: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,\n recommendation: 'Check sitemap validity using Google Search Console.',\n detectedAt: new Date().toISOString(),\n });\n }\n\n return analysis;\n}\n\n/**\n * Recursively analyze a sitemap and all its children\n */\nexport async function analyzeAllSitemaps(\n sitemapUrl: string,\n maxDepth = 3\n): Promise<SitemapAnalysis[]> {\n const results: SitemapAnalysis[] = [];\n const visited = new Set<string>();\n\n async function analyze(url: string, depth: number): Promise<void> {\n if (depth > maxDepth || visited.has(url)) return;\n visited.add(url);\n\n const analysis = await analyzeSitemap(url);\n results.push(analysis);\n\n // Recursively analyze child sitemaps\n for (const childUrl of analysis.childSitemaps) {\n await analyze(childUrl, depth + 1);\n }\n }\n\n await analyze(sitemapUrl, 0);\n return results;\n}\n\nfunction hash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n"]}
package/dist/index.mjs CHANGED
@@ -898,6 +898,22 @@ async function analyzeRobotsTxt(siteUrl) {
898
898
  }
899
899
  analysis.exists = true;
900
900
  analysis.content = await response.text();
901
+ if (analysis.content.includes("content-signal") || analysis.content.includes("Content-Signal") || analysis.content.includes("ai-input") || analysis.content.includes("ai-train")) {
902
+ analysis.issues.push({
903
+ id: "cloudflare-managed-robots",
904
+ url: robotsUrl,
905
+ category: "technical",
906
+ severity: "warning",
907
+ title: "Cloudflare managed robots.txt detected",
908
+ description: `Your robots.txt is being overwritten by Cloudflare's "Content Signals Policy". Your app/robots.ts file is not being served.`,
909
+ recommendation: 'Disable in Cloudflare Dashboard: Security \u2192 Settings \u2192 "Manage your robots.txt" \u2192 Set to "Off".',
910
+ detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
911
+ metadata: {
912
+ cloudflareFeature: "Managed robots.txt",
913
+ docsUrl: "https://developers.cloudflare.com/bots/additional-configurations/managed-robots-txt/"
914
+ }
915
+ });
916
+ }
901
917
  const robots = robotsParser(robotsUrl, analysis.content);
902
918
  analysis.sitemaps = robots.getSitemaps();
903
919
  if (analysis.sitemaps.length === 0) {
@@ -1757,6 +1773,65 @@ function generateClaudeContext(report) {
1757
1773
  lines.push("- Parallel `@folder` - skipped");
1758
1774
  lines.push("- Private `_folder` - skipped");
1759
1775
  lines.push("");
1776
+ lines.push("## SEO Files (Next.js App Router)");
1777
+ lines.push("");
1778
+ lines.push("**Required files in `app/`:**");
1779
+ lines.push("");
1780
+ lines.push("### sitemap.xml/route.ts");
1781
+ lines.push("```typescript");
1782
+ lines.push("import { createSitemapHandler } from '@djangocfg/nextjs/sitemap';");
1783
+ lines.push("");
1784
+ lines.push('export const dynamic = "force-static";');
1785
+ lines.push("export const { GET } = createSitemapHandler({");
1786
+ lines.push(" siteUrl,");
1787
+ lines.push(" staticPages: [");
1788
+ lines.push(' { loc: "/", priority: 1.0, changefreq: "daily" },');
1789
+ lines.push(' { loc: "/about", priority: 0.8 },');
1790
+ lines.push(" ],");
1791
+ lines.push(" dynamicPages: async () => fetchPagesFromAPI(),");
1792
+ lines.push("});");
1793
+ lines.push("```");
1794
+ lines.push("");
1795
+ lines.push("### robots.ts");
1796
+ lines.push("```typescript");
1797
+ lines.push("import type { MetadataRoute } from 'next';");
1798
+ lines.push("");
1799
+ lines.push("export default function robots(): MetadataRoute.Robots {");
1800
+ lines.push(" return {");
1801
+ lines.push(' rules: { userAgent: "*", allow: "/" },');
1802
+ lines.push(" sitemap: `${siteUrl}/sitemap.xml`,");
1803
+ lines.push(" };");
1804
+ lines.push("}");
1805
+ lines.push("```");
1806
+ lines.push("");
1807
+ lines.push("### Cloudflare Override");
1808
+ lines.push("");
1809
+ lines.push('If robots.txt shows "Content-Signal" or "ai-train" \u2014 Cloudflare is overriding your file.');
1810
+ lines.push('**Fix:** Dashboard \u2192 Security \u2192 Settings \u2192 "Manage your robots.txt" \u2192 Set to "Off"');
1811
+ lines.push("");
1812
+ lines.push("### Declarative Routes with SEO");
1813
+ lines.push("");
1814
+ lines.push("Create `app/_routes/` with SEO metadata for sitemap:");
1815
+ lines.push("```typescript");
1816
+ lines.push("import { defineRoute } from '@djangocfg/nextjs/navigation';");
1817
+ lines.push("");
1818
+ lines.push("export const home = defineRoute('/', {");
1819
+ lines.push(" label: 'Home',");
1820
+ lines.push(" protected: false,");
1821
+ lines.push(" priority: 1.0, // Sitemap priority 0.0-1.0");
1822
+ lines.push(" changefreq: 'daily', // always|hourly|daily|weekly|monthly|yearly|never");
1823
+ lines.push(" noindex: false, // Exclude from sitemap");
1824
+ lines.push("});");
1825
+ lines.push("");
1826
+ lines.push("export const staticRoutes = [home, about, contact];");
1827
+ lines.push("```");
1828
+ lines.push("");
1829
+ lines.push("Then in `sitemap.xml/route.ts`:");
1830
+ lines.push("```typescript");
1831
+ lines.push("import { routes } from '@/app/_routes';");
1832
+ lines.push("routes.getAllStaticRoutes().filter(r => !r.metadata.noindex)");
1833
+ lines.push("```");
1834
+ lines.push("");
1760
1835
  lines.push("## Link Guidelines");
1761
1836
  lines.push("");
1762
1837
  lines.push("### Nextra/MDX Projects (content/)");