featuredrop 1.4.0 → 2.2.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 (62) hide show
  1. package/README.md +287 -760
  2. package/dist/adapters.cjs +1757 -0
  3. package/dist/adapters.cjs.map +1 -0
  4. package/dist/adapters.d.cts +744 -0
  5. package/dist/adapters.d.ts +744 -0
  6. package/dist/adapters.js +1745 -0
  7. package/dist/adapters.js.map +1 -0
  8. package/dist/admin.cjs +148 -32
  9. package/dist/admin.cjs.map +1 -1
  10. package/dist/admin.d.cts +14 -3
  11. package/dist/admin.d.ts +14 -3
  12. package/dist/admin.js +148 -32
  13. package/dist/admin.js.map +1 -1
  14. package/dist/bridges.cjs +111 -13
  15. package/dist/bridges.cjs.map +1 -1
  16. package/dist/bridges.d.cts +12 -5
  17. package/dist/bridges.d.ts +12 -5
  18. package/dist/bridges.js +111 -13
  19. package/dist/bridges.js.map +1 -1
  20. package/dist/ci.cjs +34 -0
  21. package/dist/ci.cjs.map +1 -1
  22. package/dist/ci.d.cts +5 -1
  23. package/dist/ci.d.ts +5 -1
  24. package/dist/ci.js +34 -1
  25. package/dist/ci.js.map +1 -1
  26. package/dist/cms.cjs +835 -0
  27. package/dist/cms.cjs.map +1 -0
  28. package/dist/cms.d.cts +236 -0
  29. package/dist/cms.d.ts +236 -0
  30. package/dist/cms.js +829 -0
  31. package/dist/cms.js.map +1 -0
  32. package/dist/flags.cjs +27 -7
  33. package/dist/flags.cjs.map +1 -1
  34. package/dist/flags.d.cts +14 -0
  35. package/dist/flags.d.ts +14 -0
  36. package/dist/flags.js +27 -7
  37. package/dist/flags.js.map +1 -1
  38. package/dist/index.cjs +52 -4481
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +1 -1340
  41. package/dist/index.d.ts +1 -1340
  42. package/dist/index.js +53 -4388
  43. package/dist/index.js.map +1 -1
  44. package/dist/markdown.cjs +257 -0
  45. package/dist/markdown.cjs.map +1 -0
  46. package/dist/markdown.d.cts +9 -0
  47. package/dist/markdown.d.ts +9 -0
  48. package/dist/markdown.js +234 -0
  49. package/dist/markdown.js.map +1 -0
  50. package/dist/renderer.cjs +503 -0
  51. package/dist/renderer.cjs.map +1 -0
  52. package/dist/renderer.d.cts +250 -0
  53. package/dist/renderer.d.ts +250 -0
  54. package/dist/renderer.js +501 -0
  55. package/dist/renderer.js.map +1 -0
  56. package/dist/rss.cjs +291 -0
  57. package/dist/rss.cjs.map +1 -0
  58. package/dist/rss.d.cts +158 -0
  59. package/dist/rss.d.ts +158 -0
  60. package/dist/rss.js +268 -0
  61. package/dist/rss.js.map +1 -0
  62. package/package.json +72 -6
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/markdown.ts","../src/rss.ts","../src/bridges.ts"],"names":["sanitized","decoded"],"mappings":"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","file":"bridges.js","sourcesContent":["import * as moduleApi from \"module\";\n\n// Lightweight markdown parser with optional `marked` + `shiki` support.\n// The function is synchronous and always returns sanitized HTML.\n\ntype MarkedRenderer = {\n link?: (href: string | null, title: string | null, text: string) => string;\n image?: (href: string | null, title: string | null, text: string) => string;\n paragraph?: (text: string) => string;\n heading?: (text: string, level: number) => string;\n};\n\ntype MarkedModule = {\n Renderer?: new () => MarkedRenderer;\n parse?: (markdown: string, options?: { renderer?: MarkedRenderer }) => string | Promise<string>;\n};\n\ntype ShikiLike = {\n codeToHtml?: (code: string, options?: { lang?: string; theme?: string }) => string | Promise<string>;\n};\n\nconst dynamicRequire =\n typeof moduleApi.createRequire === \"function\" ? moduleApi.createRequire(import.meta.url) : null;\n\nlet cachedMarked: MarkedModule | null | false = null;\nlet cachedShiki: ShikiLike | null | false = null;\n\nfunction optionalRequire<T>(name: string): T | null {\n if (!dynamicRequire) return null;\n try {\n // Using dynamic require so missing optional peers don't break bundling/runtime.\n return dynamicRequire(name) as T;\n } catch (error: unknown) {\n if (error && typeof error === \"object\" && \"code\" in error && (error as { code?: string }).code === \"MODULE_NOT_FOUND\") {\n return null;\n }\n // Any other error should still be treated as a failure to keep parsing resilient.\n return null;\n }\n}\n\nfunction getMarked(): MarkedModule | null {\n if (cachedMarked !== null) return cachedMarked || null;\n cachedMarked = optionalRequire<MarkedModule>(\"marked\") ?? false;\n return cachedMarked || null;\n}\n\nfunction getShiki(): ShikiLike | null {\n if (cachedShiki !== null) return cachedShiki || null;\n cachedShiki = optionalRequire<ShikiLike>(\"shiki\") ?? false;\n return cachedShiki || null;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction sanitizeUrl(url: string | null | undefined): string | null {\n if (!url) return null;\n const trimmed = url.trim();\n if (!trimmed) return null;\n\n const lower = trimmed.toLowerCase();\n if (lower.startsWith(\"javascript:\")) return null;\n if (lower.startsWith(\"data:\")) return null;\n if (lower.startsWith(\"vbscript:\")) return null;\n\n // Disallow characters that can break attribute context\n if (/['\"<>\\s]/.test(trimmed)) return null;\n\n return trimmed;\n}\n\nfunction sanitizeHtml(html: string): string {\n return html\n // Remove script/style tags entirely\n .replace(/<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style[\\s\\S]*?>[\\s\\S]*?<\\/style>/gi, \"\")\n // Remove inline event handlers (on*)\n .replace(/\\s+on[a-z]+\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi, \"\")\n // Remove javascript: or data: URLs in href/src/xlink:href\n .replace(/\\s+(?:href|src|xlink:href)\\s*=\\s*(\"|')(?:javascript:|data:)[^\"']*\\1/gi, \"\");\n}\n\nfunction decodeAllowedEntities(html: string): string {\n const allowTags = [\n \"p\",\n \"strong\",\n \"em\",\n \"a\",\n \"code\",\n \"pre\",\n \"img\",\n \"ul\",\n \"ol\",\n \"li\",\n \"blockquote\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"br\",\n ];\n\n // Decode common entities inside allowed tags only\n return html.replace(/&lt;(\\/?)([a-z0-9]+)([^>]*)&gt;/gi, (match, slash, tag, rest) => {\n if (!allowTags.includes(tag.toLowerCase())) return match;\n const decodedRest = rest\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\");\n return `<${slash}${tag}${decodedRest}>`;\n });\n}\n\nfunction renderCodeBlock(code: string, language: string | undefined): string {\n const shiki = getShiki();\n if (shiki?.codeToHtml) {\n try {\n const rendered = shiki.codeToHtml(code, { lang: language || \"text\", theme: \"github-dark\" });\n if (typeof rendered === \"string\") return rendered;\n } catch {\n // Fall through to non-highlighted rendering\n }\n }\n\n const langAttr = language ? ` class=\"language-${escapeHtml(language)}\"` : \"\";\n return `<pre><code${langAttr}>${escapeHtml(code)}</code></pre>`;\n}\n\nfunction inlineMarkdown(text: string): string {\n // Escape user-provided HTML before applying markdown conversions.\n let result = escapeHtml(text);\n\n // Protect inline code spans so subsequent replacements don't mangle them.\n const codeSpans: string[] = [];\n result = result.replace(/`([^`]+)`/g, (_match, code) => {\n const idx = codeSpans.length;\n codeSpans.push(`<code>${escapeHtml(code)}</code>`);\n return `§§CODE${idx}§§`;\n });\n\n // Images: ![alt](url)\n result = result.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_match, alt, url) => {\n const safeUrl = sanitizeUrl(url);\n const safeAlt = escapeHtml(alt ?? \"\");\n if (!safeUrl) return safeAlt;\n return `<img src=\"${escapeHtml(safeUrl)}\" alt=\"${safeAlt}\" />`;\n });\n\n // Links: [text](url)\n result = result.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label, url) => {\n const safeUrl = sanitizeUrl(url);\n const safeLabel = escapeHtml(label ?? \"\");\n if (!safeUrl) return safeLabel;\n return `<a href=\"${escapeHtml(safeUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${safeLabel}</a>`;\n });\n\n // Bold and italic (basic)\n result = result.replace(/\\*\\*([^*]+)\\*\\*/g, \"<strong>$1</strong>\");\n result = result.replace(/\\*([^*]+)\\*/g, \"<em>$1</em>\");\n\n // Restore code spans\n result = result.replace(/§§CODE(\\d+)§§/g, (_m, idx) => codeSpans[Number(idx)] ?? \"\");\n\n return result;\n}\n\nfunction fallbackParse(markdown: string): string {\n const lines = markdown.split(/\\r?\\n/);\n const blocks: string[] = [];\n let listBuffer: string[] | null = null;\n let quoteBuffer: string[] | null = null;\n let inCodeBlock = false;\n let codeLang: string | undefined;\n let codeLines: string[] = [];\n\n const flushList = () => {\n if (!listBuffer) return;\n blocks.push(`<ul>${listBuffer.map((item) => `<li>${item}</li>`).join(\"\")}</ul>`);\n listBuffer = null;\n };\n\n const flushQuote = () => {\n if (!quoteBuffer) return;\n const content = quoteBuffer.map((line) => inlineMarkdown(line.trim())).join(\"<br>\");\n blocks.push(`<blockquote>${content}</blockquote>`);\n quoteBuffer = null;\n };\n\n const flushCode = () => {\n if (!inCodeBlock) return;\n blocks.push(renderCodeBlock(codeLines.join(\"\\n\"), codeLang));\n codeLines = [];\n codeLang = undefined;\n inCodeBlock = false;\n };\n\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\s+$/, \"\");\n\n const codeFence = line.match(/^```(.*)$/);\n if (codeFence) {\n if (inCodeBlock) {\n flushCode();\n } else {\n flushList();\n flushQuote();\n inCodeBlock = true;\n codeLang = codeFence[1]?.trim() || undefined;\n codeLines = [];\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeLines.push(rawLine);\n continue;\n }\n\n const listMatch = line.match(/^\\s*[-*+]\\s+(.*)$/);\n if (listMatch) {\n flushQuote();\n listBuffer = listBuffer ?? [];\n listBuffer.push(inlineMarkdown(listMatch[1].trim()));\n continue;\n }\n\n if (listBuffer) flushList();\n\n const headingMatch = line.match(/^(#{1,6})\\s+(.*)$/);\n if (headingMatch) {\n flushQuote();\n const level = headingMatch[1].length;\n const content = inlineMarkdown(headingMatch[2].trim());\n blocks.push(`<h${level}>${content}</h${level}>`);\n continue;\n }\n\n const quoteMatch = line.match(/^>\\s?(.*)$/);\n if (quoteMatch) {\n quoteBuffer = quoteBuffer ?? [];\n quoteBuffer.push(quoteMatch[1]);\n continue;\n }\n\n if (quoteBuffer) flushQuote();\n\n if (!line.trim()) {\n continue;\n }\n\n blocks.push(`<p>${inlineMarkdown(line.trim())}</p>`);\n }\n\n flushList();\n flushQuote();\n flushCode();\n\n return blocks.join(\"\\n\");\n}\n\nfunction renderWithMarked(markdown: string, marked: MarkedModule): string | null {\n if (!marked.parse) return null;\n\n const renderer = marked.Renderer ? new marked.Renderer() : undefined;\n\n if (renderer) {\n renderer.link = (href, _title, text) => {\n const safeUrl = sanitizeUrl(href);\n if (!safeUrl) return escapeHtml(text);\n return `<a href=\"${escapeHtml(safeUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${text}</a>`;\n };\n renderer.image = (href, _title, text) => {\n const safeUrl = sanitizeUrl(href);\n const safeAlt = escapeHtml(text ?? \"\");\n if (!safeUrl) return safeAlt;\n return `<img src=\"${escapeHtml(safeUrl)}\" alt=\"${safeAlt}\" />`;\n };\n }\n\n const output = marked.parse(markdown, renderer ? { renderer } : undefined);\n if (typeof output === \"string\") return output;\n return output ? String(output) : null;\n}\n\n/**\n * Parse a feature description from markdown into sanitized HTML.\n * - Uses `marked` when installed (optional peer dep)\n * - Falls back to a tiny built-in parser when `marked` is absent\n * - Strips script tags, event handlers, and javascript:/data: URLs\n */\nexport function parseDescription(markdown: string): string {\n if (!markdown) return \"\";\n\n const marked = getMarked();\n if (marked) {\n try {\n const rendered = renderWithMarked(markdown, marked);\n if (rendered) {\n const sanitized = sanitizeHtml(rendered);\n const decoded = decodeAllowedEntities(sanitized);\n return sanitizeHtml(decoded);\n }\n } catch {\n // If marked fails for any reason, fall back to the tiny parser.\n }\n }\n\n // Fast path: raw HTML provided without `marked` installed\n if (/<[^>]+>/.test(markdown)) {\n const sanitized = sanitizeHtml(markdown);\n const decoded = decodeAllowedEntities(sanitized);\n return sanitizeHtml(decoded);\n }\n\n const fallback = fallbackParse(markdown);\n const sanitized = sanitizeHtml(fallback);\n const decoded = decodeAllowedEntities(sanitized);\n return sanitizeHtml(decoded);\n}\n","import type { FeatureManifest } from \"./types\";\nimport { parseDescription } from \"./markdown\";\n\nfunction escape(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n/**\n * Generate a simple RSS 2.0 feed from a feature manifest.\n * Titles and descriptions are sanitized via `parseDescription`.\n */\nexport function generateRSS(manifest: FeatureManifest, options?: { title?: string; link?: string; description?: string }): string {\n const title = escape(options?.title ?? \"Featuredrop Changelog\");\n const link = escape(options?.link ?? \"\");\n const desc = escape(options?.description ?? \"Product updates\");\n\n const items = manifest\n .slice()\n .sort((a, b) => new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime())\n .map((item) => {\n const descriptionHtml = item.description ? parseDescription(item.description) : \"\";\n const itemLink = item.url ? escape(item.url) : \"\";\n return [\n \"<item>\",\n `<title>${escape(item.label)}</title>`,\n itemLink ? `<link>${itemLink}</link>` : \"\",\n `<guid isPermaLink=\\\"false\\\">${escape(item.id)}</guid>`,\n `<pubDate>${new Date(item.releasedAt).toUTCString()}</pubDate>`,\n `<description><![CDATA[${descriptionHtml}]]></description>`,\n \"</item>\",\n ].join(\"\");\n })\n .join(\"\");\n\n return [\n \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n \"<rss version=\\\"2.0\\\">\",\n \"<channel>\",\n `<title>${title}</title>`,\n link ? `<link>${link}</link>` : \"\",\n `<description>${desc}</description>`,\n items,\n \"</channel>\",\n \"</rss>\",\n ].join(\"\");\n}\n","import { generateRSS } from \"./rss\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\n\nasync function postJson(url: string, payload: unknown, headers?: Record<string, string>): Promise<void> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(headers ?? {}),\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n throw new Error(`[featuredrop] Bridge request failed (${response.status}) for ${url}`);\n }\n}\n\nfunction formatFeatureLine(feature: FeatureEntry): string {\n const released = new Date(feature.releasedAt).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n return `${feature.label} (${released})`;\n}\n\nexport interface SlackBridgeOptions {\n webhookUrl: string;\n username?: string;\n iconEmoji?: string;\n channel?: string;\n formatter?: (feature: FeatureEntry) => Record<string, unknown>;\n}\n\nexport const SlackBridge = {\n async notify(feature: FeatureEntry, options: SlackBridgeOptions): Promise<void> {\n const payload = options.formatter\n ? options.formatter(feature)\n : {\n username: options.username,\n icon_emoji: options.iconEmoji,\n channel: options.channel,\n text: `New feature published: *${feature.label}*`,\n attachments: [\n {\n color: \"#2563eb\",\n title: feature.label,\n text: feature.description ?? \"No description provided.\",\n title_link: feature.url,\n footer: `featuredrop | ${feature.id}`,\n },\n ],\n };\n await postJson(options.webhookUrl, payload);\n },\n};\n\nexport interface DiscordBridgeOptions {\n webhookUrl: string;\n username?: string;\n avatarUrl?: string;\n formatter?: (feature: FeatureEntry) => Record<string, unknown>;\n}\n\nexport const DiscordBridge = {\n async notify(feature: FeatureEntry, options: DiscordBridgeOptions): Promise<void> {\n const payload = options.formatter\n ? options.formatter(feature)\n : {\n username: options.username ?? \"featuredrop\",\n avatar_url: options.avatarUrl,\n embeds: [\n {\n title: feature.label,\n description: feature.description ?? \"No description provided.\",\n url: feature.url,\n color: 0x2563eb,\n footer: {\n text: `featuredrop | ${feature.id}`,\n },\n },\n ],\n };\n await postJson(options.webhookUrl, payload);\n },\n};\n\nexport interface WebhookBridgeOptions {\n url: string;\n headers?: Record<string, string>;\n event?: string;\n body?: Record<string, unknown>;\n}\n\nexport const WebhookBridge = {\n async post(feature: FeatureEntry, options: WebhookBridgeOptions): Promise<void> {\n const payload = {\n event: options.event ?? \"feature.published\",\n feature,\n sentAt: new Date().toISOString(),\n ...(options.body ?? {}),\n };\n await postJson(options.url, payload, options.headers);\n },\n};\n\nexport interface EmailDigestGeneratorOptions {\n title?: string;\n intro?: string;\n template?: \"default\" | \"minimal\";\n productName?: string;\n}\n\nexport const EmailDigestGenerator = {\n generate(features: readonly FeatureEntry[], options: EmailDigestGeneratorOptions = {}): string {\n const title = options.title ?? \"Product Updates\";\n const intro = options.intro ?? \"Here are the latest updates:\";\n const productName = options.productName ?? \"Your Product\";\n const template = options.template ?? \"default\";\n\n const listItems = features\n .map((feature) => {\n const safeLabel = feature.label.replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n const safeDescription = (feature.description ?? \"\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n const link = feature.url\n ? `<a href=\"${feature.url}\" style=\"color:#2563eb;text-decoration:none;\">Read more</a>`\n : \"\";\n\n if (template === \"minimal\") {\n return `<li><strong>${safeLabel}</strong>${safeDescription ? ` - ${safeDescription}` : \"\"}</li>`;\n }\n\n return [\n \"<li style=\\\"margin:0 0 14px;\\\">\",\n `<p style=\"margin:0 0 4px;font-weight:600;color:#111827;\">${safeLabel}</p>`,\n safeDescription\n ? `<p style=\"margin:0 0 6px;color:#4b5563;line-height:1.45;\">${safeDescription}</p>`\n : \"\",\n link ? `<p style=\"margin:0;\">${link}</p>` : \"\",\n \"</li>\",\n ].join(\"\");\n })\n .join(\"\");\n\n if (template === \"minimal\") {\n return [\n \"<!doctype html>\",\n \"<html><body>\",\n `<h2>${title}</h2>`,\n `<p>${intro}</p>`,\n `<ul>${listItems}</ul>`,\n \"</body></html>\",\n ].join(\"\");\n }\n\n const summary = features.map((feature) => formatFeatureLine(feature)).join(\" | \");\n return [\n \"<!doctype html>\",\n \"<html>\",\n \"<body style=\\\"font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#f8fafc;padding:20px;\\\">\",\n \"<div style=\\\"max-width:640px;margin:0 auto;background:#ffffff;border:1px solid #e5e7eb;border-radius:12px;padding:20px;\\\">\",\n `<p style=\"margin:0 0 12px;color:#6b7280;font-size:12px;letter-spacing:0.08em;text-transform:uppercase;\">${productName}</p>`,\n `<h1 style=\"margin:0 0 8px;font-size:22px;color:#111827;\">${title}</h1>`,\n `<p style=\"margin:0 0 14px;color:#374151;\">${intro}</p>`,\n `<p style=\"margin:0 0 18px;color:#6b7280;font-size:13px;\">${summary}</p>`,\n `<ul style=\"padding-left:18px;margin:0;\">${listItems}</ul>`,\n \"</div>\",\n \"</body>\",\n \"</html>\",\n ].join(\"\");\n },\n};\n\nexport interface RSSFeedGeneratorOptions {\n title?: string;\n link?: string;\n description?: string;\n}\n\nexport const RSSFeedGenerator = {\n generate(manifest: FeatureManifest, options?: RSSFeedGeneratorOptions): string {\n return generateRSS(manifest, options);\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/markdown.ts","../src/rss.ts","../src/bridges.ts"],"names":["sanitized","decoded"],"mappings":";;;AAqBA,IAAM,iBACJ,OAAiB,SAAA,CAAA,aAAA,KAAkB,aAAuB,SAAA,CAAA,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA,GAAI,IAAA;AAE7F,IAAI,YAAA,GAA4C,IAAA;AAChD,IAAI,WAAA,GAAwC,IAAA;AAE5C,SAAS,gBAAmB,IAAA,EAAwB;AAClD,EAAA,IAAI,CAAC,gBAAgB,OAAO,IAAA;AAC5B,EAAA,IAAI;AAEF,IAAA,OAAO,eAAe,IAAI,CAAA;AAAA,EAC5B,SAAS,KAAA,EAAgB;AACvB,IAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,UAAU,KAAA,IAAU,KAAA,CAA4B,SAAS,kBAAA,EAAoB;AACrH,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,SAAA,GAAiC;AACxC,EAAA,IAAI,YAAA,KAAiB,IAAA,EAAM,OAAO,YAAA,IAAgB,IAAA;AAClD,EAAA,YAAA,GAAe,eAAA,CAA8B,QAAQ,CAAA,IAAK,KAAA;AAC1D,EAAA,OAAO,YAAA,IAAgB,IAAA;AACzB;AAEA,SAAS,QAAA,GAA6B;AACpC,EAAA,IAAI,WAAA,KAAgB,IAAA,EAAM,OAAO,WAAA,IAAe,IAAA;AAChD,EAAA,WAAA,GAAc,eAAA,CAA2B,OAAO,CAAA,IAAK,KAAA;AACrD,EAAA,OAAO,WAAA,IAAe,IAAA;AACxB;AAEA,SAAS,WAAW,KAAA,EAAuB;AACzC,EAAA,OAAO,MACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,OAAO,CAAA;AAC1B;AAEA,SAAS,YAAY,GAAA,EAA+C;AAClE,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,MAAM,OAAA,GAAU,IAAI,IAAA,EAAK;AACzB,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,MAAM,KAAA,GAAQ,QAAQ,WAAA,EAAY;AAClC,EAAA,IAAI,KAAA,CAAM,UAAA,CAAW,aAAa,CAAA,EAAG,OAAO,IAAA;AAC5C,EAAA,IAAI,KAAA,CAAM,UAAA,CAAW,OAAO,CAAA,EAAG,OAAO,IAAA;AACtC,EAAA,IAAI,KAAA,CAAM,UAAA,CAAW,WAAW,CAAA,EAAG,OAAO,IAAA;AAG1C,EAAA,IAAI,UAAA,CAAW,IAAA,CAAK,OAAO,CAAA,EAAG,OAAO,IAAA;AAErC,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,aAAa,IAAA,EAAsB;AAC1C,EAAA,OAAO,IAAA,CAEJ,OAAA,CAAQ,sCAAA,EAAwC,EAAE,EAClD,OAAA,CAAQ,oCAAA,EAAsC,EAAE,CAAA,CAEhD,QAAQ,+CAAA,EAAiD,EAAE,CAAA,CAE3D,OAAA,CAAQ,yEAAyE,EAAE,CAAA;AACxF;AAEA,SAAS,sBAAsB,IAAA,EAAsB;AACnD,EAAA,MAAM,SAAA,GAAY;AAAA,IAChB,GAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA;AAAA,IACA,GAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,YAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,OAAO,KAAK,OAAA,CAAQ,mCAAA,EAAqC,CAAC,KAAA,EAAO,KAAA,EAAO,KAAK,IAAA,KAAS;AACpF,IAAA,IAAI,CAAC,SAAA,CAAU,QAAA,CAAS,IAAI,WAAA,EAAa,GAAG,OAAO,KAAA;AACnD,IAAA,MAAM,WAAA,GAAc,KACjB,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA,CACtB,OAAA,CAAQ,UAAU,GAAG,CAAA,CACrB,QAAQ,QAAA,EAAU,GAAG,EACrB,OAAA,CAAQ,OAAA,EAAS,GAAG,CAAA,CACpB,OAAA,CAAQ,SAAS,GAAG,CAAA;AACvB,IAAA,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA,EAAG,GAAG,GAAG,WAAW,CAAA,CAAA,CAAA;AAAA,EACtC,CAAC,CAAA;AACH;AAEA,SAAS,eAAA,CAAgB,MAAc,QAAA,EAAsC;AAC3E,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,IAAI,OAAO,UAAA,EAAY;AACrB,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,UAAA,CAAW,IAAA,EAAM,EAAE,MAAM,QAAA,IAAY,MAAA,EAAQ,KAAA,EAAO,aAAA,EAAe,CAAA;AAC1F,MAAA,IAAI,OAAO,QAAA,KAAa,QAAA,EAAU,OAAO,QAAA;AAAA,IAC3C,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,QAAA,GAAW,CAAA,iBAAA,EAAoB,UAAA,CAAW,QAAQ,CAAC,CAAA,CAAA,CAAA,GAAM,EAAA;AAC1E,EAAA,OAAO,CAAA,UAAA,EAAa,QAAQ,CAAA,CAAA,EAAI,UAAA,CAAW,IAAI,CAAC,CAAA,aAAA,CAAA;AAClD;AAEA,SAAS,eAAe,IAAA,EAAsB;AAE5C,EAAA,IAAI,MAAA,GAAS,WAAW,IAAI,CAAA;AAG5B,EAAA,MAAM,YAAsB,EAAC;AAC7B,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,YAAA,EAAc,CAAC,QAAQ,IAAA,KAAS;AACtD,IAAA,MAAM,MAAM,SAAA,CAAU,MAAA;AACtB,IAAA,SAAA,CAAU,IAAA,CAAK,CAAA,MAAA,EAAS,UAAA,CAAW,IAAI,CAAC,CAAA,OAAA,CAAS,CAAA;AACjD,IAAA,OAAO,eAAS,GAAG,CAAA,QAAA,CAAA;AAAA,EACrB,CAAC,CAAA;AAGD,EAAA,MAAA,GAAS,OAAO,OAAA,CAAQ,2BAAA,EAA6B,CAAC,MAAA,EAAQ,KAAK,GAAA,KAAQ;AACzE,IAAA,MAAM,OAAA,GAAU,YAAY,GAAG,CAAA;AAC/B,IAAA,MAAM,OAAA,GAAU,UAAA,CAAW,GAAA,IAAO,EAAE,CAAA;AACpC,IAAA,IAAI,CAAC,SAAS,OAAO,OAAA;AACrB,IAAA,OAAO,CAAA,UAAA,EAAa,UAAA,CAAW,OAAO,CAAC,UAAU,OAAO,CAAA,IAAA,CAAA;AAAA,EAC1D,CAAC,CAAA;AAGD,EAAA,MAAA,GAAS,OAAO,OAAA,CAAQ,0BAAA,EAA4B,CAAC,MAAA,EAAQ,OAAO,GAAA,KAAQ;AAC1E,IAAA,MAAM,OAAA,GAAU,YAAY,GAAG,CAAA;AAC/B,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,KAAA,IAAS,EAAE,CAAA;AACxC,IAAA,IAAI,CAAC,SAAS,OAAO,SAAA;AACrB,IAAA,OAAO,CAAA,SAAA,EAAY,UAAA,CAAW,OAAO,CAAC,+CAA+C,SAAS,CAAA,IAAA,CAAA;AAAA,EAChG,CAAC,CAAA;AAGD,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,kBAAA,EAAoB,qBAAqB,CAAA;AACjE,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,cAAA,EAAgB,aAAa,CAAA;AAGrD,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,gBAAA,EAAkB,CAAC,EAAA,EAAI,GAAA,KAAQ,SAAA,CAAU,MAAA,CAAO,GAAG,CAAC,CAAA,IAAK,EAAE,CAAA;AAEnF,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,cAAc,QAAA,EAA0B;AAC/C,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA;AACpC,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI,UAAA,GAA8B,IAAA;AAClC,EAAA,IAAI,WAAA,GAA+B,IAAA;AACnC,EAAA,IAAI,WAAA,GAAc,KAAA;AAClB,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI,YAAsB,EAAC;AAE3B,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,IAAI,CAAC,UAAA,EAAY;AACjB,IAAA,MAAA,CAAO,IAAA,CAAK,CAAA,IAAA,EAAO,UAAA,CAAW,GAAA,CAAI,CAAC,IAAA,KAAS,CAAA,IAAA,EAAO,IAAI,CAAA,KAAA,CAAO,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC,CAAA,KAAA,CAAO,CAAA;AAC/E,IAAA,UAAA,GAAa,IAAA;AAAA,EACf,CAAA;AAEA,EAAA,MAAM,aAAa,MAAM;AACvB,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,MAAM,OAAA,GAAU,WAAA,CAAY,GAAA,CAAI,CAAC,IAAA,KAAS,cAAA,CAAe,IAAA,CAAK,IAAA,EAAM,CAAC,CAAA,CAAE,IAAA,CAAK,MAAM,CAAA;AAClF,IAAA,MAAA,CAAO,IAAA,CAAK,CAAA,YAAA,EAAe,OAAO,CAAA,aAAA,CAAe,CAAA;AACjD,IAAA,WAAA,GAAc,IAAA;AAAA,EAChB,CAAA;AAEA,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,MAAA,CAAO,KAAK,eAAA,CAAgB,SAAA,CAAU,KAAK,IAAI,CAAA,EAAG,QAAQ,CAAC,CAAA;AAC3D,IAAA,SAAA,GAAY,EAAC;AACb,IAAA,QAAA,GAAW,MAAA;AACX,IAAA,WAAA,GAAc,KAAA;AAAA,EAChB,CAAA;AAEA,EAAA,KAAA,MAAW,WAAW,KAAA,EAAO;AAC3B,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAEvC,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA;AACxC,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,SAAA,EAAU;AAAA,MACZ,CAAA,MAAO;AACL,QAAA,SAAA,EAAU;AACV,QAAA,UAAA,EAAW;AACX,QAAA,WAAA,GAAc,IAAA;AACd,QAAA,QAAA,GAAW,SAAA,CAAU,CAAC,CAAA,EAAG,IAAA,EAAK,IAAK,MAAA;AACnC,QAAA,SAAA,GAAY,EAAC;AAAA,MACf;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,SAAA,CAAU,KAAK,OAAO,CAAA;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,mBAAmB,CAAA;AAChD,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,UAAA,EAAW;AACX,MAAA,UAAA,GAAa,cAAc,EAAC;AAC5B,MAAA,UAAA,CAAW,KAAK,cAAA,CAAe,SAAA,CAAU,CAAC,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AACnD,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,YAAY,SAAA,EAAU;AAE1B,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,mBAAmB,CAAA;AACnD,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,UAAA,EAAW;AACX,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,CAAC,CAAA,CAAE,MAAA;AAC9B,MAAA,MAAM,UAAU,cAAA,CAAe,YAAA,CAAa,CAAC,CAAA,CAAE,MAAM,CAAA;AACrD,MAAA,MAAA,CAAO,KAAK,CAAA,EAAA,EAAK,KAAK,IAAI,OAAO,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA,CAAG,CAAA;AAC/C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,YAAY,CAAA;AAC1C,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,WAAA,GAAc,eAAe,EAAC;AAC9B,MAAA,WAAA,CAAY,IAAA,CAAK,UAAA,CAAW,CAAC,CAAC,CAAA;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,aAAa,UAAA,EAAW;AAE5B,IAAA,IAAI,CAAC,IAAA,CAAK,IAAA,EAAK,EAAG;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAA,CAAO,KAAK,CAAA,GAAA,EAAM,cAAA,CAAe,KAAK,IAAA,EAAM,CAAC,CAAA,IAAA,CAAM,CAAA;AAAA,EACrD;AAEA,EAAA,SAAA,EAAU;AACV,EAAA,UAAA,EAAW;AACX,EAAA,SAAA,EAAU;AAEV,EAAA,OAAO,MAAA,CAAO,KAAK,IAAI,CAAA;AACzB;AAEA,SAAS,gBAAA,CAAiB,UAAkB,MAAA,EAAqC;AAC/E,EAAA,IAAI,CAAC,MAAA,CAAO,KAAA,EAAO,OAAO,IAAA;AAE1B,EAAA,MAAM,WAAW,MAAA,CAAO,QAAA,GAAW,IAAI,MAAA,CAAO,UAAS,GAAI,MAAA;AAE3D,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,QAAA,CAAS,IAAA,GAAO,CAAC,IAAA,EAAM,MAAA,EAAQ,IAAA,KAAS;AACtC,MAAA,MAAM,OAAA,GAAU,YAAY,IAAI,CAAA;AAChC,MAAA,IAAI,CAAC,OAAA,EAAS,OAAO,UAAA,CAAW,IAAI,CAAA;AACpC,MAAA,OAAO,CAAA,SAAA,EAAY,UAAA,CAAW,OAAO,CAAC,+CAA+C,IAAI,CAAA,IAAA,CAAA;AAAA,IAC3F,CAAA;AACA,IAAA,QAAA,CAAS,KAAA,GAAQ,CAAC,IAAA,EAAM,MAAA,EAAQ,IAAA,KAAS;AACvC,MAAA,MAAM,OAAA,GAAU,YAAY,IAAI,CAAA;AAChC,MAAA,MAAM,OAAA,GAAU,UAAA,CAAW,IAAA,IAAQ,EAAE,CAAA;AACrC,MAAA,IAAI,CAAC,SAAS,OAAO,OAAA;AACrB,MAAA,OAAO,CAAA,UAAA,EAAa,UAAA,CAAW,OAAO,CAAC,UAAU,OAAO,CAAA,IAAA,CAAA;AAAA,IAC1D,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,OAAO,KAAA,CAAM,QAAA,EAAU,WAAW,EAAE,QAAA,KAAa,MAAS,CAAA;AACzE,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,EAAU,OAAO,MAAA;AACvC,EAAA,OAAO,MAAA,GAAS,MAAA,CAAO,MAAM,CAAA,GAAI,IAAA;AACnC;AAQO,SAAS,iBAAiB,QAAA,EAA0B;AACzD,EAAA,IAAI,CAAC,UAAU,OAAO,EAAA;AAEtB,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,gBAAA,CAAiB,QAAA,EAAU,MAAM,CAAA;AAClD,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,MAAMA,UAAAA,GAAY,aAAa,QAAQ,CAAA;AACvC,QAAA,MAAMC,QAAAA,GAAU,sBAAsBD,UAAS,CAAA;AAC/C,QAAA,OAAO,aAAaC,QAAO,CAAA;AAAA,MAC7B;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAGA,EAAA,IAAI,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC5B,IAAA,MAAMD,UAAAA,GAAY,aAAa,QAAQ,CAAA;AACvC,IAAA,MAAMC,QAAAA,GAAU,sBAAsBD,UAAS,CAAA;AAC/C,IAAA,OAAO,aAAaC,QAAO,CAAA;AAAA,EAC7B;AAEA,EAAA,MAAM,QAAA,GAAW,cAAc,QAAQ,CAAA;AACvC,EAAA,MAAM,SAAA,GAAY,aAAa,QAAQ,CAAA;AACvC,EAAA,MAAM,OAAA,GAAU,sBAAsB,SAAS,CAAA;AAC/C,EAAA,OAAO,aAAa,OAAO,CAAA;AAC7B;;;ACtUA,SAAS,OAAO,GAAA,EAAqB;AACnC,EAAA,OAAO,GAAA,CACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,EACrB,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,CAAA,CACpB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B;AAMO,SAAS,WAAA,CAAY,UAA2B,OAAA,EAA2E;AAChI,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,EAAS,KAAA,IAAS,uBAAuB,CAAA;AAC9D,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,EAAS,IAAA,IAAQ,EAAE,CAAA;AACvC,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,EAAS,WAAA,IAAe,iBAAiB,CAAA;AAE7D,EAAA,MAAM,KAAA,GAAQ,QAAA,CACX,KAAA,EAAM,CACN,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,IAAA,CAAK,CAAA,CAAE,UAAU,EAAE,OAAA,EAAQ,GAAI,IAAI,IAAA,CAAK,CAAA,CAAE,UAAU,CAAA,CAAE,OAAA,EAAS,CAAA,CAClF,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,MAAM,kBAAkB,IAAA,CAAK,WAAA,GAAc,gBAAA,CAAiB,IAAA,CAAK,WAAW,CAAA,GAAI,EAAA;AAChF,IAAA,MAAM,WAAW,IAAA,CAAK,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,GAAI,EAAA;AAC/C,IAAA,OAAO;AAAA,MACL,QAAA;AAAA,MACA,CAAA,OAAA,EAAU,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA,QAAA,CAAA;AAAA,MAC5B,QAAA,GAAW,CAAA,MAAA,EAAS,QAAQ,CAAA,OAAA,CAAA,GAAY,EAAA;AAAA,MACxC,CAAA,0BAAA,EAA+B,MAAA,CAAO,IAAA,CAAK,EAAE,CAAC,CAAA,OAAA,CAAA;AAAA,MAC9C,YAAY,IAAI,IAAA,CAAK,KAAK,UAAU,CAAA,CAAE,aAAa,CAAA,UAAA,CAAA;AAAA,MACnD,yBAAyB,eAAe,CAAA,iBAAA,CAAA;AAAA,MACxC;AAAA,KACF,CAAE,KAAK,EAAE,CAAA;AAAA,EACX,CAAC,CAAA,CACA,IAAA,CAAK,EAAE,CAAA;AAEV,EAAA,OAAO;AAAA,IACL,wCAAA;AAAA,IACA,qBAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAU,KAAK,CAAA,QAAA,CAAA;AAAA,IACf,IAAA,GAAO,CAAA,MAAA,EAAS,IAAI,CAAA,OAAA,CAAA,GAAY,EAAA;AAAA,IAChC,gBAAgB,IAAI,CAAA,cAAA,CAAA;AAAA,IACpB,KAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,EAAE,CAAA;AACX;;;ACrCA,IAAM,yBAAyB,CAAC,GAAA,EAAK,KAAK,GAAA,EAAK,GAAA,EAAK,KAAK,GAAG,CAAA;AAE5D,IAAM,kBAAA,GAAN,cAAiC,KAAA,CAAM;AAAA,EAC5B,MAAA;AAAA,EACA,SAAA;AAAA,EAET,WAAA,CAAY,OAAA,EAAiB,OAAA,GAAoD,EAAC,EAAG;AACnF,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AACZ,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,SAAA,IAAa,KAAA;AAAA,EACxC;AACF,CAAA;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,IAAI,EAAA,IAAM,CAAA,EAAG,OAAO,OAAA,CAAQ,OAAA,EAAQ;AACpC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,UAAA,CAAW,SAAS,EAAE,CAAA;AAAA,EACxB,CAAC,CAAA;AACH;AAEA,SAAS,iBAAA,CACP,WACA,YAAA,EACmF;AACnF,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,YAAA,EAAc;AAC/B,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,MAAA;AAAA,MACR,SAAS,MAAM;AAAA,MAEf,CAAA;AAAA,MACA,UAAU,MAAM;AAAA,KAClB;AAAA,EACF;AAEA,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,OAAA;AAEJ,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,IAAI,aAAa,OAAA,EAAS;AACxB,MAAA,UAAA,CAAW,KAAA,CAAM,aAAa,MAAM,CAAA;AAAA,IACtC,CAAA,MAAO;AACL,MAAA,OAAA,GAAU,MAAM,UAAA,CAAW,KAAA,CAAM,YAAA,CAAa,MAAM,CAAA;AACpD,MAAA,YAAA,CAAa,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IAChE;AAAA,EACF;AAEA,EAAA,IAAI,SAAA,IAAa,YAAY,CAAA,EAAG;AAC9B,IAAA,SAAA,GAAY,WAAW,MAAM;AAC3B,MAAA,gBAAA,GAAmB,IAAA;AACnB,MAAA,UAAA,CAAW,KAAA,EAAM;AAAA,IACnB,GAAG,SAAS,CAAA;AAAA,EACd;AAEA,EAAA,OAAO;AAAA,IACL,QAAQ,UAAA,CAAW,MAAA;AAAA,IACnB,SAAS,MAAM;AACb,MAAA,IAAI,SAAA,eAAwB,SAAS,CAAA;AACrC,MAAA,IAAI,YAAA,IAAgB,OAAA,EAAS,YAAA,CAAa,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAAA,IAChF,CAAA;AAAA,IACA,UAAU,MAAM;AAAA,GAClB;AACF;AAEA,eAAe,iBAAiB,QAAA,EAAqC;AACnE,EAAA,MAAM,OAAA,GACJ,YACA,OAAO,QAAA,KAAa,YACpB,MAAA,IAAU,QAAA,IACV,OAAO,QAAA,CAAS,IAAA,KAAS,UAAA;AAC3B,EAAA,IAAI,CAAC,SAAS,OAAO,EAAA;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAA;AAAA,EACT;AACF;AAEA,eAAe,QAAA,CACb,GAAA,EACA,OAAA,EACA,OAAA,GAAgC,EAAC,EAClB;AACf,EAAA,MAAM,aAAa,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,cAAc,CAAC,CAAA;AACtD,EAAA,MAAM,eAAe,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,gBAAgB,GAAG,CAAA;AAC5D,EAAA,MAAM,aAAA,GAAgB,IAAI,GAAA,CAAI,OAAA,CAAQ,mBAAmB,sBAAsB,CAAA;AAE/E,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,WAAS;AACP,IAAA,MAAM,EAAE,QAAQ,OAAA,EAAS,QAAA,KAAa,iBAAA,CAAkB,OAAA,CAAQ,SAAA,EAAW,OAAA,CAAQ,MAAM,CAAA;AACzF,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,QAChC,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,GAAI,OAAA,CAAQ,OAAA,IAAW;AAAC,SAC1B;AAAA,QACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAAA,QAC5B;AAAA,OACD,CAAA;AAED,MAAA,IAAI,SAAS,EAAA,EAAI;AAEjB,MAAA,MAAM,eAAA,GAAkB,aAAA,CAAc,GAAA,CAAI,QAAA,CAAS,MAAM,CAAA;AACzD,MAAA,MAAM,YAAA,GAAe,MAAM,gBAAA,CAAiB,QAAQ,CAAA;AACpD,MAAA,MAAM,OAAA,GAAU,YAAA,GACZ,CAAA,qCAAA,EAAwC,QAAA,CAAS,MAAM,CAAA,MAAA,EAAS,GAAG,CAAA,EAAA,EAAK,YAAY,CAAA,CAAA,GACpF,CAAA,qCAAA,EAAwC,QAAA,CAAS,MAAM,SAAS,GAAG,CAAA,CAAA;AAEvE,MAAA,IAAI,CAAC,eAAA,IAAmB,OAAA,IAAW,UAAA,EAAY;AAC7C,QAAA,MAAM,IAAI,mBAAmB,OAAA,EAAS;AAAA,UACpC,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,SAAA,EAAW;AAAA,SACZ,CAAA;AAAA,MACH;AAAA,IACF,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,uBAAuB,KAAA,YAAiB,kBAAA;AAC9C,MAAA,MAAM,YAAA,GACJ,KAAA,YAAiB,YAAA,GACb,KAAA,CAAM,IAAA,KAAS,YAAA,GACf,KAAA,IACE,OAAO,KAAA,KAAU,QAAA,IACjB,MAAA,IAAU,KAAA,IACT,MAA4B,IAAA,KAAS,YAAA;AAE9C,MAAA,IAAI,YAAA,IAAgB,UAAS,EAAG;AAC9B,QAAA,MAAM,IAAI,kBAAA;AAAA,UACR,CAAA,6CAAA,EAAgD,OAAA,CAAQ,SAAS,CAAA,OAAA,EAAU,GAAG,CAAA;AAAA,SAChF;AAAA,MACF;AAEA,MAAA,MAAM,cAAc,oBAAA,GAChB,KAAA,CAAM,SAAA,IAAa,OAAA,GAAU,aAC7B,OAAA,GAAU,UAAA;AAEd,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,IAAI,KAAA,YAAiB,OAAO,MAAM,KAAA;AAClC,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,GAAG,CAAA,CAAE,CAAA;AAAA,MAClE;AAAA,IACF,CAAA,SAAE;AACA,MAAA,OAAA,EAAQ;AAAA,IACV;AAEA,IAAA,OAAA,IAAW,CAAA;AACX,IAAA,MAAM,MAAA,GAAS,YAAA,GAAe,CAAA,KAAM,OAAA,GAAU,CAAA,CAAA;AAC9C,IAAA,MAAM,MAAM,MAAM,CAAA;AAAA,EACpB;AACF;AAEA,SAAS,kBAAkB,OAAA,EAA+B;AACxD,EAAA,MAAM,WAAW,IAAI,IAAA,CAAK,QAAQ,UAAU,CAAA,CAAE,mBAAmB,OAAA,EAAS;AAAA,IACxE,IAAA,EAAM,SAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,GAAA,EAAK;AAAA,GACN,CAAA;AACD,EAAA,OAAO,CAAA,EAAG,OAAA,CAAQ,KAAK,CAAA,EAAA,EAAK,QAAQ,CAAA,CAAA,CAAA;AACtC;AAUO,IAAM,WAAA,GAAc;AAAA,EACzB,MAAM,MAAA,CAAO,OAAA,EAAuB,OAAA,EAA4C;AAC9E,IAAA,MAAM,UAAU,OAAA,CAAQ,SAAA,GACpB,OAAA,CAAQ,SAAA,CAAU,OAAO,CAAA,GACzB;AAAA,MACE,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,YAAY,OAAA,CAAQ,SAAA;AAAA,MACpB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,IAAA,EAAM,CAAA,wBAAA,EAA2B,OAAA,CAAQ,KAAK,CAAA,CAAA,CAAA;AAAA,MAC9C,WAAA,EAAa;AAAA,QACX;AAAA,UACE,KAAA,EAAO,SAAA;AAAA,UACP,OAAO,OAAA,CAAQ,KAAA;AAAA,UACf,IAAA,EAAM,QAAQ,WAAA,IAAe,0BAAA;AAAA,UAC7B,YAAY,OAAA,CAAQ,GAAA;AAAA,UACpB,MAAA,EAAQ,CAAA,cAAA,EAAiB,OAAA,CAAQ,EAAE,CAAA;AAAA;AACrC;AACF,KACF;AACJ,IAAA,MAAM,QAAA,CAAS,OAAA,CAAQ,UAAA,EAAY,OAAA,EAAS,OAAO,CAAA;AAAA,EACrD;AACF;AASO,IAAM,aAAA,GAAgB;AAAA,EAC3B,MAAM,MAAA,CAAO,OAAA,EAAuB,OAAA,EAA8C;AAChF,IAAA,MAAM,UAAU,OAAA,CAAQ,SAAA,GACpB,OAAA,CAAQ,SAAA,CAAU,OAAO,CAAA,GACzB;AAAA,MACE,QAAA,EAAU,QAAQ,QAAA,IAAY,aAAA;AAAA,MAC9B,YAAY,OAAA,CAAQ,SAAA;AAAA,MACpB,MAAA,EAAQ;AAAA,QACN;AAAA,UACE,OAAO,OAAA,CAAQ,KAAA;AAAA,UACf,WAAA,EAAa,QAAQ,WAAA,IAAe,0BAAA;AAAA,UACpC,KAAK,OAAA,CAAQ,GAAA;AAAA,UACb,KAAA,EAAO,OAAA;AAAA,UACP,MAAA,EAAQ;AAAA,YACN,IAAA,EAAM,CAAA,cAAA,EAAiB,OAAA,CAAQ,EAAE,CAAA;AAAA;AACnC;AACF;AACF,KACF;AACJ,IAAA,MAAM,QAAA,CAAS,OAAA,CAAQ,UAAA,EAAY,OAAA,EAAS,OAAO,CAAA;AAAA,EACrD;AACF;AAQO,IAAM,aAAA,GAAgB;AAAA,EAC3B,MAAM,IAAA,CAAK,OAAA,EAAuB,OAAA,EAA8C;AAC9E,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,KAAA,EAAO,QAAQ,KAAA,IAAS,mBAAA;AAAA,MACxB,OAAA;AAAA,MACA,MAAA,EAAA,iBAAQ,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAC/B,GAAI,OAAA,CAAQ,IAAA,IAAQ;AAAC,KACvB;AACA,IAAA,MAAM,QAAA,CAAS,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,OAAO,CAAA;AAAA,EAC9C;AACF;AASO,IAAM,oBAAA,GAAuB;AAAA,EAClC,QAAA,CAAS,QAAA,EAAmC,OAAA,GAAuC,EAAC,EAAW;AAC7F,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,iBAAA;AAC/B,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,8BAAA;AAC/B,IAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,IAAe,cAAA;AAC3C,IAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,SAAA;AAErC,IAAA,MAAM,SAAA,GAAY,QAAA,CACf,GAAA,CAAI,CAAC,OAAA,KAAY;AAChB,MAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,CAAM,OAAA,CAAQ,MAAM,MAAM,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA;AAC1E,MAAA,MAAM,eAAA,GAAA,CAAmB,OAAA,CAAQ,WAAA,IAAe,EAAA,EAC7C,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA;AACvB,MAAA,MAAM,OAAO,OAAA,CAAQ,GAAA,GACjB,CAAA,SAAA,EAAY,OAAA,CAAQ,GAAG,CAAA,2DAAA,CAAA,GACvB,EAAA;AAEJ,MAAA,IAAI,aAAa,SAAA,EAAW;AAC1B,QAAA,OAAO,eAAe,SAAS,CAAA,SAAA,EAAY,kBAAkB,CAAA,GAAA,EAAM,eAAe,KAAK,EAAE,CAAA,KAAA,CAAA;AAAA,MAC3F;AAEA,MAAA,OAAO;AAAA,QACL,+BAAA;AAAA,QACA,4DAA4D,SAAS,CAAA,IAAA,CAAA;AAAA,QACrE,eAAA,GACI,CAAA,0DAAA,EAA6D,eAAe,CAAA,IAAA,CAAA,GAC5E,EAAA;AAAA,QACJ,IAAA,GAAO,CAAA,qBAAA,EAAwB,IAAI,CAAA,IAAA,CAAA,GAAS,EAAA;AAAA,QAC5C;AAAA,OACF,CAAE,KAAK,EAAE,CAAA;AAAA,IACX,CAAC,CAAA,CACA,IAAA,CAAK,EAAE,CAAA;AAEV,IAAA,IAAI,aAAa,SAAA,EAAW;AAC1B,MAAA,OAAO;AAAA,QACL,iBAAA;AAAA,QACA,cAAA;AAAA,QACA,OAAO,KAAK,CAAA,KAAA,CAAA;AAAA,QACZ,MAAM,KAAK,CAAA,IAAA,CAAA;AAAA,QACX,OAAO,SAAS,CAAA,KAAA,CAAA;AAAA,QAChB;AAAA,OACF,CAAE,KAAK,EAAE,CAAA;AAAA,IACX;AAEA,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,KAAY,kBAAkB,OAAO,CAAC,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA;AAChF,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,QAAA;AAAA,MACA,CAAA,kHAAA,CAAA;AAAA,MACA,0HAAA;AAAA,MACA,2GAA2G,WAAW,CAAA,IAAA,CAAA;AAAA,MACtH,4DAA4D,KAAK,CAAA,KAAA,CAAA;AAAA,MACjE,6CAA6C,KAAK,CAAA,IAAA,CAAA;AAAA,MAClD,4DAA4D,OAAO,CAAA,IAAA,CAAA;AAAA,MACnE,2CAA2C,SAAS,CAAA,KAAA,CAAA;AAAA,MACpD,QAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF,CAAE,KAAK,EAAE,CAAA;AAAA,EACX;AACF;AAQO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,QAAA,CAAS,UAA2B,OAAA,EAA2C;AAC7E,IAAA,OAAO,WAAA,CAAY,UAAU,OAAO,CAAA;AAAA,EACtC;AACF","file":"bridges.js","sourcesContent":["import * as moduleApi from \"module\";\n\n// Lightweight markdown parser with optional `marked` + `shiki` support.\n// The function is synchronous and always returns sanitized HTML.\n\ntype MarkedRenderer = {\n link?: (href: string | null, title: string | null, text: string) => string;\n image?: (href: string | null, title: string | null, text: string) => string;\n paragraph?: (text: string) => string;\n heading?: (text: string, level: number) => string;\n};\n\ntype MarkedModule = {\n Renderer?: new () => MarkedRenderer;\n parse?: (markdown: string, options?: { renderer?: MarkedRenderer }) => string | Promise<string>;\n};\n\ntype ShikiLike = {\n codeToHtml?: (code: string, options?: { lang?: string; theme?: string }) => string | Promise<string>;\n};\n\nconst dynamicRequire =\n typeof moduleApi.createRequire === \"function\" ? moduleApi.createRequire(import.meta.url) : null;\n\nlet cachedMarked: MarkedModule | null | false = null;\nlet cachedShiki: ShikiLike | null | false = null;\n\nfunction optionalRequire<T>(name: string): T | null {\n if (!dynamicRequire) return null;\n try {\n // Using dynamic require so missing optional peers don't break bundling/runtime.\n return dynamicRequire(name) as T;\n } catch (error: unknown) {\n if (error && typeof error === \"object\" && \"code\" in error && (error as { code?: string }).code === \"MODULE_NOT_FOUND\") {\n return null;\n }\n // Any other error should still be treated as a failure to keep parsing resilient.\n return null;\n }\n}\n\nfunction getMarked(): MarkedModule | null {\n if (cachedMarked !== null) return cachedMarked || null;\n cachedMarked = optionalRequire<MarkedModule>(\"marked\") ?? false;\n return cachedMarked || null;\n}\n\nfunction getShiki(): ShikiLike | null {\n if (cachedShiki !== null) return cachedShiki || null;\n cachedShiki = optionalRequire<ShikiLike>(\"shiki\") ?? false;\n return cachedShiki || null;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction sanitizeUrl(url: string | null | undefined): string | null {\n if (!url) return null;\n const trimmed = url.trim();\n if (!trimmed) return null;\n\n const lower = trimmed.toLowerCase();\n if (lower.startsWith(\"javascript:\")) return null;\n if (lower.startsWith(\"data:\")) return null;\n if (lower.startsWith(\"vbscript:\")) return null;\n\n // Disallow characters that can break attribute context\n if (/['\"<>\\s]/.test(trimmed)) return null;\n\n return trimmed;\n}\n\nfunction sanitizeHtml(html: string): string {\n return html\n // Remove script/style tags entirely\n .replace(/<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style[\\s\\S]*?>[\\s\\S]*?<\\/style>/gi, \"\")\n // Remove inline event handlers (on*)\n .replace(/\\s+on[a-z]+\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi, \"\")\n // Remove javascript: or data: URLs in href/src/xlink:href\n .replace(/\\s+(?:href|src|xlink:href)\\s*=\\s*(\"|')(?:javascript:|data:)[^\"']*\\1/gi, \"\");\n}\n\nfunction decodeAllowedEntities(html: string): string {\n const allowTags = [\n \"p\",\n \"strong\",\n \"em\",\n \"a\",\n \"code\",\n \"pre\",\n \"img\",\n \"ul\",\n \"ol\",\n \"li\",\n \"blockquote\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"br\",\n ];\n\n // Decode common entities inside allowed tags only\n return html.replace(/&lt;(\\/?)([a-z0-9]+)([^>]*)&gt;/gi, (match, slash, tag, rest) => {\n if (!allowTags.includes(tag.toLowerCase())) return match;\n const decodedRest = rest\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\");\n return `<${slash}${tag}${decodedRest}>`;\n });\n}\n\nfunction renderCodeBlock(code: string, language: string | undefined): string {\n const shiki = getShiki();\n if (shiki?.codeToHtml) {\n try {\n const rendered = shiki.codeToHtml(code, { lang: language || \"text\", theme: \"github-dark\" });\n if (typeof rendered === \"string\") return rendered;\n } catch {\n // Fall through to non-highlighted rendering\n }\n }\n\n const langAttr = language ? ` class=\"language-${escapeHtml(language)}\"` : \"\";\n return `<pre><code${langAttr}>${escapeHtml(code)}</code></pre>`;\n}\n\nfunction inlineMarkdown(text: string): string {\n // Escape user-provided HTML before applying markdown conversions.\n let result = escapeHtml(text);\n\n // Protect inline code spans so subsequent replacements don't mangle them.\n const codeSpans: string[] = [];\n result = result.replace(/`([^`]+)`/g, (_match, code) => {\n const idx = codeSpans.length;\n codeSpans.push(`<code>${escapeHtml(code)}</code>`);\n return `§§CODE${idx}§§`;\n });\n\n // Images: ![alt](url)\n result = result.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_match, alt, url) => {\n const safeUrl = sanitizeUrl(url);\n const safeAlt = escapeHtml(alt ?? \"\");\n if (!safeUrl) return safeAlt;\n return `<img src=\"${escapeHtml(safeUrl)}\" alt=\"${safeAlt}\" />`;\n });\n\n // Links: [text](url)\n result = result.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label, url) => {\n const safeUrl = sanitizeUrl(url);\n const safeLabel = escapeHtml(label ?? \"\");\n if (!safeUrl) return safeLabel;\n return `<a href=\"${escapeHtml(safeUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${safeLabel}</a>`;\n });\n\n // Bold and italic (basic)\n result = result.replace(/\\*\\*([^*]+)\\*\\*/g, \"<strong>$1</strong>\");\n result = result.replace(/\\*([^*]+)\\*/g, \"<em>$1</em>\");\n\n // Restore code spans\n result = result.replace(/§§CODE(\\d+)§§/g, (_m, idx) => codeSpans[Number(idx)] ?? \"\");\n\n return result;\n}\n\nfunction fallbackParse(markdown: string): string {\n const lines = markdown.split(/\\r?\\n/);\n const blocks: string[] = [];\n let listBuffer: string[] | null = null;\n let quoteBuffer: string[] | null = null;\n let inCodeBlock = false;\n let codeLang: string | undefined;\n let codeLines: string[] = [];\n\n const flushList = () => {\n if (!listBuffer) return;\n blocks.push(`<ul>${listBuffer.map((item) => `<li>${item}</li>`).join(\"\")}</ul>`);\n listBuffer = null;\n };\n\n const flushQuote = () => {\n if (!quoteBuffer) return;\n const content = quoteBuffer.map((line) => inlineMarkdown(line.trim())).join(\"<br>\");\n blocks.push(`<blockquote>${content}</blockquote>`);\n quoteBuffer = null;\n };\n\n const flushCode = () => {\n if (!inCodeBlock) return;\n blocks.push(renderCodeBlock(codeLines.join(\"\\n\"), codeLang));\n codeLines = [];\n codeLang = undefined;\n inCodeBlock = false;\n };\n\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\s+$/, \"\");\n\n const codeFence = line.match(/^```(.*)$/);\n if (codeFence) {\n if (inCodeBlock) {\n flushCode();\n } else {\n flushList();\n flushQuote();\n inCodeBlock = true;\n codeLang = codeFence[1]?.trim() || undefined;\n codeLines = [];\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeLines.push(rawLine);\n continue;\n }\n\n const listMatch = line.match(/^\\s*[-*+]\\s+(.*)$/);\n if (listMatch) {\n flushQuote();\n listBuffer = listBuffer ?? [];\n listBuffer.push(inlineMarkdown(listMatch[1].trim()));\n continue;\n }\n\n if (listBuffer) flushList();\n\n const headingMatch = line.match(/^(#{1,6})\\s+(.*)$/);\n if (headingMatch) {\n flushQuote();\n const level = headingMatch[1].length;\n const content = inlineMarkdown(headingMatch[2].trim());\n blocks.push(`<h${level}>${content}</h${level}>`);\n continue;\n }\n\n const quoteMatch = line.match(/^>\\s?(.*)$/);\n if (quoteMatch) {\n quoteBuffer = quoteBuffer ?? [];\n quoteBuffer.push(quoteMatch[1]);\n continue;\n }\n\n if (quoteBuffer) flushQuote();\n\n if (!line.trim()) {\n continue;\n }\n\n blocks.push(`<p>${inlineMarkdown(line.trim())}</p>`);\n }\n\n flushList();\n flushQuote();\n flushCode();\n\n return blocks.join(\"\\n\");\n}\n\nfunction renderWithMarked(markdown: string, marked: MarkedModule): string | null {\n if (!marked.parse) return null;\n\n const renderer = marked.Renderer ? new marked.Renderer() : undefined;\n\n if (renderer) {\n renderer.link = (href, _title, text) => {\n const safeUrl = sanitizeUrl(href);\n if (!safeUrl) return escapeHtml(text);\n return `<a href=\"${escapeHtml(safeUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${text}</a>`;\n };\n renderer.image = (href, _title, text) => {\n const safeUrl = sanitizeUrl(href);\n const safeAlt = escapeHtml(text ?? \"\");\n if (!safeUrl) return safeAlt;\n return `<img src=\"${escapeHtml(safeUrl)}\" alt=\"${safeAlt}\" />`;\n };\n }\n\n const output = marked.parse(markdown, renderer ? { renderer } : undefined);\n if (typeof output === \"string\") return output;\n return output ? String(output) : null;\n}\n\n/**\n * Parse a feature description from markdown into sanitized HTML.\n * - Uses `marked` when installed (optional peer dep)\n * - Falls back to a tiny built-in parser when `marked` is absent\n * - Strips script tags, event handlers, and javascript:/data: URLs\n */\nexport function parseDescription(markdown: string): string {\n if (!markdown) return \"\";\n\n const marked = getMarked();\n if (marked) {\n try {\n const rendered = renderWithMarked(markdown, marked);\n if (rendered) {\n const sanitized = sanitizeHtml(rendered);\n const decoded = decodeAllowedEntities(sanitized);\n return sanitizeHtml(decoded);\n }\n } catch {\n // If marked fails for any reason, fall back to the tiny parser.\n }\n }\n\n // Fast path: raw HTML provided without `marked` installed\n if (/<[^>]+>/.test(markdown)) {\n const sanitized = sanitizeHtml(markdown);\n const decoded = decodeAllowedEntities(sanitized);\n return sanitizeHtml(decoded);\n }\n\n const fallback = fallbackParse(markdown);\n const sanitized = sanitizeHtml(fallback);\n const decoded = decodeAllowedEntities(sanitized);\n return sanitizeHtml(decoded);\n}\n","import type { FeatureManifest } from \"./types\";\nimport { parseDescription } from \"./markdown\";\n\nfunction escape(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n/**\n * Generate a simple RSS 2.0 feed from a feature manifest.\n * Titles and descriptions are sanitized via `parseDescription`.\n */\nexport function generateRSS(manifest: FeatureManifest, options?: { title?: string; link?: string; description?: string }): string {\n const title = escape(options?.title ?? \"Featuredrop Changelog\");\n const link = escape(options?.link ?? \"\");\n const desc = escape(options?.description ?? \"Product updates\");\n\n const items = manifest\n .slice()\n .sort((a, b) => new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime())\n .map((item) => {\n const descriptionHtml = item.description ? parseDescription(item.description) : \"\";\n const itemLink = item.url ? escape(item.url) : \"\";\n return [\n \"<item>\",\n `<title>${escape(item.label)}</title>`,\n itemLink ? `<link>${itemLink}</link>` : \"\",\n `<guid isPermaLink=\\\"false\\\">${escape(item.id)}</guid>`,\n `<pubDate>${new Date(item.releasedAt).toUTCString()}</pubDate>`,\n `<description><![CDATA[${descriptionHtml}]]></description>`,\n \"</item>\",\n ].join(\"\");\n })\n .join(\"\");\n\n return [\n \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n \"<rss version=\\\"2.0\\\">\",\n \"<channel>\",\n `<title>${title}</title>`,\n link ? `<link>${link}</link>` : \"\",\n `<description>${desc}</description>`,\n items,\n \"</channel>\",\n \"</rss>\",\n ].join(\"\");\n}\n","import { generateRSS } from \"./rss\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\n\nexport interface BridgeRequestOptions {\n headers?: Record<string, string>;\n timeoutMs?: number;\n maxRetries?: number;\n retryDelayMs?: number;\n retryOnStatuses?: number[];\n signal?: AbortSignal;\n}\n\nconst DEFAULT_RETRY_STATUSES = [408, 429, 500, 502, 503, 504];\n\nclass BridgeRequestError extends Error {\n readonly status?: number;\n readonly retryable: boolean;\n\n constructor(message: string, options: { status?: number; retryable?: boolean } = {}) {\n super(message);\n this.name = \"BridgeRequestError\";\n this.status = options.status;\n this.retryable = options.retryable ?? false;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction createAbortSignal(\n timeoutMs: number | undefined,\n sourceSignal: AbortSignal | undefined,\n): { signal: AbortSignal | undefined; cleanup: () => void; timedOut: () => boolean } {\n if (!timeoutMs && !sourceSignal) {\n return {\n signal: undefined,\n cleanup: () => {\n // noop\n },\n timedOut: () => false,\n };\n }\n\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutTriggered = false;\n let onAbort: (() => void) | undefined;\n\n if (sourceSignal) {\n if (sourceSignal.aborted) {\n controller.abort(sourceSignal.reason);\n } else {\n onAbort = () => controller.abort(sourceSignal.reason);\n sourceSignal.addEventListener(\"abort\", onAbort, { once: true });\n }\n }\n\n if (timeoutMs && timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n timeoutTriggered = true;\n controller.abort();\n }, timeoutMs);\n }\n\n return {\n signal: controller.signal,\n cleanup: () => {\n if (timeoutId) clearTimeout(timeoutId);\n if (sourceSignal && onAbort) sourceSignal.removeEventListener(\"abort\", onAbort);\n },\n timedOut: () => timeoutTriggered,\n };\n}\n\nasync function readResponseText(response: Response): Promise<string> {\n const hasText =\n response &&\n typeof response === \"object\" &&\n \"text\" in response &&\n typeof response.text === \"function\";\n if (!hasText) return \"\";\n try {\n const text = await response.text();\n return text.trim();\n } catch {\n return \"\";\n }\n}\n\nasync function postJson(\n url: string,\n payload: unknown,\n options: BridgeRequestOptions = {},\n): Promise<void> {\n const maxRetries = Math.max(0, options.maxRetries ?? 0);\n const retryDelayMs = Math.max(0, options.retryDelayMs ?? 250);\n const retryStatuses = new Set(options.retryOnStatuses ?? DEFAULT_RETRY_STATUSES);\n\n let attempt = 0;\n for (;;) {\n const { signal, cleanup, timedOut } = createAbortSignal(options.timeoutMs, options.signal);\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(options.headers ?? {}),\n },\n body: JSON.stringify(payload),\n signal,\n });\n\n if (response.ok) return;\n\n const retryableStatus = retryStatuses.has(response.status);\n const responseText = await readResponseText(response);\n const message = responseText\n ? `[featuredrop] Bridge request failed (${response.status}) for ${url}: ${responseText}`\n : `[featuredrop] Bridge request failed (${response.status}) for ${url}`;\n\n if (!retryableStatus || attempt >= maxRetries) {\n throw new BridgeRequestError(message, {\n status: response.status,\n retryable: retryableStatus,\n });\n }\n } catch (error: unknown) {\n const isBridgeRequestError = error instanceof BridgeRequestError;\n const isAbortError =\n error instanceof DOMException\n ? error.name === \"AbortError\"\n : error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n (error as { name?: string }).name === \"AbortError\";\n\n if (isAbortError && timedOut()) {\n throw new BridgeRequestError(\n `[featuredrop] Bridge request timed out after ${options.timeoutMs}ms for ${url}`,\n );\n }\n\n const shouldRetry = isBridgeRequestError\n ? error.retryable && attempt < maxRetries\n : attempt < maxRetries;\n\n if (!shouldRetry) {\n if (error instanceof Error) throw error;\n throw new Error(`[featuredrop] Bridge request failed for ${url}`);\n }\n } finally {\n cleanup();\n }\n\n attempt += 1;\n const waitMs = retryDelayMs * 2 ** (attempt - 1);\n await sleep(waitMs);\n }\n}\n\nfunction formatFeatureLine(feature: FeatureEntry): string {\n const released = new Date(feature.releasedAt).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n return `${feature.label} (${released})`;\n}\n\nexport interface SlackBridgeOptions extends BridgeRequestOptions {\n webhookUrl: string;\n username?: string;\n iconEmoji?: string;\n channel?: string;\n formatter?: (feature: FeatureEntry) => Record<string, unknown>;\n}\n\nexport const SlackBridge = {\n async notify(feature: FeatureEntry, options: SlackBridgeOptions): Promise<void> {\n const payload = options.formatter\n ? options.formatter(feature)\n : {\n username: options.username,\n icon_emoji: options.iconEmoji,\n channel: options.channel,\n text: `New feature published: *${feature.label}*`,\n attachments: [\n {\n color: \"#2563eb\",\n title: feature.label,\n text: feature.description ?? \"No description provided.\",\n title_link: feature.url,\n footer: `featuredrop | ${feature.id}`,\n },\n ],\n };\n await postJson(options.webhookUrl, payload, options);\n },\n};\n\nexport interface DiscordBridgeOptions extends BridgeRequestOptions {\n webhookUrl: string;\n username?: string;\n avatarUrl?: string;\n formatter?: (feature: FeatureEntry) => Record<string, unknown>;\n}\n\nexport const DiscordBridge = {\n async notify(feature: FeatureEntry, options: DiscordBridgeOptions): Promise<void> {\n const payload = options.formatter\n ? options.formatter(feature)\n : {\n username: options.username ?? \"featuredrop\",\n avatar_url: options.avatarUrl,\n embeds: [\n {\n title: feature.label,\n description: feature.description ?? \"No description provided.\",\n url: feature.url,\n color: 0x2563eb,\n footer: {\n text: `featuredrop | ${feature.id}`,\n },\n },\n ],\n };\n await postJson(options.webhookUrl, payload, options);\n },\n};\n\nexport interface WebhookBridgeOptions extends BridgeRequestOptions {\n url: string;\n event?: string;\n body?: Record<string, unknown>;\n}\n\nexport const WebhookBridge = {\n async post(feature: FeatureEntry, options: WebhookBridgeOptions): Promise<void> {\n const payload = {\n event: options.event ?? \"feature.published\",\n feature,\n sentAt: new Date().toISOString(),\n ...(options.body ?? {}),\n };\n await postJson(options.url, payload, options);\n },\n};\n\nexport interface EmailDigestGeneratorOptions {\n title?: string;\n intro?: string;\n template?: \"default\" | \"minimal\";\n productName?: string;\n}\n\nexport const EmailDigestGenerator = {\n generate(features: readonly FeatureEntry[], options: EmailDigestGeneratorOptions = {}): string {\n const title = options.title ?? \"Product Updates\";\n const intro = options.intro ?? \"Here are the latest updates:\";\n const productName = options.productName ?? \"Your Product\";\n const template = options.template ?? \"default\";\n\n const listItems = features\n .map((feature) => {\n const safeLabel = feature.label.replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n const safeDescription = (feature.description ?? \"\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n const link = feature.url\n ? `<a href=\"${feature.url}\" style=\"color:#2563eb;text-decoration:none;\">Read more</a>`\n : \"\";\n\n if (template === \"minimal\") {\n return `<li><strong>${safeLabel}</strong>${safeDescription ? ` - ${safeDescription}` : \"\"}</li>`;\n }\n\n return [\n \"<li style=\\\"margin:0 0 14px;\\\">\",\n `<p style=\"margin:0 0 4px;font-weight:600;color:#111827;\">${safeLabel}</p>`,\n safeDescription\n ? `<p style=\"margin:0 0 6px;color:#4b5563;line-height:1.45;\">${safeDescription}</p>`\n : \"\",\n link ? `<p style=\"margin:0;\">${link}</p>` : \"\",\n \"</li>\",\n ].join(\"\");\n })\n .join(\"\");\n\n if (template === \"minimal\") {\n return [\n \"<!doctype html>\",\n \"<html><body>\",\n `<h2>${title}</h2>`,\n `<p>${intro}</p>`,\n `<ul>${listItems}</ul>`,\n \"</body></html>\",\n ].join(\"\");\n }\n\n const summary = features.map((feature) => formatFeatureLine(feature)).join(\" | \");\n return [\n \"<!doctype html>\",\n \"<html>\",\n \"<body style=\\\"font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#f8fafc;padding:20px;\\\">\",\n \"<div style=\\\"max-width:640px;margin:0 auto;background:#ffffff;border:1px solid #e5e7eb;border-radius:12px;padding:20px;\\\">\",\n `<p style=\"margin:0 0 12px;color:#6b7280;font-size:12px;letter-spacing:0.08em;text-transform:uppercase;\">${productName}</p>`,\n `<h1 style=\"margin:0 0 8px;font-size:22px;color:#111827;\">${title}</h1>`,\n `<p style=\"margin:0 0 14px;color:#374151;\">${intro}</p>`,\n `<p style=\"margin:0 0 18px;color:#6b7280;font-size:13px;\">${summary}</p>`,\n `<ul style=\"padding-left:18px;margin:0;\">${listItems}</ul>`,\n \"</div>\",\n \"</body>\",\n \"</html>\",\n ].join(\"\");\n },\n};\n\nexport interface RSSFeedGeneratorOptions {\n title?: string;\n link?: string;\n description?: string;\n}\n\nexport const RSSFeedGenerator = {\n generate(manifest: FeatureManifest, options?: RSSFeedGeneratorOptions): string {\n return generateRSS(manifest, options);\n },\n};\n"]}
package/dist/ci.cjs CHANGED
@@ -317,12 +317,46 @@ function generateChangelogDiff(diff, options = {}) {
317
317
  }
