@ox-content/vite-plugin 2.80.0 → 2.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/incremental-dom.cjs +3 -2
  2. package/dist/incremental-dom.cjs.map +1 -1
  3. package/dist/incremental-dom.d.cts.map +1 -1
  4. package/dist/incremental-dom.d.mts.map +1 -1
  5. package/dist/incremental-dom.mjs +2 -1
  6. package/dist/incremental-dom.mjs.map +1 -1
  7. package/dist/index.cjs +1486 -99
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +8 -13
  10. package/dist/index.d.cts.map +1 -1
  11. package/dist/index.d.mts +8 -13
  12. package/dist/index.d.mts.map +1 -1
  13. package/dist/index.mjs +1429 -69
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/interop.cjs.map +1 -1
  16. package/dist/interop.mjs.map +1 -1
  17. package/dist/tabs.cjs +3 -4
  18. package/dist/tabs.cjs.map +1 -1
  19. package/dist/tabs.mjs +99 -2
  20. package/dist/tabs.mjs.map +1 -0
  21. package/dist/vitepress-cli.cjs +5 -4
  22. package/dist/vitepress-cli.cjs.map +1 -1
  23. package/dist/vitepress-cli.d.cts +1 -1
  24. package/dist/vitepress-cli.d.mts +1 -1
  25. package/dist/vitepress-cli.mjs +4 -2
  26. package/dist/vitepress-cli.mjs.map +1 -1
  27. package/dist/vitepress.cjs +106 -2
  28. package/dist/vitepress.cjs.map +1 -1
  29. package/dist/vitepress.mjs +32 -2
  30. package/dist/vitepress.mjs.map +1 -1
  31. package/package.json +19 -19
  32. package/dist/chunk.cjs +0 -57
  33. package/dist/github.cjs +0 -690
  34. package/dist/github.cjs.map +0 -1
  35. package/dist/github.mjs +0 -625
  36. package/dist/github.mjs.map +0 -1
  37. package/dist/github2.mjs +0 -2
  38. package/dist/media.cjs +0 -310
  39. package/dist/media.cjs.map +0 -1
  40. package/dist/media.mjs +0 -302
  41. package/dist/media.mjs.map +0 -1
  42. package/dist/media2.mjs +0 -2
  43. package/dist/mermaid.cjs +0 -114
  44. package/dist/mermaid.cjs.map +0 -1
  45. package/dist/mermaid.mjs +0 -2
  46. package/dist/mermaid2.mjs +0 -92
  47. package/dist/mermaid2.mjs.map +0 -1
  48. package/dist/napi.cjs +0 -45
  49. package/dist/napi.cjs.map +0 -1
  50. package/dist/napi.mjs +0 -34
  51. package/dist/napi.mjs.map +0 -1
  52. package/dist/ogp.cjs +0 -341
  53. package/dist/ogp.cjs.map +0 -1
  54. package/dist/ogp.mjs +0 -2
  55. package/dist/ogp2.mjs +0 -302
  56. package/dist/ogp2.mjs.map +0 -1
  57. package/dist/pm.cjs +0 -45
  58. package/dist/pm.cjs.map +0 -1
  59. package/dist/pm.mjs +0 -2
  60. package/dist/pm2.mjs +0 -38
  61. package/dist/pm2.mjs.map +0 -1
  62. package/dist/tabs2.mjs +0 -56
  63. package/dist/tabs2.mjs.map +0 -1
  64. package/dist/youtube.cjs +0 -57
  65. package/dist/youtube.cjs.map +0 -1
  66. package/dist/youtube.mjs +0 -2
  67. package/dist/youtube2.mjs +0 -35
  68. package/dist/youtube2.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"github.mjs","names":[],"sources":["../src/plugins/github/validation.ts","../src/plugins/github/source.ts","../src/plugins/github/types.ts","../src/plugins/github/api.ts","../src/plugins/github/attributes.ts","../src/plugins/github/fallback-card.ts","../src/plugins/github/repo-card.ts","../src/plugins/github/source-card.ts","../src/plugins/github/transform.ts"],"sourcesContent":["const GITHUB_REPO_RE = /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/;\n\nfunction hasControlChar(value: string): boolean {\n for (let index = 0; index < value.length; index++) {\n const code = value.charCodeAt(index);\n if (code <= 0x1f || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n\nexport function isSafeGitHubRepo(repo: string): boolean {\n return (\n GITHUB_REPO_RE.test(repo) && !repo.split(\"/\").some((part) => part === \".\" || part === \"..\")\n );\n}\n\nexport function isSafeGitHubRef(ref: string): boolean {\n return Boolean(ref) && !hasControlChar(ref) && !hasUnsafePathSegment(ref);\n}\n\nexport function isSafeGitHubPath(path: string): boolean {\n return Boolean(path) && !hasControlChar(path) && !hasUnsafePathSegment(path);\n}\n\nfunction hasUnsafePathSegment(value: string): boolean {\n return value\n .split(\"/\")\n .some((part) => !part || part === \".\" || part === \"..\" || part.includes(\"\\\\\"));\n}\n\nexport function encodePath(path: string): string {\n return path.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n","import type { GitHubLineRange, GitHubSourceRef } from \"./types\";\nimport { encodePath, isSafeGitHubPath, isSafeGitHubRef, isSafeGitHubRepo } from \"./validation\";\n\nconst EXTENSION_LANGUAGE_MAP = new Map<string, string>([\n [\"cjs\", \"javascript\"],\n [\"css\", \"css\"],\n [\"go\", \"go\"],\n [\"html\", \"html\"],\n [\"js\", \"javascript\"],\n [\"json\", \"json\"],\n [\"jsx\", \"jsx\"],\n [\"md\", \"markdown\"],\n [\"mdx\", \"mdx\"],\n [\"mjs\", \"javascript\"],\n [\"py\", \"python\"],\n [\"rb\", \"ruby\"],\n [\"rs\", \"rust\"],\n [\"sh\", \"shell\"],\n [\"svelte\", \"svelte\"],\n [\"toml\", \"toml\"],\n [\"ts\", \"typescript\"],\n [\"tsx\", \"tsx\"],\n [\"vue\", \"vue\"],\n [\"yaml\", \"yaml\"],\n [\"yml\", \"yaml\"],\n]);\n\nexport function sourceKey(source: GitHubSourceRef): string {\n return `${source.repo}@${source.ref}:${source.path}`;\n}\n\nexport function formatLineRange(lines: GitHubLineRange): string {\n return lines.start === lines.end ? `L${lines.start}` : `L${lines.start}-L${lines.end}`;\n}\n\nexport function parseGitHubLineRange(value: string | undefined): GitHubLineRange | undefined {\n if (!value) return undefined;\n const match = value.trim().match(/^#?L?(\\d+)(?:-L?(\\d+))?$/i);\n if (!match) return undefined;\n\n const start = Number.parseInt(match[1], 10);\n const end = match[2] ? Number.parseInt(match[2], 10) : start;\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 1 || end < start) {\n return undefined;\n }\n\n return { start, end };\n}\n\nexport function createGitHubPermalink(source: Omit<GitHubSourceRef, \"permalink\">): string {\n const fragment = source.lines ? `#${formatLineRange(source.lines)}` : \"\";\n return `https://github.com/${source.repo}/blob/${encodeURIComponent(source.ref)}/${encodePath(\n source.path,\n )}${fragment}`;\n}\n\nexport function parseGitHubPermalink(value: string): GitHubSourceRef | null {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n\n if (url.protocol !== \"https:\" || url.hostname !== \"github.com\") {\n return null;\n }\n\n let parts: string[];\n try {\n parts = url.pathname\n .split(\"/\")\n .filter(Boolean)\n .map((part) => decodeURIComponent(part));\n } catch {\n return null;\n }\n\n if (parts.length < 5 || parts[2] !== \"blob\") {\n return null;\n }\n\n const repo = `${parts[0]}/${parts[1]}`;\n const ref = parts[3];\n const path = parts.slice(4).join(\"/\");\n if (!isSafeGitHubRepo(repo) || !isSafeGitHubRef(ref) || !isSafeGitHubPath(path)) {\n return null;\n }\n\n const lines = parseGitHubLineRange(url.hash);\n const source = { repo, ref, path, lines };\n return {\n ...source,\n permalink: createGitHubPermalink(source),\n };\n}\n\nexport function inferLanguage(path: string): string | null {\n const fileName = path.split(\"/\").at(-1)?.toLowerCase() ?? \"\";\n if (fileName === \"dockerfile\") return \"dockerfile\";\n if (fileName === \"makefile\") return \"makefile\";\n\n const extension = fileName.includes(\".\") ? fileName.split(\".\").at(-1) : undefined;\n return extension ? (EXTENSION_LANGUAGE_MAP.get(extension) ?? extension) : null;\n}\n","export interface GitHubRepoData {\n name: string;\n full_name: string;\n description: string | null;\n html_url: string;\n stargazers_count: number;\n forks_count: number;\n language: string | null;\n owner: {\n login: string;\n avatar_url: string;\n };\n}\n\nexport interface GitHubLineRange {\n start: number;\n end: number;\n}\n\nexport interface GitHubSourceRef {\n repo: string;\n ref: string;\n path: string;\n permalink: string;\n lines?: GitHubLineRange;\n}\n\nexport interface GitHubSourceData {\n repo: string;\n ref: string;\n path: string;\n permalink: string;\n content: string;\n size: number;\n html_url: string;\n language: string | null;\n}\n\nexport interface GitHubOptions {\n /**\n * GitHub API token used for higher rate limits and private repository access.\n * @default ''\n */\n token?: string;\n\n /**\n * Cache fetched repository and source data in memory for the current process.\n * @default true\n */\n cache?: boolean;\n\n /**\n * Cache TTL in milliseconds.\n * @default 3600000\n */\n cacheTTL?: number;\n\n /**\n * Maximum source file size to inline in bytes.\n * @default 200000\n */\n maxSourceBytes?: number;\n\n /**\n * Maximum source lines to inline when no line range is specified.\n * @default 120\n */\n maxSourceLines?: number;\n}\n\nexport const defaultOptions: Required<GitHubOptions> = {\n token: \"\",\n cache: true,\n cacheTTL: 3600000,\n maxSourceBytes: 200000,\n maxSourceLines: 120,\n};\n","import { Buffer } from \"node:buffer\";\nimport { inferLanguage, sourceKey } from \"./source\";\nimport {\n defaultOptions,\n type GitHubOptions,\n type GitHubRepoData,\n type GitHubSourceData,\n type GitHubSourceRef,\n} from \"./types\";\nimport { encodePath, isSafeGitHubPath, isSafeGitHubRef, isSafeGitHubRepo } from \"./validation\";\n\nconst repoCache = new Map<string, { data: GitHubRepoData; timestamp: number }>();\nconst sourceCache = new Map<string, { data: GitHubSourceData; timestamp: number }>();\n\ninterface GitHubContentApiFile {\n type: string;\n encoding?: string;\n content?: string;\n size?: number;\n html_url?: string;\n}\n\nfunction githubHeaders(options: Required<GitHubOptions>): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n \"User-Agent\": \"ox-content-github-plugin\",\n };\n\n if (options.token) {\n headers.Authorization = `Bearer ${options.token}`;\n }\n\n return headers;\n}\n\n/**\n * Fetch repository data from GitHub API.\n */\nexport async function fetchRepoData(\n repo: string,\n options: Required<GitHubOptions>,\n): Promise<GitHubRepoData | null> {\n if (!isSafeGitHubRepo(repo)) {\n return null;\n }\n\n if (options.cache) {\n const cached = repoCache.get(repo);\n if (cached && Date.now() - cached.timestamp < options.cacheTTL) {\n return cached.data;\n }\n }\n\n try {\n const response = await fetch(`https://api.github.com/repos/${repo}`, {\n headers: githubHeaders(options),\n });\n\n if (!response.ok) {\n console.warn(`Failed to fetch GitHub repo ${repo}: ${response.status}`);\n return null;\n }\n\n const data = (await response.json()) as GitHubRepoData;\n if (options.cache) {\n repoCache.set(repo, { data, timestamp: Date.now() });\n }\n\n return data;\n } catch (error) {\n console.warn(`Error fetching GitHub repo ${repo}:`, error);\n return null;\n }\n}\n\n/**\n * Fetch source file data from GitHub API.\n */\nexport async function fetchGitHubSource(\n source: GitHubSourceRef,\n options: Required<GitHubOptions>,\n): Promise<GitHubSourceData | null> {\n if (\n !isSafeGitHubRepo(source.repo) ||\n !isSafeGitHubRef(source.ref) ||\n !isSafeGitHubPath(source.path)\n ) {\n return null;\n }\n\n const key = sourceKey(source);\n if (options.cache) {\n const cached = sourceCache.get(key);\n if (cached && Date.now() - cached.timestamp < options.cacheTTL) {\n return cached.data;\n }\n }\n\n try {\n const apiUrl = `https://api.github.com/repos/${source.repo}/contents/${encodePath(\n source.path,\n )}?ref=${encodeURIComponent(source.ref)}`;\n const response = await fetch(apiUrl, { headers: githubHeaders(options) });\n\n if (!response.ok) {\n console.warn(`Failed to fetch GitHub source ${source.permalink}: ${response.status}`);\n return null;\n }\n\n const data = (await response.json()) as GitHubContentApiFile;\n if (\n data.type !== \"file\" ||\n data.encoding !== \"base64\" ||\n !data.content ||\n (data.size ?? 0) > options.maxSourceBytes\n ) {\n return null;\n }\n\n const content = Buffer.from(data.content.replace(/\\s/g, \"\"), \"base64\").toString(\"utf8\");\n if (Buffer.byteLength(content) > options.maxSourceBytes) {\n return null;\n }\n\n const sourceData: GitHubSourceData = {\n repo: source.repo,\n ref: source.ref,\n path: source.path,\n permalink: source.permalink,\n content,\n size: data.size ?? Buffer.byteLength(content),\n html_url: data.html_url ?? source.permalink,\n language: inferLanguage(source.path),\n };\n\n if (options.cache) {\n sourceCache.set(key, { data: sourceData, timestamp: Date.now() });\n }\n\n return sourceData;\n } catch (error) {\n console.warn(`Error fetching GitHub source ${source.permalink}:`, error);\n return null;\n }\n}\n\n/**\n * Pre-fetch all GitHub repos data.\n */\nexport async function prefetchGitHubRepos(\n repos: string[],\n options?: GitHubOptions,\n): Promise<Map<string, GitHubRepoData | null>> {\n const mergedOptions = { ...defaultOptions, ...options };\n const results = new Map<string, GitHubRepoData | null>();\n\n await Promise.all(\n Array.from(new Set(repos)).map(async (repo) => {\n const data = await fetchRepoData(repo, mergedOptions);\n results.set(repo, data);\n }),\n );\n\n return results;\n}\n\n/**\n * Pre-fetch all GitHub source files.\n */\nexport async function prefetchGitHubSources(\n sources: GitHubSourceRef[],\n options?: GitHubOptions,\n): Promise<Map<string, GitHubSourceData | null>> {\n const mergedOptions = { ...defaultOptions, ...options };\n const results = new Map<string, GitHubSourceData | null>();\n const uniqueSources = Array.from(\n new Map(sources.map((source) => [sourceKey(source), source])).values(),\n );\n\n await Promise.all(\n uniqueSources.map(async (source) => {\n const data = await fetchGitHubSource(source, mergedOptions);\n results.set(sourceKey(source), data);\n }),\n );\n\n return results;\n}\n","import type { Element } from \"hast\";\nimport { createGitHubPermalink, parseGitHubLineRange, parseGitHubPermalink } from \"./source\";\nimport type { GitHubSourceRef } from \"./types\";\nimport { isSafeGitHubPath, isSafeGitHubRef, isSafeGitHubRepo } from \"./validation\";\n\nconst GITHUB_COMPONENT_RE = /<github\\b([^>]*)>/gi;\nconst ATTRIBUTE_RE = /([:\\w-]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'>/]+)))?/g;\n\n/**\n * Collect all GitHub repos from HTML for pre-fetching.\n */\nexport async function collectGitHubRepos(html: string): Promise<string[]> {\n const repos: string[] = [];\n\n GITHUB_COMPONENT_RE.lastIndex = 0;\n let match;\n while ((match = GITHUB_COMPONENT_RE.exec(html)) !== null) {\n const attrs = parseAttributes(match[1]);\n if (attrs.path || attrs.file || attrs.permalink || attrs.url || attrs.href) {\n continue;\n }\n\n const repo = attrs.repo;\n if (repo && isSafeGitHubRepo(repo)) {\n repos.push(repo);\n }\n }\n\n return repos;\n}\n\n/**\n * Collect all GitHub source references from HTML for pre-fetching.\n */\nexport async function collectGitHubSources(html: string): Promise<GitHubSourceRef[]> {\n const sources: GitHubSourceRef[] = [];\n\n GITHUB_COMPONENT_RE.lastIndex = 0;\n let match;\n while ((match = GITHUB_COMPONENT_RE.exec(html)) !== null) {\n const source = sourceRefFromAttributes(parseAttributes(match[1]));\n if (source) {\n sources.push(source);\n }\n }\n\n return sources;\n}\n\nfunction parseAttributes(raw: string): Record<string, string> {\n const attrs: Record<string, string> = {};\n ATTRIBUTE_RE.lastIndex = 0;\n let match;\n\n while ((match = ATTRIBUTE_RE.exec(raw)) !== null) {\n attrs[match[1].toLowerCase()] = match[2] ?? match[3] ?? match[4] ?? \"\";\n }\n\n return attrs;\n}\n\nexport function attributesFromElement(el: Element): Record<string, string> {\n const attrs: Record<string, string> = {};\n for (const name of [\n \"permalink\",\n \"url\",\n \"href\",\n \"repo\",\n \"path\",\n \"file\",\n \"ref\",\n \"sha\",\n \"branch\",\n \"loc\",\n \"lines\",\n \"line\",\n ]) {\n const value = getAttribute(el, name);\n if (value !== undefined) {\n attrs[name] = value;\n }\n }\n return attrs;\n}\n\nfunction getAttribute(el: Element, name: string): string | undefined {\n const value = el.properties?.[name];\n if (typeof value === \"string\") return value;\n if (Array.isArray(value)) return value.join(\" \");\n return undefined;\n}\n\nexport function sourceRefFromAttributes(attrs: Record<string, string>): GitHubSourceRef | null {\n const permalink = attrs.permalink ?? attrs.url ?? attrs.href;\n if (permalink) {\n return parseGitHubPermalink(permalink);\n }\n\n const repo = attrs.repo;\n const path = attrs.path ?? attrs.file;\n if (!repo || !path || !isSafeGitHubRepo(repo) || !isSafeGitHubPath(path)) {\n return null;\n }\n\n const ref = attrs.ref ?? attrs.sha ?? attrs.branch ?? \"main\";\n if (!isSafeGitHubRef(ref)) {\n return null;\n }\n\n const lines = parseGitHubLineRange(attrs.loc ?? attrs.lines ?? attrs.line);\n const source = { repo, ref, path, lines };\n return {\n ...source,\n permalink: createGitHubPermalink(source),\n };\n}\n","import type { Element } from \"hast\";\nimport { isSafeGitHubRepo } from \"./validation\";\n\n/**\n * Create fallback element when repo data is unavailable.\n */\nexport function createFallbackCard(repo: string): Element {\n const href = isSafeGitHubRepo(repo) ? `https://github.com/${repo}` : \"#\";\n return {\n type: \"element\",\n tagName: \"a\",\n properties: {\n className: [\"ox-github-card\", \"error\"],\n href,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n children: [\n {\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-github-header\"] },\n children: [\n {\n type: \"element\",\n tagName: \"svg\",\n properties: {\n className: [\"ox-github-icon\"],\n viewBox: \"0 0 16 16\",\n fill: \"currentColor\",\n },\n children: [\n {\n type: \"element\",\n tagName: \"path\",\n properties: {\n d: \"M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z\",\n },\n children: [],\n },\n ],\n },\n {\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-github-repo\"] },\n children: [{ type: \"text\", value: repo }],\n },\n ],\n },\n ],\n };\n}\n","import type { Element } from \"hast\";\nimport type { GitHubRepoData } from \"./types\";\n\nfunction formatNumber(num: number): string {\n if (num >= 1000000) {\n return `${(num / 1000000).toFixed(1)}M`;\n }\n if (num >= 1000) {\n return `${(num / 1000).toFixed(1)}k`;\n }\n return String(num);\n}\n\nfunction iconPath(d: string): Element {\n return {\n type: \"element\",\n tagName: \"svg\",\n properties: { viewBox: \"0 0 16 16\", fill: \"currentColor\" },\n children: [{ type: \"element\", tagName: \"path\", properties: { d }, children: [] }],\n };\n}\n\nfunction createStatsChildren(repoData: GitHubRepoData): Element[\"children\"] {\n const statsChildren: Element[\"children\"] = [];\n\n if (repoData.language) {\n statsChildren.push({\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-github-language\"] },\n children: [\n {\n type: \"element\",\n tagName: \"span\",\n properties: {\n className: [\"ox-github-language-color\"],\n \"data-lang\": repoData.language.toLowerCase(),\n },\n children: [],\n },\n { type: \"text\", value: repoData.language },\n ],\n });\n }\n\n statsChildren.push({\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-github-stat\"] },\n children: [\n iconPath(\n \"M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z\",\n ),\n { type: \"text\", value: formatNumber(repoData.stargazers_count) },\n ],\n });\n\n statsChildren.push({\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-github-stat\"] },\n children: [\n iconPath(\n \"M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z\",\n ),\n { type: \"text\", value: formatNumber(repoData.forks_count) },\n ],\n });\n\n return statsChildren;\n}\n\n/**\n * Create GitHub card element from repo data.\n */\nexport function createGitHubCard(repoData: GitHubRepoData): Element {\n return {\n type: \"element\",\n tagName: \"a\",\n properties: {\n className: [\"ox-github-card\"],\n href: repoData.html_url,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n children: [\n {\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-github-header\"] },\n children: [\n {\n ...iconPath(\n \"M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z\",\n ),\n properties: {\n className: [\"ox-github-icon\"],\n viewBox: \"0 0 16 16\",\n fill: \"currentColor\",\n },\n },\n {\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-github-repo\"] },\n children: [{ type: \"text\", value: repoData.full_name }],\n },\n ],\n },\n ...(repoData.description\n ? [\n {\n type: \"element\" as const,\n tagName: \"p\",\n properties: { className: [\"ox-github-description\"] },\n children: [{ type: \"text\" as const, value: repoData.description }],\n },\n ]\n : []),\n {\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-github-stats\"] },\n children: createStatsChildren(repoData),\n },\n ],\n };\n}\n","import type { Element } from \"hast\";\nimport { formatLineRange } from \"./source\";\nimport type { GitHubLineRange, GitHubOptions, GitHubSourceData } from \"./types\";\n\nfunction normalizeSourceLines(content: string): string[] {\n const lines = content.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n if (lines.length > 1 && lines.at(-1) === \"\") {\n lines.pop();\n }\n return lines.length > 0 ? lines : [\"\"];\n}\n\nexport function createGitHubSourceCard(\n source: GitHubSourceData,\n lines: GitHubLineRange | undefined,\n options: Required<GitHubOptions>,\n): Element {\n const allLines = normalizeSourceLines(source.content);\n const start = Math.min(lines?.start ?? 1, allLines.length);\n const end = lines\n ? Math.min(lines.end, allLines.length)\n : Math.min(allLines.length, options.maxSourceLines);\n const selectedLines = allLines.slice(start - 1, end);\n const lineRange = { start, end };\n const loc = selectedLines.length;\n const rangeLabel = formatLineRange(lineRange);\n const locLabel =\n !lines && end < allLines.length\n ? `${rangeLabel} of ${allLines.length} LOC`\n : `${rangeLabel} - ${loc} LOC`;\n const languageClass = source.language ? [`language-${source.language}`] : [];\n\n return {\n type: \"element\",\n tagName: \"figure\",\n properties: {\n className: [\"ox-github-code\"],\n \"data-loc\": String(loc),\n \"data-source\": source.permalink,\n },\n children: [\n {\n type: \"element\",\n tagName: \"figcaption\",\n properties: { className: [\"ox-github-code-header\"] },\n children: [\n {\n type: \"element\",\n tagName: \"a\",\n properties: {\n className: [\"ox-github-code-title\"],\n href: source.permalink,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n children: [{ type: \"text\", value: `${source.repo}/${source.path}` }],\n },\n {\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-github-code-loc\"] },\n children: [{ type: \"text\", value: locLabel }],\n },\n ],\n },\n {\n type: \"element\",\n tagName: \"pre\",\n properties: {\n className: [\"ox-github-code-block\", ...languageClass],\n ...(source.language ? { \"data-language\": source.language } : {}),\n },\n children: [\n {\n type: \"element\",\n tagName: \"code\",\n properties: { className: languageClass },\n children: selectedLines.map((line, index) => {\n const lineNumber = start + index;\n return {\n type: \"element\" as const,\n tagName: \"span\",\n properties: {\n className: [\"line\", \"ox-github-code-line\"],\n \"data-line\": String(lineNumber),\n },\n children: [\n {\n type: \"element\" as const,\n tagName: \"span\",\n properties: { className: [\"ox-github-code-line-number\"] },\n children: [{ type: \"text\" as const, value: String(lineNumber) }],\n },\n {\n type: \"element\" as const,\n tagName: \"span\",\n properties: { className: [\"ox-github-code-line-content\"] },\n children: [{ type: \"text\" as const, value: line || \" \" }],\n },\n ],\n };\n }),\n },\n ],\n },\n ],\n };\n}\n","import type { Element, Root } from \"hast\";\nimport rehypeParsePlugin from \"rehype-parse\";\nimport rehypeStringifyPlugin from \"rehype-stringify\";\nimport { unified } from \"unified\";\nimport { interopDefault } from \"../../interop\";\nimport { prefetchGitHubRepos, prefetchGitHubSources } from \"./api\";\nimport {\n attributesFromElement,\n collectGitHubRepos,\n collectGitHubSources,\n sourceRefFromAttributes,\n} from \"./attributes\";\nimport { createFallbackCard } from \"./fallback-card\";\nimport { createGitHubCard } from \"./repo-card\";\nimport { sourceKey } from \"./source\";\nimport { createGitHubSourceCard } from \"./source-card\";\nimport {\n defaultOptions,\n type GitHubOptions,\n type GitHubRepoData,\n type GitHubSourceData,\n} from \"./types\";\n\n// ESM-only plugins are double-wrapped by the CommonJS interop; unwrap. See #452.\nconst rehypeParse = interopDefault(rehypeParsePlugin);\nconst rehypeStringify = interopDefault(rehypeStringifyPlugin);\n\n/**\n * Rehype plugin to transform GitHub components.\n */\nfunction rehypeGitHub(\n repoDataMap: Map<string, GitHubRepoData | null>,\n sourceDataMap: Map<string, GitHubSourceData | null>,\n options: Required<GitHubOptions>,\n) {\n return (tree: Root) => {\n const visit = (node: Root | Element) => {\n if (\"children\" in node) {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n\n if (child.type !== \"element\") {\n continue;\n }\n\n if (child.tagName.toLowerCase() !== \"github\") {\n visit(child);\n continue;\n }\n\n const attrs = attributesFromElement(child);\n const source = sourceRefFromAttributes(attrs);\n\n if (source) {\n const sourceData = sourceDataMap.get(sourceKey(source));\n node.children[i] = sourceData\n ? createGitHubSourceCard(sourceData, source.lines, options)\n : createFallbackCard(source.permalink);\n continue;\n }\n\n const repo = attrs.repo;\n if (repo) {\n const repoData = repoDataMap.get(repo);\n node.children[i] = repoData ? createGitHubCard(repoData) : createFallbackCard(repo);\n }\n }\n }\n };\n\n visit(tree);\n };\n}\n\n/**\n * Transform GitHub components in HTML.\n */\nexport async function transformGitHub(\n html: string,\n repoDataMap?: Map<string, GitHubRepoData | null>,\n options?: GitHubOptions,\n): Promise<string> {\n const mergedOptions = { ...defaultOptions, ...options };\n let dataMap = repoDataMap;\n if (!dataMap) {\n const repos = await collectGitHubRepos(html);\n dataMap = await prefetchGitHubRepos(repos, mergedOptions);\n }\n const sources = await collectGitHubSources(html);\n const sourceDataMap = await prefetchGitHubSources(sources, mergedOptions);\n\n const result = await unified()\n .use(rehypeParse, { fragment: true })\n .use(rehypeGitHub, dataMap, sourceDataMap, mergedOptions)\n .use(rehypeStringify)\n .process(html);\n\n return String(result);\n}\n"],"mappings":"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"}
