| Server IP : 159.203.156.69 / Your IP : 216.73.217.172 Web Server : nginx/1.24.0 System : Linux main-ubuntu 6.8.0-71-generic #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025 x86_64 User : root ( 0) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/tanviranik.com/node_modules/vinext/dist/server/ |
Upload File : |
{"version":3,"file":"metadata-routes.js","names":[],"sources":["../../src/server/metadata-routes.ts"],"sourcesContent":["/**\n * File-based metadata route handling.\n *\n * Next.js supports special files in the app/ directory that auto-generate\n * metadata routes:\n * - sitemap.ts/.xml → /sitemap.xml (application/xml)\n * - robots.ts/.txt → /robots.txt (text/plain)\n * - manifest.ts/.json/.webmanifest → /manifest.webmanifest (application/manifest+json)\n * - icon.tsx/.png → /icon (image/*)\n * - opengraph-image.tsx/.png → /opengraph-image (image/*)\n * - twitter-image.tsx/.png → /twitter-image (image/*)\n * - apple-icon.tsx/.png → /apple-icon (image/*)\n * - favicon.ico → /favicon.ico (image/x-icon)\n *\n * Dynamic versions (ts/tsx/js) export a default function that returns the data.\n * Static versions (xml/txt/json/png/etc.) are served as-is.\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { matchRoutePattern } from \"../routing/route-pattern.js\";\n\n// -------------------------------------------------------------------\n// Types matching Next.js MetadataRoute\n// -------------------------------------------------------------------\n\nexport type SitemapEntry = {\n url: string;\n lastModified?: string | Date;\n changeFrequency?: \"always\" | \"hourly\" | \"daily\" | \"weekly\" | \"monthly\" | \"yearly\" | \"never\";\n priority?: number;\n alternates?: {\n languages?: Record<string, string>;\n };\n images?: string[];\n videos?: Array<{\n title: string;\n thumbnail_loc: string;\n description: string;\n content_loc?: string;\n player_loc?: string;\n duration?: number;\n expiration_date?: string | Date;\n rating?: number;\n view_count?: number;\n publication_date?: string | Date;\n family_friendly?: \"yes\" | \"no\";\n restriction?: { relationship: \"allow\" | \"deny\"; content: string };\n platform?: { relationship: \"allow\" | \"deny\"; content: string };\n requires_subscription?: \"yes\" | \"no\";\n uploader?: {\n info?: string;\n content?: string;\n };\n live?: \"yes\" | \"no\";\n tag?: string;\n }>;\n};\n\nexport type RobotsRule = {\n userAgent?: string | string[];\n allow?: string | string[];\n disallow?: string | string[];\n crawlDelay?: number;\n other?: Record<string, string | number | Array<string | number>>;\n};\n\nexport type RobotsConfig = {\n rules: RobotsRule | RobotsRule[];\n sitemap?: string | string[];\n host?: string;\n};\n\nexport type ManifestConfig = {\n name?: string;\n short_name?: string;\n description?: string;\n start_url?: string;\n display?: \"fullscreen\" | \"standalone\" | \"minimal-ui\" | \"browser\";\n background_color?: string;\n theme_color?: string;\n icons?: Array<{\n src: string;\n sizes?: string;\n type?: string;\n purpose?: string;\n }>;\n [key: string]: unknown;\n};\n\n// -------------------------------------------------------------------\n// Known metadata file patterns\n// -------------------------------------------------------------------\n\n/** Map of metadata file base names to their URL path and content type. */\nexport const METADATA_FILE_MAP: Record<\n string,\n {\n /** URL path this file is served at */\n urlPath: string;\n /** Content type for the response */\n contentType: string;\n /** Whether this can be dynamic (.ts/.tsx/.js) */\n canBeDynamic: boolean;\n /** File extensions for static variants */\n staticExtensions: string[];\n /** File extensions for dynamic variants */\n dynamicExtensions: string[];\n /** Whether this can be nested in sub-segments */\n nestable: boolean;\n }\n> = {\n sitemap: {\n urlPath: \"/sitemap.xml\",\n contentType: \"application/xml\",\n canBeDynamic: true,\n staticExtensions: [\".xml\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: true,\n },\n robots: {\n urlPath: \"/robots.txt\",\n contentType: \"text/plain\",\n canBeDynamic: true,\n staticExtensions: [\".txt\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: false,\n },\n manifest: {\n urlPath: \"/manifest.webmanifest\",\n contentType: \"application/manifest+json\",\n canBeDynamic: true,\n staticExtensions: [\".json\", \".webmanifest\"],\n dynamicExtensions: [\".ts\", \".js\"],\n nestable: false,\n },\n favicon: {\n urlPath: \"/favicon.ico\",\n contentType: \"image/x-icon\",\n canBeDynamic: false,\n staticExtensions: [\".ico\"],\n dynamicExtensions: [],\n nestable: false,\n },\n icon: {\n urlPath: \"/icon\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".ico\", \".jpg\", \".jpeg\", \".png\", \".svg\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"opengraph-image\": {\n urlPath: \"/opengraph-image\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\", \".gif\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"twitter-image\": {\n urlPath: \"/twitter-image\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\", \".gif\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n \"apple-icon\": {\n urlPath: \"/apple-icon\",\n contentType: \"image/png\",\n canBeDynamic: true,\n staticExtensions: [\".jpg\", \".jpeg\", \".png\"],\n dynamicExtensions: [\".ts\", \".tsx\", \".js\"],\n nestable: true,\n },\n};\n\n// -------------------------------------------------------------------\n// Serializers\n// -------------------------------------------------------------------\n\n/** Escape the five XML special characters in text content and attribute values. */\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Convert a sitemap array to XML string.\n */\nexport function sitemapToXml(entries: SitemapEntry[]): string {\n const hasAlternates = entries.some((entry) => Object.keys(entry.alternates ?? {}).length > 0);\n const hasImages = entries.some((entry) => Boolean(entry.images?.length));\n const hasVideos = entries.some((entry) => Boolean(entry.videos?.length));\n let content = \"\";\n\n content += '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\n content += '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n if (hasImages) {\n content += ' xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"';\n }\n if (hasVideos) {\n content += ' xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\"';\n }\n if (hasAlternates) {\n content += ' xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">\\n';\n } else {\n content += \">\\n\";\n }\n\n for (const entry of entries) {\n content += \"<url>\\n\";\n content += `<loc>${escapeXml(entry.url)}</loc>\\n`;\n\n const languages = entry.alternates?.languages;\n if (languages && Object.keys(languages).length) {\n for (const language in languages) {\n content += `<xhtml:link rel=\"alternate\" hreflang=\"${escapeXml(language)}\" href=\"${escapeXml(languages[language])}\" />\\n`;\n }\n }\n\n if (entry.images?.length) {\n for (const image of entry.images) {\n content += `<image:image>\\n<image:loc>${escapeXml(image)}</image:loc>\\n</image:image>\\n`;\n }\n }\n\n if (entry.videos?.length) {\n for (const video of entry.videos) {\n const videoFields = [\n \"<video:video>\",\n `<video:title>${escapeXml(String(video.title))}</video:title>`,\n `<video:thumbnail_loc>${escapeXml(String(video.thumbnail_loc))}</video:thumbnail_loc>`,\n `<video:description>${escapeXml(String(video.description))}</video:description>`,\n video.content_loc &&\n `<video:content_loc>${escapeXml(String(video.content_loc))}</video:content_loc>`,\n video.player_loc &&\n `<video:player_loc>${escapeXml(String(video.player_loc))}</video:player_loc>`,\n video.duration && `<video:duration>${video.duration}</video:duration>`,\n video.view_count && `<video:view_count>${video.view_count}</video:view_count>`,\n video.tag && `<video:tag>${escapeXml(String(video.tag))}</video:tag>`,\n video.rating && `<video:rating>${video.rating}</video:rating>`,\n video.expiration_date &&\n `<video:expiration_date>${escapeXml(String(video.expiration_date))}</video:expiration_date>`,\n video.publication_date &&\n `<video:publication_date>${escapeXml(String(video.publication_date))}</video:publication_date>`,\n video.family_friendly &&\n `<video:family_friendly>${video.family_friendly}</video:family_friendly>`,\n video.requires_subscription &&\n `<video:requires_subscription>${video.requires_subscription}</video:requires_subscription>`,\n video.live && `<video:live>${video.live}</video:live>`,\n video.restriction &&\n `<video:restriction relationship=\"${escapeXml(String(video.restriction.relationship))}\">${escapeXml(String(video.restriction.content))}</video:restriction>`,\n video.platform &&\n `<video:platform relationship=\"${escapeXml(String(video.platform.relationship))}\">${escapeXml(String(video.platform.content))}</video:platform>`,\n video.uploader &&\n `<video:uploader${video.uploader.info ? ` info=\"${escapeXml(String(video.uploader.info))}\"` : \"\"}>${escapeXml(String(video.uploader.content))}</video:uploader>`,\n \"</video:video>\\n\",\n ].filter(Boolean);\n content += videoFields.join(\"\\n\");\n }\n }\n\n if (entry.lastModified) {\n content += `<lastmod>${serializeDate(entry.lastModified)}</lastmod>\\n`;\n }\n if (entry.changeFrequency) {\n content += `<changefreq>${entry.changeFrequency}</changefreq>\\n`;\n }\n if (typeof entry.priority === \"number\") {\n content += `<priority>${entry.priority}</priority>\\n`;\n }\n content += \"</url>\\n\";\n }\n\n content += \"</urlset>\\n\";\n return content;\n}\n\n/**\n * Convert a robots config to text format.\n */\nexport function robotsToText(config: RobotsConfig): string {\n const lines: string[] = [];\n const rules = Array.isArray(config.rules) ? config.rules : [config.rules];\n\n for (const rule of rules) {\n const agents = Array.isArray(rule.userAgent) ? rule.userAgent : [rule.userAgent ?? \"*\"];\n\n for (const agent of agents) {\n lines.push(`User-Agent: ${agent}`);\n }\n\n if (rule.allow) {\n const allows = Array.isArray(rule.allow) ? rule.allow : [rule.allow];\n for (const allow of allows) {\n lines.push(`Allow: ${allow}`);\n }\n }\n\n if (rule.disallow) {\n const disallows = Array.isArray(rule.disallow) ? rule.disallow : [rule.disallow];\n for (const disallow of disallows) {\n lines.push(`Disallow: ${disallow}`);\n }\n }\n\n if (rule.crawlDelay !== undefined) {\n lines.push(`Crawl-delay: ${rule.crawlDelay}`);\n }\n\n if (rule.other) {\n for (const key of Object.keys(rule.other)) {\n const value = rule.other[key];\n if (value == null) continue;\n const values = Array.isArray(value) ? value : [value];\n for (const v of values) {\n lines.push(`${key}: ${v}`);\n }\n }\n }\n\n lines.push(\"\");\n }\n\n if (config.sitemap) {\n const sitemaps = Array.isArray(config.sitemap) ? config.sitemap : [config.sitemap];\n for (const sitemap of sitemaps) {\n lines.push(`Sitemap: ${sitemap}`);\n }\n }\n\n if (config.host) {\n lines.push(`Host: ${config.host}`);\n }\n\n return lines.join(\"\\n\").trim() + \"\\n\";\n}\n\n/**\n * Convert a manifest config to JSON string.\n */\nexport function manifestToJson(config: ManifestConfig): string {\n return JSON.stringify(config, null, 2);\n}\n\nfunction serializeDate(value: string | Date): string {\n return value instanceof Date ? value.toISOString() : value;\n}\n\n// -------------------------------------------------------------------\n// Static metadata URL resolution\n//\n// Ported from Next.js: packages/next/src/lib/metadata/get-metadata-route.ts\n// https://github.com/vercel/next.js/blob/7873aea/packages/next/src/lib/metadata/get-metadata-route.ts\n//\n// Static metadata files (like favicon.ico, icon.png) under dynamic parents\n// get a fixed URL with \"-\" placeholders instead of literal \"[param]\" segments.\n// Route groups and parallel route parents trigger a unique hash suffix to\n// avoid collisions.\n// -------------------------------------------------------------------\n\n/**\n * Regular expression pattern used to match route parameters.\n * Matches both single parameters and parameter groups.\n * Examples:\n * - `[[...slug]]` matches parameter group with key 'slug', repeat: true, optional: true\n * - `[...slug]` matches parameter group with key 'slug', repeat: true, optional: false\n * - `[[foo]]` matches parameter with key 'foo', repeat: false, optional: true\n * - `[bar]` matches parameter with key 'bar', repeat: false, optional: false\n */\nconst PARAMETER_PATTERN = /^([^[]*)\\[((?:\\[[^\\]]*\\])|[^\\]]+)\\](.*)$/;\n\nfunction isGroupSegment(segment: string): boolean {\n return segment.startsWith(\"(\") && segment.endsWith(\")\");\n}\n\nfunction isParallelRouteSegment(segment: string): boolean {\n return segment.startsWith(\"@\") && segment !== \"@children\";\n}\n\nfunction normalizeStaticMetadataRouteSegment(segment: string): string {\n let normalizedSegment = segment;\n let match = normalizedSegment.match(PARAMETER_PATTERN);\n while (match) {\n normalizedSegment = `${match[1]}-${match[3]}`;\n match = normalizedSegment.match(PARAMETER_PATTERN);\n }\n return normalizedSegment;\n}\n\nfunction getStaticMetadataRoute(appDirPath: string): string {\n const segments = appDirPath.split(\"/\").filter(Boolean);\n const normalizedSegments: string[] = [];\n for (const seg of segments) {\n // Strip route groups and all parallel route slots (including @children)\n // from the URL path. The @children slot is the default parallel route\n // and must also be invisible in the URL, matching Next.js behavior.\n if (isGroupSegment(seg) || seg.startsWith(\"@\")) continue;\n normalizedSegments.push(normalizeStaticMetadataRouteSegment(seg));\n }\n return normalizedSegments.length > 0 ? `/${normalizedSegments.join(\"/\")}` : \"\";\n}\n\nfunction hashMetadataRouteParentPath(parentPathname: string): string {\n let hash = 5381;\n for (let i = 0; i < parentPathname.length; i++) {\n hash = ((hash << 5) + hash + parentPathname.charCodeAt(i)) & 0xffffffff;\n }\n return (hash >>> 0).toString(36).slice(0, 6);\n}\n\nfunction getMetadataRouteSuffix(page: string): string {\n const lastSlash = page.lastIndexOf(\"/\");\n const parentPathname = lastSlash > 0 ? page.slice(0, lastSlash) : \"\";\n if (page.endsWith(\"/sitemap\") || page.endsWith(\"/sitemap.xml\")) return \"\";\n const segments = parentPathname.split(\"/\");\n const hasInvisibleParent = segments.some(\n (seg) => isGroupSegment(seg) || isParallelRouteSegment(seg),\n );\n if (!hasInvisibleParent) return \"\";\n return hashMetadataRouteParentPath(parentPathname);\n}\n\nfunction computeMetadataRouteSuffix(\n appDirPath: string,\n leafName: string,\n): { route: string; suffix: string } {\n const route = getStaticMetadataRoute(appDirPath);\n const pagePath =\n appDirPath === \"\" || appDirPath === \"/\" ? `/${leafName}` : `${appDirPath}/${leafName}`;\n const suffix = getMetadataRouteSuffix(pagePath);\n return { route, suffix };\n}\n\nfunction getMetadataRouteFilename(appDirPath: string, lastSegment: string): string {\n const ext = path.posix.extname(lastSegment);\n const name = lastSegment.slice(0, -ext.length || undefined);\n const { suffix } = computeMetadataRouteSuffix(appDirPath, name);\n const routeSuffix = suffix ? `-${suffix}` : \"\";\n return `${name}${routeSuffix}${ext}`;\n}\n\n/**\n * Compute the static URL for a metadata file given its app directory\n * parent path and filename.\n *\n * Example:\n * fillStaticMetadataSegment(\"/\", \"favicon.ico\") -> \"/favicon.ico\"\n * fillStaticMetadataSegment(\"/blog/[slug]\", \"favicon.ico\") -> \"/blog/-/favicon.ico\"\n * fillStaticMetadataSegment(\"/(group)/group\", \"icon.png\") -> \"/group/icon-131tc6.png\"\n */\nexport function fillStaticMetadataSegment(appDirPath: string, lastSegment: string): string {\n const route = getStaticMetadataRoute(appDirPath);\n const filename = getMetadataRouteFilename(appDirPath, lastSegment);\n return route === \"\" ? `/${filename}` : `${route}/${filename}`;\n}\n\n// -------------------------------------------------------------------\n// Metadata route discovery\n// -------------------------------------------------------------------\n\nexport type MetadataFileRoute = {\n /** Type of metadata file */\n type: string;\n /** Whether this is a dynamic (code-generated) route */\n isDynamic: boolean;\n /** Imported dynamic module for code-generated metadata routes. */\n module?: Record<string, unknown>;\n /** Absolute file path */\n filePath: string;\n /** Route prefix where this metadata applies, preserving dynamic segment names. */\n routePrefix: string;\n /** Raw app tree segments where this metadata file is colocated. */\n routeSegments?: string[];\n /** Pattern parts for matching dynamic metadata routes at request time. */\n patternParts?: string[];\n /** URL path this file is served at */\n servedUrl: string;\n /** Content type for the response */\n contentType: string;\n /** Optional metadata used to inject file-based routes into <head>. */\n headData?: MetadataRouteHeadData;\n /** Optional content hash for cache-busting metadata links. */\n contentHash?: string;\n /** Sibling .alt.txt file for static social image metadata routes. */\n altFilePath?: string;\n};\n\nexport type MetadataRouteHeadData =\n | {\n kind: \"favicon\" | \"icon\" | \"apple\";\n href: string;\n type?: string;\n sizes?: string;\n }\n | {\n kind: \"openGraph\" | \"twitter\";\n href: string;\n type?: string;\n width?: number;\n height?: number;\n alt?: string;\n }\n | {\n kind: \"manifest\";\n href: string;\n };\n\nexport function getMetadataRouteKind(\n route: Pick<MetadataFileRoute, \"type\">,\n): MetadataRouteHeadData[\"kind\"] | null {\n if (route.type === \"favicon\") return \"favicon\";\n if (route.type === \"icon\") return \"icon\";\n if (route.type === \"apple-icon\") return \"apple\";\n if (route.type === \"opengraph-image\") return \"openGraph\";\n if (route.type === \"twitter-image\") return \"twitter\";\n if (route.type === \"manifest\") return \"manifest\";\n return null;\n}\n\nexport function getMetadataImageRouteKind(\n route: Pick<MetadataFileRoute, \"type\">,\n): Extract<MetadataRouteHeadData[\"kind\"], \"icon\" | \"apple\" | \"openGraph\" | \"twitter\"> | null {\n const kind = getMetadataRouteKind(route);\n if (kind === \"icon\" || kind === \"apple\" || kind === \"openGraph\" || kind === \"twitter\") {\n return kind;\n }\n return null;\n}\n\nconst metadataImageIdPattern = /^[a-zA-Z0-9-_.]+$/;\n\nexport function isValidMetadataImageId(id: string): boolean {\n return metadataImageIdPattern.test(id);\n}\n\nexport function matchMetadataRoutePattern(\n urlParts: string[],\n patternParts: string[],\n): Record<string, string | string[]> | null {\n return matchRoutePattern(urlParts, patternParts);\n}\n\nfunction metadataRouteSuffix(parentSegments: string[], metaType: string): string {\n if (metaType === \"sitemap\") {\n // Sitemap is exempt per Next.js (robots/manifest are root-only, so\n // invisible parents never apply — but we keep the exemption list\n // matching getMetadataRouteSuffix for defensive consistency).\n return \"\";\n }\n\n const hasInvisibleParent = parentSegments.some(\n (segment) =>\n (segment.startsWith(\"(\") && segment.endsWith(\")\")) ||\n (segment.startsWith(\"@\") && segment !== \"@children\"),\n );\n if (!hasInvisibleParent) return \"\";\n\n return hashMetadataRouteParentPath(`/${parentSegments.join(\"/\")}`);\n}\n\nfunction withMetadataSuffix(urlPath: string, suffix: string): string {\n if (!suffix) return urlPath;\n const parsed = path.posix.parse(urlPath);\n return path.posix.join(parsed.dir || \"/\", `${parsed.name}-${suffix}${parsed.ext}`);\n}\n\nfunction getMetadataServedUrl(\n metaType: string,\n config: { urlPath: string },\n ext: string,\n isDynamic: boolean,\n suffix: string,\n routeBaseName: string,\n): string {\n if (\n isDynamic &&\n (metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\")\n ) {\n return withMetadataSuffix(`/${routeBaseName}`, suffix);\n }\n\n if (isDynamic) {\n return withMetadataSuffix(config.urlPath, suffix);\n }\n\n if (metaType === \"manifest\") {\n return withMetadataSuffix(`/${routeBaseName}${ext}`, suffix);\n }\n\n if (\n metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\"\n ) {\n return withMetadataSuffix(`/${routeBaseName}${ext}`, suffix);\n }\n\n return withMetadataSuffix(config.urlPath, suffix);\n}\n\nexport function matchMetadataFileBaseName(metaType: string, baseName: string): string | null {\n if (baseName === metaType) {\n return baseName;\n }\n\n if (\n metaType === \"icon\" ||\n metaType === \"apple-icon\" ||\n metaType === \"opengraph-image\" ||\n metaType === \"twitter-image\"\n ) {\n const suffix = baseName.slice(metaType.length);\n if (/^\\d$/.test(suffix)) {\n return baseName;\n }\n }\n\n return null;\n}\n\n/**\n * Scan an app directory for metadata files.\n */\nexport function scanMetadataFiles(appDir: string): MetadataFileRoute[] {\n const routes: MetadataFileRoute[] = [];\n\n // Scan the app directory recursively\n function scan(dir: string, urlPrefix: string, parentSegments: string[]): void {\n if (!fs.existsSync(dir)) return;\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const dirName = entry.name;\n if (dirName.startsWith(\"_\")) continue;\n\n const isRouteGroup = dirName.startsWith(\"(\") && dirName.endsWith(\")\");\n const isParallelRoute = dirName.startsWith(\"@\");\n const nextUrlPrefix =\n isRouteGroup || isParallelRoute ? urlPrefix : `${urlPrefix}/${dirName}`;\n scan(path.join(dir, dirName), nextUrlPrefix, [...parentSegments, dirName]);\n continue;\n }\n\n // Check each metadata file pattern\n const fileName = entry.name;\n const baseName = fileName.replace(/\\.[^.]+$/, \"\");\n const ext = fileName.slice(baseName.length);\n\n for (const [metaType, config] of Object.entries(METADATA_FILE_MAP)) {\n const routeBaseName = matchMetadataFileBaseName(metaType, baseName);\n if (!routeBaseName) continue;\n\n // Check nestability — non-nestable types only at root\n if (!config.nestable && urlPrefix !== \"\") continue;\n\n // Check if this is a static or dynamic variant\n const isStatic = config.staticExtensions.includes(ext);\n const isDynamic = config.dynamicExtensions.includes(ext);\n\n if (!isStatic && !isDynamic) continue;\n const appDirPath = parentSegments.length > 0 ? `/${parentSegments.join(\"/\")}` : \"\";\n const suffix = metadataRouteSuffix(parentSegments, metaType);\n const urlPath = getMetadataServedUrl(\n metaType,\n config,\n ext,\n isDynamic,\n suffix,\n routeBaseName,\n );\n const servedUrl = isStatic\n ? fillStaticMetadataSegment(appDirPath, `${routeBaseName}${ext}`)\n : urlPrefix === \"\"\n ? urlPath\n : `${urlPrefix}${urlPath}`;\n const altFilePath =\n isStatic && (metaType === \"opengraph-image\" || metaType === \"twitter-image\")\n ? resolveStaticMetadataAltFilePath(dir, baseName)\n : undefined;\n\n routes.push({\n type: metaType,\n isDynamic,\n filePath: path.join(dir, fileName),\n routePrefix: urlPrefix,\n routeSegments: parentSegments,\n servedUrl,\n contentType:\n isStatic && metaType === \"manifest\"\n ? config.contentType\n : isStatic\n ? getStaticContentType(ext, config.contentType)\n : config.contentType,\n altFilePath,\n });\n }\n }\n }\n\n scan(appDir, \"\", []);\n\n // Deduplicate: if both dynamic and static variants exist at the same URL,\n // keep only the dynamic one (matches Next.js behavior).\n const byUrl = new Map<string, MetadataFileRoute>();\n for (const route of routes) {\n const existing = byUrl.get(route.servedUrl);\n if (!existing) {\n byUrl.set(route.servedUrl, route);\n } else if (route.isDynamic && !existing.isDynamic) {\n // Dynamic takes priority over static\n byUrl.set(route.servedUrl, route);\n }\n // If both are static or both dynamic, keep the first one found\n }\n return Array.from(byUrl.values());\n}\n\nfunction resolveStaticMetadataAltFilePath(dir: string, baseName: string): string | undefined {\n const altPath = path.join(dir, `${baseName}.alt.txt`);\n return fs.existsSync(altPath) ? altPath : undefined;\n}\n\nfunction getStaticContentType(ext: string, fallback: string): string {\n const map: Record<string, string> = {\n \".xml\": \"application/xml\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n \".webmanifest\": \"application/manifest+json\",\n \".ico\": \"image/x-icon\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n };\n return map[ext] ?? fallback;\n}\n"],"mappings":"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"}