318
318
  return parts.length > 0 ? parts.join(". ") : "No manifest changes.";
319
319
  }
320
+ function renderMarkdownSection(title, items, maxItemsPerSection) {
321
+ if (items.length === 0) return [`### ${title} (0)`, "- None"];
322
+ const visible = items.slice(0, maxItemsPerSection);
323
+ const hiddenCount = items.length - visible.length;
324
+ const lines = [`### ${title} (${items.length})`, ...visible.map((item) => `- ${item}`)];
325
+ if (hiddenCount > 0) {
326
+ lines.push(`- ...and ${hiddenCount} more`);
327
+ }
328
+ return lines;
329
+ }
330
+ function generateChangelogDiffMarkdown(diff, options = {}) {
331
+ if (diff.added.length === 0 && diff.changed.length === 0 && diff.removed.length === 0) {
332
+ return "No manifest changes.";
333
+ }
334
+ const maxItemsPerSection = Math.max(1, options.maxItemsPerSection ?? 20);
335
+ const addedItems = diff.added.map((feature) => `**${feature.label}** (\`${feature.id}\`)`);
336
+ const changedItems = diff.changed.map((item) => {
337
+ if (!options.includeFieldChanges) {
338
+ return `**${item.after.label}** (\`${item.id}\`)`;
339
+ }
340
+ const fields = item.changedFields.join(", ");
341
+ return `**${item.after.label}** (\`${item.id}\`) \u2014 ${fields}`;
342
+ });
343
+ const removedItems = diff.removed.map((feature) => `**${feature.label}** (\`${feature.id}\`)`);
344
+ const sections = [
345
+ ...renderMarkdownSection("Added", addedItems, maxItemsPerSection),
346
+ "",
347
+ ...renderMarkdownSection("Changed", changedItems, maxItemsPerSection),
348
+ "",
349
+ ...renderMarkdownSection("Removed", removedItems, maxItemsPerSection)
350
+ ];
351
+ return sections.join("\n");
352
+ }
320
353
  function validateManifestForCI(manifest) {
321
354
  return validateManifest(manifest);
322
355
  }