package/dist/github2.mjs DELETED
@@ -1,2 +0,0 @@
1
- import { t as transformGitHub } from "./github.mjs";
2
- export { transformGitHub };
package/dist/media.cjs DELETED
@@ -1,310 +0,0 @@
1
- const require_chunk = require("./chunk.cjs");
2
- const require_napi = require("./napi.cjs");
3
- let node_path = require("node:path");
4
- node_path = require_chunk.__toESM(node_path, 1);
5
- let node_fs_promises = require("node:fs/promises");
6
- //#region src/plugins/twitter/url.ts
7
- const STATUS_PATH = /^\/(?:[^/]+|i\/web)\/status\/(\d+)(?:\/.*)?$/;
8
- function createSyndicationToken(id) {
9
- return (Number(id) / 0x38d7ea4c68000 * Math.PI).toString(36).replaceAll(/(0+|\.)/g, "");
10
- }
11
- function parseTweetReference(value) {
12
- const trimmed = value.trim();
13
- if (/^\d+$/.test(trimmed)) return {
14
- id: trimmed,
15
- url: `https://x.com/i/web/status/${trimmed}`
16
- };
17
- try {
18
- const url = new URL(trimmed);
19
- const hostname = url.hostname.toLowerCase().replace(/^(?:www\.|mobile\.)/, "");
20
- if (url.protocol !== "https:" || hostname !== "x.com" && hostname !== "twitter.com") return null;
21
- const match = url.pathname.match(STATUS_PATH);
22
- if (!match) return null;
23
- const screenName = url.pathname.startsWith("/i/web/status/") ? "i/web" : url.pathname.split("/")[1];
24
- return {
25
- id: match[1],
26
- url: `https://x.com/${screenName}/status/${match[1]}`
27
- };
28
- } catch {
29
- return null;
30
- }
31
- }
32
- function referenceFromAttributes(attributes) {
33
- const values = /* @__PURE__ */ new Map();
34
- for (const match of attributes.matchAll(/\b(url|href|id)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi)) values.set(match[1].toLowerCase(), match[2] ?? match[3] ?? match[4] ?? "");
35
- return parseTweetReference(values.get("url") ?? values.get("href") ?? values.get("id") ?? "");
36
- }
37
- //#endregion
38
- //#region src/plugins/twitter/fetch.ts
39
- const tweetCache = /* @__PURE__ */ new Map();
40
- async function fetchTweetData(id, options) {
41
- const key = `${id}-${sanitizeSegment(options.lang)}`;
42
- if (options.cache) {
43
- const memory = tweetCache.get(key);
44
- if (memory) return memory;
45
- const disk = await readCachedTweet(key, options.cacheDir);
46
- if (disk) {
47
- tweetCache.set(key, disk);
48
- return disk;
49
- }
50
- }
51
- const controller = new AbortController();
52
- const timeout = setTimeout(() => controller.abort(), options.timeout);
53
- const endpoint = new URL("https://cdn.syndication.twimg.com/tweet-result");
54
- endpoint.searchParams.set("id", id);
55
- endpoint.searchParams.set("lang", options.lang);
56
- endpoint.searchParams.set("token", createSyndicationToken(id));
57
- try {
58
- const response = await fetch(endpoint, {
59
- headers: { Accept: "application/json" },
60
- signal: controller.signal
61
- });
62
- if (!response.ok) return null;
63
- const data = await response.json();
64
- if (!isTweetData(data)) return null;
65
- if (options.cache) {
66
- tweetCache.set(key, data);
67
- await writeCachedTweet(key, data, options.cacheDir);
68
- }
69
- return data;
70
- } catch {
71
- return null;
72
- } finally {
73
- clearTimeout(timeout);
74
- }
75
- }
76
- async function materializeTweetAssets(id, data, options) {
77
- const assets = { media: [] };
78
- const avatarUrl = data.user.profile_image_url_https?.replace(/_normal(?=\.[^.]+$)/, "_bigger");
79
- if (avatarUrl) assets.avatar = await downloadAsset(avatarUrl, `${id}-avatar`, options);
80
- const media = data.mediaDetails ?? data.entities?.media ?? [];
81
- for (const [index, item] of media.entries()) {
82
- if (item.type && item.type !== "photo") continue;
83
- if (!item.media_url_https) continue;
84
- const src = await downloadAsset(item.media_url_https, `${id}-media-${index + 1}`, options);
85
- if (src) assets.media.push(assetRecord(src, item));
86
- }
87
- return assets;
88
- }
89
- async function downloadAsset(source, basename, options) {
90
- let url;
91
- try {
92
- url = new URL(source);
93
- } catch {
94
- return;
95
- }
96
- if (url.protocol !== "https:" || url.hostname.toLowerCase() !== "pbs.twimg.com") return;
97
- const filename = `${basename}${extensionFromUrl(url)}`;
98
- const output = node_path.default.join(options.mediaOutputDir, filename);
99
- try {
100
- await (0, node_fs_promises.access)(output);
101
- return joinPublicPath(options.mediaPublicPath, filename);
102
- } catch {}
103
- try {
104
- const response = await fetch(url, { headers: { Accept: "image/*" } });
105
- if (!response.ok) return void 0;
106
- await (0, node_fs_promises.mkdir)(options.mediaOutputDir, { recursive: true });
107
- await (0, node_fs_promises.writeFile)(output, new Uint8Array(await response.arrayBuffer()));
108
- return joinPublicPath(options.mediaPublicPath, filename);
109
- } catch {
110
- return;
111
- }
112
- }
113
- async function readCachedTweet(key, directory) {
114
- try {
115
- const data = JSON.parse(await (0, node_fs_promises.readFile)(node_path.default.join(directory, `${key}.json`), "utf8"));
116
- return isTweetData(data) ? data : null;
117
- } catch {
118
- return null;
119
- }
120
- }
121
- async function writeCachedTweet(key, data, directory) {
122
- try {
123
- await (0, node_fs_promises.mkdir)(directory, { recursive: true });
124
- await (0, node_fs_promises.writeFile)(node_path.default.join(directory, `${key}.json`), `${JSON.stringify(data)}\n`);
125
- } catch {}
126
- }
127
- function isTweetData(data) {
128
- if (!data || typeof data !== "object") return false;
129
- const value = data;
130
- return typeof value.text === "string" && Boolean(value.user) && typeof value.user?.name === "string" && typeof value.user.screen_name === "string";
131
- }
132
- function extensionFromUrl(url) {
133
- const match = url.pathname.match(/\.(jpe?g|png|webp|gif)$/i);
134
- return match ? `.${match[1].toLowerCase().replace("jpeg", "jpg")}` : ".jpg";
135
- }
136
- function joinPublicPath(prefix, filename) {
137
- return `${prefix.replace(/\/$/, "")}/${filename}`;
138
- }
139
- function sanitizeSegment(value) {
140
- return value.replaceAll(/[^a-zA-Z0-9_-]/g, "-");
141
- }
142
- function assetRecord(src, media) {
143
- return {
144
- src,
145
- alt: media.ext_alt_text,
146
- width: media.original_info?.width,
147
- height: media.original_info?.height
148
- };
149
- }
150
- //#endregion
151
- //#region src/plugins/twitter/render.ts
152
- function renderFetchedTweet(permalink, data, assets, options) {
153
- const profile = `https://x.com/${encodeURIComponent(data.user.screen_name)}`;
154
- const author = escapeHtml(data.user.name);
155
- const handle = escapeHtml(data.user.screen_name);
156
- const avatar = assets.avatar ? `<img class="ox-tweet__avatar" src="${escapeAttribute(assets.avatar)}" alt="" width="48" height="48" loading="lazy" decoding="async">` : "";
157
- const media = renderMedia(assets);
158
- const footer = renderFooter(permalink, data.created_at, options.lang);
159
- return [
160
- "<figure class=\"ox-tweet ox-tweet--fetched\">",
161
- "<header class=\"ox-tweet__header\">",
162
- `<a class="ox-tweet__profile" href="${escapeAttribute(profile)}" target="_blank" rel="noopener noreferrer">`,
163
- avatar,
164
- `<span class="ox-tweet__author-name">${author}</span>`,
165
- `<span class="ox-tweet__author-handle">@${handle}</span>`,
166
- "</a></header>",
167
- `<div class="ox-tweet__body">${renderTweetText(data)}</div>`,
168
- media,
169
- footer,
170
- "</figure>"
171
- ].join("");
172
- }
173
- function renderTweetText(data) {
174
- const [start, end] = data.display_text_range ?? [0, data.text.length];
175
- const entities = collectEntities(data).filter((entity) => validRange(entity.indices, start, end)).sort((left, right) => left.indices[0] - right.indices[0]);
176
- let cursor = start;
177
- let output = "";
178
- for (const entity of entities) {
179
- const [entityStart, entityEnd] = entity.indices;
180
- if (entityStart < cursor) continue;
181
- output += escapeText(data.text.slice(cursor, entityStart));
182
- if (entity.kind === "url") {
183
- const href = entity.expanded_url ?? entity.url;
184
- const label = entity.display_url ?? href;
185
- output += `<a href="${escapeAttribute(href)}" target="_blank" rel="noopener noreferrer">${escapeHtml(label)}</a>`;
186
- }
187
- cursor = entityEnd;
188
- }
189
- output += escapeText(data.text.slice(cursor, end));
190
- return output.trim();
191
- }
192
- function collectEntities(data) {
193
- return [...(data.entities?.urls ?? []).map((entity) => ({
194
- ...entity,
195
- kind: "url"
196
- })), ...(data.entities?.media ?? []).map((entity) => ({
197
- ...entity,
198
- kind: "media"
199
- }))];
200
- }
201
- function validRange(indices, start, end) {
202
- return Boolean(indices && indices[0] >= start && indices[1] <= end && indices[0] < indices[1]);
203
- }
204
- function renderMedia(assets) {
205
- if (assets.media.length === 0) return "";
206
- const images = assets.media.map((item) => {
207
- const size = [item.width ? ` width="${item.width}"` : "", item.height ? ` height="${item.height}"` : ""].join("");
208
- return `<img class="ox-tweet__media-item" src="${escapeAttribute(item.src)}" alt="${escapeAttribute(item.alt ?? "")}"${size} loading="lazy" decoding="async">`;
209
- }).join("");
210
- return `<div class="ox-tweet__media" data-count="${assets.media.length}">${images}</div>`;
211
- }
212
- function renderFooter(permalink, createdAt, lang) {
213
- if (!createdAt) return `<footer class="ox-tweet__footer"><a class="ox-tweet__permalink" href="${escapeAttribute(permalink)}" target="_blank" rel="noopener noreferrer">View on X</a></footer>`;
214
- const date = new Date(createdAt);
215
- if (Number.isNaN(date.valueOf())) return renderFooter(permalink, void 0, lang);
216
- const iso = date.toISOString();
217
- let label;
218
- try {
219
- label = new Intl.DateTimeFormat(lang, {
220
- dateStyle: "medium",
221
- timeZone: "UTC"
222
- }).format(date);
223
- } catch {
224
- label = new Intl.DateTimeFormat("en", {
225
- dateStyle: "medium",
226
- timeZone: "UTC"
227
- }).format(date);
228
- }
229
- return `<footer class="ox-tweet__footer"><a class="ox-tweet__permalink" href="${escapeAttribute(permalink)}" target="_blank" rel="noopener noreferrer"><time datetime="${iso}">${escapeHtml(label)}</time></a></footer>`;
230
- }
231
- function escapeText(value) {
232
- return escapeHtml(value).replaceAll("\n", "<br>");
233
- }
234
- function escapeAttribute(value) {
235
- return escapeHtml(value).replaceAll("`", "&#96;");
236
- }
237
- function escapeHtml(value) {
238
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;");
239
- }
240
- //#endregion
241
- //#region src/plugins/twitter/transform.ts
242
- const TWEET_ELEMENT = /<(tweet|xpost)\b([^>]*?)(?:\/\s*>|>[\s\S]*?<\/\1\s*>)/gi;
243
- function resolveTwitterEmbedOptions(options) {
244
- return {
245
- fetch: options.fetch ?? false,
246
- lang: options.lang ?? "en",
247
- timeout: options.timeout ?? 1e4,
248
- cache: options.cache ?? true,
249
- cacheDir: node_path.default.resolve(options.cacheDir ?? ".cache/ox-content/twitter"),
250
- mediaOutputDir: node_path.default.resolve(options.mediaOutputDir ?? "public/ox-content/twitter"),
251
- mediaPublicPath: options.mediaPublicPath ?? "/ox-content/twitter"
252
- };
253
- }
254
- async function transformFetchedTweets(html, options) {
255
- const resolved = resolveTwitterEmbedOptions(options);
256
- if (!resolved.fetch) return html;
257
- let output = "";
258
- let cursor = 0;
259
- for (const match of html.matchAll(TWEET_ELEMENT)) {
260
- const index = match.index ?? 0;
261
- output += html.slice(cursor, index);
262
- const reference = referenceFromAttributes(match[2]);
263
- if (!reference) {
264
- output += match[0];
265
- cursor = index + match[0].length;
266
- continue;
267
- }
268
- const data = await fetchTweetData(reference.id, resolved);
269
- if (!data) {
270
- output += match[0];
271
- cursor = index + match[0].length;
272
- continue;
273
- }
274
- const assets = await materializeTweetAssets(reference.id, data, resolved);
275
- output += renderFetchedTweet(reference.url, data, assets, resolved);
276
- cursor = index + match[0].length;
277
- }
278
- return output + html.slice(cursor);
279
- }
280
- //#endregion
281
- //#region src/plugins/media.ts
282
- var media_exports = /* @__PURE__ */ require_chunk.__exportAll({ transformMediaEmbeds: () => transformMediaEmbeds });
283
- async function transformMediaEmbeds(html, options) {
284
- if (!hasEnabledMediaEmbed(options) || !hasMediaMarker(html)) return html;
285
- let result = html;
286
- if (typeof options.twitter === "object") result = await transformFetchedTweets(result, options.twitter);
287
- if (!hasMediaMarker(result)) return result;
288
- return (await require_napi.importNapiModule()).transformMediaEmbeds(result, {
289
- spotify: options.spotify,
290
- stackBlitz: options.stackBlitz,
291
- twitter: Boolean(options.twitter),
292
- bluesky: options.bluesky,
293
- webContainer: options.webContainer
294
- });
295
- }
296
- function hasEnabledMediaEmbed(options) {
297
- return Boolean(options.spotify || options.stackBlitz || options.twitter || options.bluesky || options.webContainer);
298
- }
299
- function hasMediaMarker(html) {
300
- return /<(spotify|stackblitz|tweet|xpost|bluesky|webcontainer)[\s/>]/i.test(html);
301
- }
302
- //#endregion
303
- Object.defineProperty(exports, "media_exports", {
304
- enumerable: true,
305
- get: function() {
306
- return media_exports;
307
- }
308
- });
309
-
310
- //# sourceMappingURL=media.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.cjs","names":["path","path","importNapiModule"],"sources":["../src/plugins/twitter/url.ts","../src/plugins/twitter/fetch.ts","../src/plugins/twitter/render.ts","../src/plugins/twitter/transform.ts","../src/plugins/media.ts"],"sourcesContent":["import type { TweetReference } from \"./types\";\n\nconst STATUS_PATH = /^\\/(?:[^/]+|i\\/web)\\/status\\/(\\d+)(?:\\/.*)?$/;\n\nexport function createSyndicationToken(id: string): string {\n return ((Number(id) / 1e15) * Math.PI).toString(36).replaceAll(/(0+|\\.)/g, \"\");\n}\n\nexport function parseTweetReference(value: string): TweetReference | null {\n const trimmed = value.trim();\n if (/^\\d+$/.test(trimmed)) {\n return { id: trimmed, url: `https://x.com/i/web/status/${trimmed}` };\n }\n\n try {\n const url = new URL(trimmed);\n const hostname = url.hostname.toLowerCase().replace(/^(?:www\\.|mobile\\.)/, \"\");\n if (url.protocol !== \"https:\" || (hostname !== \"x.com\" && hostname !== \"twitter.com\")) {\n return null;\n }\n\n const match = url.pathname.match(STATUS_PATH);\n if (!match) return null;\n const screenName = url.pathname.startsWith(\"/i/web/status/\")\n ? \"i/web\"\n : url.pathname.split(\"/\")[1];\n return {\n id: match[1],\n url: `https://x.com/${screenName}/status/${match[1]}`,\n };\n } catch {\n return null;\n }\n}\n\nexport function referenceFromAttributes(attributes: string): TweetReference | null {\n const values = new Map<string, string>();\n const pattern = /\\b(url|href|id)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/gi;\n for (const match of attributes.matchAll(pattern)) {\n values.set(match[1].toLowerCase(), match[2] ?? match[3] ?? match[4] ?? \"\");\n }\n return parseTweetReference(values.get(\"url\") ?? values.get(\"href\") ?? values.get(\"id\") ?? \"\");\n}\n","import { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createSyndicationToken } from \"./url\";\nimport type { ResolvedTwitterEmbedOptions, TweetAssets, TweetData, TweetMedia } from \"./types\";\n\nconst tweetCache = new Map<string, TweetData>();\n\nexport function clearTweetCache(): void {\n tweetCache.clear();\n}\n\nexport async function fetchTweetData(\n id: string,\n options: ResolvedTwitterEmbedOptions,\n): Promise<TweetData | null> {\n const key = `${id}-${sanitizeSegment(options.lang)}`;\n if (options.cache) {\n const memory = tweetCache.get(key);\n if (memory) return memory;\n const disk = await readCachedTweet(key, options.cacheDir);\n if (disk) {\n tweetCache.set(key, disk);\n return disk;\n }\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeout);\n const endpoint = new URL(\"https://cdn.syndication.twimg.com/tweet-result\");\n endpoint.searchParams.set(\"id\", id);\n endpoint.searchParams.set(\"lang\", options.lang);\n endpoint.searchParams.set(\"token\", createSyndicationToken(id));\n\n try {\n const response = await fetch(endpoint, {\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n if (!response.ok) return null;\n const data: unknown = await response.json();\n if (!isTweetData(data)) return null;\n if (options.cache) {\n tweetCache.set(key, data);\n await writeCachedTweet(key, data, options.cacheDir);\n }\n return data;\n } catch {\n return null;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nexport async function materializeTweetAssets(\n id: string,\n data: TweetData,\n options: ResolvedTwitterEmbedOptions,\n): Promise<TweetAssets> {\n const assets: TweetAssets = { media: [] };\n const avatarUrl = data.user.profile_image_url_https?.replace(/_normal(?=\\.[^.]+$)/, \"_bigger\");\n if (avatarUrl) {\n assets.avatar = await downloadAsset(avatarUrl, `${id}-avatar`, options);\n }\n\n const media = data.mediaDetails ?? data.entities?.media ?? [];\n for (const [index, item] of media.entries()) {\n if (item.type && item.type !== \"photo\") continue;\n if (!item.media_url_https) continue;\n const src = await downloadAsset(item.media_url_https, `${id}-media-${index + 1}`, options);\n if (src) assets.media.push(assetRecord(src, item));\n }\n return assets;\n}\n\nasync function downloadAsset(\n source: string,\n basename: string,\n options: ResolvedTwitterEmbedOptions,\n): Promise<string | undefined> {\n let url: URL;\n try {\n url = new URL(source);\n } catch {\n return undefined;\n }\n if (url.protocol !== \"https:\" || url.hostname.toLowerCase() !== \"pbs.twimg.com\") {\n return undefined;\n }\n\n const extension = extensionFromUrl(url);\n const filename = `${basename}${extension}`;\n const output = path.join(options.mediaOutputDir, filename);\n try {\n await access(output);\n return joinPublicPath(options.mediaPublicPath, filename);\n } catch {\n // Download the missing asset below.\n }\n\n try {\n const response = await fetch(url, { headers: { Accept: \"image/*\" } });\n if (!response.ok) return undefined;\n await mkdir(options.mediaOutputDir, { recursive: true });\n await writeFile(output, new Uint8Array(await response.arrayBuffer()));\n return joinPublicPath(options.mediaPublicPath, filename);\n } catch {\n return undefined;\n }\n}\n\nasync function readCachedTweet(key: string, directory: string): Promise<TweetData | null> {\n try {\n const data: unknown = JSON.parse(await readFile(path.join(directory, `${key}.json`), \"utf8\"));\n return isTweetData(data) ? data : null;\n } catch {\n return null;\n }\n}\n\nasync function writeCachedTweet(key: string, data: TweetData, directory: string): Promise<void> {\n try {\n await mkdir(directory, { recursive: true });\n await writeFile(path.join(directory, `${key}.json`), `${JSON.stringify(data)}\\n`);\n } catch {\n // A read-only cache directory must not fail the build.\n }\n}\n\nfunction isTweetData(data: unknown): data is TweetData {\n if (!data || typeof data !== \"object\") return false;\n const value = data as Partial<TweetData>;\n return (\n typeof value.text === \"string\" &&\n Boolean(value.user) &&\n typeof value.user?.name === \"string\" &&\n typeof value.user.screen_name === \"string\"\n );\n}\n\nfunction extensionFromUrl(url: URL): string {\n const match = url.pathname.match(/\\.(jpe?g|png|webp|gif)$/i);\n return match ? `.${match[1].toLowerCase().replace(\"jpeg\", \"jpg\")}` : \".jpg\";\n}\n\nfunction joinPublicPath(prefix: string, filename: string): string {\n return `${prefix.replace(/\\/$/, \"\")}/${filename}`;\n}\n\nfunction sanitizeSegment(value: string): string {\n return value.replaceAll(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\nfunction assetRecord(src: string, media: TweetMedia): TweetAssets[\"media\"][number] {\n return {\n src,\n alt: media.ext_alt_text,\n width: media.original_info?.width,\n height: media.original_info?.height,\n };\n}\n","import type { ResolvedTwitterEmbedOptions, TweetAssets, TweetData, TweetEntity } from \"./types\";\n\nexport function renderFetchedTweet(\n permalink: string,\n data: TweetData,\n assets: TweetAssets,\n options: ResolvedTwitterEmbedOptions,\n): string {\n const profile = `https://x.com/${encodeURIComponent(data.user.screen_name)}`;\n const author = escapeHtml(data.user.name);\n const handle = escapeHtml(data.user.screen_name);\n const avatar = assets.avatar\n ? `<img class=\"ox-tweet__avatar\" src=\"${escapeAttribute(assets.avatar)}\" alt=\"\" width=\"48\" height=\"48\" loading=\"lazy\" decoding=\"async\">`\n : \"\";\n const media = renderMedia(assets);\n const footer = renderFooter(permalink, data.created_at, options.lang);\n\n return [\n '<figure class=\"ox-tweet ox-tweet--fetched\">',\n '<header class=\"ox-tweet__header\">',\n `<a class=\"ox-tweet__profile\" href=\"${escapeAttribute(profile)}\" target=\"_blank\" rel=\"noopener noreferrer\">`,\n avatar,\n `<span class=\"ox-tweet__author-name\">${author}</span>`,\n `<span class=\"ox-tweet__author-handle\">@${handle}</span>`,\n \"</a></header>\",\n `<div class=\"ox-tweet__body\">${renderTweetText(data)}</div>`,\n media,\n footer,\n \"</figure>\",\n ].join(\"\");\n}\n\nexport function renderTweetText(data: TweetData): string {\n const [start, end] = data.display_text_range ?? [0, data.text.length];\n const entities = collectEntities(data)\n .filter((entity) => validRange(entity.indices, start, end))\n .sort((left, right) => left.indices![0] - right.indices![0]);\n\n let cursor = start;\n let output = \"\";\n for (const entity of entities) {\n const [entityStart, entityEnd] = entity.indices!;\n if (entityStart < cursor) continue;\n output += escapeText(data.text.slice(cursor, entityStart));\n if (entity.kind === \"url\") {\n const href = entity.expanded_url ?? entity.url;\n const label = entity.display_url ?? href;\n output += `<a href=\"${escapeAttribute(href)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escapeHtml(label)}</a>`;\n }\n cursor = entityEnd;\n }\n output += escapeText(data.text.slice(cursor, end));\n return output.trim();\n}\n\nfunction collectEntities(data: TweetData): Array<TweetEntity & { kind: \"url\" | \"media\" }> {\n return [\n ...(data.entities?.urls ?? []).map((entity) => ({ ...entity, kind: \"url\" as const })),\n ...(data.entities?.media ?? []).map((entity) => ({ ...entity, kind: \"media\" as const })),\n ];\n}\n\nfunction validRange(\n indices: [number, number] | undefined,\n start: number,\n end: number,\n): indices is [number, number] {\n return Boolean(indices && indices[0] >= start && indices[1] <= end && indices[0] < indices[1]);\n}\n\nfunction renderMedia(assets: TweetAssets): string {\n if (assets.media.length === 0) return \"\";\n const images = assets.media\n .map((item) => {\n const size = [\n item.width ? ` width=\"${item.width}\"` : \"\",\n item.height ? ` height=\"${item.height}\"` : \"\",\n ].join(\"\");\n return `<img class=\"ox-tweet__media-item\" src=\"${escapeAttribute(item.src)}\" alt=\"${escapeAttribute(item.alt ?? \"\")}\"${size} loading=\"lazy\" decoding=\"async\">`;\n })\n .join(\"\");\n return `<div class=\"ox-tweet__media\" data-count=\"${assets.media.length}\">${images}</div>`;\n}\n\nfunction renderFooter(permalink: string, createdAt: string | undefined, lang: string): string {\n if (!createdAt) {\n return `<footer class=\"ox-tweet__footer\"><a class=\"ox-tweet__permalink\" href=\"${escapeAttribute(permalink)}\" target=\"_blank\" rel=\"noopener noreferrer\">View on X</a></footer>`;\n }\n const date = new Date(createdAt);\n if (Number.isNaN(date.valueOf())) return renderFooter(permalink, undefined, lang);\n const iso = date.toISOString();\n let label: string;\n try {\n label = new Intl.DateTimeFormat(lang, { dateStyle: \"medium\", timeZone: \"UTC\" }).format(date);\n } catch {\n label = new Intl.DateTimeFormat(\"en\", { dateStyle: \"medium\", timeZone: \"UTC\" }).format(date);\n }\n return `<footer class=\"ox-tweet__footer\"><a class=\"ox-tweet__permalink\" href=\"${escapeAttribute(permalink)}\" target=\"_blank\" rel=\"noopener noreferrer\"><time datetime=\"${iso}\">${escapeHtml(label)}</time></a></footer>`;\n}\n\nfunction escapeText(value: string): string {\n return escapeHtml(value).replaceAll(\"\\n\", \"<br>\");\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll(\"`\", \"&#96;\");\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#39;\");\n}\n","import path from \"node:path\";\nimport { fetchTweetData, materializeTweetAssets } from \"./fetch\";\nimport { renderFetchedTweet } from \"./render\";\nimport type { ResolvedTwitterEmbedOptions, TwitterEmbedOptions } from \"./types\";\nimport { referenceFromAttributes } from \"./url\";\n\nconst TWEET_ELEMENT = /<(tweet|xpost)\\b([^>]*?)(?:\\/\\s*>|>[\\s\\S]*?<\\/\\1\\s*>)/gi;\n\nexport function resolveTwitterEmbedOptions(\n options: TwitterEmbedOptions,\n): ResolvedTwitterEmbedOptions {\n return {\n fetch: options.fetch ?? false,\n lang: options.lang ?? \"en\",\n timeout: options.timeout ?? 10000,\n cache: options.cache ?? true,\n cacheDir: path.resolve(options.cacheDir ?? \".cache/ox-content/twitter\"),\n mediaOutputDir: path.resolve(options.mediaOutputDir ?? \"public/ox-content/twitter\"),\n mediaPublicPath: options.mediaPublicPath ?? \"/ox-content/twitter\",\n };\n}\n\nexport async function transformFetchedTweets(\n html: string,\n options: TwitterEmbedOptions,\n): Promise<string> {\n const resolved = resolveTwitterEmbedOptions(options);\n if (!resolved.fetch) return html;\n\n let output = \"\";\n let cursor = 0;\n for (const match of html.matchAll(TWEET_ELEMENT)) {\n const index = match.index ?? 0;\n output += html.slice(cursor, index);\n const reference = referenceFromAttributes(match[2]);\n if (!reference) {\n output += match[0];\n cursor = index + match[0].length;\n continue;\n }\n\n const data = await fetchTweetData(reference.id, resolved);\n if (!data) {\n output += match[0];\n cursor = index + match[0].length;\n continue;\n }\n\n const assets = await materializeTweetAssets(reference.id, data, resolved);\n output += renderFetchedTweet(reference.url, data, assets, resolved);\n cursor = index + match[0].length;\n }\n return output + html.slice(cursor);\n}\n","import { importNapiModule } from \"../napi\";\nimport { transformFetchedTweets } from \"./twitter\";\nimport type { TwitterEmbedOptions } from \"./twitter\";\n\nexport interface MediaEmbedOptions {\n /**\n * Render `<Spotify>` embeds.\n * @default false\n */\n spotify?: boolean;\n\n /**\n * Render `<StackBlitz>` embeds.\n * @default false\n */\n stackBlitz?: boolean;\n\n /**\n * Render `<Tweet>` / `<XPost>` static cards. Pass `{ fetch: true }` to\n * resolve the post content and self-host its media at build time.\n * @default false\n */\n twitter?: boolean | TwitterEmbedOptions;\n\n /**\n * Render `<Bluesky>` static cards.\n * @default false\n */\n bluesky?: boolean;\n\n /**\n * Render `<WebContainer>` lazy placeholder blocks.\n * @default false\n */\n webContainer?: boolean;\n}\n\nexport async function transformMediaEmbeds(\n html: string,\n options: MediaEmbedOptions,\n): Promise<string> {\n if (!hasEnabledMediaEmbed(options) || !hasMediaMarker(html)) {\n return html;\n }\n\n let result = html;\n if (typeof options.twitter === \"object\") {\n result = await transformFetchedTweets(result, options.twitter);\n }\n if (!hasMediaMarker(result)) return result;\n\n const mod = await importNapiModule();\n return mod.transformMediaEmbeds(result, {\n spotify: options.spotify,\n stackBlitz: options.stackBlitz,\n twitter: Boolean(options.twitter),\n bluesky: options.bluesky,\n webContainer: options.webContainer,\n });\n}\n\nfunction hasEnabledMediaEmbed(options: MediaEmbedOptions): boolean {\n return Boolean(\n options.spotify ||\n options.stackBlitz ||\n options.twitter ||\n options.bluesky ||\n options.webContainer,\n );\n}\n\nfunction hasMediaMarker(html: string): boolean {\n return /<(spotify|stackblitz|tweet|xpost|bluesky|webcontainer)[\\s/>]/i.test(html);\n}\n"],"mappings":";;;;;;AAEA,MAAM,cAAc;AAEpB,SAAgB,uBAAuB,IAAoB;CACzD,QAAS,OAAO,GAAG,GAAG,kBAAQ,KAAK,IAAI,SAAS,GAAG,CAAC,WAAW,YAAY,GAAG;;AAGhF,SAAgB,oBAAoB,OAAsC;CACxE,MAAM,UAAU,MAAM,MAAM;CAC5B,IAAI,QAAQ,KAAK,QAAQ,EACvB,OAAO;EAAE,IAAI;EAAS,KAAK,8BAA8B;EAAW;CAGtE,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,QAAQ;EAC5B,MAAM,WAAW,IAAI,SAAS,aAAa,CAAC,QAAQ,uBAAuB,GAAG;EAC9E,IAAI,IAAI,aAAa,YAAa,aAAa,WAAW,aAAa,eACrE,OAAO;EAGT,MAAM,QAAQ,IAAI,SAAS,MAAM,YAAY;EAC7C,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,aAAa,IAAI,SAAS,WAAW,iBAAiB,GACxD,UACA,IAAI,SAAS,MAAM,IAAI,CAAC;EAC5B,OAAO;GACL,IAAI,MAAM;GACV,KAAK,iBAAiB,WAAW,UAAU,MAAM;GAClD;SACK;EACN,OAAO;;;AAIX,SAAgB,wBAAwB,YAA2C;CACjF,MAAM,yBAAS,IAAI,KAAqB;CAExC,KAAK,MAAM,SAAS,WAAW,SAAS,4DAAQ,EAC9C,OAAO,IAAI,MAAM,GAAG,aAAa,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,GAAG;CAE5E,OAAO,oBAAoB,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,KAAK,IAAI,GAAG;;;;ACpC/F,MAAM,6BAAa,IAAI,KAAwB;AAM/C,eAAsB,eACpB,IACA,SAC2B;CAC3B,MAAM,MAAM,GAAG,GAAG,GAAG,gBAAgB,QAAQ,KAAK;CAClD,IAAI,QAAQ,OAAO;EACjB,MAAM,SAAS,WAAW,IAAI,IAAI;EAClC,IAAI,QAAQ,OAAO;EACnB,MAAM,OAAO,MAAM,gBAAgB,KAAK,QAAQ,SAAS;EACzD,IAAI,MAAM;GACR,WAAW,IAAI,KAAK,KAAK;GACzB,OAAO;;;CAIX,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,UAAU,iBAAiB,WAAW,OAAO,EAAE,QAAQ,QAAQ;CACrE,MAAM,WAAW,IAAI,IAAI,iDAAiD;CAC1E,SAAS,aAAa,IAAI,MAAM,GAAG;CACnC,SAAS,aAAa,IAAI,QAAQ,QAAQ,KAAK;CAC/C,SAAS,aAAa,IAAI,SAAS,uBAAuB,GAAG,CAAC;CAE9D,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,UAAU;GACrC,SAAS,EAAE,QAAQ,oBAAoB;GACvC,QAAQ,WAAW;GACpB,CAAC;EACF,IAAI,CAAC,SAAS,IAAI,OAAO;EACzB,MAAM,OAAgB,MAAM,SAAS,MAAM;EAC3C,IAAI,CAAC,YAAY,KAAK,EAAE,OAAO;EAC/B,IAAI,QAAQ,OAAO;GACjB,WAAW,IAAI,KAAK,KAAK;GACzB,MAAM,iBAAiB,KAAK,MAAM,QAAQ,SAAS;;EAErD,OAAO;SACD;EACN,OAAO;WACC;EACR,aAAa,QAAQ;;;AAIzB,eAAsB,uBACpB,IACA,MACA,SACsB;CACtB,MAAM,SAAsB,EAAE,OAAO,EAAE,EAAE;CACzC,MAAM,YAAY,KAAK,KAAK,yBAAyB,QAAQ,uBAAuB,UAAU;CAC9F,IAAI,WACF,OAAO,SAAS,MAAM,cAAc,WAAW,GAAG,GAAG,UAAU,QAAQ;CAGzE,MAAM,QAAQ,KAAK,gBAAgB,KAAK,UAAU,SAAS,EAAE;CAC7D,KAAK,MAAM,CAAC,OAAO,SAAS,MAAM,SAAS,EAAE;EAC3C,IAAI,KAAK,QAAQ,KAAK,SAAS,SAAS;EACxC,IAAI,CAAC,KAAK,iBAAiB;EAC3B,MAAM,MAAM,MAAM,cAAc,KAAK,iBAAiB,GAAG,GAAG,SAAS,QAAQ,KAAK,QAAQ;EAC1F,IAAI,KAAK,OAAO,MAAM,KAAK,YAAY,KAAK,KAAK,CAAC;;CAEpD,OAAO;;AAGT,eAAe,cACb,QACA,UACA,SAC6B;CAC7B,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,OAAO;SACf;EACN;;CAEF,IAAI,IAAI,aAAa,YAAY,IAAI,SAAS,aAAa,KAAK,iBAC9D;CAIF,MAAM,WAAW,GAAG,WADF,iBAAiB,IACK;CACxC,MAAM,SAASA,UAAAA,QAAK,KAAK,QAAQ,gBAAgB,SAAS;CAC1D,IAAI;EACF,OAAA,GAAA,iBAAA,QAAa,OAAO;EACpB,OAAO,eAAe,QAAQ,iBAAiB,SAAS;SAClD;CAIR,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE,SAAS,EAAE,QAAQ,WAAW,EAAE,CAAC;EACrE,IAAI,CAAC,SAAS,IAAI,OAAO,KAAA;EACzB,OAAA,GAAA,iBAAA,OAAY,QAAQ,gBAAgB,EAAE,WAAW,MAAM,CAAC;EACxD,OAAA,GAAA,iBAAA,WAAgB,QAAQ,IAAI,WAAW,MAAM,SAAS,aAAa,CAAC,CAAC;EACrE,OAAO,eAAe,QAAQ,iBAAiB,SAAS;SAClD;EACN;;;AAIJ,eAAe,gBAAgB,KAAa,WAA8C;CACxF,IAAI;EACF,MAAM,OAAgB,KAAK,MAAM,OAAA,GAAA,iBAAA,UAAeA,UAAAA,QAAK,KAAK,WAAW,GAAG,IAAI,OAAO,EAAE,OAAO,CAAC;EAC7F,OAAO,YAAY,KAAK,GAAG,OAAO;SAC5B;EACN,OAAO;;;AAIX,eAAe,iBAAiB,KAAa,MAAiB,WAAkC;CAC9F,IAAI;EACF,OAAA,GAAA,iBAAA,OAAY,WAAW,EAAE,WAAW,MAAM,CAAC;EAC3C,OAAA,GAAA,iBAAA,WAAgBA,UAAAA,QAAK,KAAK,WAAW,GAAG,IAAI,OAAO,EAAE,GAAG,KAAK,UAAU,KAAK,CAAC,IAAI;SAC3E;;AAKV,SAAS,YAAY,MAAkC;CACrD,IAAI,CAAC,QAAQ,OAAO,SAAS,UAAU,OAAO;CAC9C,MAAM,QAAQ;CACd,OACE,OAAO,MAAM,SAAS,YACtB,QAAQ,MAAM,KAAK,IACnB,OAAO,MAAM,MAAM,SAAS,YAC5B,OAAO,MAAM,KAAK,gBAAgB;;AAItC,SAAS,iBAAiB,KAAkB;CAC1C,MAAM,QAAQ,IAAI,SAAS,MAAM,2BAA2B;CAC5D,OAAO,QAAQ,IAAI,MAAM,GAAG,aAAa,CAAC,QAAQ,QAAQ,MAAM,KAAK;;AAGvE,SAAS,eAAe,QAAgB,UAA0B;CAChE,OAAO,GAAG,OAAO,QAAQ,OAAO,GAAG,CAAC,GAAG;;AAGzC,SAAS,gBAAgB,OAAuB;CAC9C,OAAO,MAAM,WAAW,mBAAmB,IAAI;;AAGjD,SAAS,YAAY,KAAa,OAAiD;CACjF,OAAO;EACL;EACA,KAAK,MAAM;EACX,OAAO,MAAM,eAAe;EAC5B,QAAQ,MAAM,eAAe;EAC9B;;;;AC5JH,SAAgB,mBACd,WACA,MACA,QACA,SACQ;CACR,MAAM,UAAU,iBAAiB,mBAAmB,KAAK,KAAK,YAAY;CAC1E,MAAM,SAAS,WAAW,KAAK,KAAK,KAAK;CACzC,MAAM,SAAS,WAAW,KAAK,KAAK,YAAY;CAChD,MAAM,SAAS,OAAO,SAClB,sCAAsC,gBAAgB,OAAO,OAAO,CAAC,oEACrE;CACJ,MAAM,QAAQ,YAAY,OAAO;CACjC,MAAM,SAAS,aAAa,WAAW,KAAK,YAAY,QAAQ,KAAK;CAErE,OAAO;EACL;EACA;EACA,sCAAsC,gBAAgB,QAAQ,CAAC;EAC/D;EACA,uCAAuC,OAAO;EAC9C,0CAA0C,OAAO;EACjD;EACA,+BAA+B,gBAAgB,KAAK,CAAC;EACrD;EACA;EACA;EACD,CAAC,KAAK,GAAG;;AAGZ,SAAgB,gBAAgB,MAAyB;CACvD,MAAM,CAAC,OAAO,OAAO,KAAK,sBAAsB,CAAC,GAAG,KAAK,KAAK,OAAO;CACrE,MAAM,WAAW,gBAAgB,KAAK,CACnC,QAAQ,WAAW,WAAW,OAAO,SAAS,OAAO,IAAI,CAAC,CAC1D,MAAM,MAAM,UAAU,KAAK,QAAS,KAAK,MAAM,QAAS,GAAG;CAE9D,IAAI,SAAS;CACb,IAAI,SAAS;CACb,KAAK,MAAM,UAAU,UAAU;EAC7B,MAAM,CAAC,aAAa,aAAa,OAAO;EACxC,IAAI,cAAc,QAAQ;EAC1B,UAAU,WAAW,KAAK,KAAK,MAAM,QAAQ,YAAY,CAAC;EAC1D,IAAI,OAAO,SAAS,OAAO;GACzB,MAAM,OAAO,OAAO,gBAAgB,OAAO;GAC3C,MAAM,QAAQ,OAAO,eAAe;GACpC,UAAU,YAAY,gBAAgB,KAAK,CAAC,8CAA8C,WAAW,MAAM,CAAC;;EAE9G,SAAS;;CAEX,UAAU,WAAW,KAAK,KAAK,MAAM,QAAQ,IAAI,CAAC;CAClD,OAAO,OAAO,MAAM;;AAGtB,SAAS,gBAAgB,MAAiE;CACxF,OAAO,CACL,IAAI,KAAK,UAAU,QAAQ,EAAE,EAAE,KAAK,YAAY;EAAE,GAAG;EAAQ,MAAM;EAAgB,EAAE,EACrF,IAAI,KAAK,UAAU,SAAS,EAAE,EAAE,KAAK,YAAY;EAAE,GAAG;EAAQ,MAAM;EAAkB,EAAE,CACzF;;AAGH,SAAS,WACP,SACA,OACA,KAC6B;CAC7B,OAAO,QAAQ,WAAW,QAAQ,MAAM,SAAS,QAAQ,MAAM,OAAO,QAAQ,KAAK,QAAQ,GAAG;;AAGhG,SAAS,YAAY,QAA6B;CAChD,IAAI,OAAO,MAAM,WAAW,GAAG,OAAO;CACtC,MAAM,SAAS,OAAO,MACnB,KAAK,SAAS;EACb,MAAM,OAAO,CACX,KAAK,QAAQ,WAAW,KAAK,MAAM,KAAK,IACxC,KAAK,SAAS,YAAY,KAAK,OAAO,KAAK,GAC5C,CAAC,KAAK,GAAG;EACV,OAAO,0CAA0C,gBAAgB,KAAK,IAAI,CAAC,SAAS,gBAAgB,KAAK,OAAO,GAAG,CAAC,GAAG,KAAK;GAC5H,CACD,KAAK,GAAG;CACX,OAAO,4CAA4C,OAAO,MAAM,OAAO,IAAI,OAAO;;AAGpF,SAAS,aAAa,WAAmB,WAA+B,MAAsB;CAC5F,IAAI,CAAC,WACH,OAAO,yEAAyE,gBAAgB,UAAU,CAAC;CAE7G,MAAM,OAAO,IAAI,KAAK,UAAU;CAChC,IAAI,OAAO,MAAM,KAAK,SAAS,CAAC,EAAE,OAAO,aAAa,WAAW,KAAA,GAAW,KAAK;CACjF,MAAM,MAAM,KAAK,aAAa;CAC9B,IAAI;CACJ,IAAI;EACF,QAAQ,IAAI,KAAK,eAAe,MAAM;GAAE,WAAW;GAAU,UAAU;GAAO,CAAC,CAAC,OAAO,KAAK;SACtF;EACN,QAAQ,IAAI,KAAK,eAAe,MAAM;GAAE,WAAW;GAAU,UAAU;GAAO,CAAC,CAAC,OAAO,KAAK;;CAE9F,OAAO,yEAAyE,gBAAgB,UAAU,CAAC,8DAA8D,IAAI,IAAI,WAAW,MAAM,CAAC;;AAGrM,SAAS,WAAW,OAAuB;CACzC,OAAO,WAAW,MAAM,CAAC,WAAW,MAAM,OAAO;;AAGnD,SAAS,gBAAgB,OAAuB;CAC9C,OAAO,WAAW,MAAM,CAAC,WAAW,KAAK,QAAQ;;AAGnD,SAAS,WAAW,OAAuB;CACzC,OAAO,MACJ,WAAW,KAAK,QAAQ,CACxB,WAAW,KAAK,OAAO,CACvB,WAAW,KAAK,OAAO,CACvB,WAAW,MAAK,SAAS,CACzB,WAAW,KAAK,QAAQ;;;;AC5G7B,MAAM,gBAAgB;AAEtB,SAAgB,2BACd,SAC6B;CAC7B,OAAO;EACL,OAAO,QAAQ,SAAS;EACxB,MAAM,QAAQ,QAAQ;EACtB,SAAS,QAAQ,WAAW;EAC5B,OAAO,QAAQ,SAAS;EACxB,UAAUC,UAAAA,QAAK,QAAQ,QAAQ,YAAY,4BAA4B;EACvE,gBAAgBA,UAAAA,QAAK,QAAQ,QAAQ,kBAAkB,4BAA4B;EACnF,iBAAiB,QAAQ,mBAAmB;EAC7C;;AAGH,eAAsB,uBACpB,MACA,SACiB;CACjB,MAAM,WAAW,2BAA2B,QAAQ;CACpD,IAAI,CAAC,SAAS,OAAO,OAAO;CAE5B,IAAI,SAAS;CACb,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,KAAK,SAAS,cAAc,EAAE;EAChD,MAAM,QAAQ,MAAM,SAAS;EAC7B,UAAU,KAAK,MAAM,QAAQ,MAAM;EACnC,MAAM,YAAY,wBAAwB,MAAM,GAAG;EACnD,IAAI,CAAC,WAAW;GACd,UAAU,MAAM;GAChB,SAAS,QAAQ,MAAM,GAAG;GAC1B;;EAGF,MAAM,OAAO,MAAM,eAAe,UAAU,IAAI,SAAS;EACzD,IAAI,CAAC,MAAM;GACT,UAAU,MAAM;GAChB,SAAS,QAAQ,MAAM,GAAG;GAC1B;;EAGF,MAAM,SAAS,MAAM,uBAAuB,UAAU,IAAI,MAAM,SAAS;EACzE,UAAU,mBAAmB,UAAU,KAAK,MAAM,QAAQ,SAAS;EACnE,SAAS,QAAQ,MAAM,GAAG;;CAE5B,OAAO,SAAS,KAAK,MAAM,OAAO;;;;;ACfpC,eAAsB,qBACpB,MACA,SACiB;CACjB,IAAI,CAAC,qBAAqB,QAAQ,IAAI,CAAC,eAAe,KAAK,EACzD,OAAO;CAGT,IAAI,SAAS;CACb,IAAI,OAAO,QAAQ,YAAY,UAC7B,SAAS,MAAM,uBAAuB,QAAQ,QAAQ,QAAQ;CAEhE,IAAI,CAAC,eAAe,OAAO,EAAE,OAAO;CAGpC,QAAO,MADWC,aAAAA,kBAAkB,EACzB,qBAAqB,QAAQ;EACtC,SAAS,QAAQ;EACjB,YAAY,QAAQ;EACpB,SAAS,QAAQ,QAAQ,QAAQ;EACjC,SAAS,QAAQ;EACjB,cAAc,QAAQ;EACvB,CAAC;;AAGJ,SAAS,qBAAqB,SAAqC;CACjE,OAAO,QACL,QAAQ,WACR,QAAQ,cACR,QAAQ,WACR,QAAQ,WACR,QAAQ,aACT;;AAGH,SAAS,eAAe,MAAuB;CAC7C,OAAO,gEAAgE,KAAK,KAAK"}