323
356
 
324
357
  exports.diffManifest = diffManifest;
325
358
  exports.generateChangelogDiff = generateChangelogDiff;
359
+ exports.generateChangelogDiffMarkdown = generateChangelogDiffMarkdown;
326
360
  exports.validateManifestForCI = validateManifestForCI;
327
361
  //# sourceMappingURL=ci.cjs.map
328
362
  //# sourceMappingURL=ci.cjs.map
package/dist/ci.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dependencies.ts","../src/schema.ts","../src/ci.ts"],"names":["z","isRecord"],"mappings":"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","file":"ci.cjs","sourcesContent":["import type { FeatureEntry, FeatureManifest } from \"./types\";\n\nfunction getDirectDependencies(feature: FeatureEntry): string[] {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return [];\n const seen = dependsOn.seen ?? [];\n const clicked = dependsOn.clicked ?? [];\n const dismissed = dependsOn.dismissed ?? [];\n const unique = new Set<string>();\n for (const id of [...seen, ...clicked, ...dismissed]) {\n if (id) unique.add(id);\n }\n return Array.from(unique);\n}\n\nexport function resolveDependencyOrder(manifest: FeatureManifest): string[] {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n const ordered: string[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n ordered.push(id);\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n // On cycles, append remaining IDs in original order to keep behavior stable.\n if (ordered.length < manifest.length) {\n const included = new Set(ordered);\n for (const feature of manifest) {\n if (included.has(feature.id)) continue;\n ordered.push(feature.id);\n }\n }\n\n return ordered;\n}\n\nexport function hasDependencyCycle(manifest: FeatureManifest): boolean {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n let visited = 0;\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n visited += 1;\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n return visited !== manifest.length;\n}\n\nexport function sortFeaturesByDependencies(features: FeatureEntry[]): FeatureEntry[] {\n if (features.length <= 1) return [...features];\n const order = resolveDependencyOrder(features);\n const rank = new Map(order.map((id, index) => [id, index]));\n return [...features].sort((a, b) => {\n const ra = rank.get(a.id);\n const rb = rank.get(b.id);\n if (ra === undefined || rb === undefined) return 0;\n return ra - rb;\n });\n}\n","import { hasDependencyCycle } from \"./dependencies\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\nimport { z } from \"zod\";\n\nexport interface ValidationIssue {\n path: string;\n message: string;\n code:\n | \"invalid_type\"\n | \"missing_required\"\n | \"invalid_value\"\n | \"invalid_date\"\n | \"duplicate_id\"\n | \"circular_dependency\";\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationIssue[];\n}\n\nexport const featureEntryJsonSchema = {\n type: \"object\",\n required: [\"id\", \"label\", \"releasedAt\", \"showNewUntil\"],\n properties: {\n id: { type: \"string\" },\n label: { type: \"string\" },\n description: { type: \"string\" },\n releasedAt: { type: \"string\", format: \"date-time\" },\n showNewUntil: { type: \"string\", format: \"date-time\" },\n flagKey: { type: \"string\" },\n product: { type: \"string\" },\n url: { type: \"string\" },\n image: { type: \"string\" },\n type: { enum: [\"feature\", \"improvement\", \"fix\", \"breaking\"] },\n priority: { enum: [\"critical\", \"normal\", \"low\"] },\n cta: {\n type: \"object\",\n properties: {\n label: { type: \"string\" },\n url: { type: \"string\" },\n },\n },\n meta: { type: \"object\" },\n },\n} as const;\n\nexport const featureManifestJsonSchema = {\n type: \"array\",\n items: featureEntryJsonSchema,\n} as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isValidDate(value: string): boolean {\n return Number.isFinite(new Date(value).getTime());\n}\n\nconst nonEmptyString = z.string().trim().min(1, \"must be a non-empty string\");\n\nconst isoDateString = nonEmptyString.refine(isValidDate, {\n message: \"must be a valid date\",\n params: { featuredropCode: \"invalid_date\" },\n});\n\nconst dependsOnSchema = z\n .object({\n seen: z.array(z.string()).optional(),\n clicked: z.array(z.string()).optional(),\n dismissed: z.array(z.string()).optional(),\n })\n .optional();\n\nconst ctaSchema = z\n .object({\n label: nonEmptyString,\n url: nonEmptyString,\n })\n .optional();\n\nexport const featureEntrySchema = z\n .object({\n id: nonEmptyString,\n label: nonEmptyString,\n releasedAt: isoDateString,\n showNewUntil: isoDateString,\n description: z.string().optional(),\n flagKey: z.string().optional(),\n product: z.string().optional(),\n url: z.string().optional(),\n image: z.string().optional(),\n type: z.enum([\"feature\", \"improvement\", \"fix\", \"breaking\"]).optional(),\n priority: z.enum([\"critical\", \"normal\", \"low\"]).optional(),\n cta: ctaSchema,\n meta: z.record(z.unknown()).optional(),\n dependsOn: dependsOnSchema,\n })\n .passthrough();\n\nexport const featureManifestSchema = z.array(featureEntrySchema);\n\nfunction toIssuePath(path: Array<string | number>): string {\n if (path.length === 0) return \"$\";\n let output = \"\";\n for (const part of path) {\n if (typeof part === \"number\") output += `[${part}]`;\n else output += output ? `.${part}` : part;\n }\n return output;\n}\n\nfunction mapZodIssue(issue: z.ZodIssue): ValidationIssue {\n const codeParam = (issue as { params?: Record<string, unknown> }).params?.featuredropCode;\n if (codeParam === \"invalid_date\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_date\",\n };\n }\n if (issue.code === \"invalid_type\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: issue.received === \"undefined\" ? \"missing_required\" : \"invalid_type\",\n };\n }\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_value\",\n };\n}\n\nconst UNSAFE_META_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction isSafeUrl(value: string): boolean {\n const normalized = value.trim();\n if (!normalized) return false;\n if (/^(\\/|\\.\\/|\\.\\.\\/|\\?|#)/.test(normalized)) return true;\n if (/^https?:\\/\\//i.test(normalized)) return true;\n return false;\n}\n\nfunction findUnsafeMetaPath(value: unknown, path = \"meta\"): string | null {\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index++) {\n const nested = findUnsafeMetaPath(value[index], `${path}[${index}]`);\n if (nested) return nested;\n }\n return null;\n }\n\n if (!isRecord(value)) return null;\n for (const [key, nestedValue] of Object.entries(value)) {\n if (UNSAFE_META_KEYS.has(key)) {\n return `${path}.${key}`;\n }\n const nested = findUnsafeMetaPath(nestedValue, `${path}.${key}`);\n if (nested) return nested;\n }\n return null;\n}\n\nfunction validateFeatureEntry(raw: unknown, index: number): { entry?: FeatureEntry; issues: ValidationIssue[] } {\n if (!isRecord(raw)) {\n return {\n issues: [\n {\n path: `[${index}]`,\n message: \"Feature entry must be an object\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const parsed = featureEntrySchema.safeParse(raw);\n if (!parsed.success) {\n return {\n issues: parsed.error.issues.map((issue) => ({\n ...mapZodIssue(issue),\n path: `[${index}]${issue.path.length > 0 ? `.${toIssuePath(issue.path)}` : \"\"}`,\n })),\n };\n }\n\n return {\n issues: [],\n entry: parsed.data as FeatureEntry,\n };\n}\n\nexport function validateManifest(data: unknown): ValidationResult {\n const errors: ValidationIssue[] = [];\n if (!Array.isArray(data)) {\n return {\n valid: false,\n errors: [\n {\n path: \"$\",\n message: \"Manifest must be an array\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const entries: FeatureEntry[] = [];\n const seenIds = new Set<string>();\n data.forEach((item, index) => {\n const result = validateFeatureEntry(item, index);\n errors.push(...result.issues);\n if (!result.entry) return;\n if (seenIds.has(result.entry.id)) {\n errors.push({\n path: `[${index}].id`,\n message: `Duplicate feature id \"${result.entry.id}\"`,\n code: \"duplicate_id\",\n });\n return;\n }\n seenIds.add(result.entry.id);\n entries.push(result.entry);\n });\n\n if (entries.length > 0 && hasDependencyCycle(entries as FeatureManifest)) {\n errors.push({\n path: \"$\",\n message: \"Circular dependsOn relationship detected\",\n code: \"circular_dependency\",\n });\n }\n\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index];\n if (new Date(entry.showNewUntil).getTime() <= new Date(entry.releasedAt).getTime()) {\n errors.push({\n path: `[${index}].showNewUntil`,\n message: \"showNewUntil must be after releasedAt\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.url && !isSafeUrl(entry.url)) {\n errors.push({\n path: `[${index}].url`,\n message: \"url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.image && !isSafeUrl(entry.image)) {\n errors.push({\n path: `[${index}].image`,\n message: \"image must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.cta?.url && !isSafeUrl(entry.cta.url)) {\n errors.push({\n path: `[${index}].cta.url`,\n message: \"cta.url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n const unsafeMetaPath = findUnsafeMetaPath(entry.meta);\n if (unsafeMetaPath) {\n errors.push({\n path: `[${index}].${unsafeMetaPath}`,\n message: `meta contains unsafe key \"${unsafeMetaPath.split(\".\").pop()}\"`,\n code: \"invalid_value\",\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n","import { validateManifest } from \"./schema\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\n\nexport interface ChangedFeature {\n id: string;\n before: FeatureEntry;\n after: FeatureEntry;\n changedFields: string[];\n}\n\nexport interface ManifestDiff {\n added: FeatureEntry[];\n removed: FeatureEntry[];\n changed: ChangedFeature[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction collectChangedFields(\n beforeValue: unknown,\n afterValue: unknown,\n path: string,\n output: string[],\n): void {\n if (beforeValue === afterValue) return;\n\n if (Array.isArray(beforeValue) && Array.isArray(afterValue)) {\n if (beforeValue.length !== afterValue.length) {\n output.push(path);\n return;\n }\n for (let i = 0; i < beforeValue.length; i += 1) {\n collectChangedFields(beforeValue[i], afterValue[i], `${path}[${i}]`, output);\n }\n return;\n }\n\n if (isRecord(beforeValue) && isRecord(afterValue)) {\n const keys = new Set([...Object.keys(beforeValue), ...Object.keys(afterValue)]);\n keys.forEach((key) => {\n const nextPath = path ? `${path}.${key}` : key;\n collectChangedFields(beforeValue[key], afterValue[key], nextPath, output);\n });\n return;\n }\n\n output.push(path);\n}\n\nexport function diffManifest(before: FeatureManifest, after: FeatureManifest): ManifestDiff {\n const beforeById = new Map(before.map((feature) => [feature.id, feature]));\n const afterById = new Map(after.map((feature) => [feature.id, feature]));\n\n const added = after.filter((feature) => !beforeById.has(feature.id));\n const removed = before.filter((feature) => !afterById.has(feature.id));\n\n const changed = after\n .filter((feature) => beforeById.has(feature.id))\n .map((feature) => {\n const previous = beforeById.get(feature.id);\n if (!previous) return null;\n const changedFields: string[] = [];\n collectChangedFields(previous, feature, \"\", changedFields);\n if (changedFields.length === 0) return null;\n return {\n id: feature.id,\n before: previous,\n after: feature,\n changedFields,\n } satisfies ChangedFeature;\n })\n .filter((item): item is ChangedFeature => item !== null);\n\n return { added, removed, changed };\n}\n\nexport interface ChangelogDiffOptions {\n includeFieldChanges?: boolean;\n}\n\nexport function generateChangelogDiff(\n diff: ManifestDiff,\n options: ChangelogDiffOptions = {},\n): string {\n const parts: string[] = [];\n\n if (diff.added.length > 0) {\n parts.push(`Added: ${diff.added.map((feature) => feature.label).join(\", \")}`);\n }\n\n if (diff.changed.length > 0) {\n const changedText = diff.changed.map((item) => {\n if (!options.includeFieldChanges) return item.after.label;\n return `${item.after.label} [${item.changedFields.join(\", \")}]`;\n });\n parts.push(`Changed: ${changedText.join(\", \")}`);\n }\n\n if (diff.removed.length > 0) {\n parts.push(`Removed: ${diff.removed.map((feature) => feature.label).join(\", \")}`);\n }\n\n return parts.length > 0 ? parts.join(\". \") : \"No manifest changes.\";\n}\n\nexport function validateManifestForCI(manifest: FeatureManifest) {\n return validateManifest(manifest);\n}\n"]}
1
+ {"version":3,"sources":["../src/dependencies.ts","../src/schema.ts","../src/ci.ts"],"names":["z","isRecord"],"mappings":"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","file":"ci.cjs","sourcesContent":["import type { FeatureEntry, FeatureManifest } from \"./types\";\n\nfunction getDirectDependencies(feature: FeatureEntry): string[] {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return [];\n const seen = dependsOn.seen ?? [];\n const clicked = dependsOn.clicked ?? [];\n const dismissed = dependsOn.dismissed ?? [];\n const unique = new Set<string>();\n for (const id of [...seen, ...clicked, ...dismissed]) {\n if (id) unique.add(id);\n }\n return Array.from(unique);\n}\n\nexport function resolveDependencyOrder(manifest: FeatureManifest): string[] {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n const ordered: string[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n ordered.push(id);\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n // On cycles, append remaining IDs in original order to keep behavior stable.\n if (ordered.length < manifest.length) {\n const included = new Set(ordered);\n for (const feature of manifest) {\n if (included.has(feature.id)) continue;\n ordered.push(feature.id);\n }\n }\n\n return ordered;\n}\n\nexport function hasDependencyCycle(manifest: FeatureManifest): boolean {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n let visited = 0;\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n visited += 1;\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n return visited !== manifest.length;\n}\n\nexport function sortFeaturesByDependencies(features: FeatureEntry[]): FeatureEntry[] {\n if (features.length <= 1) return [...features];\n const order = resolveDependencyOrder(features);\n const rank = new Map(order.map((id, index) => [id, index]));\n return [...features].sort((a, b) => {\n const ra = rank.get(a.id);\n const rb = rank.get(b.id);\n if (ra === undefined || rb === undefined) return 0;\n return ra - rb;\n });\n}\n","import { hasDependencyCycle } from \"./dependencies\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\nimport { z } from \"zod\";\n\nexport interface ValidationIssue {\n path: string;\n message: string;\n code:\n | \"invalid_type\"\n | \"missing_required\"\n | \"invalid_value\"\n | \"invalid_date\"\n | \"duplicate_id\"\n | \"circular_dependency\";\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationIssue[];\n}\n\nexport const featureEntryJsonSchema = {\n type: \"object\",\n required: [\"id\", \"label\", \"releasedAt\", \"showNewUntil\"],\n properties: {\n id: { type: \"string\" },\n label: { type: \"string\" },\n description: { type: \"string\" },\n releasedAt: { type: \"string\", format: \"date-time\" },\n showNewUntil: { type: \"string\", format: \"date-time\" },\n flagKey: { type: \"string\" },\n product: { type: \"string\" },\n url: { type: \"string\" },\n image: { type: \"string\" },\n type: { enum: [\"feature\", \"improvement\", \"fix\", \"breaking\"] },\n priority: { enum: [\"critical\", \"normal\", \"low\"] },\n cta: {\n type: \"object\",\n properties: {\n label: { type: \"string\" },\n url: { type: \"string\" },\n },\n },\n meta: { type: \"object\" },\n },\n} as const;\n\nexport const featureManifestJsonSchema = {\n type: \"array\",\n items: featureEntryJsonSchema,\n} as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isValidDate(value: string): boolean {\n return Number.isFinite(new Date(value).getTime());\n}\n\nconst nonEmptyString = z.string().trim().min(1, \"must be a non-empty string\");\n\nconst isoDateString = nonEmptyString.refine(isValidDate, {\n message: \"must be a valid date\",\n params: { featuredropCode: \"invalid_date\" },\n});\n\nconst dependsOnSchema = z\n .object({\n seen: z.array(z.string()).optional(),\n clicked: z.array(z.string()).optional(),\n dismissed: z.array(z.string()).optional(),\n })\n .optional();\n\nconst ctaSchema = z\n .object({\n label: nonEmptyString,\n url: nonEmptyString,\n })\n .optional();\n\nexport const featureEntrySchema = z\n .object({\n id: nonEmptyString,\n label: nonEmptyString,\n releasedAt: isoDateString,\n showNewUntil: isoDateString,\n description: z.string().optional(),\n flagKey: z.string().optional(),\n product: z.string().optional(),\n url: z.string().optional(),\n image: z.string().optional(),\n type: z.enum([\"feature\", \"improvement\", \"fix\", \"breaking\"]).optional(),\n priority: z.enum([\"critical\", \"normal\", \"low\"]).optional(),\n cta: ctaSchema,\n meta: z.record(z.unknown()).optional(),\n dependsOn: dependsOnSchema,\n })\n .passthrough();\n\nexport const featureManifestSchema = z.array(featureEntrySchema);\n\nfunction toIssuePath(path: Array<string | number>): string {\n if (path.length === 0) return \"$\";\n let output = \"\";\n for (const part of path) {\n if (typeof part === \"number\") output += `[${part}]`;\n else output += output ? `.${part}` : part;\n }\n return output;\n}\n\nfunction mapZodIssue(issue: z.ZodIssue): ValidationIssue {\n const codeParam = (issue as { params?: Record<string, unknown> }).params?.featuredropCode;\n if (codeParam === \"invalid_date\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_date\",\n };\n }\n if (issue.code === \"invalid_type\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: issue.received === \"undefined\" ? \"missing_required\" : \"invalid_type\",\n };\n }\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_value\",\n };\n}\n\nconst UNSAFE_META_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction isSafeUrl(value: string): boolean {\n const normalized = value.trim();\n if (!normalized) return false;\n if (/^(\\/|\\.\\/|\\.\\.\\/|\\?|#)/.test(normalized)) return true;\n if (/^https?:\\/\\//i.test(normalized)) return true;\n return false;\n}\n\nfunction findUnsafeMetaPath(value: unknown, path = \"meta\"): string | null {\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index++) {\n const nested = findUnsafeMetaPath(value[index], `${path}[${index}]`);\n if (nested) return nested;\n }\n return null;\n }\n\n if (!isRecord(value)) return null;\n for (const [key, nestedValue] of Object.entries(value)) {\n if (UNSAFE_META_KEYS.has(key)) {\n return `${path}.${key}`;\n }\n const nested = findUnsafeMetaPath(nestedValue, `${path}.${key}`);\n if (nested) return nested;\n }\n return null;\n}\n\nfunction validateFeatureEntry(raw: unknown, index: number): { entry?: FeatureEntry; issues: ValidationIssue[] } {\n if (!isRecord(raw)) {\n return {\n issues: [\n {\n path: `[${index}]`,\n message: \"Feature entry must be an object\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const parsed = featureEntrySchema.safeParse(raw);\n if (!parsed.success) {\n return {\n issues: parsed.error.issues.map((issue) => ({\n ...mapZodIssue(issue),\n path: `[${index}]${issue.path.length > 0 ? `.${toIssuePath(issue.path)}` : \"\"}`,\n })),\n };\n }\n\n return {\n issues: [],\n entry: parsed.data as FeatureEntry,\n };\n}\n\nexport function validateManifest(data: unknown): ValidationResult {\n const errors: ValidationIssue[] = [];\n if (!Array.isArray(data)) {\n return {\n valid: false,\n errors: [\n {\n path: \"$\",\n message: \"Manifest must be an array\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const entries: FeatureEntry[] = [];\n const seenIds = new Set<string>();\n data.forEach((item, index) => {\n const result = validateFeatureEntry(item, index);\n errors.push(...result.issues);\n if (!result.entry) return;\n if (seenIds.has(result.entry.id)) {\n errors.push({\n path: `[${index}].id`,\n message: `Duplicate feature id \"${result.entry.id}\"`,\n code: \"duplicate_id\",\n });\n return;\n }\n seenIds.add(result.entry.id);\n entries.push(result.entry);\n });\n\n if (entries.length > 0 && hasDependencyCycle(entries as FeatureManifest)) {\n errors.push({\n path: \"$\",\n message: \"Circular dependsOn relationship detected\",\n code: \"circular_dependency\",\n });\n }\n\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index];\n if (new Date(entry.showNewUntil).getTime() <= new Date(entry.releasedAt).getTime()) {\n errors.push({\n path: `[${index}].showNewUntil`,\n message: \"showNewUntil must be after releasedAt\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.url && !isSafeUrl(entry.url)) {\n errors.push({\n path: `[${index}].url`,\n message: \"url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.image && !isSafeUrl(entry.image)) {\n errors.push({\n path: `[${index}].image`,\n message: \"image must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.cta?.url && !isSafeUrl(entry.cta.url)) {\n errors.push({\n path: `[${index}].cta.url`,\n message: \"cta.url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n const unsafeMetaPath = findUnsafeMetaPath(entry.meta);\n if (unsafeMetaPath) {\n errors.push({\n path: `[${index}].${unsafeMetaPath}`,\n message: `meta contains unsafe key \"${unsafeMetaPath.split(\".\").pop()}\"`,\n code: \"invalid_value\",\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n","import { validateManifest } from \"./schema\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\n\nexport interface ChangedFeature {\n id: string;\n before: FeatureEntry;\n after: FeatureEntry;\n changedFields: string[];\n}\n\nexport interface ManifestDiff {\n added: FeatureEntry[];\n removed: FeatureEntry[];\n changed: ChangedFeature[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction collectChangedFields(\n beforeValue: unknown,\n afterValue: unknown,\n path: string,\n output: string[],\n): void {\n if (beforeValue === afterValue) return;\n\n if (Array.isArray(beforeValue) && Array.isArray(afterValue)) {\n if (beforeValue.length !== afterValue.length) {\n output.push(path);\n return;\n }\n for (let i = 0; i < beforeValue.length; i += 1) {\n collectChangedFields(beforeValue[i], afterValue[i], `${path}[${i}]`, output);\n }\n return;\n }\n\n if (isRecord(beforeValue) && isRecord(afterValue)) {\n const keys = new Set([...Object.keys(beforeValue), ...Object.keys(afterValue)]);\n keys.forEach((key) => {\n const nextPath = path ? `${path}.${key}` : key;\n collectChangedFields(beforeValue[key], afterValue[key], nextPath, output);\n });\n return;\n }\n\n output.push(path);\n}\n\nexport function diffManifest(before: FeatureManifest, after: FeatureManifest): ManifestDiff {\n const beforeById = new Map(before.map((feature) => [feature.id, feature]));\n const afterById = new Map(after.map((feature) => [feature.id, feature]));\n\n const added = after.filter((feature) => !beforeById.has(feature.id));\n const removed = before.filter((feature) => !afterById.has(feature.id));\n\n const changed = after\n .filter((feature) => beforeById.has(feature.id))\n .map((feature) => {\n const previous = beforeById.get(feature.id);\n if (!previous) return null;\n const changedFields: string[] = [];\n collectChangedFields(previous, feature, \"\", changedFields);\n if (changedFields.length === 0) return null;\n return {\n id: feature.id,\n before: previous,\n after: feature,\n changedFields,\n } satisfies ChangedFeature;\n })\n .filter((item): item is ChangedFeature => item !== null);\n\n return { added, removed, changed };\n}\n\nexport interface ChangelogDiffOptions {\n includeFieldChanges?: boolean;\n}\n\nexport function generateChangelogDiff(\n diff: ManifestDiff,\n options: ChangelogDiffOptions = {},\n): string {\n const parts: string[] = [];\n\n if (diff.added.length > 0) {\n parts.push(`Added: ${diff.added.map((feature) => feature.label).join(\", \")}`);\n }\n\n if (diff.changed.length > 0) {\n const changedText = diff.changed.map((item) => {\n if (!options.includeFieldChanges) return item.after.label;\n return `${item.after.label} [${item.changedFields.join(\", \")}]`;\n });\n parts.push(`Changed: ${changedText.join(\", \")}`);\n }\n\n if (diff.removed.length > 0) {\n parts.push(`Removed: ${diff.removed.map((feature) => feature.label).join(\", \")}`);\n }\n\n return parts.length > 0 ? parts.join(\". \") : \"No manifest changes.\";\n}\n\nexport interface ChangelogMarkdownOptions extends ChangelogDiffOptions {\n maxItemsPerSection?: number;\n}\n\nfunction renderMarkdownSection(\n title: string,\n items: string[],\n maxItemsPerSection: number,\n): string[] {\n if (items.length === 0) return [`### ${title} (0)`, \"- None\"];\n\n const visible = items.slice(0, maxItemsPerSection);\n const hiddenCount = items.length - visible.length;\n\n const lines = [`### ${title} (${items.length})`, ...visible.map((item) => `- ${item}`)];\n if (hiddenCount > 0) {\n lines.push(`- ...and ${hiddenCount} more`);\n }\n return lines;\n}\n\nexport function generateChangelogDiffMarkdown(\n diff: ManifestDiff,\n options: ChangelogMarkdownOptions = {},\n): string {\n if (diff.added.length === 0 && diff.changed.length === 0 && diff.removed.length === 0) {\n return \"No manifest changes.\";\n }\n\n const maxItemsPerSection = Math.max(1, options.maxItemsPerSection ?? 20);\n const addedItems = diff.added.map((feature) => `**${feature.label}** (\\`${feature.id}\\`)`);\n const changedItems = diff.changed.map((item) => {\n if (!options.includeFieldChanges) {\n return `**${item.after.label}** (\\`${item.id}\\`)`;\n }\n const fields = item.changedFields.join(\", \");\n return `**${item.after.label}** (\\`${item.id}\\`) — ${fields}`;\n });\n const removedItems = diff.removed.map((feature) => `**${feature.label}** (\\`${feature.id}\\`)`);\n\n const sections = [\n ...renderMarkdownSection(\"Added\", addedItems, maxItemsPerSection),\n \"\",\n ...renderMarkdownSection(\"Changed\", changedItems, maxItemsPerSection),\n \"\",\n ...renderMarkdownSection(\"Removed\", removedItems, maxItemsPerSection),\n ];\n\n return sections.join(\"\\n\");\n}\n\nexport function validateManifestForCI(manifest: FeatureManifest) {\n return validateManifest(manifest);\n}\n"]}
package/dist/ci.d.cts CHANGED
@@ -171,6 +171,10 @@ interface ChangelogDiffOptions {
171
171
  includeFieldChanges?: boolean;
172
172
  }
173
173
  declare function generateChangelogDiff(diff: ManifestDiff, options?: ChangelogDiffOptions): string;
174
+ interface ChangelogMarkdownOptions extends ChangelogDiffOptions {
175
+ maxItemsPerSection?: number;
176
+ }
177
+ declare function generateChangelogDiffMarkdown(diff: ManifestDiff, options?: ChangelogMarkdownOptions): string;
174
178
  declare function validateManifestForCI(manifest: FeatureManifest): ValidationResult;
175
179
 
176
- export { type ChangedFeature, type ChangelogDiffOptions, type ManifestDiff, diffManifest, generateChangelogDiff, validateManifestForCI };
180
+ export { type ChangedFeature, type ChangelogDiffOptions, type ChangelogMarkdownOptions, type ManifestDiff, diffManifest, generateChangelogDiff, generateChangelogDiffMarkdown, validateManifestForCI };
package/dist/ci.d.ts CHANGED
@@ -171,6 +171,10 @@ interface ChangelogDiffOptions {
171
171
  includeFieldChanges?: boolean;
172
172
  }
173
173
  declare function generateChangelogDiff(diff: ManifestDiff, options?: ChangelogDiffOptions): string;
174
+ interface ChangelogMarkdownOptions extends ChangelogDiffOptions {
175
+ maxItemsPerSection?: number;
176
+ }
177
+ declare function generateChangelogDiffMarkdown(diff: ManifestDiff, options?: ChangelogMarkdownOptions): string;
174
178
  declare function validateManifestForCI(manifest: FeatureManifest): ValidationResult;
175
179
 
176
- export { type ChangedFeature, type ChangelogDiffOptions, type ManifestDiff, diffManifest, generateChangelogDiff, validateManifestForCI };
180
+ export { type ChangedFeature, type ChangelogDiffOptions, type ChangelogMarkdownOptions, type ManifestDiff, diffManifest, generateChangelogDiff, generateChangelogDiffMarkdown, validateManifestForCI };
package/dist/ci.js CHANGED
@@ -315,10 +315,43 @@ function generateChangelogDiff(diff, options = {}) {
315
315
  }
316
316
  return parts.length > 0 ? parts.join(". ") : "No manifest changes.";
317
317
  }
318
+ function renderMarkdownSection(title, items, maxItemsPerSection) {
319
+ if (items.length === 0) return [`### ${title} (0)`, "- None"];
320
+ const visible = items.slice(0, maxItemsPerSection);
321
+ const hiddenCount = items.length - visible.length;
322
+ const lines = [`### ${title} (${items.length})`, ...visible.map((item) => `- ${item}`)];
323
+ if (hiddenCount > 0) {
324
+ lines.push(`- ...and ${hiddenCount} more`);
325
+ }
326
+ return lines;
327
+ }
328
+ function generateChangelogDiffMarkdown(diff, options = {}) {
329
+ if (diff.added.length === 0 && diff.changed.length === 0 && diff.removed.length === 0) {
330
+ return "No manifest changes.";
331
+ }
332
+ const maxItemsPerSection = Math.max(1, options.maxItemsPerSection ?? 20);
333
+ const addedItems = diff.added.map((feature) => `**${feature.label}** (\`${feature.id}\`)`);
334
+ const changedItems = diff.changed.map((item) => {
335
+ if (!options.includeFieldChanges) {
336
+ return `**${item.after.label}** (\`${item.id}\`)`;
337
+ }
338
+ const fields = item.changedFields.join(", ");
339
+ return `**${item.after.label}** (\`${item.id}\`) \u2014 ${fields}`;
340
+ });
341
+ const removedItems = diff.removed.map((feature) => `**${feature.label}** (\`${feature.id}\`)`);
342
+ const sections = [
343
+ ...renderMarkdownSection("Added", addedItems, maxItemsPerSection),
344
+ "",
345
+ ...renderMarkdownSection("Changed", changedItems, maxItemsPerSection),
346
+ "",
347
+ ...renderMarkdownSection("Removed", removedItems, maxItemsPerSection)
348
+ ];
349
+ return sections.join("\n");
350
+ }
318
351
  function validateManifestForCI(manifest) {
319
352
  return validateManifest(manifest);
320
353
  }
321
354
 
322
- export { diffManifest, generateChangelogDiff, validateManifestForCI };
355
+ export { diffManifest, generateChangelogDiff, generateChangelogDiffMarkdown, validateManifestForCI };
323
356
  //# sourceMappingURL=ci.js.map
324
357
  //# sourceMappingURL=ci.js.map
package/dist/ci.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dependencies.ts","../src/schema.ts","../src/ci.ts"],"names":["isRecord"],"mappings":"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","file":"ci.js","sourcesContent":["import type { FeatureEntry, FeatureManifest } from \"./types\";\n\nfunction getDirectDependencies(feature: FeatureEntry): string[] {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return [];\n const seen = dependsOn.seen ?? [];\n const clicked = dependsOn.clicked ?? [];\n const dismissed = dependsOn.dismissed ?? [];\n const unique = new Set<string>();\n for (const id of [...seen, ...clicked, ...dismissed]) {\n if (id) unique.add(id);\n }\n return Array.from(unique);\n}\n\nexport function resolveDependencyOrder(manifest: FeatureManifest): string[] {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n const ordered: string[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n ordered.push(id);\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n // On cycles, append remaining IDs in original order to keep behavior stable.\n if (ordered.length < manifest.length) {\n const included = new Set(ordered);\n for (const feature of manifest) {\n if (included.has(feature.id)) continue;\n ordered.push(feature.id);\n }\n }\n\n return ordered;\n}\n\nexport function hasDependencyCycle(manifest: FeatureManifest): boolean {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n let visited = 0;\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n visited += 1;\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n return visited !== manifest.length;\n}\n\nexport function sortFeaturesByDependencies(features: FeatureEntry[]): FeatureEntry[] {\n if (features.length <= 1) return [...features];\n const order = resolveDependencyOrder(features);\n const rank = new Map(order.map((id, index) => [id, index]));\n return [...features].sort((a, b) => {\n const ra = rank.get(a.id);\n const rb = rank.get(b.id);\n if (ra === undefined || rb === undefined) return 0;\n return ra - rb;\n });\n}\n","import { hasDependencyCycle } from \"./dependencies\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\nimport { z } from \"zod\";\n\nexport interface ValidationIssue {\n path: string;\n message: string;\n code:\n | \"invalid_type\"\n | \"missing_required\"\n | \"invalid_value\"\n | \"invalid_date\"\n | \"duplicate_id\"\n | \"circular_dependency\";\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationIssue[];\n}\n\nexport const featureEntryJsonSchema = {\n type: \"object\",\n required: [\"id\", \"label\", \"releasedAt\", \"showNewUntil\"],\n properties: {\n id: { type: \"string\" },\n label: { type: \"string\" },\n description: { type: \"string\" },\n releasedAt: { type: \"string\", format: \"date-time\" },\n showNewUntil: { type: \"string\", format: \"date-time\" },\n flagKey: { type: \"string\" },\n product: { type: \"string\" },\n url: { type: \"string\" },\n image: { type: \"string\" },\n type: { enum: [\"feature\", \"improvement\", \"fix\", \"breaking\"] },\n priority: { enum: [\"critical\", \"normal\", \"low\"] },\n cta: {\n type: \"object\",\n properties: {\n label: { type: \"string\" },\n url: { type: \"string\" },\n },\n },\n meta: { type: \"object\" },\n },\n} as const;\n\nexport const featureManifestJsonSchema = {\n type: \"array\",\n items: featureEntryJsonSchema,\n} as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isValidDate(value: string): boolean {\n return Number.isFinite(new Date(value).getTime());\n}\n\nconst nonEmptyString = z.string().trim().min(1, \"must be a non-empty string\");\n\nconst isoDateString = nonEmptyString.refine(isValidDate, {\n message: \"must be a valid date\",\n params: { featuredropCode: \"invalid_date\" },\n});\n\nconst dependsOnSchema = z\n .object({\n seen: z.array(z.string()).optional(),\n clicked: z.array(z.string()).optional(),\n dismissed: z.array(z.string()).optional(),\n })\n .optional();\n\nconst ctaSchema = z\n .object({\n label: nonEmptyString,\n url: nonEmptyString,\n })\n .optional();\n\nexport const featureEntrySchema = z\n .object({\n id: nonEmptyString,\n label: nonEmptyString,\n releasedAt: isoDateString,\n showNewUntil: isoDateString,\n description: z.string().optional(),\n flagKey: z.string().optional(),\n product: z.string().optional(),\n url: z.string().optional(),\n image: z.string().optional(),\n type: z.enum([\"feature\", \"improvement\", \"fix\", \"breaking\"]).optional(),\n priority: z.enum([\"critical\", \"normal\", \"low\"]).optional(),\n cta: ctaSchema,\n meta: z.record(z.unknown()).optional(),\n dependsOn: dependsOnSchema,\n })\n .passthrough();\n\nexport const featureManifestSchema = z.array(featureEntrySchema);\n\nfunction toIssuePath(path: Array<string | number>): string {\n if (path.length === 0) return \"$\";\n let output = \"\";\n for (const part of path) {\n if (typeof part === \"number\") output += `[${part}]`;\n else output += output ? `.${part}` : part;\n }\n return output;\n}\n\nfunction mapZodIssue(issue: z.ZodIssue): ValidationIssue {\n const codeParam = (issue as { params?: Record<string, unknown> }).params?.featuredropCode;\n if (codeParam === \"invalid_date\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_date\",\n };\n }\n if (issue.code === \"invalid_type\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: issue.received === \"undefined\" ? \"missing_required\" : \"invalid_type\",\n };\n }\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_value\",\n };\n}\n\nconst UNSAFE_META_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction isSafeUrl(value: string): boolean {\n const normalized = value.trim();\n if (!normalized) return false;\n if (/^(\\/|\\.\\/|\\.\\.\\/|\\?|#)/.test(normalized)) return true;\n if (/^https?:\\/\\//i.test(normalized)) return true;\n return false;\n}\n\nfunction findUnsafeMetaPath(value: unknown, path = \"meta\"): string | null {\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index++) {\n const nested = findUnsafeMetaPath(value[index], `${path}[${index}]`);\n if (nested) return nested;\n }\n return null;\n }\n\n if (!isRecord(value)) return null;\n for (const [key, nestedValue] of Object.entries(value)) {\n if (UNSAFE_META_KEYS.has(key)) {\n return `${path}.${key}`;\n }\n const nested = findUnsafeMetaPath(nestedValue, `${path}.${key}`);\n if (nested) return nested;\n }\n return null;\n}\n\nfunction validateFeatureEntry(raw: unknown, index: number): { entry?: FeatureEntry; issues: ValidationIssue[] } {\n if (!isRecord(raw)) {\n return {\n issues: [\n {\n path: `[${index}]`,\n message: \"Feature entry must be an object\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const parsed = featureEntrySchema.safeParse(raw);\n if (!parsed.success) {\n return {\n issues: parsed.error.issues.map((issue) => ({\n ...mapZodIssue(issue),\n path: `[${index}]${issue.path.length > 0 ? `.${toIssuePath(issue.path)}` : \"\"}`,\n })),\n };\n }\n\n return {\n issues: [],\n entry: parsed.data as FeatureEntry,\n };\n}\n\nexport function validateManifest(data: unknown): ValidationResult {\n const errors: ValidationIssue[] = [];\n if (!Array.isArray(data)) {\n return {\n valid: false,\n errors: [\n {\n path: \"$\",\n message: \"Manifest must be an array\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const entries: FeatureEntry[] = [];\n const seenIds = new Set<string>();\n data.forEach((item, index) => {\n const result = validateFeatureEntry(item, index);\n errors.push(...result.issues);\n if (!result.entry) return;\n if (seenIds.has(result.entry.id)) {\n errors.push({\n path: `[${index}].id`,\n message: `Duplicate feature id \"${result.entry.id}\"`,\n code: \"duplicate_id\",\n });\n return;\n }\n seenIds.add(result.entry.id);\n entries.push(result.entry);\n });\n\n if (entries.length > 0 && hasDependencyCycle(entries as FeatureManifest)) {\n errors.push({\n path: \"$\",\n message: \"Circular dependsOn relationship detected\",\n code: \"circular_dependency\",\n });\n }\n\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index];\n if (new Date(entry.showNewUntil).getTime() <= new Date(entry.releasedAt).getTime()) {\n errors.push({\n path: `[${index}].showNewUntil`,\n message: \"showNewUntil must be after releasedAt\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.url && !isSafeUrl(entry.url)) {\n errors.push({\n path: `[${index}].url`,\n message: \"url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.image && !isSafeUrl(entry.image)) {\n errors.push({\n path: `[${index}].image`,\n message: \"image must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.cta?.url && !isSafeUrl(entry.cta.url)) {\n errors.push({\n path: `[${index}].cta.url`,\n message: \"cta.url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n const unsafeMetaPath = findUnsafeMetaPath(entry.meta);\n if (unsafeMetaPath) {\n errors.push({\n path: `[${index}].${unsafeMetaPath}`,\n message: `meta contains unsafe key \"${unsafeMetaPath.split(\".\").pop()}\"`,\n code: \"invalid_value\",\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n","import { validateManifest } from \"./schema\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\n\nexport interface ChangedFeature {\n id: string;\n before: FeatureEntry;\n after: FeatureEntry;\n changedFields: string[];\n}\n\nexport interface ManifestDiff {\n added: FeatureEntry[];\n removed: FeatureEntry[];\n changed: ChangedFeature[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction collectChangedFields(\n beforeValue: unknown,\n afterValue: unknown,\n path: string,\n output: string[],\n): void {\n if (beforeValue === afterValue) return;\n\n if (Array.isArray(beforeValue) && Array.isArray(afterValue)) {\n if (beforeValue.length !== afterValue.length) {\n output.push(path);\n return;\n }\n for (let i = 0; i < beforeValue.length; i += 1) {\n collectChangedFields(beforeValue[i], afterValue[i], `${path}[${i}]`, output);\n }\n return;\n }\n\n if (isRecord(beforeValue) && isRecord(afterValue)) {\n const keys = new Set([...Object.keys(beforeValue), ...Object.keys(afterValue)]);\n keys.forEach((key) => {\n const nextPath = path ? `${path}.${key}` : key;\n collectChangedFields(beforeValue[key], afterValue[key], nextPath, output);\n });\n return;\n }\n\n output.push(path);\n}\n\nexport function diffManifest(before: FeatureManifest, after: FeatureManifest): ManifestDiff {\n const beforeById = new Map(before.map((feature) => [feature.id, feature]));\n const afterById = new Map(after.map((feature) => [feature.id, feature]));\n\n const added = after.filter((feature) => !beforeById.has(feature.id));\n const removed = before.filter((feature) => !afterById.has(feature.id));\n\n const changed = after\n .filter((feature) => beforeById.has(feature.id))\n .map((feature) => {\n const previous = beforeById.get(feature.id);\n if (!previous) return null;\n const changedFields: string[] = [];\n collectChangedFields(previous, feature, \"\", changedFields);\n if (changedFields.length === 0) return null;\n return {\n id: feature.id,\n before: previous,\n after: feature,\n changedFields,\n } satisfies ChangedFeature;\n })\n .filter((item): item is ChangedFeature => item !== null);\n\n return { added, removed, changed };\n}\n\nexport interface ChangelogDiffOptions {\n includeFieldChanges?: boolean;\n}\n\nexport function generateChangelogDiff(\n diff: ManifestDiff,\n options: ChangelogDiffOptions = {},\n): string {\n const parts: string[] = [];\n\n if (diff.added.length > 0) {\n parts.push(`Added: ${diff.added.map((feature) => feature.label).join(\", \")}`);\n }\n\n if (diff.changed.length > 0) {\n const changedText = diff.changed.map((item) => {\n if (!options.includeFieldChanges) return item.after.label;\n return `${item.after.label} [${item.changedFields.join(\", \")}]`;\n });\n parts.push(`Changed: ${changedText.join(\", \")}`);\n }\n\n if (diff.removed.length > 0) {\n parts.push(`Removed: ${diff.removed.map((feature) => feature.label).join(\", \")}`);\n }\n\n return parts.length > 0 ? parts.join(\". \") : \"No manifest changes.\";\n}\n\nexport function validateManifestForCI(manifest: FeatureManifest) {\n return validateManifest(manifest);\n}\n"]}
1
+ {"version":3,"sources":["../src/dependencies.ts","../src/schema.ts","../src/ci.ts"],"names":["isRecord"],"mappings":";;;AAEA,SAAS,sBAAsB,OAAA,EAAiC;AAC9D,EAAA,MAAM,YAAY,OAAA,CAAQ,SAAA;AAC1B,EAAA,IAAI,CAAC,SAAA,EAAW,OAAO,EAAC;AACxB,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,IAAA,IAAQ,EAAC;AAChC,EAAA,MAAM,OAAA,GAAU,SAAA,CAAU,OAAA,IAAW,EAAC;AACtC,EAAA,MAAM,SAAA,GAAY,SAAA,CAAU,SAAA,IAAa,EAAC;AAC1C,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAY;AAC/B,EAAA,KAAA,MAAW,EAAA,IAAM,CAAC,GAAG,IAAA,EAAM,GAAG,OAAA,EAAS,GAAG,SAAS,CAAA,EAAG;AACpD,IAAA,IAAI,EAAA,EAAI,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA;AAAA,EACvB;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAC1B;AAqDO,SAAS,mBAAmB,QAAA,EAAoC;AACrE,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAC,OAAA,KAAY,OAAA,CAAQ,EAAE,CAAC,CAAA;AACzD,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAyB;AAC9C,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAoB;AAEzC,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,EAAA,kBAAI,IAAI,KAAK,CAAA;AAClC,IAAA,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,EAAA,EAAI,CAAC,CAAA;AAAA,EAC5B;AAEA,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,KAAA,MAAW,YAAA,IAAgB,qBAAA,CAAsB,OAAO,CAAA,EAAG;AACzD,MAAA,IAAI,CAAC,GAAA,CAAI,GAAA,CAAI,YAAY,CAAA,EAAG;AAC5B,MAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,GAAA,CAAI,YAAY,CAAA;AACvC,MAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA,EAAG;AACrC,MAAA,KAAA,CAAM,GAAA,CAAI,QAAQ,EAAE,CAAA;AACpB,MAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,EAAA,EAAA,CAAK,QAAA,CAAS,IAAI,OAAA,CAAQ,EAAE,CAAA,IAAK,CAAA,IAAK,CAAC,CAAA;AAAA,IAC9D;AAAA,EACF;AAEA,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA,IAAK,OAAO,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,EAAE,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,OAAO,KAAA,CAAM,SAAS,CAAA,EAAG;AACvB,IAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,IAAA,IAAI,CAAC,EAAA,EAAI;AACT,IAAA,OAAA,IAAW,CAAA;AACX,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AAC7B,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,KAAA,MAAW,UAAU,KAAA,EAAO;AAC1B,MAAA,MAAM,UAAA,GAAA,CAAc,QAAA,CAAS,GAAA,CAAI,MAAM,KAAK,CAAA,IAAK,CAAA;AACjD,MAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,UAAU,CAAA;AAC/B,MAAA,IAAI,UAAA,KAAe,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA;AAAA,IACzC;AAAA,EACF;AAEA,EAAA,OAAO,YAAY,QAAA,CAAS,MAAA;AAC9B;ACtDA,SAAS,SAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,CAAC,CAAC,KAAA,IAAS,OAAO,UAAU,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA;AACrE;AAEA,SAAS,YAAY,KAAA,EAAwB;AAC3C,EAAA,OAAO,OAAO,QAAA,CAAS,IAAI,KAAK,KAAK,CAAA,CAAE,SAAS,CAAA;AAClD;AAEA,IAAM,cAAA,GAAiB,EAAE,MAAA,EAAO,CAAE,MAAK,CAAE,GAAA,CAAI,GAAG,4BAA4B,CAAA;AAE5E,IAAM,aAAA,GAAgB,cAAA,CAAe,MAAA,CAAO,WAAA,EAAa;AAAA,EACvD,OAAA,EAAS,sBAAA;AAAA,EACT,MAAA,EAAQ,EAAE,eAAA,EAAiB,cAAA;AAC7B,CAAC,CAAA;AAED,IAAM,eAAA,GAAkB,EACrB,MAAA,CAAO;AAAA,EACN,MAAM,CAAA,CAAE,KAAA,CAAM,EAAE,MAAA,EAAQ,EAAE,QAAA,EAAS;AAAA,EACnC,SAAS,CAAA,CAAE,KAAA,CAAM,EAAE,MAAA,EAAQ,EAAE,QAAA,EAAS;AAAA,EACtC,WAAW,CAAA,CAAE,KAAA,CAAM,EAAE,MAAA,EAAQ,EAAE,QAAA;AACjC,CAAC,EACA,QAAA,EAAS;AAEZ,IAAM,SAAA,GAAY,EACf,MAAA,CAAO;AAAA,EACN,KAAA,EAAO,cAAA;AAAA,EACP,GAAA,EAAK;AACP,CAAC,EACA,QAAA,EAAS;AAEL,IAAM,kBAAA,GAAqB,EAC/B,MAAA,CAAO;AAAA,EACN,EAAA,EAAI,cAAA;AAAA,EACJ,KAAA,EAAO,cAAA;AAAA,EACP,UAAA,EAAY,aAAA;AAAA,EACZ,YAAA,EAAc,aAAA;AAAA,EACd,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,IAAA,EAAM,CAAA,CAAE,IAAA,CAAK,CAAC,SAAA,EAAW,eAAe,KAAA,EAAO,UAAU,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACrE,QAAA,EAAU,EAAE,IAAA,CAAK,CAAC,YAAY,QAAA,EAAU,KAAK,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACzD,GAAA,EAAK,SAAA;AAAA,EACL,MAAM,CAAA,CAAE,MAAA,CAAO,EAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EACrC,SAAA,EAAW;AACb,CAAC,EACA,WAAA,EAAY;AAEsB,CAAA,CAAE,KAAA,CAAM,kBAAkB;AAE/D,SAAS,YAAY,IAAA,EAAsC;AACzD,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,GAAA;AAC9B,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,MAAW,QAAQ,IAAA,EAAM;AACvB,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,MAAA,IAAU,IAAI,IAAI,CAAA,CAAA,CAAA;AAAA,SAC3C,MAAA,IAAU,MAAA,GAAS,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,GAAK,IAAA;AAAA,EACvC;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,YAAY,KAAA,EAAoC;AACvD,EAAA,MAAM,SAAA,GAAa,MAA+C,MAAA,EAAQ,eAAA;AAC1E,EAAA,IAAI,cAAc,cAAA,EAAgB;AAChC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA;AAAA,MAC5B,SAAS,KAAA,CAAM,OAAA;AAAA,MACf,IAAA,EAAM;AAAA,KACR;AAAA,EACF;AACA,EAAA,IAAI,KAAA,CAAM,SAAS,cAAA,EAAgB;AACjC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA;AAAA,MAC5B,SAAS,KAAA,CAAM,OAAA;AAAA,MACf,IAAA,EAAM,KAAA,CAAM,QAAA,KAAa,WAAA,GAAc,kBAAA,GAAqB;AAAA,KAC9D;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA;AAAA,IAC5B,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,IAAA,EAAM;AAAA,GACR;AACF;AAEA,IAAM,mCAAmB,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,aAAA,EAAe,WAAW,CAAC,CAAA;AAE1E,SAAS,UAAU,KAAA,EAAwB;AACzC,EAAA,MAAM,UAAA,GAAa,MAAM,IAAA,EAAK;AAC9B,EAAA,IAAI,CAAC,YAAY,OAAO,KAAA;AACxB,EAAA,IAAI,wBAAA,CAAyB,IAAA,CAAK,UAAU,CAAA,EAAG,OAAO,IAAA;AACtD,EAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,UAAU,CAAA,EAAG,OAAO,IAAA;AAC7C,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,kBAAA,CAAmB,KAAA,EAAgB,IAAA,GAAO,MAAA,EAAuB;AACxE,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,CAAM,QAAQ,KAAA,EAAA,EAAS;AACjD,MAAA,MAAM,MAAA,GAAS,mBAAmB,KAAA,CAAM,KAAK,GAAG,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,CAAG,CAAA;AACnE,MAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,IACrB;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,IAAA;AAC7B,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,WAAW,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtD,IAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,GAAG,CAAA,EAAG;AAC7B,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AAAA,IACvB;AACA,IAAA,MAAM,SAAS,kBAAA,CAAmB,WAAA,EAAa,GAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAC/D,IAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,EACrB;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,oBAAA,CAAqB,KAAc,KAAA,EAAoE;AAC9G,EAAA,IAAI,CAAC,QAAA,CAAS,GAAG,CAAA,EAAG;AAClB,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ;AAAA,QACN;AAAA,UACE,IAAA,EAAM,IAAI,KAAK,CAAA,CAAA,CAAA;AAAA,UACf,OAAA,EAAS,iCAAA;AAAA,UACT,IAAA,EAAM;AAAA;AACR;AACF,KACF;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,kBAAA,CAAmB,SAAA,CAAU,GAAG,CAAA;AAC/C,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,OAAO;AAAA,MACL,QAAQ,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,QAC1C,GAAG,YAAY,KAAK,CAAA;AAAA,QACpB,IAAA,EAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,MAAM,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,CAAA,CAAA,EAAI,WAAA,CAAY,KAAA,CAAM,IAAI,CAAC,KAAK,EAAE,CAAA;AAAA,OAC/E,CAAE;AAAA,KACJ;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,QAAQ,EAAC;AAAA,IACT,OAAO,MAAA,CAAO;AAAA,GAChB;AACF;AAEO,SAAS,iBAAiB,IAAA,EAAiC;AAChE,EAAA,MAAM,SAA4B,EAAC;AACnC,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AACxB,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,KAAA;AAAA,MACP,MAAA,EAAQ;AAAA,QACN;AAAA,UACE,IAAA,EAAM,GAAA;AAAA,UACN,OAAA,EAAS,2BAAA;AAAA,UACT,IAAA,EAAM;AAAA;AACR;AACF,KACF;AAAA,EACF;AAEA,EAAA,MAAM,UAA0B,EAAC;AACjC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AAC5B,IAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,IAAA,EAAM,KAAK,CAAA;AAC/C,IAAA,MAAA,CAAO,IAAA,CAAK,GAAG,MAAA,CAAO,MAAM,CAAA;AAC5B,IAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AACnB,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,EAAG;AAChC,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,IAAI,KAAK,CAAA,IAAA,CAAA;AAAA,QACf,OAAA,EAAS,CAAA,sBAAA,EAAyB,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,CAAA,CAAA;AAAA,QACjD,IAAA,EAAM;AAAA,OACP,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,OAAA,CAAQ,GAAA,CAAI,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA;AAC3B,IAAA,OAAA,CAAQ,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,EAC3B,CAAC,CAAA;AAED,EAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,kBAAA,CAAmB,OAA0B,CAAA,EAAG;AACxE,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,GAAA;AAAA,MACN,OAAA,EAAS,0CAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,OAAA,CAAQ,QAAQ,KAAA,EAAA,EAAS;AACnD,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAK,CAAA;AAC3B,IAAA,IAAI,IAAI,IAAA,CAAK,KAAA,CAAM,YAAY,CAAA,CAAE,OAAA,EAAQ,IAAK,IAAI,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,CAAE,SAAQ,EAAG;AAClF,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,IAAI,KAAK,CAAA,cAAA,CAAA;AAAA,QACf,OAAA,EAAS,uCAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,MAAM,GAAA,IAAO,CAAC,SAAA,CAAU,KAAA,CAAM,GAAG,CAAA,EAAG;AACtC,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,IAAI,KAAK,CAAA,KAAA,CAAA;AAAA,QACf,OAAA,EAAS,sCAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,MAAM,KAAA,IAAS,CAAC,SAAA,CAAU,KAAA,CAAM,KAAK,CAAA,EAAG;AAC1C,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,IAAI,KAAK,CAAA,OAAA,CAAA;AAAA,QACf,OAAA,EAAS,wCAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,KAAA,CAAM,KAAK,GAAA,IAAO,CAAC,UAAU,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,EAAG;AAC/C,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,IAAI,KAAK,CAAA,SAAA,CAAA;AAAA,QACf,OAAA,EAAS,0CAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,MAAM,cAAA,GAAiB,kBAAA,CAAmB,KAAA,CAAM,IAAI,CAAA;AACpD,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,CAAA,CAAA,EAAI,KAAK,CAAA,EAAA,EAAK,cAAc,CAAA,CAAA;AAAA,QAClC,SAAS,CAAA,0BAAA,EAA6B,cAAA,CAAe,MAAM,GAAG,CAAA,CAAE,KAAK,CAAA,CAAA,CAAA;AAAA,QACrE,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,OAAO,MAAA,KAAW,CAAA;AAAA,IACzB;AAAA,GACF;AACF;;;AC5QA,SAASA,UAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAA,CAAQ,KAAK,CAAA,IAAK,OAAO,UAAU,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA;AAC5E;AAEA,SAAS,oBAAA,CACP,WAAA,EACA,UAAA,EACA,IAAA,EACA,MAAA,EACM;AACN,EAAA,IAAI,gBAAgB,UAAA,EAAY;AAEhC,EAAA,IAAI,MAAM,OAAA,CAAQ,WAAW,KAAK,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,EAAG;AAC3D,IAAA,IAAI,WAAA,CAAY,MAAA,KAAW,UAAA,CAAW,MAAA,EAAQ;AAC5C,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,MAAA;AAAA,IACF;AACA,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,WAAA,CAAY,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC9C,MAAA,oBAAA,CAAqB,WAAA,CAAY,CAAC,CAAA,EAAG,UAAA,CAAW,CAAC,CAAA,EAAG,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAA,EAAK,MAAM,CAAA;AAAA,IAC7E;AACA,IAAA;AAAA,EACF;AAEA,EAAA,IAAIA,SAAAA,CAAS,WAAW,CAAA,IAAKA,SAAAA,CAAS,UAAU,CAAA,EAAG;AACjD,IAAA,MAAM,IAAA,mBAAO,IAAI,GAAA,CAAI,CAAC,GAAG,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAAG,GAAG,MAAA,CAAO,IAAA,CAAK,UAAU,CAAC,CAAC,CAAA;AAC9E,IAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,GAAA,KAAQ;AACpB,MAAA,MAAM,WAAW,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAC3C,MAAA,oBAAA,CAAqB,YAAY,GAAG,CAAA,EAAG,WAAW,GAAG,CAAA,EAAG,UAAU,MAAM,CAAA;AAAA,IAC1E,CAAC,CAAA;AACD,IAAA;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAClB;AAEO,SAAS,YAAA,CAAa,QAAyB,KAAA,EAAsC;AAC1F,EAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,CAAC,OAAA,KAAY,CAAC,OAAA,CAAQ,EAAA,EAAI,OAAO,CAAC,CAAC,CAAA;AACzE,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,OAAA,KAAY,CAAC,OAAA,CAAQ,EAAA,EAAI,OAAO,CAAC,CAAC,CAAA;AAEvE,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,CAAC,OAAA,KAAY,CAAC,UAAA,CAAW,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAC,CAAA;AACnE,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,CAAC,OAAA,KAAY,CAAC,SAAA,CAAU,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAC,CAAA;AAErE,EAAA,MAAM,OAAA,GAAU,KAAA,CACb,MAAA,CAAO,CAAC,OAAA,KAAY,UAAA,CAAW,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAC,CAAA,CAC9C,GAAA,CAAI,CAAC,OAAA,KAAY;AAChB,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA;AAC1C,IAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,IAAA,MAAM,gBAA0B,EAAC;AACjC,IAAA,oBAAA,CAAqB,QAAA,EAAU,OAAA,EAAS,EAAA,EAAI,aAAa,CAAA;AACzD,IAAA,IAAI,aAAA,CAAc,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AACvC,IAAA,OAAO;AAAA,MACL,IAAI,OAAA,CAAQ,EAAA;AAAA,MACZ,MAAA,EAAQ,QAAA;AAAA,MACR,KAAA,EAAO,OAAA;AAAA,MACP;AAAA,KACF;AAAA,EACF,CAAC,CAAA,CACA,MAAA,CAAO,CAAC,IAAA,KAAiC,SAAS,IAAI,CAAA;AAEzD,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,OAAA,EAAQ;AACnC;AAMO,SAAS,qBAAA,CACd,IAAA,EACA,OAAA,GAAgC,EAAC,EACzB;AACR,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AACzB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,OAAA,EAAU,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,CAAC,OAAA,KAAY,OAAA,CAAQ,KAAK,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EAC9E;AAEA,EAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC3B,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,IAAA,KAAS;AAC7C,MAAA,IAAI,CAAC,OAAA,CAAQ,mBAAA,EAAqB,OAAO,KAAK,KAAA,CAAM,KAAA;AACpD,MAAA,OAAO,CAAA,EAAG,KAAK,KAAA,CAAM,KAAK,KAAK,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,IAC9D,CAAC,CAAA;AACD,IAAA,KAAA,CAAM,KAAK,CAAA,SAAA,EAAY,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACjD;AAEA,EAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC3B,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,SAAA,EAAY,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,OAAA,KAAY,OAAA,CAAQ,KAAK,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EAClF;AAEA,EAAA,OAAO,MAAM,MAAA,GAAS,CAAA,GAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,GAAI,sBAAA;AAC/C;AAMA,SAAS,qBAAA,CACP,KAAA,EACA,KAAA,EACA,kBAAA,EACU;AACV,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG,OAAO,CAAC,CAAA,IAAA,EAAO,KAAK,QAAQ,QAAQ,CAAA;AAE5D,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,kBAAkB,CAAA;AACjD,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,MAAA,GAAS,OAAA,CAAQ,MAAA;AAE3C,EAAA,MAAM,QAAQ,CAAC,CAAA,IAAA,EAAO,KAAK,CAAA,EAAA,EAAK,MAAM,MAAM,CAAA,CAAA,CAAA,EAAK,GAAG,OAAA,CAAQ,IAAI,CAAC,IAAA,KAAS,CAAA,EAAA,EAAK,IAAI,EAAE,CAAC,CAAA;AACtF,EAAA,IAAI,cAAc,CAAA,EAAG;AACnB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,SAAA,EAAY,WAAW,CAAA,KAAA,CAAO,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,6BAAA,CACd,IAAA,EACA,OAAA,GAAoC,EAAC,EAC7B;AACR,EAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,KAAW,CAAA,IAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AACrF,IAAA,OAAO,sBAAA;AAAA,EACT;AAEA,EAAA,MAAM,qBAAqB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,sBAAsB,EAAE,CAAA;AACvE,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,CAAC,OAAA,KAAY,CAAA,EAAA,EAAK,OAAA,CAAQ,KAAK,CAAA,MAAA,EAAS,OAAA,CAAQ,EAAE,CAAA,GAAA,CAAK,CAAA;AACzF,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,IAAA,KAAS;AAC9C,IAAA,IAAI,CAAC,QAAQ,mBAAA,EAAqB;AAChC,MAAA,OAAO,KAAK,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,MAAA,EAAS,KAAK,EAAE,CAAA,GAAA,CAAA;AAAA,IAC9C;AACA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AAC3C,IAAA,OAAO,CAAA,EAAA,EAAK,KAAK,KAAA,CAAM,KAAK,SAAS,IAAA,CAAK,EAAE,cAAS,MAAM,CAAA,CAAA;AAAA,EAC7D,CAAC,CAAA;AACD,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,OAAA,KAAY,CAAA,EAAA,EAAK,OAAA,CAAQ,KAAK,CAAA,MAAA,EAAS,OAAA,CAAQ,EAAE,CAAA,GAAA,CAAK,CAAA;AAE7F,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,GAAG,qBAAA,CAAsB,OAAA,EAAS,UAAA,EAAY,kBAAkB,CAAA;AAAA,IAChE,EAAA;AAAA,IACA,GAAG,qBAAA,CAAsB,SAAA,EAAW,YAAA,EAAc,kBAAkB,CAAA;AAAA,IACpE,EAAA;AAAA,IACA,GAAG,qBAAA,CAAsB,SAAA,EAAW,YAAA,EAAc,kBAAkB;AAAA,GACtE;AAEA,EAAA,OAAO,QAAA,CAAS,KAAK,IAAI,CAAA;AAC3B;AAEO,SAAS,sBAAsB,QAAA,EAA2B;AAC/D,EAAA,OAAO,iBAAiB,QAAQ,CAAA;AAClC","file":"ci.js","sourcesContent":["import type { FeatureEntry, FeatureManifest } from \"./types\";\n\nfunction getDirectDependencies(feature: FeatureEntry): string[] {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return [];\n const seen = dependsOn.seen ?? [];\n const clicked = dependsOn.clicked ?? [];\n const dismissed = dependsOn.dismissed ?? [];\n const unique = new Set<string>();\n for (const id of [...seen, ...clicked, ...dismissed]) {\n if (id) unique.add(id);\n }\n return Array.from(unique);\n}\n\nexport function resolveDependencyOrder(manifest: FeatureManifest): string[] {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n const ordered: string[] = [];\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n ordered.push(id);\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n // On cycles, append remaining IDs in original order to keep behavior stable.\n if (ordered.length < manifest.length) {\n const included = new Set(ordered);\n for (const feature of manifest) {\n if (included.has(feature.id)) continue;\n ordered.push(feature.id);\n }\n }\n\n return ordered;\n}\n\nexport function hasDependencyCycle(manifest: FeatureManifest): boolean {\n const ids = new Set(manifest.map((feature) => feature.id));\n const outgoing = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n\n for (const feature of manifest) {\n outgoing.set(feature.id, new Set());\n indegree.set(feature.id, 0);\n }\n\n for (const feature of manifest) {\n for (const dependencyId of getDirectDependencies(feature)) {\n if (!ids.has(dependencyId)) continue;\n const edges = outgoing.get(dependencyId);\n if (!edges || edges.has(feature.id)) continue;\n edges.add(feature.id);\n indegree.set(feature.id, (indegree.get(feature.id) ?? 0) + 1);\n }\n }\n\n const queue: string[] = [];\n for (const feature of manifest) {\n if ((indegree.get(feature.id) ?? 0) === 0) queue.push(feature.id);\n }\n\n let visited = 0;\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id) continue;\n visited += 1;\n const edges = outgoing.get(id);\n if (!edges) continue;\n for (const nextId of edges) {\n const nextDegree = (indegree.get(nextId) ?? 0) - 1;\n indegree.set(nextId, nextDegree);\n if (nextDegree === 0) queue.push(nextId);\n }\n }\n\n return visited !== manifest.length;\n}\n\nexport function sortFeaturesByDependencies(features: FeatureEntry[]): FeatureEntry[] {\n if (features.length <= 1) return [...features];\n const order = resolveDependencyOrder(features);\n const rank = new Map(order.map((id, index) => [id, index]));\n return [...features].sort((a, b) => {\n const ra = rank.get(a.id);\n const rb = rank.get(b.id);\n if (ra === undefined || rb === undefined) return 0;\n return ra - rb;\n });\n}\n","import { hasDependencyCycle } from \"./dependencies\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\nimport { z } from \"zod\";\n\nexport interface ValidationIssue {\n path: string;\n message: string;\n code:\n | \"invalid_type\"\n | \"missing_required\"\n | \"invalid_value\"\n | \"invalid_date\"\n | \"duplicate_id\"\n | \"circular_dependency\";\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationIssue[];\n}\n\nexport const featureEntryJsonSchema = {\n type: \"object\",\n required: [\"id\", \"label\", \"releasedAt\", \"showNewUntil\"],\n properties: {\n id: { type: \"string\" },\n label: { type: \"string\" },\n description: { type: \"string\" },\n releasedAt: { type: \"string\", format: \"date-time\" },\n showNewUntil: { type: \"string\", format: \"date-time\" },\n flagKey: { type: \"string\" },\n product: { type: \"string\" },\n url: { type: \"string\" },\n image: { type: \"string\" },\n type: { enum: [\"feature\", \"improvement\", \"fix\", \"breaking\"] },\n priority: { enum: [\"critical\", \"normal\", \"low\"] },\n cta: {\n type: \"object\",\n properties: {\n label: { type: \"string\" },\n url: { type: \"string\" },\n },\n },\n meta: { type: \"object\" },\n },\n} as const;\n\nexport const featureManifestJsonSchema = {\n type: \"array\",\n items: featureEntryJsonSchema,\n} as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isValidDate(value: string): boolean {\n return Number.isFinite(new Date(value).getTime());\n}\n\nconst nonEmptyString = z.string().trim().min(1, \"must be a non-empty string\");\n\nconst isoDateString = nonEmptyString.refine(isValidDate, {\n message: \"must be a valid date\",\n params: { featuredropCode: \"invalid_date\" },\n});\n\nconst dependsOnSchema = z\n .object({\n seen: z.array(z.string()).optional(),\n clicked: z.array(z.string()).optional(),\n dismissed: z.array(z.string()).optional(),\n })\n .optional();\n\nconst ctaSchema = z\n .object({\n label: nonEmptyString,\n url: nonEmptyString,\n })\n .optional();\n\nexport const featureEntrySchema = z\n .object({\n id: nonEmptyString,\n label: nonEmptyString,\n releasedAt: isoDateString,\n showNewUntil: isoDateString,\n description: z.string().optional(),\n flagKey: z.string().optional(),\n product: z.string().optional(),\n url: z.string().optional(),\n image: z.string().optional(),\n type: z.enum([\"feature\", \"improvement\", \"fix\", \"breaking\"]).optional(),\n priority: z.enum([\"critical\", \"normal\", \"low\"]).optional(),\n cta: ctaSchema,\n meta: z.record(z.unknown()).optional(),\n dependsOn: dependsOnSchema,\n })\n .passthrough();\n\nexport const featureManifestSchema = z.array(featureEntrySchema);\n\nfunction toIssuePath(path: Array<string | number>): string {\n if (path.length === 0) return \"$\";\n let output = \"\";\n for (const part of path) {\n if (typeof part === \"number\") output += `[${part}]`;\n else output += output ? `.${part}` : part;\n }\n return output;\n}\n\nfunction mapZodIssue(issue: z.ZodIssue): ValidationIssue {\n const codeParam = (issue as { params?: Record<string, unknown> }).params?.featuredropCode;\n if (codeParam === \"invalid_date\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_date\",\n };\n }\n if (issue.code === \"invalid_type\") {\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: issue.received === \"undefined\" ? \"missing_required\" : \"invalid_type\",\n };\n }\n return {\n path: toIssuePath(issue.path),\n message: issue.message,\n code: \"invalid_value\",\n };\n}\n\nconst UNSAFE_META_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction isSafeUrl(value: string): boolean {\n const normalized = value.trim();\n if (!normalized) return false;\n if (/^(\\/|\\.\\/|\\.\\.\\/|\\?|#)/.test(normalized)) return true;\n if (/^https?:\\/\\//i.test(normalized)) return true;\n return false;\n}\n\nfunction findUnsafeMetaPath(value: unknown, path = \"meta\"): string | null {\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index++) {\n const nested = findUnsafeMetaPath(value[index], `${path}[${index}]`);\n if (nested) return nested;\n }\n return null;\n }\n\n if (!isRecord(value)) return null;\n for (const [key, nestedValue] of Object.entries(value)) {\n if (UNSAFE_META_KEYS.has(key)) {\n return `${path}.${key}`;\n }\n const nested = findUnsafeMetaPath(nestedValue, `${path}.${key}`);\n if (nested) return nested;\n }\n return null;\n}\n\nfunction validateFeatureEntry(raw: unknown, index: number): { entry?: FeatureEntry; issues: ValidationIssue[] } {\n if (!isRecord(raw)) {\n return {\n issues: [\n {\n path: `[${index}]`,\n message: \"Feature entry must be an object\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const parsed = featureEntrySchema.safeParse(raw);\n if (!parsed.success) {\n return {\n issues: parsed.error.issues.map((issue) => ({\n ...mapZodIssue(issue),\n path: `[${index}]${issue.path.length > 0 ? `.${toIssuePath(issue.path)}` : \"\"}`,\n })),\n };\n }\n\n return {\n issues: [],\n entry: parsed.data as FeatureEntry,\n };\n}\n\nexport function validateManifest(data: unknown): ValidationResult {\n const errors: ValidationIssue[] = [];\n if (!Array.isArray(data)) {\n return {\n valid: false,\n errors: [\n {\n path: \"$\",\n message: \"Manifest must be an array\",\n code: \"invalid_type\",\n },\n ],\n };\n }\n\n const entries: FeatureEntry[] = [];\n const seenIds = new Set<string>();\n data.forEach((item, index) => {\n const result = validateFeatureEntry(item, index);\n errors.push(...result.issues);\n if (!result.entry) return;\n if (seenIds.has(result.entry.id)) {\n errors.push({\n path: `[${index}].id`,\n message: `Duplicate feature id \"${result.entry.id}\"`,\n code: \"duplicate_id\",\n });\n return;\n }\n seenIds.add(result.entry.id);\n entries.push(result.entry);\n });\n\n if (entries.length > 0 && hasDependencyCycle(entries as FeatureManifest)) {\n errors.push({\n path: \"$\",\n message: \"Circular dependsOn relationship detected\",\n code: \"circular_dependency\",\n });\n }\n\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index];\n if (new Date(entry.showNewUntil).getTime() <= new Date(entry.releasedAt).getTime()) {\n errors.push({\n path: `[${index}].showNewUntil`,\n message: \"showNewUntil must be after releasedAt\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.url && !isSafeUrl(entry.url)) {\n errors.push({\n path: `[${index}].url`,\n message: \"url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.image && !isSafeUrl(entry.image)) {\n errors.push({\n path: `[${index}].image`,\n message: \"image must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n if (entry.cta?.url && !isSafeUrl(entry.cta.url)) {\n errors.push({\n path: `[${index}].cta.url`,\n message: \"cta.url must be http, https, or relative\",\n code: \"invalid_value\",\n });\n }\n\n const unsafeMetaPath = findUnsafeMetaPath(entry.meta);\n if (unsafeMetaPath) {\n errors.push({\n path: `[${index}].${unsafeMetaPath}`,\n message: `meta contains unsafe key \"${unsafeMetaPath.split(\".\").pop()}\"`,\n code: \"invalid_value\",\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n","import { validateManifest } from \"./schema\";\nimport type { FeatureEntry, FeatureManifest } from \"./types\";\n\nexport interface ChangedFeature {\n id: string;\n before: FeatureEntry;\n after: FeatureEntry;\n changedFields: string[];\n}\n\nexport interface ManifestDiff {\n added: FeatureEntry[];\n removed: FeatureEntry[];\n changed: ChangedFeature[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction collectChangedFields(\n beforeValue: unknown,\n afterValue: unknown,\n path: string,\n output: string[],\n): void {\n if (beforeValue === afterValue) return;\n\n if (Array.isArray(beforeValue) && Array.isArray(afterValue)) {\n if (beforeValue.length !== afterValue.length) {\n output.push(path);\n return;\n }\n for (let i = 0; i < beforeValue.length; i += 1) {\n collectChangedFields(beforeValue[i], afterValue[i], `${path}[${i}]`, output);\n }\n return;\n }\n\n if (isRecord(beforeValue) && isRecord(afterValue)) {\n const keys = new Set([...Object.keys(beforeValue), ...Object.keys(afterValue)]);\n keys.forEach((key) => {\n const nextPath = path ? `${path}.${key}` : key;\n collectChangedFields(beforeValue[key], afterValue[key], nextPath, output);\n });\n return;\n }\n\n output.push(path);\n}\n\nexport function diffManifest(before: FeatureManifest, after: FeatureManifest): ManifestDiff {\n const beforeById = new Map(before.map((feature) => [feature.id, feature]));\n const afterById = new Map(after.map((feature) => [feature.id, feature]));\n\n const added = after.filter((feature) => !beforeById.has(feature.id));\n const removed = before.filter((feature) => !afterById.has(feature.id));\n\n const changed = after\n .filter((feature) => beforeById.has(feature.id))\n .map((feature) => {\n const previous = beforeById.get(feature.id);\n if (!previous) return null;\n const changedFields: string[] = [];\n collectChangedFields(previous, feature, \"\", changedFields);\n if (changedFields.length === 0) return null;\n return {\n id: feature.id,\n before: previous,\n after: feature,\n changedFields,\n } satisfies ChangedFeature;\n })\n .filter((item): item is ChangedFeature => item !== null);\n\n return { added, removed, changed };\n}\n\nexport interface ChangelogDiffOptions {\n includeFieldChanges?: boolean;\n}\n\nexport function generateChangelogDiff(\n diff: ManifestDiff,\n options: ChangelogDiffOptions = {},\n): string {\n const parts: string[] = [];\n\n if (diff.added.length > 0) {\n parts.push(`Added: ${diff.added.map((feature) => feature.label).join(\", \")}`);\n }\n\n if (diff.changed.length > 0) {\n const changedText = diff.changed.map((item) => {\n if (!options.includeFieldChanges) return item.after.label;\n return `${item.after.label} [${item.changedFields.join(\", \")}]`;\n });\n parts.push(`Changed: ${changedText.join(\", \")}`);\n }\n\n if (diff.removed.length > 0) {\n parts.push(`Removed: ${diff.removed.map((feature) => feature.label).join(\", \")}`);\n }\n\n return parts.length > 0 ? parts.join(\". \") : \"No manifest changes.\";\n}\n\nexport interface ChangelogMarkdownOptions extends ChangelogDiffOptions {\n maxItemsPerSection?: number;\n}\n\nfunction renderMarkdownSection(\n title: string,\n items: string[],\n maxItemsPerSection: number,\n): string[] {\n if (items.length === 0) return [`### ${title} (0)`, \"- None\"];\n\n const visible = items.slice(0, maxItemsPerSection);\n const hiddenCount = items.length - visible.length;\n\n const lines = [`### ${title} (${items.length})`, ...visible.map((item) => `- ${item}`)];\n if (hiddenCount > 0) {\n lines.push(`- ...and ${hiddenCount} more`);\n }\n return lines;\n}\n\nexport function generateChangelogDiffMarkdown(\n diff: ManifestDiff,\n options: ChangelogMarkdownOptions = {},\n): string {\n if (diff.added.length === 0 && diff.changed.length === 0 && diff.removed.length === 0) {\n return \"No manifest changes.\";\n }\n\n const maxItemsPerSection = Math.max(1, options.maxItemsPerSection ?? 20);\n const addedItems = diff.added.map((feature) => `**${feature.label}** (\\`${feature.id}\\`)`);\n const changedItems = diff.changed.map((item) => {\n if (!options.includeFieldChanges) {\n return `**${item.after.label}** (\\`${item.id}\\`)`;\n }\n const fields = item.changedFields.join(\", \");\n return `**${item.after.label}** (\\`${item.id}\\`) — ${fields}`;\n });\n const removedItems = diff.removed.map((feature) => `**${feature.label}** (\\`${feature.id}\\`)`);\n\n const sections = [\n ...renderMarkdownSection(\"Added\", addedItems, maxItemsPerSection),\n \"\",\n ...renderMarkdownSection(\"Changed\", changedItems, maxItemsPerSection),\n \"\",\n ...renderMarkdownSection(\"Removed\", removedItems, maxItemsPerSection),\n ];\n\n return sections.join(\"\\n\");\n}\n\nexport function validateManifestForCI(manifest: FeatureManifest) {\n return validateManifest(manifest);\n}\n"]}