blume 1.7.2 → 2.0.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.
- package/AGENTS.md +19 -0
- package/CHANGELOG.md +227 -0
- package/README.md +34 -21
- package/dist/cli/chunk-11j0384y.js +148 -0
- package/dist/cli/chunk-11j0384y.js.map +10 -0
- package/dist/cli/{chunk-xhtpx3ff.js → chunk-1w8dp3qb.js} +17 -16
- package/dist/cli/{chunk-xhtpx3ff.js.map → chunk-1w8dp3qb.js.map} +3 -3
- package/dist/cli/chunk-2q1dwty4.js +75 -0
- package/dist/cli/chunk-2q1dwty4.js.map +11 -0
- package/dist/cli/chunk-41za066z.js +122 -0
- package/dist/cli/chunk-41za066z.js.map +11 -0
- package/dist/cli/chunk-5a2z0198.js +133 -0
- package/dist/cli/chunk-5a2z0198.js.map +10 -0
- package/dist/cli/{chunk-9he6crym.js → chunk-6k8vp3ta.js} +25 -13
- package/dist/cli/{chunk-9he6crym.js.map → chunk-6k8vp3ta.js.map} +4 -4
- package/dist/cli/{chunk-mt76t7dj.js → chunk-79njf86q.js} +133 -54
- package/dist/cli/chunk-79njf86q.js.map +11 -0
- package/dist/cli/{chunk-3w7b2vcx.js → chunk-7ez8ny0t.js} +2 -2
- package/dist/cli/{chunk-688e0dde.js → chunk-88cpgt6h.js} +1 -1
- package/dist/cli/chunk-a9kptbw5.js +361 -0
- package/dist/cli/chunk-a9kptbw5.js.map +14 -0
- package/dist/cli/chunk-abh8yjkn.js +31 -0
- package/dist/cli/chunk-abh8yjkn.js.map +10 -0
- package/dist/cli/chunk-b5aj94ah.js +91 -0
- package/dist/cli/chunk-b5aj94ah.js.map +10 -0
- package/dist/cli/{chunk-hs3gbh8p.js → chunk-bctazmbk.js} +9 -5
- package/dist/cli/chunk-bctazmbk.js.map +10 -0
- package/dist/cli/chunk-beat36xx.js +279 -0
- package/dist/cli/chunk-beat36xx.js.map +10 -0
- package/dist/cli/chunk-bnbmcwfb.js +145 -0
- package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
- package/dist/cli/{chunk-9bkjd11x.js → chunk-bw22s759.js} +15 -5
- package/dist/cli/{chunk-9bkjd11x.js.map → chunk-bw22s759.js.map} +4 -4
- package/dist/cli/chunk-by2290sx.js +39 -0
- package/dist/cli/chunk-by2290sx.js.map +10 -0
- package/dist/cli/chunk-d1tadaw7.js +79 -0
- package/dist/cli/chunk-d1tadaw7.js.map +10 -0
- package/dist/cli/{chunk-t3tj0dgr.js → chunk-d80hr03s.js} +24 -19
- package/dist/cli/chunk-d80hr03s.js.map +15 -0
- package/dist/cli/chunk-ernrthtr.js +97 -0
- package/dist/cli/chunk-ernrthtr.js.map +10 -0
- package/dist/cli/chunk-f2972sbt.js +374 -0
- package/dist/cli/chunk-f2972sbt.js.map +10 -0
- package/dist/cli/{chunk-exeeb35e.js → chunk-f7t03s3g.js} +2 -2
- package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
- package/dist/cli/chunk-fa25z98p.js.map +11 -0
- package/dist/cli/{chunk-12dxjqk7.js → chunk-fh5hj5jt.js} +44 -21
- package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
- package/dist/cli/{chunk-8cd8tj54.js → chunk-j8mw0za6.js} +86 -57
- package/dist/cli/chunk-j8mw0za6.js.map +35 -0
- package/dist/cli/chunk-jts8mvcz.js +106 -0
- package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
- package/dist/cli/{chunk-ejjx8znq.js → chunk-mnqj32sj.js} +505 -536
- package/dist/cli/chunk-mnqj32sj.js.map +12 -0
- package/dist/cli/{chunk-196vjxp9.js → chunk-mwt1k8n7.js} +100 -372
- package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
- package/dist/cli/chunk-nk3ts2xk.js +51 -0
- package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
- package/dist/cli/{chunk-n9sra6sy.js → chunk-pat2zzwc.js} +10 -14
- package/dist/cli/{chunk-n9sra6sy.js.map → chunk-pat2zzwc.js.map} +2 -2
- package/dist/cli/chunk-pnnvybbk.js +176 -0
- package/dist/cli/chunk-pnnvybbk.js.map +11 -0
- package/dist/cli/{chunk-cvky9gb2.js → chunk-sqn5t4q0.js} +81 -87
- package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
- package/dist/cli/{chunk-eevwt1sc.js → chunk-tzne8qfq.js} +15 -15
- package/dist/cli/{chunk-eevwt1sc.js.map → chunk-tzne8qfq.js.map} +1 -1
- package/dist/cli/chunk-xaz13gwg.js +12449 -0
- package/dist/cli/chunk-xaz13gwg.js.map +182 -0
- package/dist/cli/chunk-y3e45rc8.js +102 -0
- package/dist/cli/chunk-y3e45rc8.js.map +10 -0
- package/dist/cli/chunk-z01ze5c1.js +261 -0
- package/dist/cli/chunk-z01ze5c1.js.map +10 -0
- package/dist/cli/{chunk-5n7t497w.js → chunk-z1f5arsg.js} +247 -755
- package/dist/cli/chunk-z1f5arsg.js.map +36 -0
- package/dist/cli/{chunk-hdm2dkd2.js → chunk-zg2gtj10.js} +1086 -2596
- package/dist/cli/chunk-zg2gtj10.js.map +35 -0
- package/dist/cli/{chunk-ppfvdcd4.js → chunk-zxccj738.js} +1 -1
- package/dist/cli/index.js +214 -57
- package/dist/cli/index.js.map +8 -7
- package/dist/types/ai/agent-readability.d.ts +52 -0
- package/dist/types/ai/ai-catalog.d.ts +42 -0
- package/dist/types/ai/api/paths.d.ts +17 -0
- package/dist/types/ai/api-catalog.d.ts +18 -0
- package/dist/types/ai/ask.d.ts +368 -0
- package/dist/types/ai/changelog-markdown.d.ts +2 -0
- package/dist/types/ai/component-markdown.d.ts +2 -2
- package/dist/types/ai/index.d.ts +24 -0
- package/dist/types/ai/link-headers.d.ts +24 -0
- package/dist/types/ai/llms.d.ts +25 -0
- package/dist/types/ai/markdown.d.ts +45 -0
- package/dist/types/ai/mcp/discovery.d.ts +68 -0
- package/dist/types/ai/mcp/tools.d.ts +16 -0
- package/dist/types/ai/openapi-components.d.ts +43 -0
- package/dist/types/ai/relative-links.d.ts +26 -0
- package/dist/types/ai/serializers.d.ts +15 -0
- package/dist/types/ai/skills.d.ts +42 -0
- package/dist/types/ai/tar.d.ts +25 -0
- package/dist/types/ai/visibility.d.ts +17 -0
- package/dist/types/ai/web-bot-auth.d.ts +16 -0
- package/dist/types/analytics/adobe.d.ts +35 -0
- package/dist/types/analytics/amplitude.d.ts +50 -0
- package/dist/types/analytics/clarity.d.ts +31 -0
- package/dist/types/analytics/clearbit.d.ts +29 -0
- package/dist/types/analytics/cloudflare.d.ts +41 -0
- package/dist/types/analytics/fathom.d.ts +41 -0
- package/dist/types/analytics/google-analytics.d.ts +44 -0
- package/dist/types/analytics/google-tag-manager.d.ts +40 -0
- package/dist/types/analytics/head.d.ts +30 -0
- package/dist/types/analytics/heap.d.ts +40 -0
- package/dist/types/analytics/hightouch.d.ts +44 -0
- package/dist/types/analytics/hotjar.d.ts +33 -0
- package/dist/types/analytics/index.d.ts +61 -0
- package/dist/types/analytics/inline.d.ts +17 -0
- package/dist/types/analytics/logrocket.d.ts +44 -0
- package/dist/types/analytics/mixpanel.d.ts +67 -0
- package/dist/types/analytics/pirsch.d.ts +42 -0
- package/dist/types/analytics/plausible.d.ts +56 -0
- package/dist/types/analytics/posthog.d.ts +45 -0
- package/dist/types/analytics/schema.d.ts +320 -0
- package/dist/types/analytics/script.d.ts +46 -0
- package/dist/types/analytics/segment.d.ts +50 -0
- package/dist/types/analytics/vercel.d.ts +48 -0
- package/dist/types/astro/integration.d.ts +76 -0
- package/dist/types/astro/markdown-negotiation.d.ts +23 -0
- package/dist/types/astro/module-types.d.ts +14 -0
- package/dist/types/astro/pages.d.ts +44 -0
- package/dist/types/cli/env.d.ts +12 -0
- package/dist/types/cli/init/scaffold.d.ts +154 -0
- package/dist/types/components/layout/nav-utils.d.ts +11 -0
- package/dist/types/core/adapter.d.ts +47 -0
- package/dist/types/core/api-name.d.ts +7 -0
- package/dist/types/core/changelog-index.d.ts +13 -0
- package/dist/types/core/config-input.d.ts +209 -505
- package/dist/types/core/config.d.ts +60 -34
- package/dist/types/core/content-assets.d.ts +76 -0
- package/dist/types/core/custom-pages.d.ts +33 -0
- package/dist/types/core/data.d.ts +28 -11
- package/dist/types/core/define-components.d.ts +12 -9
- package/dist/types/core/deployment-env.d.ts +6 -11
- package/dist/types/core/frontmatter.d.ts +10 -0
- package/dist/types/core/graph.d.ts +18 -0
- package/dist/types/core/heading-markers.d.ts +54 -0
- package/dist/types/core/i18n-ui.d.ts +6 -2
- package/dist/types/core/i18n.d.ts +87 -0
- package/dist/types/core/includes.d.ts +138 -0
- package/dist/types/core/last-modified.d.ts +47 -0
- package/dist/types/core/links.d.ts +95 -0
- package/dist/types/core/locale-links.d.ts +60 -0
- package/dist/types/core/manifest.d.ts +17 -0
- package/dist/types/core/meta.d.ts +38 -0
- package/dist/types/core/nav-diagnostics.d.ts +26 -0
- package/dist/types/core/navigation.d.ts +6 -0
- package/dist/types/core/node-require.d.ts +19 -0
- package/dist/types/core/package-json.d.ts +13 -0
- package/dist/types/core/probe.d.ts +42 -0
- package/dist/types/core/project-graph.d.ts +51 -0
- package/dist/types/core/project.d.ts +2 -0
- package/dist/types/core/safe-href.d.ts +2 -0
- package/dist/types/core/safe-links.d.ts +26 -0
- package/dist/types/core/schema.d.ts +2291 -441
- package/dist/types/core/site-url.d.ts +16 -0
- package/dist/types/core/sources/assets.d.ts +36 -0
- package/dist/types/core/sources/cache.d.ts +37 -0
- package/dist/types/core/sources/collection.d.ts +28 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
- package/dist/types/core/sources/contentful.d.ts +40 -0
- package/dist/types/core/sources/filesystem.d.ts +24 -0
- package/dist/types/core/sources/github-releases.d.ts +31 -0
- package/dist/types/core/sources/json.d.ts +30 -0
- package/dist/types/core/sources/lexical.d.ts +19 -0
- package/dist/types/core/sources/lower.d.ts +75 -0
- package/dist/types/core/sources/mdx-remote.d.ts +28 -0
- package/dist/types/core/sources/normalize.d.ts +147 -0
- package/dist/types/core/sources/notion.d.ts +131 -0
- package/dist/types/core/sources/obsidian.d.ts +46 -0
- package/dist/types/core/sources/payload.d.ts +39 -0
- package/dist/types/core/sources/portable-text.d.ts +42 -0
- package/dist/types/core/sources/read.d.ts +23 -0
- package/dist/types/core/sources/remote.d.ts +74 -0
- package/dist/types/core/sources/resolve.d.ts +19 -0
- package/dist/types/core/sources/sanity.d.ts +43 -0
- package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
- package/dist/types/core/sources/strapi.d.ts +33 -0
- package/dist/types/core/sources/types.d.ts +7 -0
- package/dist/types/core/sources/watch.d.ts +45 -0
- package/dist/types/core/text-width.d.ts +11 -0
- package/dist/types/core/types.d.ts +20 -1
- package/dist/types/core/unrecognized-keys.d.ts +7 -0
- package/dist/types/core/versions.d.ts +72 -0
- package/dist/types/core/yaml.d.ts +9 -0
- package/dist/types/deploy/adapter-output.d.ts +45 -0
- package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
- package/dist/types/deploy/adapters/index.d.ts +29 -0
- package/dist/types/deploy/adapters/netlify.d.ts +37 -0
- package/dist/types/deploy/adapters/node.d.ts +37 -0
- package/dist/types/deploy/adapters/registry.d.ts +133 -0
- package/dist/types/deploy/adapters/types.d.ts +71 -0
- package/dist/types/deploy/adapters/vercel.d.ts +38 -0
- package/dist/types/deploy/artifacts.d.ts +65 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
- package/dist/types/deploy/function-bundle.d.ts +80 -0
- package/dist/types/deploy/headers.d.ts +50 -0
- package/dist/types/deploy/node-headers.d.ts +42 -0
- package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
- package/dist/types/deploy/platforms/index.d.ts +18 -0
- package/dist/types/deploy/platforms/netlify.d.ts +13 -0
- package/dist/types/deploy/platforms/node.d.ts +11 -0
- package/dist/types/deploy/platforms/paths.d.ts +27 -0
- package/dist/types/deploy/platforms/static.d.ts +10 -0
- package/dist/types/deploy/platforms/types.d.ts +104 -0
- package/dist/types/deploy/platforms/vercel.d.ts +32 -0
- package/dist/types/deploy/redirects.d.ts +53 -0
- package/dist/types/deploy/robots.d.ts +8 -0
- package/dist/types/deploy/rss.d.ts +31 -0
- package/dist/types/deploy/sitemap.d.ts +21 -0
- package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
- package/dist/types/markdown/code-title.d.ts +32 -0
- package/dist/types/markdown/fence-meta.d.ts +23 -0
- package/dist/types/markdown/themes.d.ts +3 -3
- package/dist/types/openapi/asyncapi.d.ts +129 -0
- package/dist/types/openapi/graphql-build.d.ts +8 -0
- package/dist/types/openapi/graphql.d.ts +122 -0
- package/dist/types/openapi/model.d.ts +158 -0
- package/dist/types/openapi/parse.d.ts +57 -0
- package/dist/types/openapi/references.d.ts +37 -25
- package/dist/types/openapi/render-mdx.d.ts +33 -0
- package/dist/types/openapi/sentence.d.ts +7 -0
- package/dist/types/openapi/signature.d.ts +10 -0
- package/dist/types/openapi/source.d.ts +22 -0
- package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
- package/dist/types/reference/asyncapi.d.ts +166 -0
- package/dist/types/reference/graphql.d.ts +181 -0
- package/dist/types/reference/index.d.ts +32 -0
- package/dist/types/reference/openapi.d.ts +165 -0
- package/dist/types/reference/options.d.ts +157 -0
- package/dist/types/reference/scalar.d.ts +136 -0
- package/dist/types/reference/schema.d.ts +630 -0
- package/dist/types/search/adapters/algolia.d.ts +32 -0
- package/dist/types/search/adapters/flexsearch.d.ts +12 -0
- package/dist/types/search/adapters/index.d.ts +31 -0
- package/dist/types/search/adapters/mixedbread.d.ts +22 -0
- package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
- package/dist/types/search/adapters/orama.d.ts +13 -0
- package/dist/types/search/adapters/pagefind.d.ts +12 -0
- package/dist/types/search/adapters/registry.d.ts +228 -0
- package/dist/types/search/adapters/types.d.ts +34 -0
- package/dist/types/search/adapters/typesense.d.ts +42 -0
- package/dist/types/search/build.d.ts +23 -0
- package/dist/types/search/documents.d.ts +90 -0
- package/dist/types/search/facets.d.ts +3 -0
- package/dist/types/search/sync/algolia.d.ts +14 -0
- package/dist/types/search/sync/index.d.ts +14 -0
- package/dist/types/search/sync/orama-cloud.d.ts +10 -0
- package/dist/types/search/sync/typesense.d.ts +14 -0
- package/dist/types/sources/contentful.d.ts +68 -0
- package/dist/types/sources/custom.d.ts +20 -0
- package/dist/types/sources/filesystem.d.ts +42 -0
- package/dist/types/sources/github-releases.d.ts +46 -0
- package/dist/types/sources/index.d.ts +48 -0
- package/dist/types/sources/mdx-remote.d.ts +63 -0
- package/dist/types/sources/notion.d.ts +65 -0
- package/dist/types/sources/obsidian.d.ts +34 -0
- package/dist/types/sources/payload.d.ts +68 -0
- package/dist/types/sources/registry.d.ts +1414 -0
- package/dist/types/sources/sanity.d.ts +69 -0
- package/dist/types/sources/shared.d.ts +46 -0
- package/dist/types/sources/strapi.d.ts +66 -0
- package/dist/types/theme/icon-kind.d.ts +11 -0
- package/dist/types/theme/icons.d.ts +20 -0
- package/docs/01-quickstart.mdx +18 -18
- package/docs/02-deployment.mdx +50 -26
- package/docs/03-upgrading.mdx +351 -0
- package/docs/04-migrating.mdx +58 -0
- package/docs/08-faq.mdx +3 -3
- package/docs/advanced/blog.mdx +13 -6
- package/docs/advanced/changelog.mdx +23 -35
- package/docs/advanced/custom-pages.mdx +20 -8
- package/docs/advanced/meta.ts +1 -8
- package/docs/advanced/skills.mdx +8 -0
- package/docs/cli/audit.mdx +646 -0
- package/docs/cli/doctor.mdx +29 -0
- package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
- package/docs/cli/index.mdx +105 -0
- package/docs/cli/meta.ts +7 -0
- package/docs/{reference → cli}/translate.mdx +1 -1
- package/docs/cli/validate.mdx +41 -0
- package/docs/cli/version.mdx +40 -0
- package/docs/configuration/analytics.mdx +350 -59
- package/docs/configuration/ask-ai.mdx +176 -61
- package/docs/configuration/customization.mdx +15 -9
- package/docs/configuration/index.mdx +52 -31
- package/docs/configuration/search.mdx +75 -54
- package/docs/configuration/theming.mdx +24 -15
- package/docs/content/components.mdx +21 -5
- package/docs/{reference → content}/frontmatter.mdx +37 -1
- package/docs/content/i18n.mdx +8 -6
- package/docs/content/includes.mdx +2 -4
- package/docs/content/index.mdx +1 -1
- package/docs/content/islands.mdx +10 -5
- package/docs/content/meta.mdx +1 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +12 -7
- package/docs/content/sources.mdx +145 -50
- package/docs/content/syntax.mdx +26 -12
- package/docs/content/versioning.mdx +3 -3
- package/docs/discoverability/agent-discovery.mdx +91 -10
- package/docs/discoverability/index.mdx +5 -5
- package/docs/discoverability/json-api.mdx +4 -4
- package/docs/discoverability/llms-txt.mdx +6 -6
- package/docs/discoverability/markdown.mdx +4 -4
- package/docs/discoverability/mcp.mdx +11 -11
- package/docs/discoverability/sitemap-and-robots.mdx +3 -3
- package/docs/index.mdx +2 -2
- package/docs/references/asyncapi.mdx +59 -0
- package/docs/{advanced → references}/graphql.mdx +45 -32
- package/docs/{reference → references}/meta.ts +2 -2
- package/docs/references/openapi.mdx +171 -0
- package/docs/references/scalar.mdx +64 -0
- package/package.json +42 -8
- package/skills/blume/SKILL.md +21 -8
- package/skills/blume-migrate/SKILL.md +22 -21
- package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
- package/skills/blume-migrate/references/docusaurus.md +5 -4
- package/skills/blume-migrate/references/fumadocs.md +4 -4
- package/skills/blume-migrate/references/mintlify.md +23 -8
- package/skills/blume-migrate/references/monorepo.md +6 -6
- package/skills/blume-migrate/references/starlight.md +4 -4
- package/src/ai/agent-readability.ts +26 -22
- package/src/ai/ai-catalog.ts +259 -0
- package/src/ai/api/handlers.ts +46 -11
- package/src/ai/api-catalog.ts +8 -8
- package/src/ai/ask-data.ts +1 -1
- package/src/ai/ask.ts +624 -100
- package/src/ai/changelog-markdown.ts +91 -0
- package/src/ai/component-markdown.ts +328 -12
- package/src/ai/index.ts +45 -0
- package/src/ai/link-headers.ts +19 -6
- package/src/ai/llms.ts +26 -15
- package/src/ai/markdown.ts +35 -5
- package/src/ai/mcp/data.ts +9 -5
- package/src/ai/mcp/discovery.ts +1 -1
- package/src/ai/openapi-components.ts +4 -1
- package/src/ai/relative-links.ts +170 -0
- package/src/ai/serializers.ts +2 -2
- package/src/ai/skills.ts +1 -1
- package/src/ai/web-bot-auth.ts +2 -2
- package/src/analytics/adobe.ts +46 -0
- package/src/analytics/amplitude.ts +79 -0
- package/src/analytics/clarity.ts +46 -0
- package/src/analytics/clearbit.ts +47 -0
- package/src/analytics/cloudflare.ts +67 -0
- package/src/analytics/fathom.ts +64 -0
- package/src/analytics/google-analytics.ts +84 -0
- package/src/analytics/google-tag-manager.ts +61 -0
- package/src/analytics/head.ts +130 -0
- package/src/analytics/heap.ts +65 -0
- package/src/analytics/hightouch.ts +77 -0
- package/src/analytics/hotjar.ts +47 -0
- package/src/analytics/index.ts +71 -0
- package/src/analytics/inline.ts +21 -0
- package/src/analytics/logrocket.ts +71 -0
- package/src/analytics/mixpanel.ts +92 -0
- package/src/analytics/pirsch.ts +66 -0
- package/src/analytics/plausible.ts +83 -0
- package/src/analytics/posthog.ts +78 -0
- package/src/analytics/schema.ts +60 -0
- package/src/analytics/script.ts +60 -0
- package/src/analytics/segment.ts +85 -0
- package/src/analytics/vercel.ts +50 -0
- package/src/astro/adapter-root.ts +7 -9
- package/src/astro/component-slots.ts +131 -91
- package/src/astro/generate.ts +114 -345
- package/src/astro/integration.ts +2 -6
- package/src/astro/pages.ts +13 -101
- package/src/astro/render-deps.ts +379 -0
- package/src/astro/runtime-deps.ts +201 -0
- package/src/astro/templates.ts +554 -541
- package/src/audit/agent.ts +24 -0
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +2 -2
- package/src/audit/checks/dns-aid.ts +1 -1
- package/src/audit/checks/duplicates.ts +3 -1
- package/src/audit/checks/i18n.ts +1 -1
- package/src/audit/checks/indexability.ts +7 -7
- package/src/audit/checks/links.ts +2 -2
- package/src/audit/checks/llms.ts +6 -6
- package/src/audit/checks/network.ts +3 -3
- package/src/audit/checks/og-image.ts +2 -2
- package/src/audit/checks/robots.ts +1 -1
- package/src/audit/checks/sitemap.ts +2 -2
- package/src/audit/checks/social.ts +1 -1
- package/src/audit/run.ts +4 -3
- package/src/audit/terms.ts +31 -0
- package/src/audit/url.ts +13 -13
- package/src/cli/command-meta.ts +10 -0
- package/src/cli/commands/audit.ts +39 -20
- package/src/cli/commands/build.ts +71 -314
- package/src/cli/commands/check.ts +1 -0
- package/src/cli/commands/dev.ts +40 -1
- package/src/cli/commands/doctor.ts +90 -14
- package/src/cli/commands/eject.ts +44 -7
- package/src/cli/commands/eval.ts +2 -2
- package/src/cli/commands/init.ts +161 -41
- package/src/cli/commands/migrate.ts +121 -0
- package/src/cli/commands/preview.ts +7 -1
- package/src/cli/commands/translate.ts +2 -2
- package/src/cli/commands/upgrade.ts +141 -0
- package/src/cli/commands/version.ts +57 -44
- package/src/cli/eject-scripts.ts +121 -6
- package/src/cli/index.ts +11 -1
- package/src/cli/init/install.ts +70 -0
- package/src/cli/init/questions.ts +7 -0
- package/src/cli/init/scaffold.ts +459 -75
- package/src/cli/lazy-command.ts +37 -1
- package/src/cli/prepare.ts +40 -6
- package/src/cli/required-secrets.ts +38 -11
- package/src/cli/unknown-flags.ts +266 -0
- package/src/cli/yarn-pnp.ts +52 -0
- package/src/components/content/AccordionItem.astro +7 -1
- package/src/components/content/Card.astro +4 -3
- package/src/components/content/ColorItem.astro +22 -4
- package/src/components/content/GithubInfo.astro +2 -2
- package/src/components/content/Prompt.astro +25 -25
- package/src/components/content/Tabs.astro +3 -1
- package/src/components/content/Tile.astro +2 -3
- package/src/components/content/Tooltip.astro +57 -9
- package/src/components/content/content-strings.ts +34 -0
- package/src/components/content/diff.ts +1 -1
- package/src/components/content/mermaid-element.ts +13 -2
- package/src/components/content/prompt-markdown.ts +292 -0
- package/src/components/content/tooltip-id.ts +41 -0
- package/src/components/islands/hooks.ts +75 -3
- package/src/components/layout/Analytics.astro +21 -79
- package/src/components/layout/Banner.astro +3 -1
- package/src/components/layout/DiscoveryLinks.astro +69 -0
- package/src/components/layout/Header.astro +83 -20
- package/src/components/layout/LanguageSwitcher.astro +4 -1
- package/src/components/layout/Logo.astro +23 -2
- package/src/components/layout/NavSelector.astro +13 -2
- package/src/components/layout/NavTree.astro +12 -3
- package/src/components/layout/NavTreeScript.astro +17 -3
- package/src/components/layout/PageActions.astro +3 -3
- package/src/components/layout/PageFeedback.astro +11 -1
- package/src/components/layout/PageLayout.astro +52 -5
- package/src/components/layout/ReferenceLayout.astro +21 -12
- package/src/components/layout/RootLayout.astro +69 -43
- package/src/components/layout/Search.astro +30 -6
- package/src/components/layout/WebMcp.astro +1 -1
- package/src/components/layout/analytics-client.ts +101 -15
- package/src/components/layout/drawer-inert.ts +113 -15
- package/src/components/layout/dropdown-clamp.ts +105 -0
- package/src/components/layout/head-scripts.ts +15 -6
- package/src/components/layout/nav-utils.ts +17 -0
- package/src/components/layout/search/algolia.ts +8 -8
- package/src/components/layout/search/orama-cloud.ts +9 -7
- package/src/components/layout/search/typesense.ts +11 -17
- package/src/components/openapi/MessageComposer.astro +2 -2
- package/src/components/openapi/Playground.astro +2 -2
- package/src/components/openapi/playground-client.ts +79 -10
- package/src/core/changelog-index.ts +24 -0
- package/src/core/component-overrides.ts +399 -154
- package/src/core/config-input.ts +212 -543
- package/src/core/config.ts +130 -41
- package/src/core/custom-pages.ts +105 -0
- package/src/core/data.ts +32 -11
- package/src/core/define-components.ts +12 -9
- package/src/core/deployment-env.ts +18 -74
- package/src/core/diagnostics.ts +14 -7
- package/src/core/graph.ts +69 -25
- package/src/core/i18n-ui.ts +6 -2
- package/src/core/i18n.ts +17 -0
- package/src/core/includes.ts +156 -38
- package/src/core/last-modified.ts +6 -11
- package/src/core/links.ts +166 -2
- package/src/core/manifest.ts +10 -3
- package/src/core/navigation.ts +137 -19
- package/src/core/new-tab.ts +35 -0
- package/src/core/node-require.ts +21 -0
- package/src/core/project-graph.ts +42 -26
- package/src/core/project.ts +9 -4
- package/src/core/request-body.ts +61 -0
- package/src/core/safe-href.ts +28 -0
- package/src/core/safe-links.ts +68 -0
- package/src/core/schema.ts +531 -721
- package/src/core/server-features.ts +8 -9
- package/src/core/sources/assets.ts +47 -11
- package/src/core/sources/collection.ts +67 -0
- package/src/core/sources/contentful-rich-text.ts +285 -0
- package/src/core/sources/contentful.ts +173 -0
- package/src/core/sources/github-releases.ts +51 -1
- package/src/core/sources/json.ts +71 -0
- package/src/core/sources/lexical.ts +195 -0
- package/src/core/sources/lower.ts +226 -0
- package/src/core/sources/normalize.ts +52 -2
- package/src/core/sources/notion.ts +39 -28
- package/src/core/sources/payload.ts +135 -0
- package/src/core/sources/portable-text.ts +11 -16
- package/src/core/sources/remote.ts +226 -0
- package/src/core/sources/resolve.ts +104 -166
- package/src/core/sources/sanity.ts +16 -49
- package/src/core/sources/strapi-blocks.ts +124 -0
- package/src/core/sources/strapi.ts +191 -0
- package/src/core/sources/types.ts +12 -1
- package/src/core/types.ts +20 -1
- package/src/core/ui-packs/ar.ts +6 -2
- package/src/core/ui-packs/bg.ts +6 -2
- package/src/core/ui-packs/bn.ts +6 -2
- package/src/core/ui-packs/ca.ts +3 -1
- package/src/core/ui-packs/cs.ts +6 -2
- package/src/core/ui-packs/da.ts +6 -2
- package/src/core/ui-packs/de.ts +6 -2
- package/src/core/ui-packs/el.ts +3 -1
- package/src/core/ui-packs/es.ts +3 -1
- package/src/core/ui-packs/fa.ts +6 -2
- package/src/core/ui-packs/fi.ts +6 -2
- package/src/core/ui-packs/fr.ts +3 -1
- package/src/core/ui-packs/he.ts +6 -2
- package/src/core/ui-packs/hi.ts +6 -2
- package/src/core/ui-packs/hr.ts +6 -2
- package/src/core/ui-packs/hu.ts +6 -2
- package/src/core/ui-packs/id.ts +6 -2
- package/src/core/ui-packs/it.ts +3 -1
- package/src/core/ui-packs/ja.ts +3 -1
- package/src/core/ui-packs/ko.ts +3 -1
- package/src/core/ui-packs/nl.ts +6 -2
- package/src/core/ui-packs/no.ts +6 -2
- package/src/core/ui-packs/pl.ts +6 -2
- package/src/core/ui-packs/pt-br.ts +3 -1
- package/src/core/ui-packs/pt.ts +3 -1
- package/src/core/ui-packs/ro.ts +6 -2
- package/src/core/ui-packs/ru.ts +6 -2
- package/src/core/ui-packs/sk.ts +6 -2
- package/src/core/ui-packs/sr.ts +6 -2
- package/src/core/ui-packs/sv.ts +6 -2
- package/src/core/ui-packs/th.ts +3 -1
- package/src/core/ui-packs/tr.ts +6 -2
- package/src/core/ui-packs/uk.ts +6 -2
- package/src/core/ui-packs/vi.ts +3 -1
- package/src/core/ui-packs/zh-tw.ts +3 -1
- package/src/core/ui-packs/zh.ts +3 -1
- package/src/core/unrecognized-keys.ts +10 -0
- package/src/core/version-cut.ts +116 -8
- package/src/deploy/adapter-output.ts +57 -97
- package/src/deploy/adapters/cloudflare.ts +39 -0
- package/src/deploy/adapters/index.ts +41 -0
- package/src/deploy/adapters/netlify.ts +34 -0
- package/src/deploy/adapters/node.ts +34 -0
- package/src/deploy/adapters/registry.ts +127 -0
- package/src/deploy/adapters/types.ts +92 -0
- package/src/deploy/adapters/vercel.ts +35 -0
- package/src/deploy/artifacts.ts +67 -28
- package/src/deploy/cloudflare-negotiation.ts +179 -100
- package/src/deploy/function-bundle.ts +18 -3
- package/src/deploy/headers.ts +129 -22
- package/src/deploy/node-headers.ts +198 -0
- package/src/deploy/platforms/cloudflare.ts +312 -0
- package/src/deploy/platforms/index.ts +67 -0
- package/src/deploy/platforms/netlify.ts +52 -0
- package/src/deploy/platforms/node.ts +40 -0
- package/src/deploy/platforms/paths.ts +42 -0
- package/src/deploy/platforms/static.ts +29 -0
- package/src/deploy/platforms/types.ts +112 -0
- package/src/deploy/platforms/vercel.ts +193 -0
- package/src/deploy/redirects.ts +30 -18
- package/src/deploy/robots.ts +3 -3
- package/src/deploy/rss.ts +2 -2
- package/src/deploy/sitemap.ts +2 -2
- package/src/deploy/vercel-negotiation.ts +27 -4
- package/src/eval/agents.ts +32 -1
- package/src/eval/findings.ts +19 -11
- package/src/eval/report.ts +10 -2
- package/src/markdown/external-links.ts +65 -0
- package/src/markdown/include.ts +45 -27
- package/src/markdown/index.ts +34 -9
- package/src/markdown/inline-code.ts +12 -6
- package/src/markdown/relative-links.ts +324 -0
- package/src/markdown/themes.ts +3 -3
- package/src/migrate/migrate.ts +149 -0
- package/src/openapi/parse.ts +64 -16
- package/src/openapi/proxy.ts +62 -10
- package/src/openapi/references.ts +147 -147
- package/src/openapi/render-mdx.ts +32 -10
- package/src/openapi/scalar.ts +15 -13
- package/src/openapi/sentence.ts +14 -0
- package/src/openapi/source.ts +37 -21
- package/src/openapi/spec-dependency-error.ts +15 -0
- package/src/reference/asyncapi.ts +83 -0
- package/src/reference/graphql.ts +89 -0
- package/src/reference/index.ts +40 -0
- package/src/reference/openapi.ts +83 -0
- package/src/reference/options.ts +201 -0
- package/src/reference/scalar.ts +136 -0
- package/src/reference/schema.ts +88 -0
- package/src/registry/eject.ts +97 -42
- package/src/search/adapters/algolia.ts +46 -0
- package/src/search/adapters/flexsearch.ts +29 -0
- package/src/search/adapters/index.ts +39 -0
- package/src/search/adapters/mixedbread.ts +39 -0
- package/src/search/adapters/orama-cloud.ts +51 -0
- package/src/search/adapters/orama.ts +24 -0
- package/src/search/adapters/pagefind.ts +27 -0
- package/src/search/adapters/registry.ts +131 -0
- package/src/search/adapters/types.ts +46 -0
- package/src/search/adapters/typesense.ts +57 -0
- package/src/search/build.ts +33 -7
- package/src/search/documents.ts +6 -0
- package/src/search/sync/algolia.ts +12 -11
- package/src/search/sync/index.ts +35 -20
- package/src/search/sync/orama-cloud.ts +12 -9
- package/src/search/sync/typesense.ts +15 -13
- package/src/sources/contentful.ts +63 -0
- package/src/sources/custom.ts +38 -0
- package/src/sources/filesystem.ts +51 -0
- package/src/sources/github-releases.ts +52 -0
- package/src/sources/index.ts +60 -0
- package/src/sources/mdx-remote.ts +76 -0
- package/src/sources/notion.ts +63 -0
- package/src/sources/obsidian.ts +38 -0
- package/src/sources/payload.ts +60 -0
- package/src/sources/registry.ts +182 -0
- package/src/sources/sanity.ts +66 -0
- package/src/sources/shared.ts +52 -0
- package/src/sources/strapi.ts +58 -0
- package/src/theme/entry.ts +47 -2
- package/src/translate/report.ts +40 -7
- package/src/upgrade/upgrade.ts +499 -0
- package/dist/cli/chunk-12dxjqk7.js.map +0 -10
- package/dist/cli/chunk-196vjxp9.js.map +0 -13
- package/dist/cli/chunk-2mzebbbz.js +0 -69
- package/dist/cli/chunk-2z47ypj8.js.map +0 -11
- package/dist/cli/chunk-30e87n55.js +0 -108
- package/dist/cli/chunk-30e87n55.js.map +0 -10
- package/dist/cli/chunk-450a7rcr.js +0 -185
- package/dist/cli/chunk-450a7rcr.js.map +0 -11
- package/dist/cli/chunk-5n7t497w.js.map +0 -40
- package/dist/cli/chunk-61j18dwk.js +0 -5342
- package/dist/cli/chunk-61j18dwk.js.map +0 -58
- package/dist/cli/chunk-88by27n5.js +0 -17
- package/dist/cli/chunk-88by27n5.js.map +0 -10
- package/dist/cli/chunk-8cd8tj54.js.map +0 -34
- package/dist/cli/chunk-aztttvb3.js +0 -381
- package/dist/cli/chunk-aztttvb3.js.map +0 -12
- package/dist/cli/chunk-cvky9gb2.js.map +0 -11
- package/dist/cli/chunk-ejjx8znq.js.map +0 -15
- package/dist/cli/chunk-fmceyezb.js +0 -1007
- package/dist/cli/chunk-fmceyezb.js.map +0 -13
- package/dist/cli/chunk-hdm2dkd2.js.map +0 -48
- package/dist/cli/chunk-hs3gbh8p.js.map +0 -10
- package/dist/cli/chunk-jbj4qhfw.js +0 -30
- package/dist/cli/chunk-jbj4qhfw.js.map +0 -10
- package/dist/cli/chunk-mqb2ka8m.js +0 -68
- package/dist/cli/chunk-mqb2ka8m.js.map +0 -10
- package/dist/cli/chunk-mt76t7dj.js.map +0 -11
- package/dist/cli/chunk-q4rae3bg.js +0 -60
- package/dist/cli/chunk-q4rae3bg.js.map +0 -10
- package/dist/cli/chunk-ra1v2nc2.js +0 -35
- package/dist/cli/chunk-ra1v2nc2.js.map +0 -10
- package/dist/cli/chunk-t3tj0dgr.js.map +0 -15
- package/dist/cli/chunk-tqa1s0k8.js +0 -69
- package/dist/cli/chunk-tqa1s0k8.js.map +0 -11
- package/dist/cli/chunk-vh9w1sgp.js +0 -73
- package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
- package/dist/cli/chunk-vkrsvbr5.js +0 -107
- package/dist/cli/chunk-vkrsvbr5.js.map +0 -11
- package/dist/cli/chunk-vrfp10qk.js +0 -81
- package/dist/cli/chunk-vrfp10qk.js.map +0 -10
- package/dist/cli/chunk-wjt80jps.js +0 -1049
- package/dist/cli/chunk-wjt80jps.js.map +0 -24
- package/docs/advanced/api-reference.mdx +0 -240
- package/docs/reference/cli.mdx +0 -197
- package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
- package/src/components/content/changelog-element.ts +0 -69
- package/src/search/providers.ts +0 -91
- /package/dist/cli/{chunk-3w7b2vcx.js.map → chunk-7ez8ny0t.js.map} +0 -0
- /package/dist/cli/{chunk-688e0dde.js.map → chunk-88cpgt6h.js.map} +0 -0
- /package/dist/cli/{chunk-exeeb35e.js.map → chunk-f7t03s3g.js.map} +0 -0
- /package/dist/cli/{chunk-ppfvdcd4.js.map → chunk-zxccj738.js.map} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/custom-pages.ts", "../src/core/sources/collection.ts", "../src/sources/filesystem.ts", "../src/core/adapter.ts", "../src/sources/shared.ts", "../src/core/changelog-index.ts", "../src/astro/pages.ts", "../src/core/ui-packs/ar.ts", "../src/core/ui-packs/bg.ts", "../src/core/ui-packs/bn.ts", "../src/core/ui-packs/ca.ts", "../src/core/ui-packs/cs.ts", "../src/core/ui-packs/da.ts", "../src/core/ui-packs/de.ts", "../src/core/ui-packs/el.ts", "../src/core/ui-packs/es.ts", "../src/core/ui-packs/fa.ts", "../src/core/ui-packs/fi.ts", "../src/core/ui-packs/fr.ts", "../src/core/ui-packs/he.ts", "../src/core/ui-packs/hi.ts", "../src/core/ui-packs/hr.ts", "../src/core/ui-packs/hu.ts", "../src/core/ui-packs/id.ts", "../src/core/ui-packs/it.ts", "../src/core/ui-packs/ja.ts", "../src/core/ui-packs/ko.ts", "../src/core/ui-packs/nl.ts", "../src/core/ui-packs/no.ts", "../src/core/ui-packs/pl.ts", "../src/core/ui-packs/pt-br.ts", "../src/core/ui-packs/pt.ts", "../src/core/ui-packs/ro.ts", "../src/core/ui-packs/ru.ts", "../src/core/ui-packs/sk.ts", "../src/core/ui-packs/sr.ts", "../src/core/ui-packs/sv.ts", "../src/core/ui-packs/th.ts", "../src/core/ui-packs/tr.ts", "../src/core/ui-packs/uk.ts", "../src/core/ui-packs/vi.ts", "../src/core/ui-packs/zh-tw.ts", "../src/core/ui-packs/zh.ts", "../src/core/ui-packs/index.ts", "../src/core/i18n.ts", "../src/core/links.ts", "../src/core/content-assets.ts", "../src/core/code-fences.ts", "../src/core/sources/cache.ts", "../src/core/sources/normalize.ts", "../src/core/heading-markers.ts", "../src/core/schema.ts", "../src/ai/ask.ts", "../src/core/unrecognized-keys.ts", "../src/analytics/schema.ts", "../src/analytics/adobe.ts", "../src/analytics/amplitude.ts", "../src/analytics/inline.ts", "../src/analytics/clarity.ts", "../src/analytics/clearbit.ts", "../src/analytics/cloudflare.ts", "../src/analytics/fathom.ts", "../src/analytics/google-analytics.ts", "../src/analytics/google-tag-manager.ts", "../src/analytics/heap.ts", "../src/analytics/hightouch.ts", "../src/analytics/hotjar.ts", "../src/analytics/logrocket.ts", "../src/analytics/mixpanel.ts", "../src/analytics/pirsch.ts", "../src/analytics/plausible.ts", "../src/analytics/posthog.ts", "../src/analytics/script.ts", "../src/analytics/segment.ts", "../src/analytics/vercel.ts", "../src/deploy/adapters/registry.ts", "../src/deploy/adapters/types.ts", "../src/deploy/adapters/cloudflare.ts", "../src/deploy/adapters/netlify.ts", "../src/deploy/adapters/node.ts", "../src/deploy/adapters/vercel.ts", "../src/openapi/references.ts", "../src/reference/schema.ts", "../src/reference/asyncapi.ts", "../src/reference/options.ts", "../src/reference/graphql.ts", "../src/reference/openapi.ts", "../src/reference/scalar.ts", "../src/search/adapters/orama.ts", "../src/search/adapters/registry.ts", "../src/search/adapters/algolia.ts", "../src/search/adapters/flexsearch.ts", "../src/search/adapters/mixedbread.ts", "../src/search/adapters/orama-cloud.ts", "../src/search/adapters/pagefind.ts", "../src/search/adapters/typesense.ts", "../src/seo/x-handle.ts", "../src/sources/registry.ts", "../src/sources/contentful.ts", "../src/sources/custom.ts", "../src/sources/github-releases.ts", "../src/sources/mdx-remote.ts", "../src/sources/notion.ts", "../src/sources/obsidian.ts", "../src/sources/payload.ts", "../src/sources/sanity.ts", "../src/sources/strapi.ts", "../src/theme/fonts.ts", "../src/core/github.ts", "../src/core/i18n-ui.ts", "../src/core/open-in-chat.ts", "../src/core/standard-schema.ts", "../src/core/versions.ts", "../src/core/sources/read.ts", "../src/core/includes.ts", "../src/core/frontmatter.ts", "../src/core/yaml.ts", "../src/core/locale-links.ts", "../src/core/probe.ts", "../src/cli/init/scaffold.ts", "../src/core/package-json.ts", "../src/deploy/platforms/cloudflare.ts", "../src/ai/api/paths.ts", "../src/core/api-name.ts", "../src/ai/api-catalog.ts", "../src/ai/mcp/discovery.ts", "../src/ai/skills.ts", "../src/ai/tar.ts", "../src/ai/ai-catalog.ts", "../src/ai/link-headers.ts", "../src/ai/markdown.ts", "../src/ai/changelog-markdown.ts", "../src/ai/component-markdown.ts", "../src/components/content/youtube.ts", "../src/markdown/features.ts", "../src/deploy/rss.ts", "../src/ai/relative-links.ts", "../src/openapi/model.ts", "../src/openapi/asyncapi.ts", "../src/openapi/graphql.ts", "../src/openapi/parse.ts", "../src/core/node-require.ts", "../src/openapi/graphql-build.ts", "../src/openapi/spec-dependency-error.ts", "../src/openapi/render-mdx.ts", "../src/core/safe-links.ts", "../src/core/safe-href.ts", "../src/core/sources/lower.ts", "../src/core/text-width.ts", "../src/openapi/sentence.ts", "../src/openapi/signature.ts", "../src/openapi/source.ts", "../src/ai/openapi-components.ts", "../src/ai/serializers.ts", "../src/ai/visibility.ts", "../src/ai/llms.ts", "../src/deploy/cloudflare-negotiation.ts", "../src/deploy/redirects.ts", "../src/deploy/platforms/paths.ts", "../src/deploy/platforms/netlify.ts", "../src/deploy/node-headers.ts", "../src/ai/web-bot-auth.ts", "../src/deploy/headers.ts", "../src/deploy/platforms/node.ts", "../src/deploy/platforms/vercel.ts", "../src/deploy/function-bundle.ts", "../src/deploy/vercel-negotiation.ts", "../src/deploy/platforms/static.ts", "../src/deploy/platforms/index.ts", "../src/core/project.ts", "../src/core/config.ts", "../src/core/deployment-env.ts", "../src/core/load-module.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { extname, relative } from \"pathe\";\nimport { glob, globSync } from \"tinyglobby\";\n\n/**\n * Custom `.astro` pages (the `pages/` folder): discovery and the routes they\n * serve. Lives in core so the content graph can see them too — a header tab or\n * brand link that points at a custom page must know the page exists only at\n * its own path, not under every locale prefix.\n */\n\n/** A user `.astro` page and the route pattern Blume injects it at. */\nexport interface CustomPageRoute {\n /** Route pattern, e.g. `/changelog` or `/examples/[slug]`. */\n pattern: string;\n /** Absolute path to the user's `.astro` page file. */\n entrypoint: string;\n}\n\nconst PAGE_GLOB = [\"**/*.astro\"];\n\n/**\n * Astro's routing convention: a file or folder whose name starts with `_` is a\n * private partial — importable (shared layouts, home-page sections), but never\n * built into a route. Blume injects pages itself, so it must reproduce the same\n * exclusion or every `pages/_home/Hero.astro`-style component ships as an HTML\n * page.\n */\nconst isPrivatePage = (rel: string): boolean =>\n rel.split(\"/\").some((segment) => segment.startsWith(\"_\"));\n\n/** Map discovered page files to routes; shared by the async/sync discoverers. */\nconst toPageRoutes = (\n pagesRoot: string,\n files: string[]\n): CustomPageRoute[] => {\n files.sort();\n const routes: CustomPageRoute[] = [];\n for (const file of files) {\n const rel = relative(pagesRoot, file);\n if (isPrivatePage(rel)) {\n continue;\n }\n const withoutExt = rel.slice(0, rel.length - extname(rel).length);\n const parts = withoutExt.split(\"/\");\n // Only a trailing `index` maps to its parent dir; a folder literally named\n // `index` (e.g. `index/foo.astro`) must keep its segment.\n if (parts.at(-1) === \"index\") {\n parts.pop();\n }\n const pattern = parts.length === 0 ? \"/\" : `/${parts.join(\"/\")}`;\n routes.push({ entrypoint: file, pattern });\n }\n return routes;\n};\n\n/**\n * Discover user `.astro` pages and map them to route patterns. Files keep their\n * original location; only the route pattern is derived (index -> parent,\n * dynamic `[param]` segments preserved).\n */\nexport const discoverPages = async (\n pagesRoot: string\n): Promise<CustomPageRoute[]> =>\n toPageRoutes(\n pagesRoot,\n await glob(PAGE_GLOB, { absolute: true, cwd: pagesRoot, onlyFiles: true })\n );\n\n/** {@link discoverPages} for synchronous callers (e.g. the sitemap builder). */\nexport const discoverPagesSync = (pagesRoot: string): CustomPageRoute[] =>\n toPageRoutes(\n pagesRoot,\n globSync(PAGE_GLOB, { absolute: true, cwd: pagesRoot, onlyFiles: true })\n );\n\n/** Skip private (`_partial`, `.well-known`) and Astro dynamic (`[param]`) parts. */\nconst PRIVATE_SEGMENT = /^[._]/u;\n\n/** Segments of a static, shareable page pattern; null for dynamic/private ones. */\nexport const staticSegments = (pattern: string): string[] | null => {\n const segments = pattern.split(\"/\").filter(Boolean);\n return segments.some(\n (part) => PRIVATE_SEGMENT.test(part) || part.includes(\"[\")\n )\n ? null\n : segments;\n};\n\n/**\n * The static routes served by custom `.astro` pages — the same filtering as\n * the generated OG cards, but yielding the routes themselves. Feeds the route\n * sets that must know every servable page beyond the content graph (the link\n * checker, the sitemap); dynamic (`[param]`) and private segments are skipped\n * because their concrete URLs can't be enumerated statically.\n */\nexport const customStaticRoutes = (pages: { pattern: string }[]): string[] => {\n const routes = new Set<string>();\n for (const { pattern } of pages) {\n const segments = staticSegments(pattern);\n if (segments !== null) {\n routes.add(segments.length === 0 ? \"/\" : `/${segments.join(\"/\")}`);\n }\n }\n return [...routes];\n};\n",
|
|
6
|
+
"import { isAbsolute, join, resolve } from \"pathe\";\n\nimport {\n DEFAULT_CONTENT_EXCLUDE,\n DEFAULT_CONTENT_INCLUDE,\n} from \"../../sources/filesystem.ts\";\nimport type { ContentSourceAdapter } from \"../../sources/registry.ts\";\nimport type { ResolvedConfig } from \"../schema.ts\";\n\n/** Resolve a source `root` against the project root (absolute passes through). */\nexport const resolveSourceRoot = (projectRoot: string, root: string): string =>\n isAbsolute(root) ? root : join(resolve(projectRoot), root);\n\n/** The configured sources of one adapter `kind`, in config order. */\nexport const sourcesOfKind = <Kind extends ContentSourceAdapter[\"kind\"]>(\n config: ResolvedConfig,\n kind: Kind\n): Extract<ContentSourceAdapter, { kind: Kind }>[] =>\n config.content.sources.filter(\n (source): source is Extract<ContentSourceAdapter, { kind: Kind }> =>\n source.kind === kind\n );\n\n/**\n * The generated `docs` glob collection: its base directory and the include /\n * exclude globs applied under it. Astro's glob loader ids each entry by its\n * path relative to `base`, and a filesystem source ids each entry relative to\n * its own root — so the two only agree when the collection is rooted at that\n * source. The collection therefore roots at the first `filesystem()` source\n * (the implicit one, for a zero-config project). Further filesystem sources\n * must share that root and partition it with globs: every filesystem source's\n * `include` feeds the collection, and only a pattern every one of them\n * excludes is excluded, so no source's pages are globbed away. A source\n * rooted elsewhere can't share the base and is caught by the entry-id guard in\n * `scanProject`. With no filesystem source at all the collection globs nothing\n * and its base is the default `docs` directory, which only anchors paths.\n */\nexport interface DocsCollection {\n base: string;\n include: string[];\n exclude: string[];\n}\n\nexport const resolveDocsCollection = (\n config: ResolvedConfig,\n projectRoot: string\n): DocsCollection => {\n const [first, ...rest] = sourcesOfKind(config, \"filesystem\");\n if (!first) {\n return {\n base: resolveSourceRoot(projectRoot, \"docs\"),\n exclude: DEFAULT_CONTENT_EXCLUDE,\n include: DEFAULT_CONTENT_INCLUDE,\n };\n }\n const include = [\n ...new Set([first, ...rest].flatMap((source) => source.options.include)),\n ];\n const exclude = first.options.exclude.filter((pattern) =>\n rest.every((source) => source.options.exclude.includes(pattern))\n );\n return {\n base: resolveSourceRoot(projectRoot, first.options.root),\n exclude,\n include,\n };\n};\n",
|
|
7
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions } from \"./shared.ts\";\nimport { DEFAULT_CONTENT_GLOB, sharedSourceOptionsSchema } from \"./shared.ts\";\n\n/** What `include` defaults to: every Markdown/MDX file under the root. */\nexport const DEFAULT_CONTENT_INCLUDE = [DEFAULT_CONTENT_GLOB];\n/** What `exclude` defaults to: underscore- and dot-prefixed paths. */\nexport const DEFAULT_CONTENT_EXCLUDE = [\"**/_*\", \"**/.*\"];\n\n/** Options for {@link filesystem}. */\nexport interface FilesystemOptions extends SharedSourceOptions {\n /** Glob patterns to ignore. Defaults to `[\"**\\/_*\", \"**\\/.*\"]`. */\n exclude?: string[];\n /** Glob patterns to include. Defaults to `[\"**\\/*.{md,mdx}\"]`. */\n include?: string[];\n /** Directory to read from, relative to the project root. Defaults to `docs`. */\n root?: string;\n}\n\nexport const filesystemOptionsSchema = sharedSourceOptionsSchema.extend({\n exclude: z.array(z.string()).default(DEFAULT_CONTENT_EXCLUDE),\n include: z.array(z.string()).default(DEFAULT_CONTENT_INCLUDE),\n root: z.string().default(\"docs\"),\n});\n\nexport type FilesystemAdapter = AdapterDescriptor<\n \"filesystem\",\n FilesystemOptions\n>;\n\nexport const filesystemAdapterSchema = adapterDescriptorSchema(\n \"filesystem\",\n filesystemOptionsSchema\n);\n\n/**\n * Local Markdown/MDX read from a directory. The zero-config default: with no\n * `content.sources`, the top-level `content.root`/`include`/`exclude` desugar\n * to exactly one of these.\n */\nexport const filesystem = (\n options: FilesystemOptions = {}\n): FilesystemAdapter => ({\n kind: \"filesystem\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
8
|
+
"import { z } from \"zod\";\n\n/**\n * The serializable descriptor an integration factory returns — `posthog({ key })`,\n * `vercel()`, `script({ src })` and their siblings. A descriptor is plain data:\n * the CLI evaluates `blume.config.ts` once, validates what came back, and\n * writes it into the generated project's data snapshot as a JSON literal. That\n * is where the runtime reads it — nothing generated imports the config at\n * request time — so a descriptor can't carry functions, class instances, or\n * anything else JSON drops.\n *\n * Every consumer reads the descriptor instead of switching on a provider name:\n * the head emitter and `blume doctor` branch on `kind`, the generated\n * `.blume/package.json` declares `runtimeDeps`, and the secrets check warns\n * when an entry of `requiredSecrets` is unset.\n *\n * An adapter's verbatim option passthrough is typed as {@link JsonValue} and\n * validated with `z.json()`, so a function, `undefined`, a bigint, or a\n * non-finite number fails config validation with a path instead of vanishing\n * (or throwing) when the snapshot is serialized.\n */\nexport interface AdapterDescriptor<Kind extends string, Options> {\n /** Which integration this is. */\n kind: Kind;\n /** The options the factory was called with, verbatim. */\n options: Options;\n /** Env vars the integration reads at runtime; `blume dev`/`build` warn when one is unset. */\n requiredSecrets: string[];\n /** Extra packages the generated `.blume/package.json` must declare. */\n runtimeDeps: string[];\n}\n\n/**\n * A value JSON can carry unchanged — what an adapter's passthrough options are\n * typed as. Structurally identical to what `z.json()` accepts.\n */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\n/**\n * The schema for one descriptor `kind`, validating its `options` with the\n * adapter's own option schema. Members of a `z.discriminatedUnion(\"kind\", …)`.\n */\nexport const adapterDescriptorSchema = <\n Kind extends string,\n Options extends z.ZodType,\n>(\n kind: Kind,\n options: Options\n) =>\n z.strictObject({\n kind: z.literal(kind),\n options,\n requiredSecrets: z.array(z.string()),\n runtimeDeps: z.array(z.string()),\n });\n",
|
|
9
|
+
"import { z } from \"zod\";\n\n/** The glob every content-reading adapter defaults `include` to. */\nexport const DEFAULT_CONTENT_GLOB = \"**/*.{md,mdx}\";\n\n/**\n * Options every built-in content source shares. They ride on the descriptor\n * beside the adapter's own options, so an adapter declares only what is\n * specific to it.\n */\nexport interface SharedSourceOptions {\n /**\n * Opt-in dev polling interval (seconds) for a remote source; omit to fetch\n * once and freeze for the session. Local sources (`filesystem()`,\n * `obsidian()`) watch the filesystem instead and ignore it.\n */\n pollInterval?: number;\n /** Namespaces the source's routes under `/<prefix>/`. */\n prefix?: string;\n}\n\n/** The schema for {@link SharedSourceOptions}; each adapter extends it. */\nexport const sharedSourceOptionsSchema = z.strictObject({\n pollInterval: z.number().positive().optional(),\n prefix: z.string().optional(),\n});\n\n/** Field paths mapping a CMS document onto Blume meta + body. */\nexport interface SourceFieldMap {\n /** Field holding the renderable body (rich text, or a Markdown string). */\n body?: string;\n /** Field holding the page description. */\n description?: string;\n /** Field holding the last-modified date. */\n lastModified?: string;\n /** Field holding the page slug. */\n slug?: string;\n /** Field holding the page title. */\n title?: string;\n}\n\n/** The schema for {@link SourceFieldMap}. */\nexport const sourceFieldMapSchema = z.strictObject({\n body: z.string().optional(),\n description: z.string().optional(),\n lastModified: z.string().optional(),\n slug: z.string().optional(),\n title: z.string().optional(),\n});\n\n/** Extra query parameters a REST-backed adapter appends to its request. */\nexport const queryParamsSchema = z.record(z.string(), z.string());\n",
|
|
10
|
+
"import type { ResolvedConfig } from \"./schema.ts\";\nimport { sourcesOfKind } from \"./sources/collection.ts\";\nimport type { PageRecord } from \"./types.ts\";\n\n/** Where the changelog timeline index is served. */\nexport const CHANGELOG_INDEX_ROUTE = \"/changelog\";\n\n/**\n * Whether the site serves a changelog index at {@link CHANGELOG_INDEX_ROUTE}:\n * there are visible `type: changelog` entries, or a release-backed source\n * (whose index must resolve even when a fetch fails). Blume generates the\n * timeline there unless a custom or content page already owns the route —\n * either way the route is servable, which is what navigation needs to point a\n * `/changelog` tab at the index rather than its newest entry.\n */\nexport const hasChangelogIndex = (\n pages: Pick<PageRecord, \"contentType\" | \"meta\">[],\n config: ResolvedConfig\n): boolean =>\n pages.some(\n (page) =>\n page.contentType === \"changelog\" &&\n !(page.meta.draft || page.meta.sidebar.hidden)\n ) || sourcesOfKind(config, \"github-releases\").length > 0;\n",
|
|
11
|
+
"import {\n CHANGELOG_INDEX_ROUTE,\n hasChangelogIndex,\n} from \"../core/changelog-index.ts\";\nimport { staticSegments } from \"../core/custom-pages.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport type { BlumePageRoute } from \"./integration.ts\";\n\nexport {\n customStaticRoutes,\n discoverPages,\n discoverPagesSync,\n} from \"../core/custom-pages.ts\";\n\n/**\n * Whether the project already owns `route` — through a custom `.astro` page\n * (injected, so matched on `pattern`) or a content page (matched on `route`).\n * Used to skip a generated default page (e.g. `/404`, `/changelog`) so a\n * user-authored page overrides it without a route collision.\n */\nexport const routeIsTaken = (\n pages: { pattern: string }[],\n contentPages: { route: string }[],\n route: string\n): boolean =>\n pages.some((page) => page.pattern === route) ||\n contentPages.some((page) => page.route === route);\n\n/** A custom-page route that should get a generated OG card. */\nexport interface OgCustomRoute {\n /** `og/<slug>.png` path segment; `index` for the site root. */\n slug: string;\n /** Card headline. */\n title: string;\n}\n\n/**\n * Whether the generated `/changelog` index route exists for this project —\n * `generate.ts` (which writes the page) and the sitemap/link validator all\n * share this check: there are visible `type: changelog` entries — or a\n * release-backed changelog source, whose route must resolve even when a fetch\n * fails — and no user content or custom page already owns `/changelog`.\n */\nexport const hasGeneratedChangelog = (\n project: BlumeProject,\n userPages: { pattern: string }[]\n): boolean =>\n hasChangelogIndex(project.graph.pages, project.config) &&\n !routeIsTaken(userPages, project.graph.pages, CHANGELOG_INDEX_ROUTE);\n\nconst humanizeSegment = (segment: string): string =>\n segment\n .split(/[-_]/u)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n/**\n * Pick the custom-page routes that should get a generated Open Graph card, with\n * the card's slug and text. OG is otherwise content-route only, so a custom page\n * — most importantly the landing `/`, the most-shared URL — would have no card.\n *\n * Dynamic (`[param]`) routes and private segments (`_partials`, `.well-known`)\n * are skipped: they aren't shareable pages. A `titles` entry (`seo.og.titles`,\n * keyed by route) names a card outright — the only way to say \"CLI\" when the\n * segment humanizes to \"Cli\". Otherwise the home is titled with the site title\n * and a deeper page from its last path segment. The card's brand lockup,\n * description, and footer come from the resolved config at render time.\n */\nexport const customOgRoutes = (\n pages: BlumePageRoute[],\n siteTitle: string,\n titles: Record<string, string> = {}\n): OgCustomRoute[] => {\n // Keys normalized to `/`-joined segments so `cli`, `/cli`, and `/cli/` all\n // address the page served at `/cli` (and `/` addresses the home).\n const overrides = new Map(\n Object.entries(titles).map(([route, title]) => [\n `/${route.split(\"/\").filter(Boolean).join(\"/\")}`,\n title,\n ])\n );\n const seen = new Set<string>();\n const routes: OgCustomRoute[] = [];\n // Extracted so the skip paths become early `return`s (one `continue` budget\n // per loop under the lint rule) instead of `continue` statements.\n const collectRoute = (pattern: string): void => {\n const segments = staticSegments(pattern);\n if (segments === null) {\n return;\n }\n const slug = segments.length === 0 ? \"index\" : segments.join(\"/\");\n if (seen.has(slug)) {\n return;\n }\n seen.add(slug);\n const last = segments.at(-1);\n routes.push({\n slug,\n title:\n overrides.get(`/${segments.join(\"/\")}`) ??\n (last ? humanizeSegment(last) : siteTitle),\n });\n };\n for (const { pattern } of pages) {\n collectRoute(pattern);\n }\n return routes;\n};\n",
|
|
12
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Arabic (ar) UI strings. */\nexport const ar: UIStringsOverride = {\n actions: {\n addToCursor: \"إضافة إلى Cursor\",\n addToVscode: \"إضافة إلى VS Code\",\n askAI: \"اسأل الذكاء الاصطناعي عن هذه الصفحة\",\n connectMcp: \"الاتصال بـ MCP\",\n copied: \"تم النسخ!\",\n copyClaudeCode: \"نسخ أمر Claude Code\",\n copyCode: \"نسخ الكود\",\n copyCodex: \"نسخ أمر Codex\",\n copyFailed: \"فشل النسخ\",\n copyMarkdown: \"نسخ بصيغة Markdown\",\n copyServerUrl: \"نسخ عنوان URL للخادم\",\n edit: \"التعديل على GitHub\",\n export: \"تصدير\",\n exportEpub: \"التصدير إلى EPUB\",\n exportPdf: \"التصدير إلى PDF\",\n generating: \"جارٍ الإنشاء…\",\n openIn: \"فتح في {name}\",\n openInChat: \"فتح في المحادثة\",\n openInChatPrompt: \"اقرأ {url} حتى أتمكن من طرح أسئلة حول هذه الصفحة.\",\n scrollToTop: \"العودة إلى الأعلى\",\n },\n ask: {\n ai: \"الذكاء الاصطناعي\",\n clear: \"مسح المحادثة\",\n close: \"إغلاق\",\n copy: \"نسخ المحادثة\",\n empty: \"اطرح سؤالاً حول الوثائق.\",\n error: \"عذراً، حدث خطأ ما.\",\n label: \"اطرح سؤالاً\",\n placeholder: \"اطرح سؤالاً…\",\n send: \"إرسال\",\n tip: \"نصيحة: يمكنك فتح المحادثة وإغلاقها باستخدام\",\n title: \"اسأل الذكاء الاصطناعي\",\n you: \"أنت\",\n },\n banner: { dismiss: \"إغلاق الإعلان\" },\n changelog: {\n description: \"تحديثات المنتج وملاحظات الإصدارات.\",\n title: \"سجل التغييرات\",\n },\n content: {\n copyColor: \"نسخ اللون {name} {value}\",\n copyPrompt: \"نسخ الموجّه\",\n diagramError: \"تعذّر عرض هذا المخطط.\",\n },\n feedback: {\n no: \"لا\",\n question: \"هل كانت هذه الصفحة مفيدة؟\",\n thanks: \"شكراً على ملاحظاتك!\",\n yes: \"نعم\",\n },\n languageSwitcher: { label: \"اللغة\", untranslated: \"غير مترجم\" },\n nav: {\n back: \"رجوع\",\n breadcrumb: \"مسار التنقل\",\n closeNavigation: \"إغلاق التنقل\",\n deprecated: \"مهمل\",\n featured: \"مميز\",\n githubRepository: \"مستودع GitHub\",\n navigation: \"التنقل\",\n opensInNewTab: \"يفتح في علامة تبويب جديدة\",\n primary: \"رئيسي\",\n sections: \"الأقسام\",\n toggleNavigation: \"تبديل التنقل\",\n toggleTheme: \"تبديل سمة الألوان\",\n },\n notFound: {\n description: \"لم نتمكن من العثور على الصفحة التي تبحث عنها.\",\n home: \"العودة إلى الصفحة الرئيسية\",\n title: \"الصفحة غير موجودة\",\n },\n page: {\n lastUpdated: \"آخر تحديث في\",\n next: \"التالي\",\n pagination: \"ترقيم الصفحات\",\n previous: \"السابق\",\n skipToContent: \"الانتقال إلى المحتوى\",\n },\n search: {\n all: \"الكل\",\n allLanguages: \"جميع اللغات\",\n askAi: \"اسأل الذكاء الاصطناعي\",\n askAiHint: \"احصل على إجابة فورية من الذكاء الاصطناعي\",\n button: \"بحث\",\n devOnly: \"البحث متاح في إصدار الإنتاج.\",\n error: \"حدث خطأ ما. يرجى المحاولة مرة أخرى.\",\n label: \"البحث في الوثائق\",\n navigate: \"تنقل\",\n noResults: \"لم يتم العثور على نتائج.\",\n open: \"فتح\",\n placeholder: \"البحث في الوثائق…\",\n popular: \"شائع\",\n preview: \"معاينة\",\n results: \"النتائج\",\n },\n toc: { title: \"في هذه الصفحة\" },\n};\n",
|
|
13
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Bulgarian (bg) UI strings. */\nexport const bg: UIStringsOverride = {\n actions: {\n addToCursor: \"Добави в Cursor\",\n addToVscode: \"Добави във VS Code\",\n askAI: \"Попитай ИИ за тази страница\",\n connectMcp: \"Свържи се с MCP\",\n copied: \"Копирано!\",\n copyClaudeCode: \"Копирай командата на Claude Code\",\n copyCode: \"Копирай кода\",\n copyCodex: \"Копирай командата на Codex\",\n copyFailed: \"Копирането не бе успешно\",\n copyMarkdown: \"Копирай като Markdown\",\n copyServerUrl: \"Копирай URL на сървъра\",\n edit: \"Редактирай в GitHub\",\n export: \"Експортирай\",\n exportEpub: \"Експортирай в EPUB\",\n exportPdf: \"Експортирай в PDF\",\n generating: \"Генериране…\",\n openIn: \"Отвори в {name}\",\n openInChat: \"Отвори в чата\",\n openInChatPrompt:\n \"Прочетете {url}, за да мога да задавам въпроси за тази страница.\",\n scrollToTop: \"Нагоре\",\n },\n ask: {\n ai: \"ИИ\",\n clear: \"Изчисти разговора\",\n close: \"Затвори\",\n copy: \"Копирай разговора\",\n empty: \"Задайте въпрос за документацията.\",\n error: \"Съжаляваме, нещо се обърка.\",\n label: \"Задайте въпрос\",\n placeholder: \"Задайте въпрос…\",\n send: \"Изпрати\",\n tip: \"Съвет: Можете да отваряте и затваряте чата с\",\n title: \"Попитай ИИ\",\n you: \"Вие\",\n },\n banner: { dismiss: \"Затваряне на съобщението\" },\n changelog: {\n description: \"Актуализации на продукта и бележки към изданията.\",\n title: \"Дневник на промените\",\n },\n content: {\n copyColor: \"Копирай цвета {name} {value}\",\n copyPrompt: \"Копирай подканата\",\n diagramError: \"Тази диаграма не можа да бъде показана.\",\n },\n feedback: {\n no: \"Не\",\n question: \"Беше ли полезна тази страница?\",\n thanks: \"Благодарим за обратната връзка!\",\n yes: \"Да\",\n },\n languageSwitcher: { label: \"Език\", untranslated: \"Непреведено\" },\n nav: {\n back: \"Назад\",\n breadcrumb: \"Навигационна пътека\",\n closeNavigation: \"Затвори навигацията\",\n deprecated: \"остаряло\",\n featured: \"Препоръчано\",\n githubRepository: \"Хранилище в GitHub\",\n navigation: \"Навигация\",\n opensInNewTab: \"Отваря се в нов раздел\",\n primary: \"Основно\",\n sections: \"Раздели\",\n toggleNavigation: \"Превключи навигацията\",\n toggleTheme: \"Превключи цветовата тема\",\n },\n notFound: {\n description: \"Не успяхме да намерим страницата, която търсите.\",\n home: \"Обратно към началната страница\",\n title: \"Страницата не е намерена\",\n },\n page: {\n lastUpdated: \"Последна актуализация\",\n next: \"Напред\",\n pagination: \"Пагинация\",\n previous: \"Назад\",\n skipToContent: \"Към съдържанието\",\n },\n search: {\n all: \"Всички\",\n allLanguages: \"Всички езици\",\n askAi: \"Попитай ИИ\",\n askAiHint: \"Получете незабавен отговор от ИИ\",\n button: \"Търсене\",\n devOnly: \"Търсенето е достъпно в производствената компилация.\",\n error: \"Нещо се обърка. Моля, опитайте отново.\",\n label: \"Търсене в документацията\",\n navigate: \"навигация\",\n noResults: \"Няма намерени резултати.\",\n open: \"отвори\",\n placeholder: \"Търсене в документацията…\",\n popular: \"Популярни\",\n preview: \"преглед\",\n results: \"Резултати\",\n },\n toc: { title: \"На тази страница\" },\n};\n",
|
|
14
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Bengali (bn) UI strings. */\nexport const bn: UIStringsOverride = {\n actions: {\n addToCursor: \"Cursor-এ যোগ করুন\",\n addToVscode: \"VS Code-এ যোগ করুন\",\n askAI: \"এই পৃষ্ঠা সম্পর্কে AI-কে জিজ্ঞাসা করুন\",\n connectMcp: \"MCP-তে সংযোগ করুন\",\n copied: \"অনুলিপি করা হয়েছে!\",\n copyClaudeCode: \"Claude Code কমান্ড অনুলিপি করুন\",\n copyCode: \"কোড অনুলিপি করুন\",\n copyCodex: \"Codex কমান্ড অনুলিপি করুন\",\n copyFailed: \"অনুলিপি ব্যর্থ হয়েছে\",\n copyMarkdown: \"Markdown হিসেবে অনুলিপি করুন\",\n copyServerUrl: \"সার্ভার URL অনুলিপি করুন\",\n edit: \"GitHub-এ সম্পাদনা করুন\",\n export: \"এক্সপোর্ট করুন\",\n exportEpub: \"EPUB-এ এক্সপোর্ট করুন\",\n exportPdf: \"PDF-এ এক্সপোর্ট করুন\",\n generating: \"তৈরি হচ্ছে…\",\n openIn: \"{name}-এ খুলুন\",\n openInChat: \"চ্যাটে খুলুন\",\n openInChatPrompt: \"{url} পড়ুন, যাতে আমি এই পৃষ্ঠা সম্পর্কে প্রশ্ন করতে পারি।\",\n scrollToTop: \"উপরে যান\",\n },\n ask: {\n ai: \"AI\",\n clear: \"কথোপকথন মুছুন\",\n close: \"বন্ধ করুন\",\n copy: \"কথোপকথন অনুলিপি করুন\",\n empty: \"ডকুমেন্টেশন সম্পর্কে একটি প্রশ্ন করুন।\",\n error: \"দুঃখিত, কিছু একটা ভুল হয়েছে।\",\n label: \"একটি প্রশ্ন করুন\",\n placeholder: \"একটি প্রশ্ন করুন…\",\n send: \"পাঠান\",\n tip: \"টিপ: চ্যাট খুলতে ও বন্ধ করতে চাপুন\",\n title: \"AI-কে জিজ্ঞাসা করুন\",\n you: \"আপনি\",\n },\n banner: { dismiss: \"ঘোষণা বন্ধ করুন\" },\n changelog: {\n description: \"পণ্য আপডেট এবং রিলিজ নোট।\",\n title: \"পরিবর্তন লগ\",\n },\n content: {\n copyColor: \"{name} রং {value} অনুলিপি করুন\",\n copyPrompt: \"প্রম্পট অনুলিপি করুন\",\n diagramError: \"এই ডায়াগ্রামটি রেন্ডার করা যায়নি।\",\n },\n feedback: {\n no: \"না\",\n question: \"এই পৃষ্ঠাটি কি সহায়ক ছিল?\",\n thanks: \"আপনার মতামতের জন্য ধন্যবাদ!\",\n yes: \"হ্যাঁ\",\n },\n languageSwitcher: { label: \"ভাষা\", untranslated: \"অনূদিত নয়\" },\n nav: {\n back: \"ফিরে যান\",\n breadcrumb: \"ব্রেডক্রাম্ব\",\n closeNavigation: \"নেভিগেশন বন্ধ করুন\",\n deprecated: \"অপ্রচলিত\",\n featured: \"ফিচার্ড\",\n githubRepository: \"GitHub রিপোজিটরি\",\n navigation: \"নেভিগেশন\",\n opensInNewTab: \"নতুন ট্যাবে খোলে\",\n primary: \"প্রধান\",\n sections: \"বিভাগসমূহ\",\n toggleNavigation: \"নেভিগেশন টগল করুন\",\n toggleTheme: \"রঙের থিম টগল করুন\",\n },\n notFound: {\n description: \"আপনি যে পৃষ্ঠাটি খুঁজছেন তা আমরা খুঁজে পাইনি।\",\n home: \"হোমে ফিরে যান\",\n title: \"পৃষ্ঠা পাওয়া যায়নি\",\n },\n page: {\n lastUpdated: \"সর্বশেষ আপডেট\",\n next: \"পরবর্তী\",\n pagination: \"পেজিনেশন\",\n previous: \"পূর্ববর্তী\",\n skipToContent: \"বিষয়বস্তুতে যান\",\n },\n search: {\n all: \"সব\",\n allLanguages: \"সব ভাষা\",\n askAi: \"AI-কে জিজ্ঞাসা করুন\",\n askAiHint: \"AI থেকে তাৎক্ষণিক উত্তর পান\",\n button: \"অনুসন্ধান\",\n devOnly: \"অনুসন্ধান প্রোডাকশন বিল্ডে উপলব্ধ।\",\n error: \"কিছু একটা ভুল হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।\",\n label: \"ডকুমেন্টেশন অনুসন্ধান করুন\",\n navigate: \"নেভিগেট\",\n noResults: \"কোনো ফলাফল পাওয়া যায়নি।\",\n open: \"খুলুন\",\n placeholder: \"ডকুমেন্টেশন অনুসন্ধান করুন…\",\n popular: \"জনপ্রিয়\",\n preview: \"প্রিভিউ\",\n results: \"ফলাফল\",\n },\n toc: { title: \"এই পৃষ্ঠায়\" },\n};\n",
|
|
15
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Catalan (ca) UI strings. */\nexport const ca: UIStringsOverride = {\n actions: {\n addToCursor: \"Afegeix a Cursor\",\n addToVscode: \"Afegeix a VS Code\",\n askAI: \"Pregunta a la IA sobre aquesta pàgina\",\n connectMcp: \"Connecta a MCP\",\n copied: \"Copiat!\",\n copyClaudeCode: \"Copia l'ordre de Claude Code\",\n copyCode: \"Copia el codi\",\n copyCodex: \"Copia l'ordre de Codex\",\n copyFailed: \"No s'ha pogut copiar\",\n copyMarkdown: \"Copia com a Markdown\",\n copyServerUrl: \"Copia l'URL del servidor\",\n edit: \"Edita a GitHub\",\n export: \"Exporta\",\n exportEpub: \"Exporta a EPUB\",\n exportPdf: \"Exporta a PDF\",\n generating: \"S'està generant…\",\n openIn: \"Obre a {name}\",\n openInChat: \"Obre al xat\",\n openInChatPrompt:\n \"Llegeix {url} perquè pugui fer-te preguntes sobre aquesta pàgina.\",\n scrollToTop: \"Torna a dalt\",\n },\n ask: {\n ai: \"IA\",\n clear: \"Esborra la conversa\",\n close: \"Tanca\",\n copy: \"Copia la conversa\",\n empty: \"Fes una pregunta sobre la documentació.\",\n error: \"Ho sentim, alguna cosa ha anat malament.\",\n label: \"Fes una pregunta\",\n placeholder: \"Fes una pregunta…\",\n send: \"Envia\",\n tip: \"Consell: pots obrir i tancar el xat amb\",\n title: \"Pregunta a la IA\",\n you: \"Tu\",\n },\n banner: { dismiss: \"Tanca l'anunci\" },\n changelog: {\n description: \"Actualitzacions del producte i notes de la versió.\",\n title: \"Registre de canvis\",\n },\n content: {\n copyColor: \"Copia el color {name} {value}\",\n copyPrompt: \"Copia la indicació\",\n diagramError: \"No s'ha pogut mostrar aquest diagrama.\",\n },\n feedback: {\n no: \"No\",\n question: \"Aquesta pàgina t'ha estat útil?\",\n thanks: \"Gràcies pels teus comentaris!\",\n yes: \"Sí\",\n },\n languageSwitcher: { label: \"Idioma\", untranslated: \"Sense traduir\" },\n nav: {\n back: \"Enrere\",\n breadcrumb: \"Ruta de navegació\",\n closeNavigation: \"Tanca la navegació\",\n deprecated: \"obsolet\",\n featured: \"Destacat\",\n githubRepository: \"Repositori de GitHub\",\n navigation: \"Navegació\",\n opensInNewTab: \"S'obre en una pestanya nova\",\n primary: \"Principal\",\n sections: \"Seccions\",\n toggleNavigation: \"Mostra o amaga la navegació\",\n toggleTheme: \"Canvia el tema de color\",\n },\n notFound: {\n description: \"No hem pogut trobar la pàgina que cerques.\",\n home: \"Torna a l'inici\",\n title: \"Pàgina no trobada\",\n },\n page: {\n lastUpdated: \"Última actualització el\",\n next: \"Següent\",\n pagination: \"Paginació\",\n previous: \"Anterior\",\n skipToContent: \"Vés al contingut\",\n },\n search: {\n all: \"Tots\",\n allLanguages: \"Tots els idiomes\",\n askAi: \"Pregunta a la IA\",\n askAiHint: \"Obtén una resposta instantània de la IA\",\n button: \"Cerca\",\n devOnly: \"La cerca està disponible a la compilació de producció.\",\n error: \"Alguna cosa ha anat malament. Torna-ho a provar.\",\n label: \"Cerca a la documentació\",\n navigate: \"navega\",\n noResults: \"No s'ha trobat cap resultat.\",\n open: \"obre\",\n placeholder: \"Cerca a la documentació…\",\n popular: \"Populars\",\n preview: \"previsualitza\",\n results: \"Resultats\",\n },\n toc: { title: \"En aquesta pàgina\" },\n};\n",
|
|
16
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Czech (cs) UI strings. */\nexport const cs: UIStringsOverride = {\n actions: {\n addToCursor: \"Přidat do Cursoru\",\n addToVscode: \"Přidat do VS Code\",\n askAI: \"Zeptat se AI na tuto stránku\",\n connectMcp: \"Připojit k MCP\",\n copied: \"Zkopírováno!\",\n copyClaudeCode: \"Kopírovat příkaz Claude Code\",\n copyCode: \"Kopírovat kód\",\n copyCodex: \"Kopírovat příkaz Codex\",\n copyFailed: \"Kopírování se nezdařilo\",\n copyMarkdown: \"Kopírovat jako Markdown\",\n copyServerUrl: \"Kopírovat URL serveru\",\n edit: \"Upravit na GitHubu\",\n export: \"Exportovat\",\n exportEpub: \"Exportovat do EPUB\",\n exportPdf: \"Exportovat do PDF\",\n generating: \"Generování…\",\n openIn: \"Otevřít v {name}\",\n openInChat: \"Otevřít v chatu\",\n openInChatPrompt: \"Přečtěte si {url}, ať se mohu ptát na tuto stránku.\",\n scrollToTop: \"Zpět nahoru\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Vymazat konverzaci\",\n close: \"Zavřít\",\n copy: \"Kopírovat konverzaci\",\n empty: \"Zeptejte se na dokumentaci.\",\n error: \"Omlouváme se, něco se pokazilo.\",\n label: \"Položit otázku\",\n placeholder: \"Položit otázku…\",\n send: \"Odeslat\",\n tip: \"Tip: Chat můžete otevřít a zavřít pomocí\",\n title: \"Zeptat se AI\",\n you: \"Vy\",\n },\n banner: { dismiss: \"Zavřít oznámení\" },\n changelog: {\n description: \"Novinky produktu a poznámky k vydání.\",\n title: \"Seznam změn\",\n },\n content: {\n copyColor: \"Kopírovat barvu {name} {value}\",\n copyPrompt: \"Kopírovat prompt\",\n diagramError: \"Tento diagram se nepodařilo vykreslit.\",\n },\n feedback: {\n no: \"Ne\",\n question: \"Byla tato stránka užitečná?\",\n thanks: \"Děkujeme za zpětnou vazbu!\",\n yes: \"Ano\",\n },\n languageSwitcher: { label: \"Jazyk\", untranslated: \"Nepřeloženo\" },\n nav: {\n back: \"Zpět\",\n breadcrumb: \"Drobečková navigace\",\n closeNavigation: \"Zavřít navigaci\",\n deprecated: \"zastaralé\",\n featured: \"Doporučené\",\n githubRepository: \"Repozitář na GitHubu\",\n navigation: \"Navigace\",\n opensInNewTab: \"Otevře se na nové kartě\",\n primary: \"Hlavní\",\n sections: \"Sekce\",\n toggleNavigation: \"Přepnout navigaci\",\n toggleTheme: \"Přepnout barevný motiv\",\n },\n notFound: {\n description: \"Stránku, kterou hledáte, se nepodařilo najít.\",\n home: \"Zpět na úvodní stránku\",\n title: \"Stránka nenalezena\",\n },\n page: {\n lastUpdated: \"Naposledy aktualizováno\",\n next: \"Další\",\n pagination: \"Stránkování\",\n previous: \"Předchozí\",\n skipToContent: \"Přejít k obsahu\",\n },\n search: {\n all: \"Vše\",\n allLanguages: \"Všechny jazyky\",\n askAi: \"Zeptat se AI\",\n askAiHint: \"Získejte okamžitou odpověď od AI\",\n button: \"Hledat\",\n devOnly: \"Vyhledávání je dostupné v produkčním buildu.\",\n error: \"Něco se pokazilo. Zkuste to prosím znovu.\",\n label: \"Prohledat dokumentaci\",\n navigate: \"navigace\",\n noResults: \"Nebyly nalezeny žádné výsledky.\",\n open: \"otevřít\",\n placeholder: \"Prohledat dokumentaci…\",\n popular: \"Populární\",\n preview: \"náhled\",\n results: \"Výsledky\",\n },\n toc: { title: \"Na této stránce\" },\n};\n",
|
|
17
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Danish (da) UI strings. */\nexport const da: UIStringsOverride = {\n actions: {\n addToCursor: \"Føj til Cursor\",\n addToVscode: \"Føj til VS Code\",\n askAI: \"Spørg AI om denne side\",\n connectMcp: \"Opret forbindelse til MCP\",\n copied: \"Kopieret!\",\n copyClaudeCode: \"Kopiér Claude Code-kommando\",\n copyCode: \"Kopiér kode\",\n copyCodex: \"Kopiér Codex-kommando\",\n copyFailed: \"Kopiering mislykkedes\",\n copyMarkdown: \"Kopiér som Markdown\",\n copyServerUrl: \"Kopiér server-URL\",\n edit: \"Rediger på GitHub\",\n export: \"Eksportér\",\n exportEpub: \"Eksportér til EPUB\",\n exportPdf: \"Eksportér til PDF\",\n generating: \"Genererer…\",\n openIn: \"Åbn i {name}\",\n openInChat: \"Åbn i chat\",\n openInChatPrompt: \"Læs {url}, så jeg kan stille spørgsmål om denne side.\",\n scrollToTop: \"Tilbage til toppen\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Ryd samtalen\",\n close: \"Luk\",\n copy: \"Kopiér samtalen\",\n empty: \"Stil et spørgsmål om dokumentationen.\",\n error: \"Beklager, noget gik galt.\",\n label: \"Stil et spørgsmål\",\n placeholder: \"Stil et spørgsmål…\",\n send: \"Send\",\n tip: \"Tip: Du kan åbne og lukke chatten med\",\n title: \"Spørg AI\",\n you: \"Du\",\n },\n banner: { dismiss: \"Luk meddelelsen\" },\n changelog: {\n description: \"Produktopdateringer og udgivelsesnoter.\",\n title: \"Ændringslog\",\n },\n content: {\n copyColor: \"Kopiér farven {name} {value}\",\n copyPrompt: \"Kopiér prompt\",\n diagramError: \"Dette diagram kunne ikke vises.\",\n },\n feedback: {\n no: \"Nej\",\n question: \"Var denne side nyttig?\",\n thanks: \"Tak for din feedback!\",\n yes: \"Ja\",\n },\n languageSwitcher: { label: \"Sprog\", untranslated: \"Ikke oversat\" },\n nav: {\n back: \"Tilbage\",\n breadcrumb: \"Brødkrummesti\",\n closeNavigation: \"Luk navigationen\",\n deprecated: \"forældet\",\n featured: \"Udvalgt\",\n githubRepository: \"GitHub-repositorium\",\n navigation: \"Navigation\",\n opensInNewTab: \"Åbner i en ny fane\",\n primary: \"Primær\",\n sections: \"Sektioner\",\n toggleNavigation: \"Vis eller skjul navigationen\",\n toggleTheme: \"Skift farvetema\",\n },\n notFound: {\n description: \"Vi kunne ikke finde den side, du leder efter.\",\n home: \"Tilbage til forsiden\",\n title: \"Siden blev ikke fundet\",\n },\n page: {\n lastUpdated: \"Senest opdateret den\",\n next: \"Næste\",\n pagination: \"Paginering\",\n previous: \"Forrige\",\n skipToContent: \"Spring til indhold\",\n },\n search: {\n all: \"Alle\",\n allLanguages: \"Alle sprog\",\n askAi: \"Spørg AI\",\n askAiHint: \"Få et øjeblikkeligt svar fra AI\",\n button: \"Søg\",\n devOnly: \"Søgning er tilgængelig i produktionsbygningen.\",\n error: \"Noget gik galt. Prøv igen.\",\n label: \"Søg i dokumentationen\",\n navigate: \"navigér\",\n noResults: \"Ingen resultater fundet.\",\n open: \"åbn\",\n placeholder: \"Søg i dokumentationen…\",\n popular: \"Populært\",\n preview: \"forhåndsvis\",\n results: \"Resultater\",\n },\n toc: { title: \"På denne side\" },\n};\n",
|
|
18
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** German (de) UI strings. */\nexport const de: UIStringsOverride = {\n actions: {\n addToCursor: \"Zu Cursor hinzufügen\",\n addToVscode: \"Zu VS Code hinzufügen\",\n askAI: \"KI zu dieser Seite fragen\",\n connectMcp: \"Mit MCP verbinden\",\n copied: \"Kopiert!\",\n copyClaudeCode: \"Claude-Code-Befehl kopieren\",\n copyCode: \"Code kopieren\",\n copyCodex: \"Codex-Befehl kopieren\",\n copyFailed: \"Kopieren fehlgeschlagen\",\n copyMarkdown: \"Als Markdown kopieren\",\n copyServerUrl: \"Server-URL kopieren\",\n edit: \"Auf GitHub bearbeiten\",\n export: \"Exportieren\",\n exportEpub: \"Als EPUB exportieren\",\n exportPdf: \"Als PDF exportieren\",\n generating: \"Wird generiert…\",\n openIn: \"In {name} öffnen\",\n openInChat: \"Im Chat öffnen\",\n openInChatPrompt:\n \"Lies {url}, damit ich dir Fragen zu dieser Seite stellen kann.\",\n scrollToTop: \"Nach oben scrollen\",\n },\n ask: {\n ai: \"KI\",\n clear: \"Unterhaltung löschen\",\n close: \"Schließen\",\n copy: \"Unterhaltung kopieren\",\n empty: \"Stelle eine Frage zur Dokumentation.\",\n error: \"Entschuldigung, etwas ist schiefgelaufen.\",\n label: \"Eine Frage stellen\",\n placeholder: \"Eine Frage stellen…\",\n send: \"Senden\",\n tip: \"Tipp: Du kannst den Chat öffnen und schließen mit\",\n title: \"KI fragen\",\n you: \"Du\",\n },\n banner: { dismiss: \"Ankündigung schließen\" },\n changelog: {\n description: \"Produkt-Updates und Versionshinweise.\",\n title: \"Änderungsprotokoll\",\n },\n content: {\n copyColor: \"Farbe {name} {value} kopieren\",\n copyPrompt: \"Prompt kopieren\",\n diagramError: \"Dieses Diagramm konnte nicht dargestellt werden.\",\n },\n feedback: {\n no: \"Nein\",\n question: \"War diese Seite hilfreich?\",\n thanks: \"Danke für dein Feedback!\",\n yes: \"Ja\",\n },\n languageSwitcher: { label: \"Sprache\", untranslated: \"Nicht übersetzt\" },\n nav: {\n back: \"Zurück\",\n breadcrumb: \"Brotkrümelnavigation\",\n closeNavigation: \"Navigation schließen\",\n deprecated: \"veraltet\",\n featured: \"Empfohlen\",\n githubRepository: \"GitHub-Repository\",\n navigation: \"Navigation\",\n opensInNewTab: \"Öffnet sich in einem neuen Tab\",\n primary: \"Primär\",\n sections: \"Abschnitte\",\n toggleNavigation: \"Navigation umschalten\",\n toggleTheme: \"Farbschema umschalten\",\n },\n notFound: {\n description: \"Wir konnten die gesuchte Seite nicht finden.\",\n home: \"Zurück zur Startseite\",\n title: \"Seite nicht gefunden\",\n },\n page: {\n lastUpdated: \"Zuletzt aktualisiert am\",\n next: \"Weiter\",\n pagination: \"Seitennummerierung\",\n previous: \"Zurück\",\n skipToContent: \"Zum Inhalt springen\",\n },\n search: {\n all: \"Alle\",\n allLanguages: \"Alle Sprachen\",\n askAi: \"KI fragen\",\n askAiHint: \"Erhalte sofort eine Antwort von der KI\",\n button: \"Suchen\",\n devOnly: \"Die Suche ist im Produktions-Build verfügbar.\",\n error: \"Etwas ist schiefgelaufen. Bitte versuche es erneut.\",\n label: \"Dokumentation durchsuchen\",\n navigate: \"navigieren\",\n noResults: \"Keine Ergebnisse gefunden.\",\n open: \"öffnen\",\n placeholder: \"Dokumentation durchsuchen…\",\n popular: \"Beliebt\",\n preview: \"vorschau\",\n results: \"Ergebnisse\",\n },\n toc: { title: \"Auf dieser Seite\" },\n};\n",
|
|
19
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Greek (el) UI strings. */\nexport const el: UIStringsOverride = {\n actions: {\n addToCursor: \"Προσθήκη στο Cursor\",\n addToVscode: \"Προσθήκη στο VS Code\",\n askAI: \"Ρωτήστε την AI για αυτή τη σελίδα\",\n connectMcp: \"Σύνδεση με MCP\",\n copied: \"Αντιγράφηκε!\",\n copyClaudeCode: \"Αντιγραφή εντολής Claude Code\",\n copyCode: \"Αντιγραφή κώδικα\",\n copyCodex: \"Αντιγραφή εντολής Codex\",\n copyFailed: \"Η αντιγραφή απέτυχε\",\n copyMarkdown: \"Αντιγραφή ως Markdown\",\n copyServerUrl: \"Αντιγραφή URL διακομιστή\",\n edit: \"Επεξεργασία στο GitHub\",\n export: \"Εξαγωγή\",\n exportEpub: \"Εξαγωγή σε EPUB\",\n exportPdf: \"Εξαγωγή σε PDF\",\n generating: \"Δημιουργία…\",\n openIn: \"Άνοιγμα στο {name}\",\n openInChat: \"Άνοιγμα στη συνομιλία\",\n openInChatPrompt:\n \"Διαβάστε το {url} για να μπορώ να κάνω ερωτήσεις για αυτή τη σελίδα.\",\n scrollToTop: \"Επιστροφή στην κορυφή\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Εκκαθάριση συνομιλίας\",\n close: \"Κλείσιμο\",\n copy: \"Αντιγραφή συνομιλίας\",\n empty: \"Κάντε μια ερώτηση σχετικά με την τεκμηρίωση.\",\n error: \"Λυπούμαστε, κάτι πήγε στραβά.\",\n label: \"Κάντε μια ερώτηση\",\n placeholder: \"Κάντε μια ερώτηση…\",\n send: \"Αποστολή\",\n tip: \"Συμβουλή: Μπορείτε να ανοίγετε και να κλείνετε τη συνομιλία με\",\n title: \"Ρωτήστε την AI\",\n you: \"Εσείς\",\n },\n banner: { dismiss: \"Κλείσιμο ανακοίνωσης\" },\n changelog: {\n description: \"Ενημερώσεις προϊόντος και σημειώσεις έκδοσης.\",\n title: \"Ιστορικό αλλαγών\",\n },\n content: {\n copyColor: \"Αντιγραφή χρώματος {name} {value}\",\n copyPrompt: \"Αντιγραφή προτροπής\",\n diagramError: \"Δεν ήταν δυνατή η απόδοση αυτού του διαγράμματος.\",\n },\n feedback: {\n no: \"Όχι\",\n question: \"Σας φάνηκε χρήσιμη αυτή η σελίδα;\",\n thanks: \"Ευχαριστούμε για τα σχόλιά σας!\",\n yes: \"Ναι\",\n },\n languageSwitcher: { label: \"Γλώσσα\", untranslated: \"Δεν έχει μεταφραστεί\" },\n nav: {\n back: \"Πίσω\",\n breadcrumb: \"Διαδρομή πλοήγησης\",\n closeNavigation: \"Κλείσιμο πλοήγησης\",\n deprecated: \"παρωχημένο\",\n featured: \"Προτεινόμενα\",\n githubRepository: \"Αποθετήριο GitHub\",\n navigation: \"Πλοήγηση\",\n opensInNewTab: \"Ανοίγει σε νέα καρτέλα\",\n primary: \"Κύρια\",\n sections: \"Ενότητες\",\n toggleNavigation: \"Εναλλαγή πλοήγησης\",\n toggleTheme: \"Εναλλαγή χρωματικού θέματος\",\n },\n notFound: {\n description: \"Δεν μπορέσαμε να βρούμε τη σελίδα που ψάχνετε.\",\n home: \"Επιστροφή στην αρχική\",\n title: \"Η σελίδα δεν βρέθηκε\",\n },\n page: {\n lastUpdated: \"Τελευταία ενημέρωση\",\n next: \"Επόμενο\",\n pagination: \"Σελιδοποίηση\",\n previous: \"Προηγούμενο\",\n skipToContent: \"Μετάβαση στο περιεχόμενο\",\n },\n search: {\n all: \"Όλα\",\n allLanguages: \"Όλες οι γλώσσες\",\n askAi: \"Ρωτήστε την AI\",\n askAiHint: \"Λάβετε άμεση απάντηση από την AI\",\n button: \"Αναζήτηση\",\n devOnly: \"Η αναζήτηση είναι διαθέσιμη στην έκδοση παραγωγής.\",\n error: \"Κάτι πήγε στραβά. Δοκιμάστε ξανά.\",\n label: \"Αναζήτηση στην τεκμηρίωση\",\n navigate: \"πλοήγηση\",\n noResults: \"Δεν βρέθηκαν αποτελέσματα.\",\n open: \"άνοιγμα\",\n placeholder: \"Αναζήτηση στην τεκμηρίωση…\",\n popular: \"Δημοφιλή\",\n preview: \"προεπισκόπηση\",\n results: \"Αποτελέσματα\",\n },\n toc: { title: \"Σε αυτή τη σελίδα\" },\n};\n",
|
|
20
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Spanish (es) UI strings. */\nexport const es: UIStringsOverride = {\n actions: {\n addToCursor: \"Añadir a Cursor\",\n addToVscode: \"Añadir a VS Code\",\n askAI: \"Preguntar a la IA sobre esta página\",\n connectMcp: \"Conectar a MCP\",\n copied: \"¡Copiado!\",\n copyClaudeCode: \"Copiar comando de Claude Code\",\n copyCode: \"Copiar código\",\n copyCodex: \"Copiar comando de Codex\",\n copyFailed: \"Error al copiar\",\n copyMarkdown: \"Copiar como Markdown\",\n copyServerUrl: \"Copiar URL del servidor\",\n edit: \"Editar en GitHub\",\n export: \"Exportar\",\n exportEpub: \"Exportar a EPUB\",\n exportPdf: \"Exportar a PDF\",\n generating: \"Generando…\",\n openIn: \"Abrir en {name}\",\n openInChat: \"Abrir en el chat\",\n openInChatPrompt:\n \"Lee {url} para que pueda hacerte preguntas sobre esta página.\",\n scrollToTop: \"Volver arriba\",\n },\n ask: {\n ai: \"IA\",\n clear: \"Borrar la conversación\",\n close: \"Cerrar\",\n copy: \"Copiar la conversación\",\n empty: \"Haz una pregunta sobre la documentación.\",\n error: \"Lo sentimos, algo salió mal.\",\n label: \"Haz una pregunta\",\n placeholder: \"Haz una pregunta…\",\n send: \"Enviar\",\n tip: \"Consejo: puedes abrir y cerrar el chat con\",\n title: \"Preguntar a la IA\",\n you: \"Tú\",\n },\n banner: { dismiss: \"Cerrar el anuncio\" },\n changelog: {\n description: \"Novedades del producto y notas de la versión.\",\n title: \"Registro de cambios\",\n },\n content: {\n copyColor: \"Copiar el color {name} {value}\",\n copyPrompt: \"Copiar prompt\",\n diagramError: \"No se pudo mostrar este diagrama.\",\n },\n feedback: {\n no: \"No\",\n question: \"¿Te ha resultado útil esta página?\",\n thanks: \"¡Gracias por tus comentarios!\",\n yes: \"Sí\",\n },\n languageSwitcher: { label: \"Idioma\", untranslated: \"Sin traducir\" },\n nav: {\n back: \"Atrás\",\n breadcrumb: \"Ruta de navegación\",\n closeNavigation: \"Cerrar la navegación\",\n deprecated: \"obsoleto\",\n featured: \"Destacado\",\n githubRepository: \"Repositorio de GitHub\",\n navigation: \"Navegación\",\n opensInNewTab: \"Se abre en una pestaña nueva\",\n primary: \"Principal\",\n sections: \"Secciones\",\n toggleNavigation: \"Mostrar u ocultar la navegación\",\n toggleTheme: \"Cambiar el tema de color\",\n },\n notFound: {\n description: \"No hemos podido encontrar la página que buscas.\",\n home: \"Volver al inicio\",\n title: \"Página no encontrada\",\n },\n page: {\n lastUpdated: \"Última actualización el\",\n next: \"Siguiente\",\n pagination: \"Paginación\",\n previous: \"Anterior\",\n skipToContent: \"Saltar al contenido\",\n },\n search: {\n all: \"Todos\",\n allLanguages: \"Todos los idiomas\",\n askAi: \"Preguntar a la IA\",\n askAiHint: \"Obtén una respuesta instantánea de la IA\",\n button: \"Buscar\",\n devOnly: \"La búsqueda está disponible en la compilación de producción.\",\n error: \"Algo salió mal. Inténtalo de nuevo.\",\n label: \"Buscar en la documentación\",\n navigate: \"navegar\",\n noResults: \"No se encontraron resultados.\",\n open: \"abrir\",\n placeholder: \"Buscar en la documentación…\",\n popular: \"Populares\",\n preview: \"vista previa\",\n results: \"Resultados\",\n },\n toc: { title: \"En esta página\" },\n};\n",
|
|
21
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Persian (fa) UI strings. */\nexport const fa: UIStringsOverride = {\n actions: {\n addToCursor: \"افزودن به Cursor\",\n addToVscode: \"افزودن به VS Code\",\n askAI: \"از هوش مصنوعی درباره این صفحه بپرسید\",\n connectMcp: \"اتصال به MCP\",\n copied: \"کپی شد!\",\n copyClaudeCode: \"کپی دستور Claude Code\",\n copyCode: \"کپی کد\",\n copyCodex: \"کپی دستور Codex\",\n copyFailed: \"کپی ناموفق بود\",\n copyMarkdown: \"کپی بهصورت Markdown\",\n copyServerUrl: \"کپی نشانی سرور\",\n edit: \"ویرایش در GitHub\",\n export: \"برونبری\",\n exportEpub: \"برونبری به EPUB\",\n exportPdf: \"برونبری به PDF\",\n generating: \"در حال تولید…\",\n openIn: \"باز کردن در {name}\",\n openInChat: \"باز کردن در گفتگو\",\n openInChatPrompt: \"{url} را بخوانید تا بتوانم درباره این صفحه سؤال بپرسم.\",\n scrollToTop: \"بازگشت به بالا\",\n },\n ask: {\n ai: \"هوش مصنوعی\",\n clear: \"پاک کردن گفتگو\",\n close: \"بستن\",\n copy: \"کپی گفتگو\",\n empty: \"سؤالی درباره مستندات بپرسید.\",\n error: \"متأسفیم، مشکلی پیش آمد.\",\n label: \"یک سؤال بپرسید\",\n placeholder: \"یک سؤال بپرسید…\",\n send: \"ارسال\",\n tip: \"نکته: باز و بسته کردن گفتگو با\",\n title: \"از هوش مصنوعی بپرسید\",\n you: \"شما\",\n },\n banner: { dismiss: \"بستن اطلاعیه\" },\n changelog: {\n description: \"بهروزرسانیهای محصول و یادداشتهای انتشار.\",\n title: \"گزارش تغییرات\",\n },\n content: {\n copyColor: \"کپی رنگ {name} {value}\",\n copyPrompt: \"کپی پرامپت\",\n diagramError: \"نمایش این نمودار ممکن نشد.\",\n },\n feedback: {\n no: \"خیر\",\n question: \"آیا این صفحه مفید بود؟\",\n thanks: \"از بازخورد شما سپاسگزاریم!\",\n yes: \"بله\",\n },\n languageSwitcher: { label: \"زبان\", untranslated: \"ترجمهنشده\" },\n nav: {\n back: \"بازگشت\",\n breadcrumb: \"مسیر ناوبری\",\n closeNavigation: \"بستن ناوبری\",\n deprecated: \"منسوخ\",\n featured: \"ویژه\",\n githubRepository: \"مخزن GitHub\",\n navigation: \"ناوبری\",\n opensInNewTab: \"در زبانهای جدید باز میشود\",\n primary: \"اصلی\",\n sections: \"بخشها\",\n toggleNavigation: \"تغییر وضعیت ناوبری\",\n toggleTheme: \"تغییر پوسته رنگی\",\n },\n notFound: {\n description: \"صفحهای که به دنبال آن هستید پیدا نشد.\",\n home: \"بازگشت به صفحه اصلی\",\n title: \"صفحه پیدا نشد\",\n },\n page: {\n lastUpdated: \"آخرین بهروزرسانی\",\n next: \"بعدی\",\n pagination: \"صفحهبندی\",\n previous: \"قبلی\",\n skipToContent: \"پرش به محتوا\",\n },\n search: {\n all: \"همه\",\n allLanguages: \"همه زبانها\",\n askAi: \"از هوش مصنوعی بپرسید\",\n askAiHint: \"پاسخی فوری از هوش مصنوعی دریافت کنید\",\n button: \"جستجو\",\n devOnly: \"جستجو در نسخه تولید در دسترس است.\",\n error: \"مشکلی پیش آمد. لطفاً دوباره تلاش کنید.\",\n label: \"جستجو در مستندات\",\n navigate: \"پیمایش\",\n noResults: \"نتیجهای یافت نشد.\",\n open: \"باز کردن\",\n placeholder: \"جستجو در مستندات…\",\n popular: \"محبوب\",\n preview: \"پیشنمایش\",\n results: \"نتایج\",\n },\n toc: { title: \"در این صفحه\" },\n};\n",
|
|
22
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Finnish (fi) UI strings. */\nexport const fi: UIStringsOverride = {\n actions: {\n addToCursor: \"Lisää Cursoriin\",\n addToVscode: \"Lisää VS Codeen\",\n askAI: \"Kysy tekoälyltä tästä sivusta\",\n connectMcp: \"Yhdistä MCP:hen\",\n copied: \"Kopioitu!\",\n copyClaudeCode: \"Kopioi Claude Code -komento\",\n copyCode: \"Kopioi koodi\",\n copyCodex: \"Kopioi Codex-komento\",\n copyFailed: \"Kopiointi epäonnistui\",\n copyMarkdown: \"Kopioi Markdownina\",\n copyServerUrl: \"Kopioi palvelimen URL\",\n edit: \"Muokkaa GitHubissa\",\n export: \"Vie\",\n exportEpub: \"Vie EPUB-muotoon\",\n exportPdf: \"Vie PDF-muotoon\",\n generating: \"Luodaan…\",\n openIn: \"Avaa sovelluksessa {name}\",\n openInChat: \"Avaa keskustelussa\",\n openInChatPrompt: \"Lue {url}, jotta voin kysyä kysymyksiä tästä sivusta.\",\n scrollToTop: \"Takaisin ylös\",\n },\n ask: {\n ai: \"Tekoäly\",\n clear: \"Tyhjennä keskustelu\",\n close: \"Sulje\",\n copy: \"Kopioi keskustelu\",\n empty: \"Kysy kysymys dokumentaatiosta.\",\n error: \"Pahoittelut, jokin meni pieleen.\",\n label: \"Kysy kysymys\",\n placeholder: \"Kysy kysymys…\",\n send: \"Lähetä\",\n tip: \"Vinkki: Voit avata ja sulkea keskustelun näppäimillä\",\n title: \"Kysy tekoälyltä\",\n you: \"Sinä\",\n },\n banner: { dismiss: \"Sulje ilmoitus\" },\n changelog: {\n description: \"Tuotepäivitykset ja julkaisutiedot.\",\n title: \"Muutosloki\",\n },\n content: {\n copyColor: \"Kopioi väri {name} {value}\",\n copyPrompt: \"Kopioi kehote\",\n diagramError: \"Tätä kaaviota ei voitu näyttää.\",\n },\n feedback: {\n no: \"Ei\",\n question: \"Oliko tästä sivusta apua?\",\n thanks: \"Kiitos palautteestasi!\",\n yes: \"Kyllä\",\n },\n languageSwitcher: { label: \"Kieli\", untranslated: \"Ei käännetty\" },\n nav: {\n back: \"Takaisin\",\n breadcrumb: \"Murupolku\",\n closeNavigation: \"Sulje navigaatio\",\n deprecated: \"vanhentunut\",\n featured: \"Suositellut\",\n githubRepository: \"GitHub-repositorio\",\n navigation: \"Navigaatio\",\n opensInNewTab: \"Avautuu uudelle välilehdelle\",\n primary: \"Ensisijainen\",\n sections: \"Osiot\",\n toggleNavigation: \"Näytä tai piilota navigaatio\",\n toggleTheme: \"Vaihda väriteemaa\",\n },\n notFound: {\n description: \"Etsimääsi sivua ei löytynyt.\",\n home: \"Takaisin etusivulle\",\n title: \"Sivua ei löytynyt\",\n },\n page: {\n lastUpdated: \"Viimeksi päivitetty\",\n next: \"Seuraava\",\n pagination: \"Sivutus\",\n previous: \"Edellinen\",\n skipToContent: \"Siirry sisältöön\",\n },\n search: {\n all: \"Kaikki\",\n allLanguages: \"Kaikki kielet\",\n askAi: \"Kysy tekoälyltä\",\n askAiHint: \"Saat välittömän vastauksen tekoälyltä\",\n button: \"Hae\",\n devOnly: \"Haku on käytettävissä tuotantokäännöksessä.\",\n error: \"Jokin meni pieleen. Yritä uudelleen.\",\n label: \"Hae dokumentaatiosta\",\n navigate: \"siirry\",\n noResults: \"Ei tuloksia.\",\n open: \"avaa\",\n placeholder: \"Hae dokumentaatiosta…\",\n popular: \"Suositut\",\n preview: \"esikatselu\",\n results: \"Tulokset\",\n },\n toc: { title: \"Tällä sivulla\" },\n};\n",
|
|
23
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** French (fr) UI strings. */\nexport const fr: UIStringsOverride = {\n actions: {\n addToCursor: \"Ajouter à Cursor\",\n addToVscode: \"Ajouter à VS Code\",\n askAI: \"Demander à l'IA à propos de cette page\",\n connectMcp: \"Se connecter à MCP\",\n copied: \"Copié !\",\n copyClaudeCode: \"Copier la commande Claude Code\",\n copyCode: \"Copier le code\",\n copyCodex: \"Copier la commande Codex\",\n copyFailed: \"Échec de la copie\",\n copyMarkdown: \"Copier en Markdown\",\n copyServerUrl: \"Copier l'URL du serveur\",\n edit: \"Modifier sur GitHub\",\n export: \"Exporter\",\n exportEpub: \"Exporter en EPUB\",\n exportPdf: \"Exporter en PDF\",\n generating: \"Génération…\",\n openIn: \"Ouvrir dans {name}\",\n openInChat: \"Ouvrir dans le chat\",\n openInChatPrompt:\n \"Lisez {url} pour que je puisse vous poser des questions sur cette page.\",\n scrollToTop: \"Revenir en haut\",\n },\n ask: {\n ai: \"IA\",\n clear: \"Effacer la conversation\",\n close: \"Fermer\",\n copy: \"Copier la conversation\",\n empty: \"Posez une question sur la documentation.\",\n error: \"Désolé, une erreur s'est produite.\",\n label: \"Poser une question\",\n placeholder: \"Posez une question…\",\n send: \"Envoyer\",\n tip: \"Astuce : vous pouvez ouvrir et fermer le chat avec\",\n title: \"Demander à l'IA\",\n you: \"Vous\",\n },\n banner: { dismiss: \"Fermer l'annonce\" },\n changelog: {\n description: \"Nouveautés du produit et notes de version.\",\n title: \"Journal des modifications\",\n },\n content: {\n copyColor: \"Copier la couleur {name} {value}\",\n copyPrompt: \"Copier le prompt\",\n diagramError: \"Impossible d'afficher ce diagramme.\",\n },\n feedback: {\n no: \"Non\",\n question: \"Cette page vous a-t-elle été utile ?\",\n thanks: \"Merci pour votre retour !\",\n yes: \"Oui\",\n },\n languageSwitcher: { label: \"Langue\", untranslated: \"Non traduit\" },\n nav: {\n back: \"Retour\",\n breadcrumb: \"Fil d'Ariane\",\n closeNavigation: \"Fermer la navigation\",\n deprecated: \"obsolète\",\n featured: \"En vedette\",\n githubRepository: \"Dépôt GitHub\",\n navigation: \"Navigation\",\n opensInNewTab: \"S'ouvre dans un nouvel onglet\",\n primary: \"Principal\",\n sections: \"Sections\",\n toggleNavigation: \"Afficher ou masquer la navigation\",\n toggleTheme: \"Changer de thème de couleur\",\n },\n notFound: {\n description: \"Nous n'avons pas trouvé la page que vous recherchez.\",\n home: \"Retour à l'accueil\",\n title: \"Page introuvable\",\n },\n page: {\n lastUpdated: \"Dernière mise à jour le\",\n next: \"Suivant\",\n pagination: \"Pagination\",\n previous: \"Précédent\",\n skipToContent: \"Aller au contenu\",\n },\n search: {\n all: \"Tous\",\n allLanguages: \"Toutes les langues\",\n askAi: \"Demander à l'IA\",\n askAiHint: \"Obtenez une réponse instantanée de l'IA\",\n button: \"Rechercher\",\n devOnly: \"La recherche est disponible dans la version de production.\",\n error: \"Une erreur s'est produite. Veuillez réessayer.\",\n label: \"Rechercher dans la doc\",\n navigate: \"naviguer\",\n noResults: \"Aucun résultat.\",\n open: \"ouvrir\",\n placeholder: \"Rechercher dans la documentation…\",\n popular: \"Populaires\",\n preview: \"aperçu\",\n results: \"Résultats\",\n },\n toc: { title: \"Sur cette page\" },\n};\n",
|
|
24
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Hebrew (he) UI strings. */\nexport const he: UIStringsOverride = {\n actions: {\n addToCursor: \"הוסף ל-Cursor\",\n addToVscode: \"הוסף ל-VS Code\",\n askAI: \"שאל את ה-AI על העמוד הזה\",\n connectMcp: \"התחבר ל-MCP\",\n copied: \"הועתק!\",\n copyClaudeCode: \"העתק פקודת Claude Code\",\n copyCode: \"העתק קוד\",\n copyCodex: \"העתק פקודת Codex\",\n copyFailed: \"ההעתקה נכשלה\",\n copyMarkdown: \"העתק כ-Markdown\",\n copyServerUrl: \"העתק כתובת URL של השרת\",\n edit: \"ערוך ב-GitHub\",\n export: \"ייצוא\",\n exportEpub: \"ייצוא ל-EPUB\",\n exportPdf: \"ייצוא ל-PDF\",\n generating: \"מייצר…\",\n openIn: \"פתח ב-{name}\",\n openInChat: \"פתח בצ'אט\",\n openInChatPrompt: \"קרא את {url} כדי שאוכל לשאול שאלות על העמוד הזה.\",\n scrollToTop: \"חזרה למעלה\",\n },\n ask: {\n ai: \"AI\",\n clear: \"נקה שיחה\",\n close: \"סגור\",\n copy: \"העתק שיחה\",\n empty: \"שאל שאלה על התיעוד.\",\n error: \"מצטערים, משהו השתבש.\",\n label: \"שאל שאלה\",\n placeholder: \"שאל שאלה…\",\n send: \"שלח\",\n tip: \"טיפ: אפשר לפתוח ולסגור את הצ'אט באמצעות\",\n title: \"שאל את ה-AI\",\n you: \"אתה\",\n },\n banner: { dismiss: \"סגירת ההודעה\" },\n changelog: {\n description: \"עדכוני מוצר והערות גרסה.\",\n title: \"יומן שינויים\",\n },\n content: {\n copyColor: \"העתק את הצבע {name} {value}\",\n copyPrompt: \"העתק הנחיה\",\n diagramError: \"לא ניתן להציג את התרשים הזה.\",\n },\n feedback: {\n no: \"לא\",\n question: \"האם העמוד הזה היה מועיל?\",\n thanks: \"תודה על המשוב שלך!\",\n yes: \"כן\",\n },\n languageSwitcher: { label: \"שפה\", untranslated: \"לא מתורגם\" },\n nav: {\n back: \"חזרה\",\n breadcrumb: \"פירורי לחם\",\n closeNavigation: \"סגור ניווט\",\n deprecated: \"הוצא משימוש\",\n featured: \"מומלץ\",\n githubRepository: \"מאגר GitHub\",\n navigation: \"ניווט\",\n opensInNewTab: \"נפתח בכרטיסייה חדשה\",\n primary: \"ראשי\",\n sections: \"מקטעים\",\n toggleNavigation: \"החלף מצב ניווט\",\n toggleTheme: \"החלף ערכת צבעים\",\n },\n notFound: {\n description: \"לא הצלחנו למצוא את העמוד שחיפשת.\",\n home: \"חזרה לעמוד הבית\",\n title: \"העמוד לא נמצא\",\n },\n page: {\n lastUpdated: \"עודכן לאחרונה\",\n next: \"הבא\",\n pagination: \"עימוד\",\n previous: \"הקודם\",\n skipToContent: \"דלג לתוכן\",\n },\n search: {\n all: \"הכל\",\n allLanguages: \"כל השפות\",\n askAi: \"שאל את ה-AI\",\n askAiHint: \"קבל תשובה מיידית מה-AI\",\n button: \"חיפוש\",\n devOnly: \"החיפוש זמין בבנייה לייצור.\",\n error: \"משהו השתבש. נסה שוב.\",\n label: \"חפש בתיעוד\",\n navigate: \"ניווט\",\n noResults: \"לא נמצאו תוצאות.\",\n open: \"פתיחה\",\n placeholder: \"חפש בתיעוד…\",\n popular: \"פופולרי\",\n preview: \"תצוגה מקדימה\",\n results: \"תוצאות\",\n },\n toc: { title: \"בעמוד זה\" },\n};\n",
|
|
25
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Hindi (hi) UI strings. */\nexport const hi: UIStringsOverride = {\n actions: {\n addToCursor: \"Cursor में जोड़ें\",\n addToVscode: \"VS Code में जोड़ें\",\n askAI: \"इस पेज के बारे में AI से पूछें\",\n connectMcp: \"MCP से कनेक्ट करें\",\n copied: \"कॉपी किया गया!\",\n copyClaudeCode: \"Claude Code कमांड कॉपी करें\",\n copyCode: \"कोड कॉपी करें\",\n copyCodex: \"Codex कमांड कॉपी करें\",\n copyFailed: \"कॉपी विफल रहा\",\n copyMarkdown: \"Markdown के रूप में कॉपी करें\",\n copyServerUrl: \"सर्वर URL कॉपी करें\",\n edit: \"GitHub पर संपादित करें\",\n export: \"एक्सपोर्ट करें\",\n exportEpub: \"EPUB में एक्सपोर्ट करें\",\n exportPdf: \"PDF में एक्सपोर्ट करें\",\n generating: \"जनरेट हो रहा है…\",\n openIn: \"{name} में खोलें\",\n openInChat: \"चैट में खोलें\",\n openInChatPrompt: \"{url} पढ़ें ताकि मैं इस पेज के बारे में प्रश्न पूछ सकूँ।\",\n scrollToTop: \"ऊपर जाएँ\",\n },\n ask: {\n ai: \"AI\",\n clear: \"बातचीत साफ़ करें\",\n close: \"बंद करें\",\n copy: \"बातचीत कॉपी करें\",\n empty: \"दस्तावेज़ के बारे में एक प्रश्न पूछें।\",\n error: \"क्षमा करें, कुछ गलत हो गया।\",\n label: \"एक प्रश्न पूछें\",\n placeholder: \"एक प्रश्न पूछें…\",\n send: \"भेजें\",\n tip: \"सुझाव: चैट खोलने और बंद करने के लिए दबाएँ\",\n title: \"AI से पूछें\",\n you: \"आप\",\n },\n banner: { dismiss: \"घोषणा बंद करें\" },\n changelog: {\n description: \"उत्पाद अपडेट और रिलीज़ नोट्स।\",\n title: \"परिवर्तन लॉग\",\n },\n content: {\n copyColor: \"{name} रंग {value} कॉपी करें\",\n copyPrompt: \"प्रॉम्प्ट कॉपी करें\",\n diagramError: \"यह डायग्राम रेंडर नहीं हो सका।\",\n },\n feedback: {\n no: \"नहीं\",\n question: \"क्या यह पेज सहायक था?\",\n thanks: \"आपकी प्रतिक्रिया के लिए धन्यवाद!\",\n yes: \"हाँ\",\n },\n languageSwitcher: { label: \"भाषा\", untranslated: \"अनुवादित नहीं\" },\n nav: {\n back: \"वापस\",\n breadcrumb: \"ब्रेडक्रम\",\n closeNavigation: \"नेविगेशन बंद करें\",\n deprecated: \"अप्रचलित\",\n featured: \"फ़ीचर्ड\",\n githubRepository: \"GitHub रिपॉज़िटरी\",\n navigation: \"नेविगेशन\",\n opensInNewTab: \"नए टैब में खुलता है\",\n primary: \"प्राथमिक\",\n sections: \"अनुभाग\",\n toggleNavigation: \"नेविगेशन टॉगल करें\",\n toggleTheme: \"रंग थीम टॉगल करें\",\n },\n notFound: {\n description: \"आप जिस पेज को खोज रहे हैं वह हमें नहीं मिला।\",\n home: \"होम पर वापस जाएँ\",\n title: \"पेज नहीं मिला\",\n },\n page: {\n lastUpdated: \"अंतिम अपडेट\",\n next: \"अगला\",\n pagination: \"पृष्ठांकन\",\n previous: \"पिछला\",\n skipToContent: \"सामग्री पर जाएँ\",\n },\n search: {\n all: \"सभी\",\n allLanguages: \"सभी भाषाएँ\",\n askAi: \"AI से पूछें\",\n askAiHint: \"AI से तुरंत जवाब पाएँ\",\n button: \"खोजें\",\n devOnly: \"खोज प्रोडक्शन बिल्ड में उपलब्ध है।\",\n error: \"कुछ गलत हो गया। कृपया फिर से कोशिश करें।\",\n label: \"दस्तावेज़ खोजें\",\n navigate: \"नेविगेट\",\n noResults: \"कोई परिणाम नहीं मिला।\",\n open: \"खोलें\",\n placeholder: \"दस्तावेज़ खोजें…\",\n popular: \"लोकप्रिय\",\n preview: \"प्रीव्यू\",\n results: \"परिणाम\",\n },\n toc: { title: \"इस पेज पर\" },\n};\n",
|
|
26
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Croatian (hr) UI strings. */\nexport const hr: UIStringsOverride = {\n actions: {\n addToCursor: \"Dodaj u Cursor\",\n addToVscode: \"Dodaj u VS Code\",\n askAI: \"Pitaj AI o ovoj stranici\",\n connectMcp: \"Poveži se s MCP-om\",\n copied: \"Kopirano!\",\n copyClaudeCode: \"Kopiraj naredbu Claude Code\",\n copyCode: \"Kopiraj kôd\",\n copyCodex: \"Kopiraj naredbu Codex\",\n copyFailed: \"Kopiranje nije uspjelo\",\n copyMarkdown: \"Kopiraj kao Markdown\",\n copyServerUrl: \"Kopiraj URL poslužitelja\",\n edit: \"Uredi na GitHubu\",\n export: \"Izvezi\",\n exportEpub: \"Izvezi u EPUB\",\n exportPdf: \"Izvezi u PDF\",\n generating: \"Generiranje…\",\n openIn: \"Otvori u {name}\",\n openInChat: \"Otvori u chatu\",\n openInChatPrompt:\n \"Pročitajte {url} — postavljat ću pitanja o ovoj stranici.\",\n scrollToTop: \"Natrag na vrh\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Očisti razgovor\",\n close: \"Zatvori\",\n copy: \"Kopiraj razgovor\",\n empty: \"Postavite pitanje o dokumentaciji.\",\n error: \"Žao nam je, nešto je pošlo po zlu.\",\n label: \"Postavi pitanje\",\n placeholder: \"Postavite pitanje…\",\n send: \"Pošalji\",\n tip: \"Savjet: Chat možete otvoriti i zatvoriti pomoću\",\n title: \"Pitaj AI\",\n you: \"Vi\",\n },\n banner: { dismiss: \"Zatvori obavijest\" },\n changelog: {\n description: \"Ažuriranja proizvoda i napomene o izdanjima.\",\n title: \"Popis promjena\",\n },\n content: {\n copyColor: \"Kopiraj boju {name} {value}\",\n copyPrompt: \"Kopiraj upit\",\n diagramError: \"Ovaj dijagram nije moguće prikazati.\",\n },\n feedback: {\n no: \"Ne\",\n question: \"Je li vam ova stranica bila korisna?\",\n thanks: \"Hvala na povratnoj informaciji!\",\n yes: \"Da\",\n },\n languageSwitcher: { label: \"Jezik\", untranslated: \"Nije prevedeno\" },\n nav: {\n back: \"Natrag\",\n breadcrumb: \"Navigacijski put\",\n closeNavigation: \"Zatvori navigaciju\",\n deprecated: \"zastarjelo\",\n featured: \"Istaknuto\",\n githubRepository: \"GitHub repozitorij\",\n navigation: \"Navigacija\",\n opensInNewTab: \"Otvara se u novoj kartici\",\n primary: \"Glavna\",\n sections: \"Odjeljci\",\n toggleNavigation: \"Otvori ili zatvori navigaciju\",\n toggleTheme: \"Promijeni temu boja\",\n },\n notFound: {\n description: \"Nismo mogli pronaći stranicu koju tražite.\",\n home: \"Natrag na početnu\",\n title: \"Stranica nije pronađena\",\n },\n page: {\n lastUpdated: \"Posljednje ažuriranje\",\n next: \"Sljedeće\",\n pagination: \"Straničenje\",\n previous: \"Prethodno\",\n skipToContent: \"Prijeđi na sadržaj\",\n },\n search: {\n all: \"Sve\",\n allLanguages: \"Svi jezici\",\n askAi: \"Pitaj AI\",\n askAiHint: \"Dobijte trenutačni odgovor od AI-ja\",\n button: \"Pretraži\",\n devOnly: \"Pretraživanje je dostupno u produkcijskoj verziji.\",\n error: \"Nešto je pošlo po zlu. Pokušajte ponovno.\",\n label: \"Pretraži dokumentaciju\",\n navigate: \"navigacija\",\n noResults: \"Nema rezultata.\",\n open: \"otvori\",\n placeholder: \"Pretraži dokumentaciju…\",\n popular: \"Popularno\",\n preview: \"pregled\",\n results: \"Rezultati\",\n },\n toc: { title: \"Na ovoj stranici\" },\n};\n",
|
|
27
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Hungarian (hu) UI strings. */\nexport const hu: UIStringsOverride = {\n actions: {\n addToCursor: \"Hozzáadás a Cursorhoz\",\n addToVscode: \"Hozzáadás a VS Code-hoz\",\n askAI: \"Kérdezd az AI-t erről az oldalról\",\n connectMcp: \"Kapcsolódás az MCP-hez\",\n copied: \"Másolva!\",\n copyClaudeCode: \"Claude Code parancs másolása\",\n copyCode: \"Kód másolása\",\n copyCodex: \"Codex parancs másolása\",\n copyFailed: \"A másolás nem sikerült\",\n copyMarkdown: \"Másolás Markdownként\",\n copyServerUrl: \"Szerver URL másolása\",\n edit: \"Szerkesztés a GitHubon\",\n export: \"Exportálás\",\n exportEpub: \"Exportálás EPUB-ba\",\n exportPdf: \"Exportálás PDF-be\",\n generating: \"Generálás…\",\n openIn: \"Megnyitás itt: {name}\",\n openInChat: \"Megnyitás a csevegésben\",\n openInChatPrompt:\n \"Olvasd el a következőt: {url}, hogy kérdéseket tehessek fel erről az oldalról.\",\n scrollToTop: \"Vissza a tetejére\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Beszélgetés törlése\",\n close: \"Bezárás\",\n copy: \"Beszélgetés másolása\",\n empty: \"Tegyél fel kérdést a dokumentációval kapcsolatban.\",\n error: \"Sajnáljuk, valami hiba történt.\",\n label: \"Tegyél fel egy kérdést\",\n placeholder: \"Tegyél fel egy kérdést…\",\n send: \"Küldés\",\n tip: \"Tipp: A csevegést ezzel nyithatod meg és zárhatod be:\",\n title: \"Kérdezd az AI-t\",\n you: \"Te\",\n },\n banner: { dismiss: \"Közlemény bezárása\" },\n changelog: {\n description: \"Termékfrissítések és kiadási megjegyzések.\",\n title: \"Változásnapló\",\n },\n content: {\n copyColor: \"{name} szín másolása: {value}\",\n copyPrompt: \"Prompt másolása\",\n diagramError: \"Ezt a diagramot nem sikerült megjeleníteni.\",\n },\n feedback: {\n no: \"Nem\",\n question: \"Hasznos volt ez az oldal?\",\n thanks: \"Köszönjük a visszajelzésed!\",\n yes: \"Igen\",\n },\n languageSwitcher: { label: \"Nyelv\", untranslated: \"Nincs lefordítva\" },\n nav: {\n back: \"Vissza\",\n breadcrumb: \"Morzsamenü\",\n closeNavigation: \"Navigáció bezárása\",\n deprecated: \"elavult\",\n featured: \"Kiemelt\",\n githubRepository: \"GitHub-tároló\",\n navigation: \"Navigáció\",\n opensInNewTab: \"Új lapon nyílik meg\",\n primary: \"Elsődleges\",\n sections: \"Szakaszok\",\n toggleNavigation: \"Navigáció ki-/bekapcsolása\",\n toggleTheme: \"Színtéma váltása\",\n },\n notFound: {\n description: \"Nem találtuk a keresett oldalt.\",\n home: \"Vissza a kezdőlapra\",\n title: \"Az oldal nem található\",\n },\n page: {\n lastUpdated: \"Utoljára frissítve\",\n next: \"Következő\",\n pagination: \"Lapozás\",\n previous: \"Előző\",\n skipToContent: \"Ugrás a tartalomra\",\n },\n search: {\n all: \"Összes\",\n allLanguages: \"Összes nyelv\",\n askAi: \"Kérdezd az AI-t\",\n askAiHint: \"Kapj azonnali választ az AI-tól\",\n button: \"Keresés\",\n devOnly: \"A keresés az éles buildben érhető el.\",\n error: \"Hiba történt. Próbáld újra.\",\n label: \"Keresés a dokumentációban\",\n navigate: \"navigálás\",\n noResults: \"Nincs találat.\",\n open: \"megnyitás\",\n placeholder: \"Keresés a dokumentációban…\",\n popular: \"Népszerű\",\n preview: \"előnézet\",\n results: \"Találatok\",\n },\n toc: { title: \"Ezen az oldalon\" },\n};\n",
|
|
28
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Indonesian (id) UI strings. */\nexport const id: UIStringsOverride = {\n actions: {\n addToCursor: \"Tambahkan ke Cursor\",\n addToVscode: \"Tambahkan ke VS Code\",\n askAI: \"Tanya AI tentang halaman ini\",\n connectMcp: \"Hubungkan ke MCP\",\n copied: \"Disalin!\",\n copyClaudeCode: \"Salin perintah Claude Code\",\n copyCode: \"Salin kode\",\n copyCodex: \"Salin perintah Codex\",\n copyFailed: \"Gagal menyalin\",\n copyMarkdown: \"Salin sebagai Markdown\",\n copyServerUrl: \"Salin URL server\",\n edit: \"Edit di GitHub\",\n export: \"Ekspor\",\n exportEpub: \"Ekspor ke EPUB\",\n exportPdf: \"Ekspor ke PDF\",\n generating: \"Menghasilkan…\",\n openIn: \"Buka di {name}\",\n openInChat: \"Buka di obrolan\",\n openInChatPrompt:\n \"Baca {url} agar saya bisa mengajukan pertanyaan tentang halaman ini.\",\n scrollToTop: \"Kembali ke atas\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Hapus percakapan\",\n close: \"Tutup\",\n copy: \"Salin percakapan\",\n empty: \"Ajukan pertanyaan tentang dokumentasi.\",\n error: \"Maaf, terjadi kesalahan.\",\n label: \"Ajukan pertanyaan\",\n placeholder: \"Ajukan pertanyaan…\",\n send: \"Kirim\",\n tip: \"Tips: Anda dapat membuka dan menutup obrolan dengan\",\n title: \"Tanya AI\",\n you: \"Anda\",\n },\n banner: { dismiss: \"Tutup pengumuman\" },\n changelog: {\n description: \"Pembaruan produk dan catatan rilis.\",\n title: \"Log perubahan\",\n },\n content: {\n copyColor: \"Salin warna {name} {value}\",\n copyPrompt: \"Salin prompt\",\n diagramError: \"Tidak dapat menampilkan diagram ini.\",\n },\n feedback: {\n no: \"Tidak\",\n question: \"Apakah halaman ini membantu?\",\n thanks: \"Terima kasih atas masukan Anda!\",\n yes: \"Ya\",\n },\n languageSwitcher: { label: \"Bahasa\", untranslated: \"Belum diterjemahkan\" },\n nav: {\n back: \"Kembali\",\n breadcrumb: \"Remah roti\",\n closeNavigation: \"Tutup navigasi\",\n deprecated: \"usang\",\n featured: \"Unggulan\",\n githubRepository: \"Repositori GitHub\",\n navigation: \"Navigasi\",\n opensInNewTab: \"Terbuka di tab baru\",\n primary: \"Utama\",\n sections: \"Bagian\",\n toggleNavigation: \"Buka/tutup navigasi\",\n toggleTheme: \"Ganti tema warna\",\n },\n notFound: {\n description: \"Kami tidak dapat menemukan halaman yang Anda cari.\",\n home: \"Kembali ke beranda\",\n title: \"Halaman tidak ditemukan\",\n },\n page: {\n lastUpdated: \"Terakhir diperbarui\",\n next: \"Berikutnya\",\n pagination: \"Penomoran halaman\",\n previous: \"Sebelumnya\",\n skipToContent: \"Lewati ke konten\",\n },\n search: {\n all: \"Semua\",\n allLanguages: \"Semua bahasa\",\n askAi: \"Tanya AI\",\n askAiHint: \"Dapatkan jawaban instan dari AI\",\n button: \"Cari\",\n devOnly: \"Pencarian tersedia di build produksi.\",\n error: \"Terjadi kesalahan. Silakan coba lagi.\",\n label: \"Cari dokumentasi\",\n navigate: \"navigasi\",\n noResults: \"Tidak ada hasil ditemukan.\",\n open: \"buka\",\n placeholder: \"Cari dokumentasi…\",\n popular: \"Populer\",\n preview: \"pratinjau\",\n results: \"Hasil\",\n },\n toc: { title: \"Di halaman ini\" },\n};\n",
|
|
29
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Italian (it) UI strings. */\nexport const it: UIStringsOverride = {\n actions: {\n addToCursor: \"Aggiungi a Cursor\",\n addToVscode: \"Aggiungi a VS Code\",\n askAI: \"Chiedi all'IA di questa pagina\",\n connectMcp: \"Connetti a MCP\",\n copied: \"Copiato!\",\n copyClaudeCode: \"Copia comando di Claude Code\",\n copyCode: \"Copia codice\",\n copyCodex: \"Copia comando di Codex\",\n copyFailed: \"Copia non riuscita\",\n copyMarkdown: \"Copia come Markdown\",\n copyServerUrl: \"Copia URL del server\",\n edit: \"Modifica su GitHub\",\n export: \"Esporta\",\n exportEpub: \"Esporta in EPUB\",\n exportPdf: \"Esporta in PDF\",\n generating: \"Generazione in corso…\",\n openIn: \"Apri in {name}\",\n openInChat: \"Apri nella chat\",\n openInChatPrompt: \"Leggi {url} così posso farti domande su questa pagina.\",\n scrollToTop: \"Torna su\",\n },\n ask: {\n ai: \"IA\",\n clear: \"Cancella la conversazione\",\n close: \"Chiudi\",\n copy: \"Copia la conversazione\",\n empty: \"Fai una domanda sulla documentazione.\",\n error: \"Spiacenti, qualcosa è andato storto.\",\n label: \"Fai una domanda\",\n placeholder: \"Fai una domanda…\",\n send: \"Invia\",\n tip: \"Suggerimento: puoi aprire e chiudere la chat con\",\n title: \"Chiedi all'IA\",\n you: \"Tu\",\n },\n banner: { dismiss: \"Chiudi l'annuncio\" },\n changelog: {\n description: \"Aggiornamenti del prodotto e note di rilascio.\",\n title: \"Registro delle modifiche\",\n },\n content: {\n copyColor: \"Copia il colore {name} {value}\",\n copyPrompt: \"Copia prompt\",\n diagramError: \"Impossibile visualizzare questo diagramma.\",\n },\n feedback: {\n no: \"No\",\n question: \"Questa pagina ti è stata utile?\",\n thanks: \"Grazie per il tuo feedback!\",\n yes: \"Sì\",\n },\n languageSwitcher: { label: \"Lingua\", untranslated: \"Non tradotto\" },\n nav: {\n back: \"Indietro\",\n breadcrumb: \"Percorso di navigazione\",\n closeNavigation: \"Chiudi la navigazione\",\n deprecated: \"deprecato\",\n featured: \"In evidenza\",\n githubRepository: \"Repository GitHub\",\n navigation: \"Navigazione\",\n opensInNewTab: \"Si apre in una nuova scheda\",\n primary: \"Principale\",\n sections: \"Sezioni\",\n toggleNavigation: \"Mostra o nascondi la navigazione\",\n toggleTheme: \"Cambia il tema colore\",\n },\n notFound: {\n description: \"Non siamo riusciti a trovare la pagina che cerchi.\",\n home: \"Torna alla home\",\n title: \"Pagina non trovata\",\n },\n page: {\n lastUpdated: \"Ultimo aggiornamento il\",\n next: \"Successivo\",\n pagination: \"Paginazione\",\n previous: \"Precedente\",\n skipToContent: \"Vai al contenuto\",\n },\n search: {\n all: \"Tutti\",\n allLanguages: \"Tutte le lingue\",\n askAi: \"Chiedi all'IA\",\n askAiHint: \"Ottieni una risposta immediata dall'IA\",\n button: \"Cerca\",\n devOnly: \"La ricerca è disponibile nella build di produzione.\",\n error: \"Qualcosa è andato storto. Riprova.\",\n label: \"Cerca nella documentazione\",\n navigate: \"naviga\",\n noResults: \"Nessun risultato trovato.\",\n open: \"apri\",\n placeholder: \"Cerca nella documentazione…\",\n popular: \"Popolari\",\n preview: \"anteprima\",\n results: \"Risultati\",\n },\n toc: { title: \"In questa pagina\" },\n};\n",
|
|
30
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Japanese (ja) UI strings. */\nexport const ja: UIStringsOverride = {\n actions: {\n addToCursor: \"Cursor に追加\",\n addToVscode: \"VS Code に追加\",\n askAI: \"このページについて AI に質問\",\n connectMcp: \"MCP に接続\",\n copied: \"コピーしました!\",\n copyClaudeCode: \"Claude Code コマンドをコピー\",\n copyCode: \"コードをコピー\",\n copyCodex: \"Codex コマンドをコピー\",\n copyFailed: \"コピーに失敗しました\",\n copyMarkdown: \"Markdown としてコピー\",\n copyServerUrl: \"サーバー URL をコピー\",\n edit: \"GitHub で編集\",\n export: \"エクスポート\",\n exportEpub: \"EPUB にエクスポート\",\n exportPdf: \"PDF にエクスポート\",\n generating: \"生成中…\",\n openIn: \"{name} で開く\",\n openInChat: \"チャットで開く\",\n openInChatPrompt:\n \"{url} を読んで、このページについての質問に答えられるようにしてください。\",\n scrollToTop: \"トップに戻る\",\n },\n ask: {\n ai: \"AI\",\n clear: \"会話をクリア\",\n close: \"閉じる\",\n copy: \"会話をコピー\",\n empty: \"ドキュメントについて質問してください。\",\n error: \"申し訳ありません。問題が発生しました。\",\n label: \"質問する\",\n placeholder: \"質問を入力…\",\n send: \"送信\",\n tip: \"ヒント: 次のキーでチャットを開閉できます\",\n title: \"AI に質問\",\n you: \"あなた\",\n },\n banner: { dismiss: \"お知らせを閉じる\" },\n changelog: {\n description: \"製品のアップデートとリリースノート。\",\n title: \"変更履歴\",\n },\n content: {\n copyColor: \"カラー {name}({value})をコピー\",\n copyPrompt: \"プロンプトをコピー\",\n diagramError: \"この図を表示できませんでした。\",\n },\n feedback: {\n no: \"いいえ\",\n question: \"このページは役に立ちましたか?\",\n thanks: \"フィードバックありがとうございます!\",\n yes: \"はい\",\n },\n languageSwitcher: { label: \"言語\", untranslated: \"未翻訳\" },\n nav: {\n back: \"戻る\",\n breadcrumb: \"パンくずリスト\",\n closeNavigation: \"ナビゲーションを閉じる\",\n deprecated: \"非推奨\",\n featured: \"注目\",\n githubRepository: \"GitHub リポジトリ\",\n navigation: \"ナビゲーション\",\n opensInNewTab: \"新しいタブで開きます\",\n primary: \"メイン\",\n sections: \"セクション\",\n toggleNavigation: \"ナビゲーションを切り替え\",\n toggleTheme: \"カラーテーマを切り替え\",\n },\n notFound: {\n description: \"お探しのページが見つかりませんでした。\",\n home: \"ホームに戻る\",\n title: \"ページが見つかりません\",\n },\n page: {\n lastUpdated: \"最終更新\",\n next: \"次へ\",\n pagination: \"ページネーション\",\n previous: \"前へ\",\n skipToContent: \"コンテンツにスキップ\",\n },\n search: {\n all: \"すべて\",\n allLanguages: \"すべての言語\",\n askAi: \"AI に質問\",\n askAiHint: \"AI からすぐに回答を得る\",\n button: \"検索\",\n devOnly: \"検索は本番ビルドで利用できます。\",\n error: \"問題が発生しました。もう一度お試しください。\",\n label: \"ドキュメントを検索\",\n navigate: \"移動\",\n noResults: \"結果が見つかりませんでした。\",\n open: \"開く\",\n placeholder: \"ドキュメントを検索…\",\n popular: \"人気\",\n preview: \"プレビュー\",\n results: \"結果\",\n },\n toc: { title: \"このページの内容\" },\n};\n",
|
|
31
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Korean (ko) UI strings. */\nexport const ko: UIStringsOverride = {\n actions: {\n addToCursor: \"Cursor에 추가\",\n addToVscode: \"VS Code에 추가\",\n askAI: \"이 페이지에 대해 AI에게 질문\",\n connectMcp: \"MCP에 연결\",\n copied: \"복사됨!\",\n copyClaudeCode: \"Claude Code 명령 복사\",\n copyCode: \"코드 복사\",\n copyCodex: \"Codex 명령 복사\",\n copyFailed: \"복사 실패\",\n copyMarkdown: \"Markdown으로 복사\",\n copyServerUrl: \"서버 URL 복사\",\n edit: \"GitHub에서 편집\",\n export: \"내보내기\",\n exportEpub: \"EPUB으로 내보내기\",\n exportPdf: \"PDF로 내보내기\",\n generating: \"생성 중…\",\n openIn: \"{name}에서 열기\",\n openInChat: \"채팅에서 열기\",\n openInChatPrompt:\n \"{url} 페이지를 읽어 주세요. 이 페이지에 대해 질문하겠습니다.\",\n scrollToTop: \"맨 위로\",\n },\n ask: {\n ai: \"AI\",\n clear: \"대화 지우기\",\n close: \"닫기\",\n copy: \"대화 복사\",\n empty: \"문서에 대해 질문하세요.\",\n error: \"죄송합니다. 문제가 발생했습니다.\",\n label: \"질문하기\",\n placeholder: \"질문하기…\",\n send: \"보내기\",\n tip: \"팁: 다음 키로 채팅을 열고 닫을 수 있습니다\",\n title: \"AI에게 질문\",\n you: \"나\",\n },\n banner: { dismiss: \"공지 닫기\" },\n changelog: {\n description: \"제품 업데이트 및 릴리스 노트.\",\n title: \"변경 로그\",\n },\n content: {\n copyColor: \"{name} 색상 {value} 복사\",\n copyPrompt: \"프롬프트 복사\",\n diagramError: \"이 다이어그램을 표시할 수 없습니다.\",\n },\n feedback: {\n no: \"아니요\",\n question: \"이 페이지가 도움이 되었나요?\",\n thanks: \"의견 주셔서 감사합니다!\",\n yes: \"예\",\n },\n languageSwitcher: { label: \"언어\", untranslated: \"번역되지 않음\" },\n nav: {\n back: \"뒤로\",\n breadcrumb: \"탐색 경로\",\n closeNavigation: \"탐색 닫기\",\n deprecated: \"지원 중단\",\n featured: \"추천\",\n githubRepository: \"GitHub 저장소\",\n navigation: \"탐색\",\n opensInNewTab: \"새 탭에서 열림\",\n primary: \"기본\",\n sections: \"섹션\",\n toggleNavigation: \"탐색 전환\",\n toggleTheme: \"색상 테마 전환\",\n },\n notFound: {\n description: \"찾으시는 페이지를 찾을 수 없습니다.\",\n home: \"홈으로 돌아가기\",\n title: \"페이지를 찾을 수 없습니다\",\n },\n page: {\n lastUpdated: \"마지막 업데이트\",\n next: \"다음\",\n pagination: \"페이지네이션\",\n previous: \"이전\",\n skipToContent: \"본문으로 건너뛰기\",\n },\n search: {\n all: \"전체\",\n allLanguages: \"모든 언어\",\n askAi: \"AI에게 질문\",\n askAiHint: \"AI에게 즉시 답변 받기\",\n button: \"검색\",\n devOnly: \"검색은 프로덕션 빌드에서 사용할 수 있습니다.\",\n error: \"문제가 발생했습니다. 다시 시도해 주세요.\",\n label: \"문서 검색\",\n navigate: \"이동\",\n noResults: \"결과를 찾을 수 없습니다.\",\n open: \"열기\",\n placeholder: \"문서 검색…\",\n popular: \"인기\",\n preview: \"미리보기\",\n results: \"결과\",\n },\n toc: { title: \"이 페이지에서\" },\n};\n",
|
|
32
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Dutch (nl) UI strings. */\nexport const nl: UIStringsOverride = {\n actions: {\n addToCursor: \"Toevoegen aan Cursor\",\n addToVscode: \"Toevoegen aan VS Code\",\n askAI: \"AI vragen over deze pagina\",\n connectMcp: \"Verbinden met MCP\",\n copied: \"Gekopieerd!\",\n copyClaudeCode: \"Claude Code-opdracht kopiëren\",\n copyCode: \"Code kopiëren\",\n copyCodex: \"Codex-opdracht kopiëren\",\n copyFailed: \"Kopiëren mislukt\",\n copyMarkdown: \"Kopiëren als Markdown\",\n copyServerUrl: \"Server-URL kopiëren\",\n edit: \"Bewerken op GitHub\",\n export: \"Exporteren\",\n exportEpub: \"Exporteren naar EPUB\",\n exportPdf: \"Exporteren naar PDF\",\n generating: \"Genereren…\",\n openIn: \"Openen in {name}\",\n openInChat: \"Openen in chat\",\n openInChatPrompt:\n \"Lees {url}, zodat ik je vragen kan stellen over deze pagina.\",\n scrollToTop: \"Naar boven scrollen\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Gesprek wissen\",\n close: \"Sluiten\",\n copy: \"Gesprek kopiëren\",\n empty: \"Stel een vraag over de documentatie.\",\n error: \"Sorry, er is iets misgegaan.\",\n label: \"Stel een vraag\",\n placeholder: \"Stel een vraag…\",\n send: \"Verzenden\",\n tip: \"Tip: Je kunt de chat openen en sluiten met\",\n title: \"AI vragen\",\n you: \"Jij\",\n },\n banner: { dismiss: \"Aankondiging sluiten\" },\n changelog: {\n description: \"Productupdates en releaseopmerkingen.\",\n title: \"Wijzigingslogboek\",\n },\n content: {\n copyColor: \"Kleur {name} {value} kopiëren\",\n copyPrompt: \"Prompt kopiëren\",\n diagramError: \"Dit diagram kon niet worden weergegeven.\",\n },\n feedback: {\n no: \"Nee\",\n question: \"Was deze pagina nuttig?\",\n thanks: \"Bedankt voor je feedback!\",\n yes: \"Ja\",\n },\n languageSwitcher: { label: \"Taal\", untranslated: \"Niet vertaald\" },\n nav: {\n back: \"Terug\",\n breadcrumb: \"Kruimelpad\",\n closeNavigation: \"Navigatie sluiten\",\n deprecated: \"verouderd\",\n featured: \"Uitgelicht\",\n githubRepository: \"GitHub-repository\",\n navigation: \"Navigatie\",\n opensInNewTab: \"Opent in een nieuw tabblad\",\n primary: \"Primair\",\n sections: \"Secties\",\n toggleNavigation: \"Navigatie tonen of verbergen\",\n toggleTheme: \"Kleurthema wisselen\",\n },\n notFound: {\n description: \"We konden de pagina die je zoekt niet vinden.\",\n home: \"Terug naar de startpagina\",\n title: \"Pagina niet gevonden\",\n },\n page: {\n lastUpdated: \"Laatst bijgewerkt op\",\n next: \"Volgende\",\n pagination: \"Paginering\",\n previous: \"Vorige\",\n skipToContent: \"Naar inhoud springen\",\n },\n search: {\n all: \"Alle\",\n allLanguages: \"Alle talen\",\n askAi: \"AI vragen\",\n askAiHint: \"Krijg direct antwoord van AI\",\n button: \"Zoeken\",\n devOnly: \"Zoeken is beschikbaar in de productiebuild.\",\n error: \"Er is iets misgegaan. Probeer het opnieuw.\",\n label: \"Documentatie doorzoeken\",\n navigate: \"navigeren\",\n noResults: \"Geen resultaten gevonden.\",\n open: \"openen\",\n placeholder: \"Documentatie doorzoeken…\",\n popular: \"Populair\",\n preview: \"voorbeeld\",\n results: \"Resultaten\",\n },\n toc: { title: \"Op deze pagina\" },\n};\n",
|
|
33
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Norwegian Bokmål (no) UI strings. */\nexport const no: UIStringsOverride = {\n actions: {\n addToCursor: \"Legg til i Cursor\",\n addToVscode: \"Legg til i VS Code\",\n askAI: \"Spør AI om denne siden\",\n connectMcp: \"Koble til MCP\",\n copied: \"Kopiert!\",\n copyClaudeCode: \"Kopier Claude Code-kommando\",\n copyCode: \"Kopier kode\",\n copyCodex: \"Kopier Codex-kommando\",\n copyFailed: \"Kopiering mislyktes\",\n copyMarkdown: \"Kopier som Markdown\",\n copyServerUrl: \"Kopier server-URL\",\n edit: \"Rediger på GitHub\",\n export: \"Eksporter\",\n exportEpub: \"Eksporter til EPUB\",\n exportPdf: \"Eksporter til PDF\",\n generating: \"Genererer…\",\n openIn: \"Åpne i {name}\",\n openInChat: \"Åpne i chat\",\n openInChatPrompt:\n \"Les {url}, slik at jeg kan stille spørsmål om denne siden.\",\n scrollToTop: \"Til toppen\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Tøm samtalen\",\n close: \"Lukk\",\n copy: \"Kopier samtalen\",\n empty: \"Still et spørsmål om dokumentasjonen.\",\n error: \"Beklager, noe gikk galt.\",\n label: \"Still et spørsmål\",\n placeholder: \"Still et spørsmål…\",\n send: \"Send\",\n tip: \"Tips: Du kan åpne og lukke chatten med\",\n title: \"Spør AI\",\n you: \"Du\",\n },\n banner: { dismiss: \"Lukk kunngjøringen\" },\n changelog: {\n description: \"Produktoppdateringer og utgivelsesnotater.\",\n title: \"Endringslogg\",\n },\n content: {\n copyColor: \"Kopier fargen {name} {value}\",\n copyPrompt: \"Kopier prompt\",\n diagramError: \"Kunne ikke vise dette diagrammet.\",\n },\n feedback: {\n no: \"Nei\",\n question: \"Var denne siden nyttig?\",\n thanks: \"Takk for tilbakemeldingen!\",\n yes: \"Ja\",\n },\n languageSwitcher: { label: \"Språk\", untranslated: \"Ikke oversatt\" },\n nav: {\n back: \"Tilbake\",\n breadcrumb: \"Brødsmulesti\",\n closeNavigation: \"Lukk navigasjonen\",\n deprecated: \"foreldet\",\n featured: \"Utvalgt\",\n githubRepository: \"GitHub-repositorium\",\n navigation: \"Navigasjon\",\n opensInNewTab: \"Åpnes i en ny fane\",\n primary: \"Primær\",\n sections: \"Seksjoner\",\n toggleNavigation: \"Vis eller skjul navigasjonen\",\n toggleTheme: \"Bytt fargetema\",\n },\n notFound: {\n description: \"Vi fant ikke siden du leter etter.\",\n home: \"Tilbake til forsiden\",\n title: \"Siden ble ikke funnet\",\n },\n page: {\n lastUpdated: \"Sist oppdatert\",\n next: \"Neste\",\n pagination: \"Paginering\",\n previous: \"Forrige\",\n skipToContent: \"Hopp til innhold\",\n },\n search: {\n all: \"Alle\",\n allLanguages: \"Alle språk\",\n askAi: \"Spør AI\",\n askAiHint: \"Få et umiddelbart svar fra AI\",\n button: \"Søk\",\n devOnly: \"Søk er tilgjengelig i produksjonsbygget.\",\n error: \"Noe gikk galt. Prøv igjen.\",\n label: \"Søk i dokumentasjonen\",\n navigate: \"naviger\",\n noResults: \"Ingen resultater funnet.\",\n open: \"åpne\",\n placeholder: \"Søk i dokumentasjonen…\",\n popular: \"Populært\",\n preview: \"forhåndsvis\",\n results: \"Resultater\",\n },\n toc: { title: \"På denne siden\" },\n};\n",
|
|
34
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Polish (pl) UI strings. */\nexport const pl: UIStringsOverride = {\n actions: {\n addToCursor: \"Dodaj do Cursor\",\n addToVscode: \"Dodaj do VS Code\",\n askAI: \"Zapytaj AI o tę stronę\",\n connectMcp: \"Połącz z MCP\",\n copied: \"Skopiowano!\",\n copyClaudeCode: \"Kopiuj polecenie Claude Code\",\n copyCode: \"Kopiuj kod\",\n copyCodex: \"Kopiuj polecenie Codex\",\n copyFailed: \"Kopiowanie nie powiodło się\",\n copyMarkdown: \"Kopiuj jako Markdown\",\n copyServerUrl: \"Kopiuj adres URL serwera\",\n edit: \"Edytuj na GitHubie\",\n export: \"Eksportuj\",\n exportEpub: \"Eksportuj do EPUB\",\n exportPdf: \"Eksportuj do PDF\",\n generating: \"Generowanie…\",\n openIn: \"Otwórz w {name}\",\n openInChat: \"Otwórz w czacie\",\n openInChatPrompt:\n \"Przeczytaj {url}, aby móc odpowiadać na pytania dotyczące tej strony.\",\n scrollToTop: \"Wróć na górę\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Wyczyść rozmowę\",\n close: \"Zamknij\",\n copy: \"Kopiuj rozmowę\",\n empty: \"Zadaj pytanie dotyczące dokumentacji.\",\n error: \"Przepraszamy, coś poszło nie tak.\",\n label: \"Zadaj pytanie\",\n placeholder: \"Zadaj pytanie…\",\n send: \"Wyślij\",\n tip: \"Wskazówka: czat możesz otwierać i zamykać za pomocą\",\n title: \"Zapytaj AI\",\n you: \"Ty\",\n },\n banner: { dismiss: \"Zamknij ogłoszenie\" },\n changelog: {\n description: \"Aktualizacje produktu i informacje o wydaniach.\",\n title: \"Dziennik zmian\",\n },\n content: {\n copyColor: \"Kopiuj kolor {name} {value}\",\n copyPrompt: \"Kopiuj prompt\",\n diagramError: \"Nie udało się wyświetlić tego diagramu.\",\n },\n feedback: {\n no: \"Nie\",\n question: \"Czy ta strona była pomocna?\",\n thanks: \"Dziękujemy za opinię!\",\n yes: \"Tak\",\n },\n languageSwitcher: { label: \"Język\", untranslated: \"Nieprzetłumaczone\" },\n nav: {\n back: \"Wstecz\",\n breadcrumb: \"Ścieżka nawigacyjna\",\n closeNavigation: \"Zamknij nawigację\",\n deprecated: \"przestarzałe\",\n featured: \"Polecane\",\n githubRepository: \"Repozytorium GitHub\",\n navigation: \"Nawigacja\",\n opensInNewTab: \"Otwiera się w nowej karcie\",\n primary: \"Główne\",\n sections: \"Sekcje\",\n toggleNavigation: \"Przełącz nawigację\",\n toggleTheme: \"Przełącz motyw kolorystyczny\",\n },\n notFound: {\n description: \"Nie znaleźliśmy strony, której szukasz.\",\n home: \"Wróć na stronę główną\",\n title: \"Nie znaleziono strony\",\n },\n page: {\n lastUpdated: \"Ostatnia aktualizacja\",\n next: \"Następny\",\n pagination: \"Paginacja\",\n previous: \"Poprzedni\",\n skipToContent: \"Przejdź do treści\",\n },\n search: {\n all: \"Wszystkie\",\n allLanguages: \"Wszystkie języki\",\n askAi: \"Zapytaj AI\",\n askAiHint: \"Uzyskaj natychmiastową odpowiedź od AI\",\n button: \"Szukaj\",\n devOnly: \"Wyszukiwanie jest dostępne w kompilacji produkcyjnej.\",\n error: \"Coś poszło nie tak. Spróbuj ponownie.\",\n label: \"Przeszukaj dokumentację\",\n navigate: \"nawigacja\",\n noResults: \"Nie znaleziono wyników.\",\n open: \"otwórz\",\n placeholder: \"Przeszukaj dokumentację…\",\n popular: \"Popularne\",\n preview: \"podgląd\",\n results: \"Wyniki\",\n },\n toc: { title: \"Na tej stronie\" },\n};\n",
|
|
35
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Portuguese — Brazil (pt-BR) UI strings. */\nexport const ptBR: UIStringsOverride = {\n actions: {\n addToCursor: \"Adicionar ao Cursor\",\n addToVscode: \"Adicionar ao VS Code\",\n askAI: \"Perguntar à IA sobre esta página\",\n connectMcp: \"Conectar ao MCP\",\n copied: \"Copiado!\",\n copyClaudeCode: \"Copiar comando do Claude Code\",\n copyCode: \"Copiar código\",\n copyCodex: \"Copiar comando do Codex\",\n copyFailed: \"Falha ao copiar\",\n copyMarkdown: \"Copiar como Markdown\",\n copyServerUrl: \"Copiar URL do servidor\",\n edit: \"Editar no GitHub\",\n export: \"Exportar\",\n exportEpub: \"Exportar para EPUB\",\n exportPdf: \"Exportar para PDF\",\n generating: \"Gerando…\",\n openIn: \"Abrir em {name}\",\n openInChat: \"Abrir no chat\",\n openInChatPrompt:\n \"Leia {url} para que eu possa fazer perguntas sobre esta página.\",\n scrollToTop: \"Voltar ao topo\",\n },\n ask: {\n ai: \"IA\",\n clear: \"Limpar a conversa\",\n close: \"Fechar\",\n copy: \"Copiar a conversa\",\n empty: \"Faça uma pergunta sobre a documentação.\",\n error: \"Desculpe, algo deu errado.\",\n label: \"Faça uma pergunta\",\n placeholder: \"Faça uma pergunta…\",\n send: \"Enviar\",\n tip: \"Dica: você pode abrir e fechar o chat com\",\n title: \"Perguntar à IA\",\n you: \"Você\",\n },\n banner: { dismiss: \"Fechar o anúncio\" },\n changelog: {\n description: \"Atualizações do produto e notas de lançamento.\",\n title: \"Registro de alterações\",\n },\n content: {\n copyColor: \"Copiar a cor {name} {value}\",\n copyPrompt: \"Copiar prompt\",\n diagramError: \"Não foi possível renderizar este diagrama.\",\n },\n feedback: {\n no: \"Não\",\n question: \"Esta página foi útil?\",\n thanks: \"Obrigado pelo seu feedback!\",\n yes: \"Sim\",\n },\n languageSwitcher: { label: \"Idioma\", untranslated: \"Não traduzido\" },\n nav: {\n back: \"Voltar\",\n breadcrumb: \"Trilha de navegação\",\n closeNavigation: \"Fechar a navegação\",\n deprecated: \"obsoleto\",\n featured: \"Em destaque\",\n githubRepository: \"Repositório do GitHub\",\n navigation: \"Navegação\",\n opensInNewTab: \"Abre em uma nova aba\",\n primary: \"Principal\",\n sections: \"Seções\",\n toggleNavigation: \"Mostrar ou ocultar a navegação\",\n toggleTheme: \"Alternar o tema de cores\",\n },\n notFound: {\n description: \"Não encontramos a página que você está procurando.\",\n home: \"Voltar para a página inicial\",\n title: \"Página não encontrada\",\n },\n page: {\n lastUpdated: \"Última atualização em\",\n next: \"Próximo\",\n pagination: \"Paginação\",\n previous: \"Anterior\",\n skipToContent: \"Pular para o conteúdo\",\n },\n search: {\n all: \"Todos\",\n allLanguages: \"Todos os idiomas\",\n askAi: \"Perguntar à IA\",\n askAiHint: \"Obtenha uma resposta instantânea da IA\",\n button: \"Pesquisar\",\n devOnly: \"A busca está disponível na build de produção.\",\n error: \"Algo deu errado. Tente novamente.\",\n label: \"Pesquisar na documentação\",\n navigate: \"navegar\",\n noResults: \"Nenhum resultado encontrado.\",\n open: \"abrir\",\n placeholder: \"Pesquisar na documentação…\",\n popular: \"Populares\",\n preview: \"pré-visualizar\",\n results: \"Resultados\",\n },\n toc: { title: \"Nesta página\" },\n};\n",
|
|
36
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Portuguese (pt) UI strings. */\nexport const pt: UIStringsOverride = {\n actions: {\n addToCursor: \"Adicionar ao Cursor\",\n addToVscode: \"Adicionar ao VS Code\",\n askAI: \"Perguntar à IA sobre esta página\",\n connectMcp: \"Ligar ao MCP\",\n copied: \"Copiado!\",\n copyClaudeCode: \"Copiar comando do Claude Code\",\n copyCode: \"Copiar código\",\n copyCodex: \"Copiar comando do Codex\",\n copyFailed: \"Falha ao copiar\",\n copyMarkdown: \"Copiar como Markdown\",\n copyServerUrl: \"Copiar URL do servidor\",\n edit: \"Editar no GitHub\",\n export: \"Exportar\",\n exportEpub: \"Exportar para EPUB\",\n exportPdf: \"Exportar para PDF\",\n generating: \"A gerar…\",\n openIn: \"Abrir em {name}\",\n openInChat: \"Abrir no chat\",\n openInChatPrompt:\n \"Leia {url} para que eu possa fazer perguntas sobre esta página.\",\n scrollToTop: \"Voltar ao topo\",\n },\n ask: {\n ai: \"IA\",\n clear: \"Limpar a conversa\",\n close: \"Fechar\",\n copy: \"Copiar a conversa\",\n empty: \"Faça uma pergunta sobre a documentação.\",\n error: \"Lamentamos, algo correu mal.\",\n label: \"Faça uma pergunta\",\n placeholder: \"Faça uma pergunta…\",\n send: \"Enviar\",\n tip: \"Dica: pode abrir e fechar o chat com\",\n title: \"Perguntar à IA\",\n you: \"Você\",\n },\n banner: { dismiss: \"Fechar o anúncio\" },\n changelog: {\n description: \"Atualizações do produto e notas de lançamento.\",\n title: \"Registo de alterações\",\n },\n content: {\n copyColor: \"Copiar a cor {name} {value}\",\n copyPrompt: \"Copiar prompt\",\n diagramError: \"Não foi possível apresentar este diagrama.\",\n },\n feedback: {\n no: \"Não\",\n question: \"Esta página foi útil?\",\n thanks: \"Obrigado pelo seu feedback!\",\n yes: \"Sim\",\n },\n languageSwitcher: { label: \"Idioma\", untranslated: \"Não traduzido\" },\n nav: {\n back: \"Voltar\",\n breadcrumb: \"Caminho de navegação\",\n closeNavigation: \"Fechar a navegação\",\n deprecated: \"obsoleto\",\n featured: \"Em destaque\",\n githubRepository: \"Repositório do GitHub\",\n navigation: \"Navegação\",\n opensInNewTab: \"Abre num novo separador\",\n primary: \"Principal\",\n sections: \"Secções\",\n toggleNavigation: \"Mostrar ou ocultar a navegação\",\n toggleTheme: \"Alternar o tema de cores\",\n },\n notFound: {\n description: \"Não encontrámos a página que procura.\",\n home: \"Voltar à página inicial\",\n title: \"Página não encontrada\",\n },\n page: {\n lastUpdated: \"Última atualização a\",\n next: \"Seguinte\",\n pagination: \"Paginação\",\n previous: \"Anterior\",\n skipToContent: \"Saltar para o conteúdo\",\n },\n search: {\n all: \"Todos\",\n allLanguages: \"Todos os idiomas\",\n askAi: \"Perguntar à IA\",\n askAiHint: \"Obtenha uma resposta instantânea da IA\",\n button: \"Pesquisar\",\n devOnly: \"A pesquisa está disponível na compilação de produção.\",\n error: \"Algo correu mal. Tente novamente.\",\n label: \"Pesquisar na documentação\",\n navigate: \"navegar\",\n noResults: \"Nenhum resultado encontrado.\",\n open: \"abrir\",\n placeholder: \"Pesquisar na documentação…\",\n popular: \"Populares\",\n preview: \"pré-visualizar\",\n results: \"Resultados\",\n },\n toc: { title: \"Nesta página\" },\n};\n",
|
|
37
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Romanian (ro) UI strings. */\nexport const ro: UIStringsOverride = {\n actions: {\n addToCursor: \"Adaugă în Cursor\",\n addToVscode: \"Adaugă în VS Code\",\n askAI: \"Întreabă AI despre această pagină\",\n connectMcp: \"Conectează-te la MCP\",\n copied: \"Copiat!\",\n copyClaudeCode: \"Copiază comanda Claude Code\",\n copyCode: \"Copiază codul\",\n copyCodex: \"Copiază comanda Codex\",\n copyFailed: \"Copierea a eșuat\",\n copyMarkdown: \"Copiază ca Markdown\",\n copyServerUrl: \"Copiază URL-ul serverului\",\n edit: \"Editează pe GitHub\",\n export: \"Exportă\",\n exportEpub: \"Exportă ca EPUB\",\n exportPdf: \"Exportă ca PDF\",\n generating: \"Se generează…\",\n openIn: \"Deschide în {name}\",\n openInChat: \"Deschide în chat\",\n openInChatPrompt:\n \"Citește {url} ca să îți pot pune întrebări despre această pagină.\",\n scrollToTop: \"Sus de tot\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Șterge conversația\",\n close: \"Închide\",\n copy: \"Copiază conversația\",\n empty: \"Pune o întrebare despre documentație.\",\n error: \"Ne pare rău, ceva nu a mers bine.\",\n label: \"Pune o întrebare\",\n placeholder: \"Pune o întrebare…\",\n send: \"Trimite\",\n tip: \"Sfat: Poți deschide și închide chatul cu\",\n title: \"Întreabă AI\",\n you: \"Tu\",\n },\n banner: { dismiss: \"Închide anunțul\" },\n changelog: {\n description: \"Actualizări ale produsului și note de lansare.\",\n title: \"Jurnal de modificări\",\n },\n content: {\n copyColor: \"Copiază culoarea {name} {value}\",\n copyPrompt: \"Copiază promptul\",\n diagramError: \"Nu s-a putut reda această diagramă.\",\n },\n feedback: {\n no: \"Nu\",\n question: \"Ți-a fost utilă această pagină?\",\n thanks: \"Mulțumim pentru feedback!\",\n yes: \"Da\",\n },\n languageSwitcher: { label: \"Limbă\", untranslated: \"Netradus\" },\n nav: {\n back: \"Înapoi\",\n breadcrumb: \"Cale de navigare\",\n closeNavigation: \"Închide navigarea\",\n deprecated: \"învechit\",\n featured: \"Recomandate\",\n githubRepository: \"Depozit GitHub\",\n navigation: \"Navigare\",\n opensInNewTab: \"Se deschide într-o filă nouă\",\n primary: \"Principal\",\n sections: \"Secțiuni\",\n toggleNavigation: \"Comută navigarea\",\n toggleTheme: \"Comută tema de culoare\",\n },\n notFound: {\n description: \"Nu am găsit pagina pe care o cauți.\",\n home: \"Înapoi la pagina principală\",\n title: \"Pagina nu a fost găsită\",\n },\n page: {\n lastUpdated: \"Ultima actualizare\",\n next: \"Următorul\",\n pagination: \"Paginare\",\n previous: \"Anteriorul\",\n skipToContent: \"Sari la conținut\",\n },\n search: {\n all: \"Toate\",\n allLanguages: \"Toate limbile\",\n askAi: \"Întreabă AI\",\n askAiHint: \"Primește un răspuns instantaneu de la AI\",\n button: \"Caută\",\n devOnly: \"Căutarea este disponibilă în versiunea de producție.\",\n error: \"Ceva nu a mers bine. Încearcă din nou.\",\n label: \"Caută în documentație\",\n navigate: \"navighează\",\n noResults: \"Niciun rezultat găsit.\",\n open: \"deschide\",\n placeholder: \"Caută în documentație…\",\n popular: \"Populare\",\n preview: \"previzualizează\",\n results: \"Rezultate\",\n },\n toc: { title: \"Pe această pagină\" },\n};\n",
|
|
38
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Russian (ru) UI strings. */\nexport const ru: UIStringsOverride = {\n actions: {\n addToCursor: \"Добавить в Cursor\",\n addToVscode: \"Добавить в VS Code\",\n askAI: \"Спросить ИИ об этой странице\",\n connectMcp: \"Подключиться к MCP\",\n copied: \"Скопировано!\",\n copyClaudeCode: \"Скопировать команду Claude Code\",\n copyCode: \"Скопировать код\",\n copyCodex: \"Скопировать команду Codex\",\n copyFailed: \"Не удалось скопировать\",\n copyMarkdown: \"Скопировать как Markdown\",\n copyServerUrl: \"Скопировать URL сервера\",\n edit: \"Редактировать на GitHub\",\n export: \"Экспорт\",\n exportEpub: \"Экспорт в EPUB\",\n exportPdf: \"Экспорт в PDF\",\n generating: \"Генерация…\",\n openIn: \"Открыть в {name}\",\n openInChat: \"Открыть в чате\",\n openInChatPrompt:\n \"Прочитайте {url} — я буду задавать вопросы об этой странице.\",\n scrollToTop: \"Наверх\",\n },\n ask: {\n ai: \"ИИ\",\n clear: \"Очистить беседу\",\n close: \"Закрыть\",\n copy: \"Скопировать беседу\",\n empty: \"Задайте вопрос по документации.\",\n error: \"Извините, что-то пошло не так.\",\n label: \"Задать вопрос\",\n placeholder: \"Задайте вопрос…\",\n send: \"Отправить\",\n tip: \"Совет: чат можно открыть и закрыть с помощью\",\n title: \"Спросить ИИ\",\n you: \"Вы\",\n },\n banner: { dismiss: \"Закрыть объявление\" },\n changelog: {\n description: \"Обновления продукта и примечания к выпускам.\",\n title: \"Журнал изменений\",\n },\n content: {\n copyColor: \"Скопировать цвет {name} {value}\",\n copyPrompt: \"Скопировать промпт\",\n diagramError: \"Не удалось отобразить эту диаграмму.\",\n },\n feedback: {\n no: \"Нет\",\n question: \"Эта страница была полезной?\",\n thanks: \"Спасибо за ваш отзыв!\",\n yes: \"Да\",\n },\n languageSwitcher: { label: \"Язык\", untranslated: \"Не переведено\" },\n nav: {\n back: \"Назад\",\n breadcrumb: \"Навигационная цепочка\",\n closeNavigation: \"Закрыть навигацию\",\n deprecated: \"устарело\",\n featured: \"Рекомендуемое\",\n githubRepository: \"Репозиторий GitHub\",\n navigation: \"Навигация\",\n opensInNewTab: \"Открывается в новой вкладке\",\n primary: \"Основное\",\n sections: \"Разделы\",\n toggleNavigation: \"Переключить навигацию\",\n toggleTheme: \"Переключить цветовую тему\",\n },\n notFound: {\n description: \"Не удалось найти страницу, которую вы ищете.\",\n home: \"Вернуться на главную\",\n title: \"Страница не найдена\",\n },\n page: {\n lastUpdated: \"Последнее обновление\",\n next: \"Далее\",\n pagination: \"Пагинация\",\n previous: \"Назад\",\n skipToContent: \"Перейти к содержимому\",\n },\n search: {\n all: \"Все\",\n allLanguages: \"Все языки\",\n askAi: \"Спросить ИИ\",\n askAiHint: \"Получите мгновенный ответ от ИИ\",\n button: \"Поиск\",\n devOnly: \"Поиск доступен в production-сборке.\",\n error: \"Что-то пошло не так. Попробуйте ещё раз.\",\n label: \"Поиск по документации\",\n navigate: \"навигация\",\n noResults: \"Ничего не найдено.\",\n open: \"открыть\",\n placeholder: \"Поиск по документации…\",\n popular: \"Популярное\",\n preview: \"предпросмотр\",\n results: \"Результаты\",\n },\n toc: { title: \"На этой странице\" },\n};\n",
|
|
39
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Slovak (sk) UI strings. */\nexport const sk: UIStringsOverride = {\n actions: {\n addToCursor: \"Pridať do Cursoru\",\n addToVscode: \"Pridať do VS Code\",\n askAI: \"Opýtať sa AI na túto stránku\",\n connectMcp: \"Pripojiť k MCP\",\n copied: \"Skopírované!\",\n copyClaudeCode: \"Kopírovať príkaz Claude Code\",\n copyCode: \"Kopírovať kód\",\n copyCodex: \"Kopírovať príkaz Codex\",\n copyFailed: \"Kopírovanie zlyhalo\",\n copyMarkdown: \"Kopírovať ako Markdown\",\n copyServerUrl: \"Kopírovať URL servera\",\n edit: \"Upraviť na GitHube\",\n export: \"Exportovať\",\n exportEpub: \"Exportovať do EPUB\",\n exportPdf: \"Exportovať do PDF\",\n generating: \"Generovanie…\",\n openIn: \"Otvoriť v {name}\",\n openInChat: \"Otvoriť v chate\",\n openInChatPrompt: \"Prečítajte si {url} — budem sa pýtať na túto stránku.\",\n scrollToTop: \"Späť nahor\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Vymazať konverzáciu\",\n close: \"Zavrieť\",\n copy: \"Kopírovať konverzáciu\",\n empty: \"Opýtajte sa na dokumentáciu.\",\n error: \"Ospravedlňujeme sa, niečo sa pokazilo.\",\n label: \"Položiť otázku\",\n placeholder: \"Položiť otázku…\",\n send: \"Odoslať\",\n tip: \"Tip: Chat môžete otvoriť a zavrieť pomocou\",\n title: \"Opýtať sa AI\",\n you: \"Vy\",\n },\n banner: { dismiss: \"Zavrieť oznámenie\" },\n changelog: {\n description: \"Novinky produktu a poznámky k vydaniu.\",\n title: \"Zoznam zmien\",\n },\n content: {\n copyColor: \"Kopírovať farbu {name} {value}\",\n copyPrompt: \"Kopírovať prompt\",\n diagramError: \"Tento diagram sa nepodarilo vykresliť.\",\n },\n feedback: {\n no: \"Nie\",\n question: \"Bola táto stránka užitočná?\",\n thanks: \"Ďakujeme za vašu spätnú väzbu!\",\n yes: \"Áno\",\n },\n languageSwitcher: { label: \"Jazyk\", untranslated: \"Nepreložené\" },\n nav: {\n back: \"Späť\",\n breadcrumb: \"Omrvinková navigácia\",\n closeNavigation: \"Zavrieť navigáciu\",\n deprecated: \"zastarané\",\n featured: \"Odporúčané\",\n githubRepository: \"Repozitár na GitHube\",\n navigation: \"Navigácia\",\n opensInNewTab: \"Otvorí sa na novej karte\",\n primary: \"Hlavné\",\n sections: \"Sekcie\",\n toggleNavigation: \"Prepnúť navigáciu\",\n toggleTheme: \"Prepnúť farebný motív\",\n },\n notFound: {\n description: \"Stránku, ktorú hľadáte, sa nepodarilo nájsť.\",\n home: \"Späť na úvodnú stránku\",\n title: \"Stránka sa nenašla\",\n },\n page: {\n lastUpdated: \"Naposledy aktualizované\",\n next: \"Ďalej\",\n pagination: \"Stránkovanie\",\n previous: \"Predchádzajúce\",\n skipToContent: \"Prejsť na obsah\",\n },\n search: {\n all: \"Všetko\",\n allLanguages: \"Všetky jazyky\",\n askAi: \"Opýtať sa AI\",\n askAiHint: \"Získajte okamžitú odpoveď od AI\",\n button: \"Hľadať\",\n devOnly: \"Vyhľadávanie je dostupné v produkčnom builde.\",\n error: \"Niečo sa pokazilo. Skúste to znova.\",\n label: \"Prehľadať dokumentáciu\",\n navigate: \"navigácia\",\n noResults: \"Nenašli sa žiadne výsledky.\",\n open: \"otvoriť\",\n placeholder: \"Prehľadať dokumentáciu…\",\n popular: \"Populárne\",\n preview: \"náhľad\",\n results: \"Výsledky\",\n },\n toc: { title: \"Na tejto stránke\" },\n};\n",
|
|
40
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Serbian (sr) UI strings. */\nexport const sr: UIStringsOverride = {\n actions: {\n addToCursor: \"Додај у Cursor\",\n addToVscode: \"Додај у VS Code\",\n askAI: \"Питајте AI о овој страници\",\n connectMcp: \"Повежи се са MCP-ом\",\n copied: \"Копирано!\",\n copyClaudeCode: \"Копирај Claude Code команду\",\n copyCode: \"Копирај код\",\n copyCodex: \"Копирај Codex команду\",\n copyFailed: \"Копирање није успело\",\n copyMarkdown: \"Копирај као Markdown\",\n copyServerUrl: \"Копирај URL сервера\",\n edit: \"Уреди на GitHub-у\",\n export: \"Извези\",\n exportEpub: \"Извези у EPUB\",\n exportPdf: \"Извези у PDF\",\n generating: \"Генерисање…\",\n openIn: \"Отвори у {name}\",\n openInChat: \"Отвори у ћаскању\",\n openInChatPrompt: \"Прочитајте {url} — постављаћу питања о овој страници.\",\n scrollToTop: \"Назад на врх\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Обриши разговор\",\n close: \"Затвори\",\n copy: \"Копирај разговор\",\n empty: \"Поставите питање о документацији.\",\n error: \"Жао нам је, нешто је пошло наопако.\",\n label: \"Постави питање\",\n placeholder: \"Поставите питање…\",\n send: \"Пошаљи\",\n tip: \"Савет: Ћаскање можете отворити и затворити помоћу\",\n title: \"Питајте AI\",\n you: \"Ви\",\n },\n banner: { dismiss: \"Затвори обавештење\" },\n changelog: {\n description: \"Ажурирања производа и белешке о издањима.\",\n title: \"Дневник измена\",\n },\n content: {\n copyColor: \"Копирај боју {name} {value}\",\n copyPrompt: \"Копирај упит\",\n diagramError: \"Није могуће приказати овај дијаграм.\",\n },\n feedback: {\n no: \"Не\",\n question: \"Да ли вам је ова страница помогла?\",\n thanks: \"Хвала на вашој повратној информацији!\",\n yes: \"Да\",\n },\n languageSwitcher: { label: \"Језик\", untranslated: \"Није преведено\" },\n nav: {\n back: \"Назад\",\n breadcrumb: \"Путања навигације\",\n closeNavigation: \"Затвори навигацију\",\n deprecated: \"застарело\",\n featured: \"Истакнуто\",\n githubRepository: \"GitHub репозиторијум\",\n navigation: \"Навигација\",\n opensInNewTab: \"Отвара се у новој картици\",\n primary: \"Главна\",\n sections: \"Одељци\",\n toggleNavigation: \"Отвори или затвори навигацију\",\n toggleTheme: \"Промени тему боја\",\n },\n notFound: {\n description: \"Нисмо могли да пронађемо страницу коју тражите.\",\n home: \"Назад на почетну\",\n title: \"Страница није пронађена\",\n },\n page: {\n lastUpdated: \"Последње ажурирање\",\n next: \"Следеће\",\n pagination: \"Пагинација\",\n previous: \"Претходно\",\n skipToContent: \"Пређи на садржај\",\n },\n search: {\n all: \"Све\",\n allLanguages: \"Сви језици\",\n askAi: \"Питајте AI\",\n askAiHint: \"Добијте тренутан одговор од AI-ја\",\n button: \"Претражи\",\n devOnly: \"Претрага је доступна у продукцијској верзији.\",\n error: \"Нешто је пошло наопако. Покушајте поново.\",\n label: \"Претражи документацију\",\n navigate: \"навигација\",\n noResults: \"Нема резултата.\",\n open: \"отвори\",\n placeholder: \"Претражи документацију…\",\n popular: \"Популарно\",\n preview: \"преглед\",\n results: \"Резултати\",\n },\n toc: { title: \"На овој страници\" },\n};\n",
|
|
41
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Swedish (sv) UI strings. */\nexport const sv: UIStringsOverride = {\n actions: {\n addToCursor: \"Lägg till i Cursor\",\n addToVscode: \"Lägg till i VS Code\",\n askAI: \"Fråga AI om den här sidan\",\n connectMcp: \"Anslut till MCP\",\n copied: \"Kopierat!\",\n copyClaudeCode: \"Kopiera Claude Code-kommando\",\n copyCode: \"Kopiera kod\",\n copyCodex: \"Kopiera Codex-kommando\",\n copyFailed: \"Kopiering misslyckades\",\n copyMarkdown: \"Kopiera som Markdown\",\n copyServerUrl: \"Kopiera server-URL\",\n edit: \"Redigera på GitHub\",\n export: \"Exportera\",\n exportEpub: \"Exportera till EPUB\",\n exportPdf: \"Exportera till PDF\",\n generating: \"Genererar…\",\n openIn: \"Öppna i {name}\",\n openInChat: \"Öppna i chatt\",\n openInChatPrompt:\n \"Läs {url} så att jag kan ställa frågor om den här sidan.\",\n scrollToTop: \"Till toppen\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Rensa konversationen\",\n close: \"Stäng\",\n copy: \"Kopiera konversationen\",\n empty: \"Ställ en fråga om dokumentationen.\",\n error: \"Tyvärr, något gick fel.\",\n label: \"Ställ en fråga\",\n placeholder: \"Ställ en fråga…\",\n send: \"Skicka\",\n tip: \"Tips: Du kan öppna och stänga chatten med\",\n title: \"Fråga AI\",\n you: \"Du\",\n },\n banner: { dismiss: \"Stäng meddelandet\" },\n changelog: {\n description: \"Produktuppdateringar och versionsinformation.\",\n title: \"Ändringslogg\",\n },\n content: {\n copyColor: \"Kopiera färgen {name} {value}\",\n copyPrompt: \"Kopiera prompt\",\n diagramError: \"Det här diagrammet kunde inte visas.\",\n },\n feedback: {\n no: \"Nej\",\n question: \"Var den här sidan till hjälp?\",\n thanks: \"Tack för din feedback!\",\n yes: \"Ja\",\n },\n languageSwitcher: { label: \"Språk\", untranslated: \"Inte översatt\" },\n nav: {\n back: \"Tillbaka\",\n breadcrumb: \"Brödsmulor\",\n closeNavigation: \"Stäng navigeringen\",\n deprecated: \"utfasad\",\n featured: \"Utvalda\",\n githubRepository: \"GitHub-repository\",\n navigation: \"Navigering\",\n opensInNewTab: \"Öppnas i en ny flik\",\n primary: \"Primär\",\n sections: \"Avsnitt\",\n toggleNavigation: \"Växla navigering\",\n toggleTheme: \"Växla färgtema\",\n },\n notFound: {\n description: \"Vi kunde inte hitta sidan du letar efter.\",\n home: \"Tillbaka till startsidan\",\n title: \"Sidan hittades inte\",\n },\n page: {\n lastUpdated: \"Senast uppdaterad\",\n next: \"Nästa\",\n pagination: \"Paginering\",\n previous: \"Föregående\",\n skipToContent: \"Hoppa till innehåll\",\n },\n search: {\n all: \"Alla\",\n allLanguages: \"Alla språk\",\n askAi: \"Fråga AI\",\n askAiHint: \"Få ett omedelbart svar från AI\",\n button: \"Sök\",\n devOnly: \"Sökning är tillgänglig i produktionsbygget.\",\n error: \"Något gick fel. Försök igen.\",\n label: \"Sök i dokumentationen\",\n navigate: \"navigera\",\n noResults: \"Inga resultat hittades.\",\n open: \"öppna\",\n placeholder: \"Sök i dokumentationen…\",\n popular: \"Populärt\",\n preview: \"förhandsvisa\",\n results: \"Resultat\",\n },\n toc: { title: \"På den här sidan\" },\n};\n",
|
|
42
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Thai (th) UI strings. */\nexport const th: UIStringsOverride = {\n actions: {\n addToCursor: \"เพิ่มไปยัง Cursor\",\n addToVscode: \"เพิ่มไปยัง VS Code\",\n askAI: \"ถาม AI เกี่ยวกับหน้านี้\",\n connectMcp: \"เชื่อมต่อกับ MCP\",\n copied: \"คัดลอกแล้ว!\",\n copyClaudeCode: \"คัดลอกคำสั่ง Claude Code\",\n copyCode: \"คัดลอกโค้ด\",\n copyCodex: \"คัดลอกคำสั่ง Codex\",\n copyFailed: \"คัดลอกไม่สำเร็จ\",\n copyMarkdown: \"คัดลอกเป็น Markdown\",\n copyServerUrl: \"คัดลอก URL ของเซิร์ฟเวอร์\",\n edit: \"แก้ไขบน GitHub\",\n export: \"ส่งออก\",\n exportEpub: \"ส่งออกเป็น EPUB\",\n exportPdf: \"ส่งออกเป็น PDF\",\n generating: \"กำลังสร้าง…\",\n openIn: \"เปิดใน {name}\",\n openInChat: \"เปิดในแชท\",\n openInChatPrompt: \"อ่าน {url} เพื่อให้ฉันถามคำถามเกี่ยวกับหน้านี้ได้\",\n scrollToTop: \"กลับไปด้านบน\",\n },\n ask: {\n ai: \"AI\",\n clear: \"ล้างการสนทนา\",\n close: \"ปิด\",\n copy: \"คัดลอกการสนทนา\",\n empty: \"ถามคำถามเกี่ยวกับเอกสาร\",\n error: \"ขออภัย เกิดข้อผิดพลาดบางอย่าง\",\n label: \"ถามคำถาม\",\n placeholder: \"ถามคำถาม…\",\n send: \"ส่ง\",\n tip: \"เคล็ดลับ: คุณสามารถเปิดและปิดแชทได้ด้วย\",\n title: \"ถาม AI\",\n you: \"คุณ\",\n },\n banner: { dismiss: \"ปิดประกาศ\" },\n changelog: {\n description: \"อัปเดตผลิตภัณฑ์และบันทึกประจำรุ่น\",\n title: \"บันทึกการเปลี่ยนแปลง\",\n },\n content: {\n copyColor: \"คัดลอกสี {name} {value}\",\n copyPrompt: \"คัดลอกพรอมต์\",\n diagramError: \"ไม่สามารถแสดงไดอะแกรมนี้ได้\",\n },\n feedback: {\n no: \"ไม่\",\n question: \"หน้านี้มีประโยชน์หรือไม่?\",\n thanks: \"ขอบคุณสำหรับความคิดเห็นของคุณ!\",\n yes: \"ใช่\",\n },\n languageSwitcher: { label: \"ภาษา\", untranslated: \"ยังไม่ได้แปล\" },\n nav: {\n back: \"ย้อนกลับ\",\n breadcrumb: \"เส้นทางนำทาง\",\n closeNavigation: \"ปิดการนำทาง\",\n deprecated: \"เลิกใช้แล้ว\",\n featured: \"แนะนำ\",\n githubRepository: \"ที่เก็บ GitHub\",\n navigation: \"การนำทาง\",\n opensInNewTab: \"เปิดในแท็บใหม่\",\n primary: \"หลัก\",\n sections: \"หมวด\",\n toggleNavigation: \"สลับการนำทาง\",\n toggleTheme: \"สลับธีมสี\",\n },\n notFound: {\n description: \"เราไม่พบหน้าที่คุณกำลังมองหา\",\n home: \"กลับไปหน้าแรก\",\n title: \"ไม่พบหน้า\",\n },\n page: {\n lastUpdated: \"อัปเดตล่าสุดเมื่อ\",\n next: \"ถัดไป\",\n pagination: \"การแบ่งหน้า\",\n previous: \"ก่อนหน้า\",\n skipToContent: \"ข้ามไปยังเนื้อหา\",\n },\n search: {\n all: \"ทั้งหมด\",\n allLanguages: \"ทุกภาษา\",\n askAi: \"ถาม AI\",\n askAiHint: \"รับคำตอบทันทีจาก AI\",\n button: \"ค้นหา\",\n devOnly: \"การค้นหาพร้อมใช้งานในบิลด์โปรดักชัน\",\n error: \"เกิดข้อผิดพลาดบางอย่าง โปรดลองอีกครั้ง\",\n label: \"ค้นหาเอกสาร\",\n navigate: \"นำทาง\",\n noResults: \"ไม่พบผลลัพธ์\",\n open: \"เปิด\",\n placeholder: \"ค้นหาเอกสาร…\",\n popular: \"ยอดนิยม\",\n preview: \"ดูตัวอย่าง\",\n results: \"ผลลัพธ์\",\n },\n toc: { title: \"ในหน้านี้\" },\n};\n",
|
|
43
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Turkish (tr) UI strings. */\nexport const tr: UIStringsOverride = {\n actions: {\n addToCursor: \"Cursor'a ekle\",\n addToVscode: \"VS Code'a ekle\",\n askAI: \"Bu sayfa hakkında yapay zekâya sor\",\n connectMcp: \"MCP'ye bağlan\",\n copied: \"Kopyalandı!\",\n copyClaudeCode: \"Claude Code komutunu kopyala\",\n copyCode: \"Kodu kopyala\",\n copyCodex: \"Codex komutunu kopyala\",\n copyFailed: \"Kopyalama başarısız oldu\",\n copyMarkdown: \"Markdown olarak kopyala\",\n copyServerUrl: \"Sunucu URL'sini kopyala\",\n edit: \"GitHub'da düzenle\",\n export: \"Dışa aktar\",\n exportEpub: \"EPUB olarak dışa aktar\",\n exportPdf: \"PDF olarak dışa aktar\",\n generating: \"Oluşturuluyor…\",\n openIn: \"{name} içinde aç\",\n openInChat: \"Sohbette aç\",\n openInChatPrompt:\n \"Bu sayfa hakkında sorular sorabilmem için {url} adresini okuyun.\",\n scrollToTop: \"Başa dön\",\n },\n ask: {\n ai: \"Yapay zekâ\",\n clear: \"Konuşmayı temizle\",\n close: \"Kapat\",\n copy: \"Konuşmayı kopyala\",\n empty: \"Belgeler hakkında bir soru sorun.\",\n error: \"Üzgünüz, bir şeyler ters gitti.\",\n label: \"Bir soru sorun\",\n placeholder: \"Bir soru sorun…\",\n send: \"Gönder\",\n tip: \"İpucu: Sohbeti şu tuşla açıp kapatabilirsiniz:\",\n title: \"Yapay zekâya sor\",\n you: \"Siz\",\n },\n banner: { dismiss: \"Duyuruyu kapat\" },\n changelog: {\n description: \"Ürün güncellemeleri ve sürüm notları.\",\n title: \"Değişiklik günlüğü\",\n },\n content: {\n copyColor: \"Rengi kopyala: {name} {value}\",\n copyPrompt: \"İstemi kopyala\",\n diagramError: \"Bu diyagram görüntülenemedi.\",\n },\n feedback: {\n no: \"Hayır\",\n question: \"Bu sayfa yardımcı oldu mu?\",\n thanks: \"Geri bildiriminiz için teşekkürler!\",\n yes: \"Evet\",\n },\n languageSwitcher: { label: \"Dil\", untranslated: \"Çevrilmemiş\" },\n nav: {\n back: \"Geri\",\n breadcrumb: \"Gezinme yolu\",\n closeNavigation: \"Gezinmeyi kapat\",\n deprecated: \"kullanımdan kaldırıldı\",\n featured: \"Öne çıkan\",\n githubRepository: \"GitHub deposu\",\n navigation: \"Gezinme\",\n opensInNewTab: \"Yeni sekmede açılır\",\n primary: \"Birincil\",\n sections: \"Bölümler\",\n toggleNavigation: \"Gezinmeyi aç/kapat\",\n toggleTheme: \"Renk temasını değiştir\",\n },\n notFound: {\n description: \"Aradığınız sayfayı bulamadık.\",\n home: \"Ana sayfaya dön\",\n title: \"Sayfa bulunamadı\",\n },\n page: {\n lastUpdated: \"Son güncelleme\",\n next: \"Sonraki\",\n pagination: \"Sayfalama\",\n previous: \"Önceki\",\n skipToContent: \"İçeriğe geç\",\n },\n search: {\n all: \"Tümü\",\n allLanguages: \"Tüm diller\",\n askAi: \"Yapay zekâya sor\",\n askAiHint: \"Yapay zekâdan anında yanıt alın\",\n button: \"Ara\",\n devOnly: \"Arama, üretim derlemesinde kullanılabilir.\",\n error: \"Bir şeyler ters gitti. Lütfen tekrar deneyin.\",\n label: \"Belgelerde ara\",\n navigate: \"gezin\",\n noResults: \"Sonuç bulunamadı.\",\n open: \"aç\",\n placeholder: \"Belgelerde ara…\",\n popular: \"Popüler\",\n preview: \"önizle\",\n results: \"Sonuçlar\",\n },\n toc: { title: \"Bu sayfada\" },\n};\n",
|
|
44
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Ukrainian (uk) UI strings. */\nexport const uk: UIStringsOverride = {\n actions: {\n addToCursor: \"Додати до Cursor\",\n addToVscode: \"Додати до VS Code\",\n askAI: \"Запитати ШІ про цю сторінку\",\n connectMcp: \"Підключитися до MCP\",\n copied: \"Скопійовано!\",\n copyClaudeCode: \"Скопіювати команду Claude Code\",\n copyCode: \"Скопіювати код\",\n copyCodex: \"Скопіювати команду Codex\",\n copyFailed: \"Не вдалося скопіювати\",\n copyMarkdown: \"Скопіювати як Markdown\",\n copyServerUrl: \"Скопіювати URL сервера\",\n edit: \"Редагувати на GitHub\",\n export: \"Експорт\",\n exportEpub: \"Експорт в EPUB\",\n exportPdf: \"Експорт у PDF\",\n generating: \"Генерація…\",\n openIn: \"Відкрити в {name}\",\n openInChat: \"Відкрити в чаті\",\n openInChatPrompt:\n \"Прочитайте {url} — я ставитиму запитання щодо цієї сторінки.\",\n scrollToTop: \"Нагору\",\n },\n ask: {\n ai: \"ШІ\",\n clear: \"Очистити бесіду\",\n close: \"Закрити\",\n copy: \"Скопіювати бесіду\",\n empty: \"Поставте запитання щодо документації.\",\n error: \"Вибачте, щось пішло не так.\",\n label: \"Поставити запитання\",\n placeholder: \"Поставте запитання…\",\n send: \"Надіслати\",\n tip: \"Порада: чат можна відкрити й закрити за допомогою\",\n title: \"Запитати ШІ\",\n you: \"Ви\",\n },\n banner: { dismiss: \"Закрити оголошення\" },\n changelog: {\n description: \"Оновлення продукту та примітки до випусків.\",\n title: \"Журнал змін\",\n },\n content: {\n copyColor: \"Скопіювати колір {name} {value}\",\n copyPrompt: \"Скопіювати промпт\",\n diagramError: \"Не вдалося відобразити цю діаграму.\",\n },\n feedback: {\n no: \"Ні\",\n question: \"Чи була ця сторінка корисною?\",\n thanks: \"Дякуємо за ваш відгук!\",\n yes: \"Так\",\n },\n languageSwitcher: { label: \"Мова\", untranslated: \"Не перекладено\" },\n nav: {\n back: \"Назад\",\n breadcrumb: \"Навігаційний ланцюжок\",\n closeNavigation: \"Закрити навігацію\",\n deprecated: \"застаріле\",\n featured: \"Рекомендоване\",\n githubRepository: \"Репозиторій GitHub\",\n navigation: \"Навігація\",\n opensInNewTab: \"Відкривається в новій вкладці\",\n primary: \"Основне\",\n sections: \"Розділи\",\n toggleNavigation: \"Перемкнути навігацію\",\n toggleTheme: \"Перемкнути колірну тему\",\n },\n notFound: {\n description: \"Не вдалося знайти сторінку, яку ви шукаєте.\",\n home: \"Повернутися на головну\",\n title: \"Сторінку не знайдено\",\n },\n page: {\n lastUpdated: \"Останнє оновлення\",\n next: \"Далі\",\n pagination: \"Пагінація\",\n previous: \"Назад\",\n skipToContent: \"Перейти до вмісту\",\n },\n search: {\n all: \"Усі\",\n allLanguages: \"Усі мови\",\n askAi: \"Запитати ШІ\",\n askAiHint: \"Отримайте миттєву відповідь від ШІ\",\n button: \"Пошук\",\n devOnly: \"Пошук доступний у production-збірці.\",\n error: \"Щось пішло не так. Спробуйте ще раз.\",\n label: \"Пошук у документації\",\n navigate: \"навігація\",\n noResults: \"Нічого не знайдено.\",\n open: \"відкрити\",\n placeholder: \"Пошук у документації…\",\n popular: \"Популярне\",\n preview: \"перегляд\",\n results: \"Результати\",\n },\n toc: { title: \"На цій сторінці\" },\n};\n",
|
|
45
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Vietnamese (vi) UI strings. */\nexport const vi: UIStringsOverride = {\n actions: {\n addToCursor: \"Thêm vào Cursor\",\n addToVscode: \"Thêm vào VS Code\",\n askAI: \"Hỏi AI về trang này\",\n connectMcp: \"Kết nối với MCP\",\n copied: \"Đã sao chép!\",\n copyClaudeCode: \"Sao chép lệnh Claude Code\",\n copyCode: \"Sao chép mã\",\n copyCodex: \"Sao chép lệnh Codex\",\n copyFailed: \"Sao chép thất bại\",\n copyMarkdown: \"Sao chép dưới dạng Markdown\",\n copyServerUrl: \"Sao chép URL máy chủ\",\n edit: \"Chỉnh sửa trên GitHub\",\n export: \"Xuất\",\n exportEpub: \"Xuất ra EPUB\",\n exportPdf: \"Xuất ra PDF\",\n generating: \"Đang tạo…\",\n openIn: \"Mở trong {name}\",\n openInChat: \"Mở trong trò chuyện\",\n openInChatPrompt: \"Hãy đọc {url} để tôi có thể đặt câu hỏi về trang này.\",\n scrollToTop: \"Lên đầu trang\",\n },\n ask: {\n ai: \"AI\",\n clear: \"Xóa cuộc trò chuyện\",\n close: \"Đóng\",\n copy: \"Sao chép cuộc trò chuyện\",\n empty: \"Đặt câu hỏi về tài liệu.\",\n error: \"Xin lỗi, đã xảy ra sự cố.\",\n label: \"Đặt câu hỏi\",\n placeholder: \"Đặt câu hỏi…\",\n send: \"Gửi\",\n tip: \"Mẹo: Bạn có thể mở và đóng trò chuyện bằng\",\n title: \"Hỏi AI\",\n you: \"Bạn\",\n },\n banner: { dismiss: \"Đóng thông báo\" },\n changelog: {\n description: \"Cập nhật sản phẩm và ghi chú phát hành.\",\n title: \"Nhật ký thay đổi\",\n },\n content: {\n copyColor: \"Sao chép màu {name} {value}\",\n copyPrompt: \"Sao chép prompt\",\n diagramError: \"Không thể hiển thị sơ đồ này.\",\n },\n feedback: {\n no: \"Không\",\n question: \"Trang này có hữu ích không?\",\n thanks: \"Cảm ơn phản hồi của bạn!\",\n yes: \"Có\",\n },\n languageSwitcher: { label: \"Ngôn ngữ\", untranslated: \"Chưa dịch\" },\n nav: {\n back: \"Quay lại\",\n breadcrumb: \"Đường dẫn điều hướng\",\n closeNavigation: \"Đóng điều hướng\",\n deprecated: \"lỗi thời\",\n featured: \"Nổi bật\",\n githubRepository: \"Kho lưu trữ GitHub\",\n navigation: \"Điều hướng\",\n opensInNewTab: \"Mở trong thẻ mới\",\n primary: \"Chính\",\n sections: \"Chuyên mục\",\n toggleNavigation: \"Chuyển đổi điều hướng\",\n toggleTheme: \"Chuyển đổi chủ đề màu\",\n },\n notFound: {\n description: \"Chúng tôi không tìm thấy trang bạn đang tìm.\",\n home: \"Về trang chủ\",\n title: \"Không tìm thấy trang\",\n },\n page: {\n lastUpdated: \"Cập nhật lần cuối\",\n next: \"Tiếp theo\",\n pagination: \"Phân trang\",\n previous: \"Trước\",\n skipToContent: \"Chuyển đến nội dung\",\n },\n search: {\n all: \"Tất cả\",\n allLanguages: \"Tất cả ngôn ngữ\",\n askAi: \"Hỏi AI\",\n askAiHint: \"Nhận câu trả lời tức thì từ AI\",\n button: \"Tìm kiếm\",\n devOnly: \"Tìm kiếm có sẵn trong bản dựng production.\",\n error: \"Đã xảy ra sự cố. Vui lòng thử lại.\",\n label: \"Tìm kiếm tài liệu\",\n navigate: \"di chuyển\",\n noResults: \"Không tìm thấy kết quả.\",\n open: \"mở\",\n placeholder: \"Tìm kiếm tài liệu…\",\n popular: \"Phổ biến\",\n preview: \"xem trước\",\n results: \"Kết quả\",\n },\n toc: { title: \"Trên trang này\" },\n};\n",
|
|
46
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Chinese — Traditional (zh-TW) UI strings. */\nexport const zhTW: UIStringsOverride = {\n actions: {\n addToCursor: \"新增至 Cursor\",\n addToVscode: \"新增至 VS Code\",\n askAI: \"向 AI 詢問此頁面\",\n connectMcp: \"連線至 MCP\",\n copied: \"已複製!\",\n copyClaudeCode: \"複製 Claude Code 指令\",\n copyCode: \"複製程式碼\",\n copyCodex: \"複製 Codex 指令\",\n copyFailed: \"複製失敗\",\n copyMarkdown: \"複製為 Markdown\",\n copyServerUrl: \"複製伺服器 URL\",\n edit: \"在 GitHub 上編輯\",\n export: \"匯出\",\n exportEpub: \"匯出為 EPUB\",\n exportPdf: \"匯出為 PDF\",\n generating: \"產生中…\",\n openIn: \"在 {name} 中開啟\",\n openInChat: \"在聊天中開啟\",\n openInChatPrompt: \"請閱讀 {url} 以便我針對此頁面提問。\",\n scrollToTop: \"回到頂部\",\n },\n ask: {\n ai: \"AI\",\n clear: \"清除對話\",\n close: \"關閉\",\n copy: \"複製對話\",\n empty: \"針對文件提出問題。\",\n error: \"抱歉,發生了一些問題。\",\n label: \"提出問題\",\n placeholder: \"提出問題…\",\n send: \"傳送\",\n tip: \"提示:可透過以下快捷鍵開啟和關閉聊天\",\n title: \"向 AI 提問\",\n you: \"你\",\n },\n banner: { dismiss: \"關閉公告\" },\n changelog: {\n description: \"產品更新與版本說明。\",\n title: \"更新日誌\",\n },\n content: {\n copyColor: \"複製顏色 {name} {value}\",\n copyPrompt: \"複製提示詞\",\n diagramError: \"無法顯示此圖表。\",\n },\n feedback: {\n no: \"沒有幫助\",\n question: \"這個頁面有幫助嗎?\",\n thanks: \"感謝你的意見回饋!\",\n yes: \"有幫助\",\n },\n languageSwitcher: { label: \"語言\", untranslated: \"未翻譯\" },\n nav: {\n back: \"返回\",\n breadcrumb: \"麵包屑導覽\",\n closeNavigation: \"關閉導覽\",\n deprecated: \"已棄用\",\n featured: \"精選\",\n githubRepository: \"GitHub 儲存庫\",\n navigation: \"導覽\",\n opensInNewTab: \"在新分頁中開啟\",\n primary: \"主要\",\n sections: \"章節\",\n toggleNavigation: \"切換導覽\",\n toggleTheme: \"切換色彩主題\",\n },\n notFound: {\n description: \"我們找不到你要瀏覽的頁面。\",\n home: \"返回首頁\",\n title: \"找不到頁面\",\n },\n page: {\n lastUpdated: \"最後更新於\",\n next: \"下一頁\",\n pagination: \"分頁\",\n previous: \"上一頁\",\n skipToContent: \"跳至內容\",\n },\n search: {\n all: \"全部\",\n allLanguages: \"所有語言\",\n askAi: \"向 AI 提問\",\n askAiHint: \"從 AI 即時取得解答\",\n button: \"搜尋\",\n devOnly: \"搜尋在正式版組建中可用。\",\n error: \"發生了一些問題,請再試一次。\",\n label: \"搜尋文件\",\n navigate: \"導覽\",\n noResults: \"找不到結果。\",\n open: \"開啟\",\n placeholder: \"搜尋文件…\",\n popular: \"熱門\",\n preview: \"預覽\",\n results: \"結果\",\n },\n toc: { title: \"本頁內容\" },\n};\n",
|
|
47
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\n\n/** Chinese — Simplified (zh) UI strings. */\nexport const zh: UIStringsOverride = {\n actions: {\n addToCursor: \"添加到 Cursor\",\n addToVscode: \"添加到 VS Code\",\n askAI: \"向 AI 询问此页面\",\n connectMcp: \"连接到 MCP\",\n copied: \"已复制!\",\n copyClaudeCode: \"复制 Claude Code 命令\",\n copyCode: \"复制代码\",\n copyCodex: \"复制 Codex 命令\",\n copyFailed: \"复制失败\",\n copyMarkdown: \"复制为 Markdown\",\n copyServerUrl: \"复制服务器 URL\",\n edit: \"在 GitHub 上编辑\",\n export: \"导出\",\n exportEpub: \"导出为 EPUB\",\n exportPdf: \"导出为 PDF\",\n generating: \"生成中…\",\n openIn: \"在 {name} 中打开\",\n openInChat: \"在聊天中打开\",\n openInChatPrompt: \"请阅读 {url} 以便我就此页面提问。\",\n scrollToTop: \"回到顶部\",\n },\n ask: {\n ai: \"AI\",\n clear: \"清空对话\",\n close: \"关闭\",\n copy: \"复制对话\",\n empty: \"就文档提出问题。\",\n error: \"抱歉,出了点问题。\",\n label: \"提出问题\",\n placeholder: \"提出问题…\",\n send: \"发送\",\n tip: \"提示:可通过以下快捷键打开和关闭聊天\",\n title: \"向 AI 提问\",\n you: \"你\",\n },\n banner: { dismiss: \"关闭公告\" },\n changelog: {\n description: \"产品更新与版本说明。\",\n title: \"更新日志\",\n },\n content: {\n copyColor: \"复制颜色 {name} {value}\",\n copyPrompt: \"复制提示词\",\n diagramError: \"无法渲染此图表。\",\n },\n feedback: {\n no: \"没有帮助\",\n question: \"这个页面有帮助吗?\",\n thanks: \"感谢你的反馈!\",\n yes: \"有帮助\",\n },\n languageSwitcher: { label: \"语言\", untranslated: \"未翻译\" },\n nav: {\n back: \"返回\",\n breadcrumb: \"面包屑导航\",\n closeNavigation: \"关闭导航\",\n deprecated: \"已弃用\",\n featured: \"精选\",\n githubRepository: \"GitHub 仓库\",\n navigation: \"导航\",\n opensInNewTab: \"在新标签页中打开\",\n primary: \"主要\",\n sections: \"章节\",\n toggleNavigation: \"切换导航\",\n toggleTheme: \"切换颜色主题\",\n },\n notFound: {\n description: \"我们找不到你要访问的页面。\",\n home: \"返回首页\",\n title: \"页面未找到\",\n },\n page: {\n lastUpdated: \"最后更新于\",\n next: \"下一页\",\n pagination: \"分页\",\n previous: \"上一页\",\n skipToContent: \"跳到内容\",\n },\n search: {\n all: \"全部\",\n allLanguages: \"所有语言\",\n askAi: \"向 AI 提问\",\n askAiHint: \"从 AI 即时获取答案\",\n button: \"搜索\",\n devOnly: \"搜索在生产构建中可用。\",\n error: \"出了点问题,请重试。\",\n label: \"搜索文档\",\n navigate: \"导航\",\n noResults: \"未找到结果。\",\n open: \"打开\",\n placeholder: \"搜索文档…\",\n popular: \"热门\",\n preview: \"预览\",\n results: \"结果\",\n },\n toc: { title: \"本页内容\" },\n};\n",
|
|
48
|
+
"import type { UIStringsOverride } from \"../i18n-ui.ts\";\nimport { ar } from \"./ar.ts\";\nimport { bg } from \"./bg.ts\";\nimport { bn } from \"./bn.ts\";\nimport { ca } from \"./ca.ts\";\nimport { cs } from \"./cs.ts\";\nimport { da } from \"./da.ts\";\nimport { de } from \"./de.ts\";\nimport { el } from \"./el.ts\";\nimport { es } from \"./es.ts\";\nimport { fa } from \"./fa.ts\";\nimport { fi } from \"./fi.ts\";\nimport { fr } from \"./fr.ts\";\nimport { he } from \"./he.ts\";\nimport { hi } from \"./hi.ts\";\nimport { hr } from \"./hr.ts\";\nimport { hu } from \"./hu.ts\";\nimport { id } from \"./id.ts\";\nimport { it } from \"./it.ts\";\nimport { ja } from \"./ja.ts\";\nimport { ko } from \"./ko.ts\";\nimport { nl } from \"./nl.ts\";\nimport { no } from \"./no.ts\";\nimport { pl } from \"./pl.ts\";\nimport { ptBR } from \"./pt-br.ts\";\nimport { pt } from \"./pt.ts\";\nimport { ro } from \"./ro.ts\";\nimport { ru } from \"./ru.ts\";\nimport { sk } from \"./sk.ts\";\nimport { sr } from \"./sr.ts\";\nimport { sv } from \"./sv.ts\";\nimport { th } from \"./th.ts\";\nimport { tr } from \"./tr.ts\";\nimport { uk } from \"./uk.ts\";\nimport { vi } from \"./vi.ts\";\nimport { zhTW } from \"./zh-tw.ts\";\nimport { zh } from \"./zh.ts\";\n\n/**\n * Built-in translation packs, one module per locale (`./<code>.ts`). English is\n * the schema baseline, so it has no pack; every other locale ships a starter\n * pack so adopters get translated chrome out of the box. Brand names (Cursor,\n * VS Code, MCP, Claude Code, Markdown, GitHub) are kept verbatim. Packs are\n * community-maintained — open a PR to add a locale or sharpen a translation.\n *\n * Keyed by locale code; regional variants use the BCP 47 form (`pt-BR`,\n * `zh-TW`). A locale's pack is merged onto English by {@link resolveUIStrings},\n * so a pack only needs the keys it translates.\n */\n/**\n * Starter packs keyed by locale code. Open-keyed on purpose: resolvers look\n * packs up by whatever locale a project configures, not only the codes here.\n */\ninterface UiPackRegistry {\n [locale: string]: UIStringsOverride;\n}\n\nexport const UI_PACKS: UiPackRegistry = {\n ar,\n bg,\n bn,\n ca,\n cs,\n da,\n de,\n el,\n es,\n fa,\n fi,\n fr,\n he,\n hi,\n hr,\n hu,\n id,\n it,\n ja,\n ko,\n nl,\n no,\n pl,\n pt,\n \"pt-BR\": ptBR,\n ro,\n ru,\n sk,\n sr,\n sv,\n th,\n tr,\n uk,\n vi,\n zh,\n \"zh-TW\": zhTW,\n};\n",
|
|
49
|
+
"import type {\n ResolvedConfig,\n ResolvedI18nConfig,\n ResolvedVersionsConfig,\n} from \"./schema.ts\";\nimport type { Diagnostic, PageRecord } from \"./types.ts\";\nimport { UI_PACKS } from \"./ui-packs/index.ts\";\n\n/**\n * Locale logic, centralized. Every seam that needs to reason about locales\n * (content discovery, navigation, manifest, runtime generation, the catch-all)\n * goes through these helpers so the routing rules live in exactly one place.\n */\n\n/** Locale codes Blume recognizes (those it ships a UI pack for, plus English). */\nconst KNOWN_LOCALES = new Set(\n [...Object.keys(UI_PACKS), \"en\"].map((code) => code.toLowerCase())\n);\n\n/** True when the project opts into i18n. */\nexport const i18nEnabled = (\n config: ResolvedConfig\n): config is ResolvedConfig & { i18n: ResolvedI18nConfig } =>\n config.i18n !== undefined;\n\n/** All configured locale codes, default first as authored. */\nexport const localeCodes = (i18n: ResolvedI18nConfig): string[] =>\n i18n.locales.map((locale) => locale.code);\n\n/** Text direction for a locale (`ltr` when unknown). */\nexport const localeDir = (\n code: string,\n i18n: ResolvedI18nConfig\n): \"ltr\" | \"rtl\" =>\n i18n.locales.find((locale) => locale.code === code)?.dir ?? \"ltr\";\n\n/**\n * The locale a missing translation falls back to: `fallbackLocale` when set,\n * the default locale when `fallbackLocale` is omitted, or `null` (disabled)\n * when explicitly set to `null`.\n */\nexport const resolveFallbackLocale = (\n i18n: ResolvedI18nConfig\n): string | null => {\n if (i18n.fallbackLocale === null) {\n return null;\n }\n return i18n.fallbackLocale ?? i18n.defaultLocale;\n};\n\n/**\n * The slice of the i18n settings URL routing reads. `ResolvedI18nConfig` and\n * the `blume:data` runtime shape both satisfy it, so route helpers serve the\n * Node-side graph and the rendered page alike.\n */\nexport interface LocaleRouting {\n defaultLocale: string;\n hideDefaultLocalePrefix: boolean;\n locales: { code: string }[];\n}\n\n/** URL prefix for a locale: `\"\"` for the hidden default, else `/<code>`. */\nexport const localePrefix = (code: string, i18n: LocaleRouting): string =>\n code === i18n.defaultLocale && i18n.hideDefaultLocalePrefix ? \"\" : `/${code}`;\n\n/**\n * Prefix a locale-agnostic route (e.g. `/guides/x` or `/`) with its locale.\n * `/` becomes `/fr` (or stays `/` for the hidden default).\n */\nexport const localizeRoute = (\n logicalRoute: string,\n code: string,\n i18n: LocaleRouting\n): string => {\n const prefix = localePrefix(code, i18n);\n if (!prefix) {\n return logicalRoute;\n }\n return logicalRoute === \"/\" ? prefix : `${prefix}${logicalRoute}`;\n};\n\n/**\n * Localize a configured link target the way header tabs are: a root-relative\n * internal path (`/`, `/docs`) moves into `code`'s prefix, and anything else —\n * an absolute URL, a fragment, a relative path — passes through. `//host/path`\n * is protocol-relative, an external URL that happens to start with a slash, so\n * it must not pick up a locale prefix (`withBasePath` draws the same line).\n * With no i18n (`null`) the path is returned as-is.\n */\nexport const localizeInternalPath = (\n path: string,\n code: string,\n i18n: LocaleRouting | null\n): string =>\n i18n && path.startsWith(\"/\") && !path.startsWith(\"//\")\n ? localizeRoute(path, code, i18n)\n : path;\n\n/**\n * Detect a leading non-default locale directory in a path's segments. The\n * default locale lives at the content root, so only non-default codes are\n * matched as a leading segment. Returns the resolved locale and the remaining\n * (locale-stripped) segments.\n */\nexport const detectLocale = (parts: string[], i18n: ResolvedI18nConfig) => {\n // BCP 47 codes are case-insensitive: a conventional lowercase folder\n // (`pt-br/`) must match a configured `pt-BR`. The configured casing is what\n // flows into routes and labels.\n const first = parts[0]?.toLowerCase();\n const matched = i18n.locales.find(\n (locale) =>\n locale.code !== i18n.defaultLocale && locale.code.toLowerCase() === first\n );\n if (matched) {\n return { locale: matched.code, rest: parts.slice(1) };\n }\n return { locale: i18n.defaultLocale, rest: parts };\n};\n\n/**\n * Resolve where a content file lives across locales, by parser:\n * - `dir`: a leading locale directory (`fr/page.mdx`)\n * - `dot`: a filename suffix (`page.fr.mdx`)\n *\n * A `.$.` infix (e.g. `changelog.$.mdx`) marks a shared, locale-agnostic file\n * that is materialized into every configured locale. Returns the locale-stripped\n * path (used for nav grouping) and the locale codes the file maps to (one for a\n * normal file, all locales for a shared one).\n */\nexport const localePlacement = (\n rel: string,\n ext: string,\n i18n: ResolvedI18nConfig\n) => {\n const base = rel.slice(0, rel.length - ext.length);\n\n // Shared `$` file: the same content in every locale. A shared file placed\n // inside a locale directory (`fr/changelog.$.mdx`) still sheds that\n // directory from its nav path — otherwise every locale's record would route\n // under `/fr/…`, nesting the default locale inside the French namespace and\n // the French copy at `/fr/fr/…`.\n if (base.endsWith(\".$\")) {\n const shared = `${base.slice(0, -2)}${ext}`;\n return {\n locales: i18n.locales.map((locale) => locale.code),\n navPath:\n i18n.parser === \"dir\"\n ? detectLocale(shared.split(\"/\"), i18n).rest.join(\"/\")\n : shared,\n };\n }\n\n if (i18n.parser === \"dot\") {\n const lastDot = base.lastIndexOf(\".\");\n // Only a dot inside the filename (not a directory) is a locale suffix. Any\n // configured locale counts — including the default, so the symmetric\n // authoring `intro.en.mdx` + `intro.fr.mdx` shares one translation key\n // instead of routing the default file to a literal `/intro.en`.\n if (lastDot > base.lastIndexOf(\"/\")) {\n // Case-insensitive, like `detectLocale`: `intro.pt-br.mdx` matches a\n // configured `pt-BR` and adopts its casing.\n const suffix = base.slice(lastDot + 1).toLowerCase();\n const matched = i18n.locales.find(\n (locale) => locale.code.toLowerCase() === suffix\n );\n if (matched) {\n return {\n locales: [matched.code],\n navPath: `${base.slice(0, lastDot)}${ext}`,\n };\n }\n }\n return { locales: [i18n.defaultLocale], navPath: rel };\n }\n\n const { locale, rest } = detectLocale(rel.split(\"/\"), i18n);\n return { locales: [locale], navPath: rest.join(\"/\") };\n};\n\n/**\n * The inverse of {@link localePlacement}: where a default-locale file's\n * translation into `locale` lives, by parser:\n * - `dir`: a leading locale directory (`guides/x.mdx` → `fr/guides/x.mdx`)\n * - `dot`: a filename suffix (`guides/x.mdx` → `guides/x.fr.mdx`)\n *\n * Under `dot`, a source authored with an explicit default-locale suffix\n * (`x.en.mdx`) swaps it for the target's (`x.fr.mdx`) — same case-insensitive\n * last-dot-inside-filename logic as `localePlacement`, so both spellings of a\n * default-locale file resolve to one canonical target.\n */\nexport const localeTargetPath = (\n rel: string,\n ext: string,\n locale: string,\n i18n: ResolvedI18nConfig\n): string => {\n if (i18n.parser === \"dot\") {\n let base = rel.slice(0, rel.length - ext.length);\n const lastDot = base.lastIndexOf(\".\");\n if (lastDot > base.lastIndexOf(\"/\")) {\n const suffix = base.slice(lastDot + 1).toLowerCase();\n if (i18n.locales.some((entry) => entry.code.toLowerCase() === suffix)) {\n base = base.slice(0, lastDot);\n }\n }\n return `${base}.${locale}${ext}`;\n }\n return `${locale}/${rel}`;\n};\n\n/**\n * Warn about top-level content folders that look like a locale (a code Blume\n * recognizes) but aren't declared in `i18n.locales`. Without this they're\n * silently treated as default-locale content under a `/<code>/…` route, which\n * is almost never intended — usually a translation that wasn't registered.\n */\nexport const i18nDiagnostics = (\n pages: PageRecord[],\n i18n: ResolvedI18nConfig,\n versions?: ResolvedVersionsConfig\n): Diagnostic[] => {\n const configured = new Set(\n i18n.locales.map((locale) => locale.code.toLowerCase())\n );\n const versionDirs = new Set(versions?.archived.map((version) => version.id));\n const seen = new Set<string>();\n const diagnostics: Diagnostic[] = [];\n for (const page of pages) {\n // The locale-looking folder is the first segment of the source-local ref\n // (e.g. `fr/guide.md`), not the namespaced id (`filesystem:fr/guide.md`).\n // Inside a version snapshot the locale dir sits one level deeper\n // (`v1.0/fr/guide.md`), so a configured version segment is skipped first.\n const parts = page.source.ref.split(\"/\");\n const first = (\n parts[0] && versionDirs.has(parts[0]) ? parts[1] : parts[0]\n )?.toLowerCase();\n if (\n first &&\n !seen.has(first) &&\n KNOWN_LOCALES.has(first) &&\n !configured.has(first)\n ) {\n seen.add(first);\n diagnostics.push({\n code: \"BLUME_I18N_UNCONFIGURED_LOCALE\",\n message: `Folder \"${first}/\" looks like a locale, but \"${first}\" is not in i18n.locales — its pages are treated as \"${i18n.defaultLocale}\" content at /${first}/….`,\n severity: \"warning\",\n suggestion: `Add { code: \"${first}\", label: \"…\" } to i18n.locales, or rename the folder if it isn't a translation.`,\n });\n }\n }\n return diagnostics;\n};\n",
|
|
50
|
+
"import { existsSync } from \"node:fs\";\n\nimport { basename, dirname, join, normalize, relative, resolve } from \"pathe\";\n\nimport { stripBasePath, withBasePath } from \"./base-path.ts\";\nimport {\n isRelativeImageTarget,\n resolveRelativeImage,\n} from \"./content-assets.ts\";\nimport type { LocaleRouting } from \"./i18n.ts\";\nimport { localizeLinkPath } from \"./locale-links.ts\";\nimport { gradeExternal, probeAll } from \"./probe.ts\";\nimport type {\n ContentGraph,\n Diagnostic,\n PageLink,\n PageRecord,\n} from \"./types.ts\";\n\nconst HTTP = /^https?:\\/\\//iu;\nconst PROTOCOL_RELATIVE = /^\\/\\//u;\nconst SCHEME = /^[a-z][a-z0-9+.-]*:/iu;\n\n/** Percent-decode a link piece; malformed sequences stay verbatim. */\nconst decodePercent = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\nconst DOC_EXT = /\\.(?:md|mdx)$/iu;\nconst FILE_EXT = /\\.[a-z0-9]+$/iu;\n\n/** Source position shared by every diagnostic raised for a link. */\ninterface LinkSite {\n column: number;\n file: string;\n line: number;\n}\n\n/**\n * Message context for a link written inside an included partial whose verdict\n * depends on *which* page splices it (relative paths resolve against the\n * including page's route; bare anchors against its headings). Without it the\n * same partial line can be reported broken while being valid from another\n * includer — with no way to tell the reports apart.\n */\nconst includedBySuffix = (link: PageLink, page: PageRecord): string =>\n link.file ? ` (included by ${basename(page.sourcePath ?? page.id)})` : \"\";\n\n/**\n * Invert the include image rebase for display: expansion rewrote a partial's\n * relative image target into the including page's directory so it resolves,\n * but the diagnostic points at the partial — report the path the author\n * actually wrote there, not the rebased one they never typed.\n */\nconst authoredImageTarget = (\n target: string,\n pagePath: string,\n partialPath: string\n): string => {\n const authored = relative(\n dirname(partialPath),\n resolve(dirname(pagePath), target)\n );\n return authored.startsWith(\".\") ? authored : `./${authored}`;\n};\n\n/** An external link occurrence queued for a network probe. */\ninterface ExternalRef extends LinkSite {\n url: string;\n}\n\n/** Lookups derived once from the content graph. */\ninterface LinkContext {\n anchors: Map<string, Set<string>>;\n /** Site-wide route mount point (`\"\"` or `/seg`); routes carry it, assets don't. */\n basePath: string;\n /** Servable routes outside the graph (custom pages, generated routes); their\n * headings are unknown, so anchors there are accepted unchecked. */\n extraRoutes: Set<string>;\n /** Where content files publish, for file links (`./setup.mdx`). */\n fileRoutes: FileRouteIndex;\n /** Locale routing, when the site is multi-locale; drives served-route resolution. */\n i18n: LocaleRouting | null;\n publicDir: string | null;\n /** Normalized `redirect.from` paths — valid targets that resolve at runtime. */\n redirects: Set<string>;\n routes: Set<string>;\n}\n\n/** Whether a resolved asset path exists under `public/`. */\nconst assetIsPresent = (resolved: string, ctx: LinkContext): boolean =>\n ctx.publicDir !== null && existsSync(join(ctx.publicDir, resolved));\n\n/** Outcome of classifying one link target. */\ntype LinkResult = Diagnostic | \"asset-unchecked\" | null;\n\n// Mirrors the ordering-prefix strip in `sources/normalize.ts`: route mapping\n// drops the prefix before recognizing `index`, so `01-index.mdx` is an index.\nconst NUMERIC_PREFIX = /^\\d+[-_.]/u;\n\n/**\n * Whether a page is a directory index (`…/index.md(x)`, ordering prefix\n * ignored). Its route already *is* its directory, so a relative link must\n * resolve against the route itself, not its parent — otherwise `./sibling`\n * from `guides/index.mdx` (route `/guides`) would resolve to `/sibling` and be\n * falsely flagged as broken. Tested against `navPath` — the locale-stripped\n * path — so a dot-parser localized index (`index.fr.mdx`) and a shared\n * locale-agnostic one (`index.$.mdx`) count too, matching how route mapping\n * recognizes them.\n */\nconst isIndexPage = (page: PageRecord): boolean =>\n /^index\\.(?:md|mdx)$/iu.test(\n basename(page.navPath).replace(NUMERIC_PREFIX, \"\")\n );\n\n/** Apply one relative-path segment to the accumulated route segments. */\nconst applyRelativePart = (segments: string[], part: string): void => {\n if (part === \"\" || part === \".\") {\n return;\n }\n if (part === \"..\") {\n segments.pop();\n return;\n }\n segments.push(part);\n};\n\n/** Resolve a relative link target against the directory of a page route. */\nconst resolveRelative = (\n pageRoute: string,\n target: string,\n isIndex: boolean\n): string => {\n const segments = pageRoute.split(\"/\").filter(Boolean);\n // Drop a leaf page's own segment so links resolve against its parent\n // directory. An index page's route already is its directory, so keep it.\n if (!isIndex) {\n segments.pop();\n }\n for (const part of target.split(\"/\")) {\n applyRelativePart(segments, part);\n }\n return `/${segments.join(\"/\")}`;\n};\n\n/** Normalize an internal path to its canonical route form. */\nconst toRoute = (path: string): string => {\n let route = path.replace(DOC_EXT, \"\");\n if (route.endsWith(\"/index\")) {\n route = route.slice(0, -\"/index\".length);\n }\n if (route.length > 1 && route.endsWith(\"/\")) {\n route = route.slice(0, -1);\n }\n return route === \"\" ? \"/\" : route;\n};\n\n/** The page a relative link is written on, as the resolver sees it. */\nexport interface RelativeLinkBase {\n /** Whether the page is its folder's index (its route is its directory). */\n isIndex: boolean;\n /** The page's own route, base path included. */\n route: string;\n}\n\n/** A root-relative path, a bare `#fragment` or `?query`, or any scheme. */\nconst NOT_RELATIVE = /^(?:[#?/]|[a-z][a-z0-9+.-]*:)/iu;\n\n/**\n * Where a relative page link written on `from` lands: a root-relative route\n * with the authored `?query#hash` kept — or `undefined` when `href` isn't a\n * relative page link (a root-relative path, a bare `#fragment` or `?query`,\n * an external URL or other scheme, or a relative asset like `./diagram.png`).\n *\n * The one reading `blume validate` checks links against and the Markdown\n * pipeline rewrites them to, so the built `href`, the link check, and the\n * browser agree. Relative paths resolve file-style: a leaf page's links\n * resolve against its parent directory, while an index page's route already is\n * its directory — `./install` on `guides/index.mdx` (`/guides`) lands on\n * `/guides/install`, where a browser reading the slashless URL would go to\n * `/install`. A `.md`/`.mdx` target is a file link: `resolveFile` maps its\n * decoded path, relative to the linking file, to the route that file\n * publishes at, so a target with its own `slug` or an ordering prefix still\n * lands on its page instead of on its raw Markdown source. Without\n * `resolveFile`, or for a file it doesn't know, the target resolves\n * route-relative with the extension dropped.\n *\n * Any other extension (`./diagram.png`) marks an asset, except where a page\n * publishes at the resolved path: `hasRoute` answers that, so a dotted page\n * name (`./node.js` for `node.js.mdx`, `./v1.2`) is still a page link.\n */\nexport const resolveRelativeHref = (\n href: string,\n from: RelativeLinkBase,\n resolveFile?: (path: string) => string | undefined,\n hasRoute?: (route: string) => boolean\n): string | undefined => {\n if (href === \"\" || NOT_RELATIVE.test(href)) {\n return undefined;\n }\n const suffixAt = href.search(/[?#]/u);\n const path = suffixAt === -1 ? href : href.slice(0, suffixAt);\n const suffix = suffixAt === -1 ? \"\" : href.slice(suffixAt);\n if (FILE_EXT.test(path) && !DOC_EXT.test(path)) {\n const route = toRoute(resolveRelative(from.route, path, from.isIndex));\n return hasRoute?.(decodePercent(route)) ? `${route}${suffix}` : undefined;\n }\n const fileRoute = DOC_EXT.test(path)\n ? resolveFile?.(decodePercent(path))\n : undefined;\n return `${fileRoute ?? toRoute(resolveRelative(from.route, path, from.isIndex))}${suffix}`;\n};\n\n/**\n * Whether a content file is its folder's index, from its name as written on\n * disk: `index.md(x)` after an ordering prefix, optionally carrying one of\n * `localeTokens` before the extension (`index.fr.mdx` under the `dot` locale\n * parser, `index.$.mdx` for a file shared by every locale).\n */\nexport const isIndexFileName = (\n name: string,\n localeTokens: readonly string[] = []\n): boolean => {\n const stem = basename(name).replace(NUMERIC_PREFIX, \"\");\n const match = /^index(?:\\.(?<token>[^./]+))?\\.(?:md|mdx)$/iu.exec(stem);\n if (!match) {\n return false;\n }\n const token = match.groups?.token;\n return token === undefined || localeTokens.includes(token);\n};\n\n/** Build a map of route -> set of heading anchor slugs. */\nconst buildAnchorIndex = (pages: PageRecord[]): Map<string, Set<string>> => {\n const anchors = new Map<string, Set<string>>();\n for (const page of pages) {\n anchors.set(\n page.route,\n new Set([\n ...page.headings.map((heading) => heading.slug),\n ...page.anchors,\n ])\n );\n }\n return anchors;\n};\n\n/** Verify a fragment resolves to a heading on the target route. */\nconst checkAnchor = (\n route: string,\n fragment: string,\n site: LinkSite,\n ctx: LinkContext,\n via = \"\"\n): Diagnostic | null => {\n const anchors = ctx.anchors.get(route);\n // Exact first: a `[#custom-id]` pin may contain uppercase, which the\n // lowercase fallback (lenient matching for slugger-generated ids) would miss.\n if (anchors?.has(fragment) || anchors?.has(fragment.toLowerCase())) {\n return null;\n }\n return {\n ...site,\n code: \"BLUME_BROKEN_ANCHOR\",\n message: `No anchor target on ${route} matches #${fragment}${via}.`,\n severity: \"warning\",\n };\n};\n\n/**\n * The route a link on `page` actually lands on. Rendered under a prefixed\n * locale, a root-relative link moves into that locale when the localized route\n * is served — a real translation (whose own headings then answer the anchor\n * check) or a fallback page (accepted unchecked via `extraRoutes`) — exactly as\n * `LocaleLinks.astro` rewrites it at render time. Otherwise the authored route\n * stands.\n */\nconst servedRoute = (\n authored: string,\n page: PageRecord,\n ctx: LinkContext\n): string =>\n ctx.i18n\n ? localizeLinkPath(authored, {\n basePath: ctx.basePath,\n i18n: ctx.i18n,\n locale: page.locale,\n routes: {\n has: (route) => ctx.routes.has(route) || ctx.extraRoutes.has(route),\n },\n })\n : authored;\n\n/** Validate a resolved internal path: asset, route, then optional anchor. */\nconst checkPathLink = (\n resolved: string,\n fragment: string,\n page: PageRecord,\n link: PageLink,\n site: LinkSite,\n ctx: LinkContext,\n via = \"\"\n): LinkResult => {\n // Page routes carry the site-wide base; an absolute author path is written\n // as if mounted at root, so base it for the route lookup (idempotent — a\n // relative link already resolved against the based `page.route`). A real\n // route always wins over the asset-extension heuristic, so a dotted route\n // (e.g. `/releases/v1.0`) isn't misread as a missing asset.\n const authoredRoute = toRoute(withBasePath(ctx.basePath, resolved));\n const route = servedRoute(authoredRoute, page, ctx);\n if (ctx.routes.has(route)) {\n return fragment ? checkAnchor(route, fragment, site, ctx, via) : null;\n }\n // A custom `.astro` page or generated route serves this path, but its\n // headings aren't indexed — accept any fragment rather than false-flag it.\n if (ctx.extraRoutes.has(route)) {\n return null;\n }\n // A configured `redirect.from` resolves at runtime, so it's a valid target.\n // Its destination (and any anchor there) is validated on its own page, so we\n // don't follow the redirect to check the fragment here.\n if (ctx.redirects.has(route)) {\n return null;\n }\n\n // Assets live in `public/` at the site root, unaffected by the base, so strip\n // it back off before probing the filesystem.\n const assetPath = stripBasePath(ctx.basePath, resolved);\n if (FILE_EXT.test(assetPath) && !DOC_EXT.test(assetPath)) {\n if (assetIsPresent(assetPath, ctx)) {\n return null;\n }\n // A colocated image embed (``) is resolved from beside\n // the page source and emitted to `_astro/` by the image pipeline, so it\n // never lands in `public/`. The *raw* target goes through the same\n // resolver that decides what the `/blume-assets/content` endpoint serves,\n // so a reference the rewriter skips (a `?v=2` suffix, a double-encoded\n // name) is reported here, not accepted. Plain links to the same path stay\n // on the public-dir probe — an href resolves as a site route, and only\n // image nodes are rewritten.\n if (link.image && page.sourcePath && isRelativeImageTarget(link.target)) {\n if (resolveRelativeImage(dirname(page.sourcePath), link.target)) {\n return null;\n }\n // A partial-origin image was rebased into the page's directory for\n // resolution but reports against the partial — cite the path as\n // authored there, so file, path, and \"next to\" agree.\n const authored = link.file\n ? authoredImageTarget(link.target, page.sourcePath, link.file)\n : link.target;\n return {\n ...site,\n code: \"BLUME_BROKEN_ASSET\",\n message: `Image ${authored} was not found next to ${basename(link.file ?? page.sourcePath)}.`,\n severity: \"warning\",\n suggestion:\n \"Add the file next to the page source or fix the reference.\",\n };\n }\n // Nowhere to look: no `public/` directory.\n if (ctx.publicDir === null) {\n return \"asset-unchecked\";\n }\n return {\n ...site,\n code: \"BLUME_BROKEN_ASSET\",\n message: `Asset ${assetPath} was not found in the public directory.`,\n severity: \"warning\",\n suggestion: `Add the file at public${assetPath} or fix the link.`,\n };\n }\n\n return {\n ...site,\n code: \"BLUME_BROKEN_LINK\",\n message: `Broken link to ${link.target}${via}: no page resolves to ${route}.`,\n severity: \"error\",\n suggestion: \"Check the path, or create the target page.\",\n };\n};\n\n/** Probe queued external links with bounded concurrency. */\nconst checkExternalLinks = async (\n refs: ExternalRef[]\n): Promise<Diagnostic[]> => {\n const results = await probeAll(refs.map((ref) => ref.url));\n\n const diagnostics: Diagnostic[] = [];\n for (const ref of refs) {\n const result = results.get(ref.url);\n const grade = result ? gradeExternal(result) : null;\n if (grade) {\n diagnostics.push({\n code: \"BLUME_DEAD_LINK\",\n column: ref.column,\n file: ref.file,\n line: ref.line,\n message: `External link ${ref.url} is unreachable (${grade.detail}).`,\n severity: grade.severity,\n });\n }\n }\n return diagnostics;\n};\n\n/** Where content files publish, for resolving file links (`./setup.mdx`). */\nexport interface FileRouteIndex {\n /**\n * Absolute source path → the route that file publishes at. A file shared by\n * every locale publishes once per locale; the default locale's route stands\n * for it (a link from a localized page moves into that locale afterwards,\n * exactly as the rendered link does). Fallback copies render another\n * locale's file, so they never stand for it.\n */\n bySource: Map<string, string>;\n /**\n * A default-locale page's locale-stripped path (`navPath`) → its route. A\n * page in a locale folder that links a sibling not translated yet\n * (`fr/guides/setup.mdx` missing) means the default tree's file\n * (`guides/setup.mdx`), whose route — its own `slug` included — then moves\n * into the reader's locale onto the fallback copy.\n */\n byDefaultNavPath: Map<string, string>;\n}\n\n/** The linking side of a file link: where the page's source lives. */\nexport interface FileLinkBase {\n navPath: string;\n sourcePath: string;\n}\n\nexport const buildFileRouteIndex = (\n pages: readonly PageRecord[],\n i18n: LocaleRouting | null\n): FileRouteIndex => {\n const bySource = new Map<string, string>();\n const byDefaultNavPath = new Map<string, string>();\n for (const page of pages) {\n const { sourcePath } = page;\n if (!sourcePath || page.fallback) {\n continue;\n }\n const isDefault = page.locale === i18n?.defaultLocale;\n if (!bySource.has(sourcePath) || isDefault) {\n bySource.set(sourcePath, page.route);\n }\n if (isDefault) {\n byDefaultNavPath.set(normalize(page.navPath), page.route);\n }\n }\n return { byDefaultNavPath, bySource };\n};\n\n/**\n * The route a file link written on `from` lands on: the linked file's own\n * route, or — when a locale folder doesn't have that file yet — the default\n * tree's file at the same place.\n */\nexport const routeOfLinkedFile = (\n index: FileRouteIndex,\n from: FileLinkBase,\n path: string\n): string | undefined =>\n index.bySource.get(resolve(dirname(from.sourcePath), path)) ??\n index.byDefaultNavPath.get(normalize(join(dirname(from.navPath), path)));\n\n/**\n * The path a relative link on `page` resolves to — the same reading the\n * Markdown pipeline rewrites the rendered `href` to (see\n * {@link resolveRelativeHref}), so what's checked is what ships. A relative\n * asset (`./diagram.png`) isn't a page link; it resolves against the route's\n * directory for the public-dir probe.\n */\nconst relativeTarget = (\n page: PageRecord,\n rawPath: string,\n ctx: LinkContext\n): string => {\n const base = { isIndex: isIndexPage(page), route: page.route };\n const { navPath, sourcePath } = page;\n const resolveFile = sourcePath\n ? (path: string) =>\n routeOfLinkedFile(ctx.fileRoutes, { navPath, sourcePath }, path)\n : undefined;\n return (\n resolveRelativeHref(rawPath, base, resolveFile, (route) =>\n ctx.routes.has(route)\n ) ?? resolveRelative(page.route, rawPath, base.isIndex)\n );\n};\n\n/** Classify a single link, queueing external refs via `onExternal`. */\nconst classifyLink = (\n page: PageRecord,\n link: PageLink,\n ctx: LinkContext,\n onExternal: (ref: ExternalRef) => void\n): LinkResult => {\n const { target } = link;\n const site: LinkSite = {\n column: link.column,\n // A link written inside an included partial reports against the partial\n // file, so the author fixes it where it lives.\n file: link.file ?? page.sourcePath ?? page.id,\n line: link.line,\n };\n\n if (HTTP.test(target) || PROTOCOL_RELATIVE.test(target)) {\n onExternal({\n ...site,\n url: PROTOCOL_RELATIVE.test(target) ? `https:${target}` : target,\n });\n return null;\n }\n if (SCHEME.test(target)) {\n // mailto:, tel:, and other non-HTTP schemes are not validated.\n return null;\n }\n\n const hashIndex = target.indexOf(\"#\");\n // Browser-copied links arrive percent-encoded (`/caf%C3%A9`, `#caf%C3%A9`)\n // while routes and anchor slugs are stored decoded — decode before comparing\n // so valid links aren't reported broken.\n const fragment = decodePercent(\n hashIndex === -1 ? \"\" : target.slice(hashIndex + 1)\n );\n let rawPath = hashIndex === -1 ? target : target.slice(0, hashIndex);\n const queryIndex = rawPath.indexOf(\"?\");\n if (queryIndex !== -1) {\n rawPath = rawPath.slice(0, queryIndex);\n }\n rawPath = decodePercent(rawPath);\n\n // A relative path (or a bare anchor) means something different from every\n // including page; an absolute path means the same thing everywhere — so\n // only includer-dependent targets carry the \"included by\" context, and\n // identical absolute-target reports collapse in the final dedupe.\n const via = rawPath.startsWith(\"/\") ? \"\" : includedBySuffix(link, page);\n if (rawPath === \"\") {\n return fragment ? checkAnchor(page.route, fragment, site, ctx, via) : null;\n }\n\n const resolved = rawPath.startsWith(\"/\")\n ? rawPath\n : relativeTarget(page, rawPath, ctx);\n return checkPathLink(resolved, fragment, page, link, site, ctx, via);\n};\n\n/**\n * Validate every link discovered in the content graph: internal page links and\n * anchors against the route map, asset links against the public dir, and\n * (opt-in) external links over the network.\n */\nexport const validateLinks = async (\n graph: ContentGraph,\n options: {\n /** Site-wide route mount point (`\"\"` or `/seg`); routes and redirects carry it. */\n basePath?: string;\n /**\n * Servable routes the graph can't know: custom `.astro` pages and generated\n * routes (e.g. the `/changelog` index). Mounted outside `basePath` (they're\n * injected at their pattern), so they are *not* based here — mirroring the\n * full-route-set resolution in `nav-diagnostics.ts`/`generateRuntime`.\n */\n extraRoutes?: string[];\n /** Locale routing when i18n is on; links then resolve into the page's locale. */\n i18n?: LocaleRouting | null;\n publicDir: string | null;\n checkExternal?: boolean;\n /** Configured redirects; their `from` paths count as valid link targets. */\n redirects?: { from: string }[];\n }\n): Promise<Diagnostic[]> => {\n const basePath = options.basePath ?? \"\";\n const ctx: LinkContext = {\n anchors: buildAnchorIndex(graph.pages),\n basePath,\n extraRoutes: new Set((options.extraRoutes ?? []).map(toRoute)),\n fileRoutes: buildFileRouteIndex(graph.pages, options.i18n ?? null),\n i18n: options.i18n ?? null,\n publicDir: options.publicDir,\n redirects: new Set(\n (options.redirects ?? []).map((redirect) =>\n toRoute(withBasePath(basePath, redirect.from))\n )\n ),\n routes: new Set(graph.routes.keys()),\n };\n const diagnostics: Diagnostic[] = [];\n const external: ExternalRef[] = [];\n let uncheckedAssets = 0;\n\n for (const page of graph.pages) {\n for (const link of page.links) {\n const result = classifyLink(page, link, ctx, (ref) => external.push(ref));\n if (result === \"asset-unchecked\") {\n uncheckedAssets += 1;\n } else if (result) {\n diagnostics.push(result);\n }\n }\n }\n\n if (uncheckedAssets > 0) {\n diagnostics.push({\n code: \"BLUME_ASSETS_UNCHECKED\",\n message: `${uncheckedAssets} asset link(s) not checked: no public/ directory found.`,\n severity: \"info\",\n });\n }\n\n if (options.checkExternal && external.length > 0) {\n diagnostics.push(...(await checkExternalLinks(external)));\n }\n\n // A partial spliced into several pages (or every locale of one) yields the\n // same diagnostic once per including page record; byte-identical reports\n // add noise without information, so only the first of each survives.\n const seen = new Set<string>();\n return diagnostics.filter((diagnostic) => {\n const key = [\n diagnostic.code,\n diagnostic.file ?? \"\",\n diagnostic.line ?? \"\",\n diagnostic.column ?? \"\",\n diagnostic.message,\n ].join(\"\\n\");\n if (seen.has(key)) {\n return false;\n }\n seen.add(key);\n return true;\n });\n};\n",
|
|
51
|
+
"import { readdirSync, statSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\n\nimport {\n basename,\n dirname,\n extname,\n normalize,\n relative,\n resolve,\n} from \"pathe\";\n\nimport { normalizeBasePath } from \"./base-path.ts\";\nimport { nextFenceState } from \"./code-fences.ts\";\nimport type { FenceState } from \"./code-fences.ts\";\nimport { hashText } from \"./sources/cache.ts\";\nimport { INLINE_CODE, MD_IMAGE, targetOffsetIn } from \"./sources/normalize.ts\";\nimport { readExpandedEntryText } from \"./sources/read.ts\";\nimport type { ContentSource } from \"./sources/types.ts\";\nimport type { PageRecord } from \"./types.ts\";\n\n/**\n * Colocated content images — `` next to the page that\n * references it. The HTML render optimizes these through `astro:assets` into\n * hashed `_astro/` files, but that mapping doesn't exist yet when the raw\n * agent-facing Markdown (`/<route>.md`, llms-full.txt, MCP) is snapshotted at\n * generate time — so a verbatim relative path would 404 for every agent\n * fetching the page by URL. Instead, the originals are served at\n * `/blume-assets/content/<project-relative path>` by a generated endpoint (see\n * `contentAssetsEndpointTemplate`), and these helpers rewrite the relative\n * references in agent-facing output to that URL.\n */\n\n/** The endpoint route prefix colocated content images are served under. */\nexport const CONTENT_ASSETS_PREFIX = \"/blume-assets/content\";\n\n// The formats Astro's image pipeline accepts, plus the web-safe pass-throughs;\n// anything else referenced relatively (a `.pdf`, a source file) is left alone.\nconst IMAGE_EXTENSIONS = new Set([\n \".apng\",\n \".avif\",\n \".bmp\",\n \".gif\",\n \".ico\",\n \".jpeg\",\n \".jpg\",\n \".png\",\n \".svg\",\n \".tiff\",\n \".webp\",\n]);\n\n/** Whether a link target is a relative filesystem path (not URL/absolute/hash). */\nconst isRelativeTarget = (target: string): boolean =>\n !(target.startsWith(\"/\") || target.startsWith(\"#\")) && !URL.canParse(target);\n\n/**\n * The endpoint param a colocated image is served under: its project-relative\n * path (readable, collision-free — it mirrors the source tree). A file outside\n * the project root can't be addressed that way (`..` segments don't survive a\n * URL), so it falls back to a content-addressed name.\n */\nexport const contentAssetParam = (\n projectRoot: string,\n absPath: string\n): string => {\n const rel = relative(projectRoot, absPath);\n if (rel.startsWith(\"..\")) {\n return `_/${hashText(absPath)}${extname(absPath)}`;\n }\n return rel;\n};\n\n/** Percent-decode an image target; malformed escapes stay verbatim. */\nconst decodeTarget = (target: string): string => {\n try {\n return decodeURI(target);\n } catch {\n return target;\n }\n};\n\n/**\n * Whether a target is *shaped* like a colocated image reference: a relative\n * filesystem path with an image extension. Exported so link validation can\n * tell \"not a colocated candidate\" apart from \"a candidate that resolves\n * nowhere\" — the former falls through to the public-dir probe, the latter is\n * a broken reference beside the page source.\n */\nexport const isRelativeImageTarget = (target: string): boolean =>\n isRelativeTarget(target) &&\n IMAGE_EXTENSIONS.has(extname(decodeTarget(target)).toLowerCase());\n\n/**\n * Whether `abs` is a file whose trailing `segments` names match the on-disk\n * entries exactly. A bare `existsSync` accepts `./Diagram.PNG` for\n * `diagram.png` (or a directory named like an image) on a case-insensitive\n * filesystem — the reference then validates and serves locally but breaks on\n * the case-sensitive Linux build.\n */\nconst existsAsWritten = (abs: string, segments: number): boolean => {\n let current = abs;\n for (let i = 0; i < segments; i += 1) {\n const parent = dirname(current);\n let entries: string[];\n try {\n entries = readdirSync(parent);\n } catch {\n return false;\n }\n if (!entries.includes(basename(current))) {\n return false;\n }\n current = parent;\n }\n const stat = statSync(abs, { throwIfNoEntry: false });\n return stat !== undefined && stat.isFile();\n};\n\n/**\n * Resolve one image target against its page's directory. Returns the absolute\n * file path when the target is relative, is an image, and exists on disk —\n * anything else (remote URLs, `public/` absolutes, broken refs, code-block\n * examples that happen to look like paths) is null and left untouched. Shared\n * with link validation, so what counts as a colocated image is decided once.\n */\nexport const resolveRelativeImage = (\n sourceDir: string,\n target: string\n): string | null => {\n if (!isRelativeImageTarget(target)) {\n return null;\n }\n const decoded = decodeTarget(target);\n // Only the segments the author wrote are checked against on-disk names;\n // `sourceDir`'s own casing is the filesystem's business, not the target's.\n const segments = normalize(decoded)\n .split(\"/\")\n .filter((part) => part !== \"\" && part !== \"..\").length;\n const abs = resolve(sourceDir, decoded);\n return existsAsWritten(abs, segments) ? abs : null;\n};\n\n/** Encode an endpoint param for use in a Markdown URL, keeping `/` separators. */\nconst encodedParam = (param: string): string =>\n param.split(\"/\").map(encodeURIComponent).join(\"/\");\n\n/**\n * Rewrite one line's relative image targets. Matches run on a copy with inline\n * code blanked out (a `` `` `` span is syntax being *shown*, not\n * an image), while replacements splice into the real line by index — the mask\n * preserves length, so the indices line up.\n */\nconst rewriteLine = (\n line: string,\n toUrl: (target: string) => string | null\n): string => {\n const masked = line.replaceAll(INLINE_CODE, (span) =>\n \" \".repeat(span.length)\n );\n let out = \"\";\n let cursor = 0;\n for (const match of masked.matchAll(MD_IMAGE)) {\n const target = match.groups?.target ?? \"\";\n const url = toUrl(target);\n if (url === null) {\n continue;\n }\n const offset =\n (match.index ?? 0) +\n targetOffsetIn(match[0], target, match.groups?.title);\n out += line.slice(cursor, offset) + url;\n cursor = offset + target.length;\n }\n return out + line.slice(cursor);\n};\n\n/**\n * Rewrite a page's relative image references to their served\n * `/blume-assets/content/…` URLs (under `deployment.base` when set). Fenced\n * code blocks and inline code are skipped; only references whose file actually\n * exists next to the source are touched. `register` observes each rewritten\n * asset so a caller can accumulate the files the endpoint must serve.\n */\nexport const rewriteRelativeImages = (options: {\n source: string;\n sourcePath: string;\n projectRoot: string;\n deployBase?: string;\n register?: (param: string, absPath: string) => void;\n}): string => {\n const { source, sourcePath, projectRoot, deployBase, register } = options;\n const sourceDir = dirname(sourcePath);\n const prefix = `${normalizeBasePath(deployBase)}${CONTENT_ASSETS_PREFIX}`;\n const toUrl = (target: string): string | null => {\n const abs = resolveRelativeImage(sourceDir, target);\n if (abs === null) {\n return null;\n }\n const param = contentAssetParam(projectRoot, abs);\n register?.(param, abs);\n return `${prefix}/${encodedParam(param)}`;\n };\n\n let fence: FenceState = null;\n const lines = source.split(\"\\n\").map((line) => {\n const next = nextFenceState(line, fence);\n const inFence = fence !== null || next !== null;\n fence = next;\n return inFence ? line : rewriteLine(line, toUrl);\n });\n return lines.join(\"\\n\");\n};\n\n/**\n * Every colocated image the project's pages reference, keyed by endpoint param.\n * Serialized to `generated/content-assets.json`, which the\n * `/blume-assets/[...asset]` endpoint reads to serve the original files. Runs\n * the same rewrite the agent-Markdown builders apply — over the same\n * include-expanded text, so a partial's colocated images (rebased into the\n * including page by the expander) are served too — keeping the served set and\n * the rewritten URLs from drifting apart.\n */\nexport const collectContentAssets = async (project: {\n context: { root: string };\n manifest: { routes: { id: string; sourcePath?: string }[] };\n graph: { pages: PageRecord[] };\n sources?: ContentSource[];\n}): Promise<Record<string, string>> => {\n const pageById = new Map(project.graph.pages.map((page) => [page.id, page]));\n const files: Record<string, string> = {};\n await Promise.all(\n project.manifest.routes.map(async (route) => {\n if (!route.sourcePath) {\n return;\n }\n const page = pageById.get(route.id);\n let source: string;\n try {\n source = page\n ? await readExpandedEntryText(project, page)\n : await readFile(route.sourcePath, \"utf-8\");\n } catch {\n return;\n }\n rewriteRelativeImages({\n projectRoot: project.context.root,\n register: (param, abs) => {\n files[param] = abs;\n },\n source,\n sourcePath: route.sourcePath,\n });\n })\n );\n return files;\n};\n",
|
|
52
|
+
"/**\n * Fenced-code state for line scanners. Kept free of imports so request-time\n * code (the Ask AI grounding excerpts) can share it with the build-time source\n * scanners without pulling the filesystem and schema modules along.\n *\n * CommonMark allows backtick *and* tilde fences, three or more characters\n * long. The scanners track which delimiter opened the current fence and how\n * long its run was (`null` when outside one), so a ``` line inside a ~~~\n * block — or inside a ````-delimited block (the wrapper `codeBlockLines`\n * emits around code that contains its own ``` fence) — is content, not a\n * toggle.\n */\nconst CODE_FENCE = /^(?<run>`{3,}|~{3,})/u;\n\n/** The open fence's delimiter char and run length, or null outside one. */\nexport type FenceState = { delimiter: \"`\" | \"~\"; length: number } | null;\n\n/**\n * Advance the fenced-code state for one line: an opening fence records its\n * delimiter and run length, only a bare run of the same character at least as\n * long closes it (CommonMark), and any other line leaves the state untouched.\n */\nexport const nextFenceState = (line: string, fence: FenceState): FenceState => {\n const trimmed = line.trimStart();\n const run = trimmed.match(CODE_FENCE)?.groups?.run;\n if (run === undefined) {\n return fence;\n }\n const rest = trimmed.slice(run.length);\n const delimiter = run.startsWith(\"`\") ? (\"`\" as const) : (\"~\" as const);\n if (fence === null) {\n // A backtick fence's info string cannot itself contain a backtick\n // (CommonMark) — a line-leading ```inline``` span is a paragraph, and\n // opening a phantom fence on it would swallow every heading and link\n // after it. Tilde fences carry no such rule.\n if (delimiter === \"`\" && rest.includes(\"`\")) {\n return fence;\n }\n return { delimiter, length: run.length };\n }\n // A closing fence may be followed only by whitespace: a same-length\n // ```js line inside an open ``` block is content, not a closer.\n return fence.delimiter === delimiter &&\n run.length >= fence.length &&\n rest.trim() === \"\"\n ? null\n : fence;\n};\n",
|
|
53
|
+
"import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport { join } from \"pathe\";\n\nimport { BlumeError } from \"../diagnostics.ts\";\nimport type { Diagnostic } from \"../types.ts\";\nimport type { SourceEntry, SourceLoadResult } from \"./types.ts\";\n\n/**\n * Small, stable content hash for cache/HMR bookkeeping — and for staged asset\n * *filenames* (see sources/assets.ts and content-assets.ts), where a collision\n * silently serves the wrong file. 64 bits of SHA-256 keeps those names\n * collision-safe at any realistic asset count; the old 31-bit DJB2 hash had a\n * ~46k-item birthday bound.\n */\nexport const hashText = (text: string): string =>\n createHash(\"sha256\").update(text).digest(\"hex\").slice(0, 16);\n\n/** A stable digest of a source's entries, for change detection while polling. */\nexport const entriesDigest = (entries: SourceEntry[]): string =>\n hashText(\n entries\n .map((entry) => `${entry.ref}:${entry.hash ?? hashText(entry.body.text)}`)\n .join(\"|\")\n );\n\n/**\n * Build an opt-in polling watcher for a remote source: re-`load()` on an\n * interval and fire `onChange` only when the entry digest changes, so a remote\n * source can hot-reload in dev without refetching the world on every keystroke.\n *\n * `load` must fetch fresh (bypassing the cache-first dev path) — polling the\n * cache-first loader would serve the identical snapshot on every tick and\n * never observe a remote change. `seed` (the source's regular, cache-first\n * loader) establishes the baseline digest from what dev actually served, so a\n * remote change landing before the first tick still fires.\n */\nexport const pollingWatch =\n (\n load: () => Promise<SourceLoadResult>,\n intervalSeconds: number,\n seed?: () => Promise<SourceLoadResult>\n ): ((onChange: () => void) => () => void) =>\n (onChange) => {\n let last = \"\";\n if (seed) {\n const seedBaseline = async (): Promise<void> => {\n try {\n const { entries } = await seed();\n last ||= entriesDigest(entries);\n } catch {\n // Fall back to first-tick seeding.\n }\n };\n void seedBaseline();\n }\n const tick = async (): Promise<void> => {\n try {\n const { entries } = await load();\n const next = entriesDigest(entries);\n if (last && next !== last) {\n onChange();\n }\n last = next;\n } catch {\n // Ignore transient poll failures; the cache keeps serving last-known-good.\n }\n };\n const timer = setInterval(() => {\n void tick();\n }, intervalSeconds * 1000);\n return () => clearInterval(timer);\n };\n\n/** A per-source snapshot of the last successful fetch, for offline tolerance. */\nexport interface SnapshotCache {\n read: () => Promise<SourceEntry[]>;\n write: (entries: SourceEntry[]) => Promise<void>;\n}\n\n/** Build a JSON snapshot cache under `<cacheDir>/entries.json`. */\nexport const snapshotCache = (cacheDir: string): SnapshotCache => {\n const file = join(cacheDir, \"entries.json\");\n return {\n read: async () => {\n try {\n // SAFETY: the snapshot file is only ever written by `write` below, from\n // a `SourceEntry[]` via JSON.stringify; a corrupt file lands in the\n // catch and reads as empty.\n return JSON.parse(await readFile(file, \"utf-8\")) as SourceEntry[];\n } catch {\n return [];\n }\n },\n write: async (entries) => {\n try {\n await mkdir(cacheDir, { recursive: true });\n await writeFile(file, `${JSON.stringify(entries)}\\n`, \"utf-8\");\n } catch {\n // Cache is best-effort; a write failure must not fail the build.\n }\n },\n };\n};\n\n/**\n * Run a remote `fetchEntries`, caching the result. When `refresh` is false and a\n * snapshot exists, serve it without fetching (cache-first dev). On fetch failure,\n * serve the last-known-good snapshot with a warning so a CMS/network outage\n * doesn't fail the build; if there is no snapshot either, surface a hard error.\n */\nexport const loadWithCache = async (\n name: string,\n cache: SnapshotCache,\n fetchEntries: () => Promise<SourceEntry[]>,\n refresh = true\n): Promise<SourceLoadResult> => {\n if (!refresh) {\n const cached = await cache.read();\n if (cached.length > 0) {\n return { diagnostics: [], entries: cached };\n }\n }\n try {\n const entries = await fetchEntries();\n await cache.write(entries);\n return { diagnostics: [], entries };\n } catch (error) {\n const fallback = await cache.read();\n if (fallback.length > 0) {\n // SAFETY: everything thrown on this path is an Error — fetch rejects\n // with a TypeError and the source adapters throw Error instances.\n const diagnostic: Diagnostic = {\n code: \"BLUME_SOURCE_OFFLINE\",\n message: `Source \"${name}\" could not be fetched (${(error as Error).message}); served ${fallback.length} cached entries.`,\n severity: \"warning\",\n };\n return { diagnostics: [diagnostic], entries: fallback };\n }\n // SAFETY: same invariant as above — `fetchEntries` failures are Errors.\n throw new BlumeError({\n code: \"BLUME_SOURCE_FETCH_FAILED\",\n message: `Source \"${name}\" failed to load and no cache is available: ${(error as Error).message}`,\n severity: \"error\",\n });\n }\n};\n",
|
|
54
|
+
"import { existsSync, readFileSync } from \"node:fs\";\n\nimport GithubSlugger from \"github-slugger\";\nimport { extname } from \"pathe\";\n\nimport { withBasePath } from \"../base-path.ts\";\nimport { nextFenceState } from \"../code-fences.ts\";\nimport type { FenceState } from \"../code-fences.ts\";\nimport { diagnosticsFromIssues, diagnosticsFromZod } from \"../diagnostics.ts\";\nimport { occupySlug, parseHeadingMarkers } from \"../heading-markers.ts\";\nimport { localePlacement, localizeRoute } from \"../i18n.ts\";\nimport { pageMetaSchema } from \"../schema.ts\";\nimport type {\n FrontmatterExtend,\n PageMeta,\n ResolvedI18nConfig,\n} from \"../schema.ts\";\nimport { trimChar } from \"../trim.ts\";\nimport type { Diagnostic, Heading, PageLink, PageRecord } from \"../types.ts\";\nimport { detectVersionRef, versionizeRoute } from \"../versions.ts\";\nimport type { NormalizeContext, SourceEntry } from \"./types.ts\";\n\nconst NUMERIC_PREFIX = /^\\d+[-_.]/u;\nconst GROUP_FOLDER = /^\\((?<label>.+)\\)$/u;\nconst WORD_SPLIT = /[-_]/u;\n\n/** Strip a leading numeric ordering prefix (`01-intro` -> `intro`). */\nconst stripNumericPrefix = (segment: string): string =>\n segment.replace(NUMERIC_PREFIX, \"\");\n\n/** Detect a group folder `(name)` and return its label, else null. */\nconst groupLabel = (segment: string): string | null =>\n segment.match(GROUP_FOLDER)?.groups?.label ?? null;\n\n/**\n * Slugify a content/route slug (Sanity, Notion, frontmatter `slug`). Heading\n * anchor ids are *not* slugged here — they use a `github-slugger` in\n * {@link extractHeadings}, matching the renderer (see `markdown/heading-anchors`)\n * so `blume validate` checks anchors against the exact rendered heading ids.\n *\n * The keep-class is Unicode letters/marks/numbers, not `\\w`: ASCII slugs are\n * unchanged, but a CJK/Cyrillic/accented slug keeps its characters instead of\n * collapsing to `\"\"` (which forced Sanity/Notion routes onto their opaque\n * document-id fallbacks) or dropping accents (`café` → `caf`). NFC first so a\n * macOS-NFD `é` (e + combining mark) slugs identically to the composed form.\n */\nexport const slugify = (text: string): string =>\n text\n .normalize(\"NFC\")\n .toLowerCase()\n .trim()\n .replaceAll(/[^\\p{L}\\p{M}\\p{N}\\s_-]/gu, \"\")\n .replaceAll(/[\\s_]+/gu, \"-\")\n .replaceAll(/-+/gu, \"-\")\n .replaceAll(/^-|-$/gu, \"\");\n\n/**\n * {@link slugify} for a slug that may span path segments (`guides/setup`).\n * `slugify` deletes `/` along with all other punctuation, which would mash\n * `guides/setup` into `guidessetup` — and collide it with a genuine `guidessetup`\n * document. Each segment is slugged on its own and the separators kept.\n */\nexport const slugifyPath = (text: string): string =>\n text.split(\"/\").map(slugify).filter(Boolean).join(\"/\");\n\n/** Title-case a slug segment for display. */\nconst titleCase = (value: string): string =>\n value\n .split(WORD_SPLIT)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n/**\n * Strip characters that cannot survive the route → URL → output-file round\n * trip. A `:` ahead of the first `/` makes `new URL()` read the segment as a\n * scheme (`Guide: Architecture.md` → `guide:`), which crashes Astro's\n * prerender write with \"The URL must be of scheme file\"; control characters\n * (an embedded newline in a filename) are silently dropped by the URL parser,\n * desyncing the route from its output path. Both are legal in macOS/Linux\n * filenames, so they are removed here rather than rejected.\n */\nconst sanitizeSegment = (segment: string): string =>\n segment.replaceAll(/[:\\p{Cc}]/gu, \"\");\n\n/** Fold one raw path part into the accumulating route segments/groups. */\nconst addRouteSegment = (\n part: string,\n segments: string[],\n groups: string[]\n): void => {\n // A leading/trailing/double slash yields an empty part; keeping it would\n // produce a malformed route (`//foo`, `/foo/`) that nothing can link to.\n if (part === \"\") {\n return;\n }\n const group = groupLabel(part);\n if (group !== null) {\n groups.push(group);\n return;\n }\n const clean = stripNumericPrefix(part);\n if (clean === \"index\") {\n return;\n }\n const safe = sanitizeSegment(clean);\n // A part that was nothing but stripped characters cannot name a segment.\n if (safe === \"\") {\n return;\n }\n segments.push(safe);\n};\n\n/** URL + nav metadata mapped from one content-root-relative path. */\ninterface MappedRoute {\n segments: string[];\n groups: string[];\n route: string;\n}\n\n/**\n * Convert a content-root-relative path into URL + nav metadata. Not exported:\n * a source that needs to predict a route goes through\n * {@link resolveEntryRoute}, so there is exactly one derivation.\n */\nconst mapRoute = (relativePath: string): MappedRoute => {\n const withoutExt = relativePath.slice(\n 0,\n relativePath.length - extname(relativePath).length\n );\n const rawParts = withoutExt.split(\"/\");\n\n const segments: string[] = [];\n const groups: string[] = [];\n\n for (const part of rawParts) {\n addRouteSegment(part, segments, groups);\n }\n\n const route = segments.length === 0 ? \"/\" : `/${segments.join(\"/\")}`;\n return { groups, route, segments };\n};\n\n// A closing hash sequence must be preceded by whitespace (CommonMark), so a\n// heading like `## What is C#` keeps its trailing `#`. Up to 3 leading spaces\n// are allowed; 4+ is an indented code block.\nconst ATX_HEADING = /^ {0,3}(?<hashes>#{1,6})\\s+(?<text>.+?)(?:\\s+#+)?\\s*$/u;\n// A setext underline: a run of `=` (level 1) or `-` (level 2) alone on a line,\n// up to 3 leading spaces. It only forms a heading directly under paragraph\n// text — see `scanHeadingLine`.\nconst SETEXT_UNDERLINE = /^ {0,3}(?<marker>=+|-+)\\s*$/u;\n// Lines that end a paragraph without being one (CommonMark): blank lines are\n// checked separately; these cover list items, blockquotes, and thematic\n// breaks, so a `---` after any of them stays a thematic break, not an\n// underline promoting the list/quote text to a heading.\nconst PARAGRAPH_INTERRUPT = /^ {0,3}(?:[-+*][ \\t]|\\d{1,9}[.)][ \\t]|>)/u;\nconst THEMATIC_BREAK =\n /^ {0,3}(?:(?:-[ \\t]*){3,}|(?:\\*[ \\t]*){3,}|(?:_[ \\t]*){3,})$/u;\nconst FRONT_MATTER_CLOSE = /^(?:-{3}|\\.{3})\\s*$/u;\n// `<Prompt>` renders its children into a permanently `hidden` DOM node (see\n// `Prompt.astro`) — the agent-facing prompt text is never visible page\n// content, only read by client JS for the copy button. Any `##` inside it\n// must not surface in the page's heading-derived table of contents. Tracked\n// as an open/close depth, the same way fenced code blocks are tracked above.\n// The opening tag is matched only at the start of a trimmed line: block-level\n// JSX in MDX starts its own line, so a mention mid-prose or mid-heading —\n// \"the `<Prompt>` component\", `## Using <Prompt>` — never opens a hidden\n// region (an unanchored match here silently ate every heading after the\n// mention). The lookahead rejects longer tag names that share the prefix,\n// like `<PromptCard>` or `<Prompt-Custom>`.\nconst PROMPT_OPEN = /^<Prompt(?![\\w-])/u;\n// Unanchored: while inside a prompt the close tag may trail the hidden\n// children text (`...copy this.</Prompt>`), not just sit on its own line.\nconst PROMPT_CLOSE = /<\\/Prompt>/u;\n\n/**\n * The body lines, minus a leading front matter block, plus the height of the\n * block that was dropped (`offset`) so line numbers can be reported against\n * the whole body. Bodies from the normalize pipeline are already\n * frontmatter-stripped, but `scanBody` also runs on raw documents — where a\n * leading `---` block (closed by `---` or `...`) is front matter, not a\n * thematic break whose closing `---` would underline the last metadata line\n * into a phantom setext heading.\n */\nconst linesWithoutFrontMatter = (body: string) => {\n const lines = body.split(\"\\n\");\n if (!/^-{3}\\s*$/u.test(lines[0] ?? \"\")) {\n return { lines, offset: 0 };\n }\n // A blank line directly after the dashes means the body *opens* with a\n // thematic break, not front matter — YAML metadata starts on the very next\n // line. Treating it as an unclosed block ate everything up to the next\n // `---`/`...` line of an already-stripped body.\n if ((lines[1] ?? \"\").trim() === \"\") {\n return { lines, offset: 0 };\n }\n const close = lines.findIndex(\n (line, index) => index > 0 && FRONT_MATTER_CLOSE.test(line)\n );\n return close === -1\n ? { lines, offset: 0 }\n : { lines: lines.slice(close + 1), offset: close + 1 };\n};\n\n// A trailing `{#id}` heading marker written without a backslash escape. Both\n// pipelines resolve escapes before parsing markers (see `ESCAPED_PUNCTUATION`),\n// so `\\{#id\\}` is the same marker — and the only spelling that survives the\n// MDX parser, where a bare `{…}` is a JSX expression and `#id` is not a valid\n// one (`Could not parse expression with acorn`). Further bracket markers may\n// follow the brace (`{#id} [toc]`), nothing else.\nconst BARE_CURLY_MARKER =\n /(?<!\\\\)\\{#(?<id>[^\\s}]+)\\}(?:\\s*\\[(?:#[^\\s\\]]+|!?toc)\\])*\\s*$/u;\n\n// A raw HTML element carrying an `id` — `<a id=\"…\">`, `<section id='…'>`,\n// the unquoted `<a id=plain>`, or the JSX spelling `<div id={\"…\"}>` — whose\n// element is a fragment-link target outside headings. Lowercase tags only: a\n// capitalized `<YouTube id=\"…\">` is a component prop, not a DOM id (the\n// `JSX_OPEN` split below). `[^<>]` bounds the attribute run, so a wrapped tag\n// (`<div\\n id=\"x\"\\n>`) still matches while a long tag-free line can't\n// backtrack quadratically, and the run never reaches into a neighboring tag.\nconst HTML_ID =\n /<[a-z][a-z0-9-]*(?:\\s[^<>]*?)?\\sid=(?:(?<quote>[\"'])(?<quoted>[^\"'<>]+)\\k<quote>|\\{(?<jsxQuote>[\"'])(?<jsx>[^\"'<>]+)\\k<jsxQuote>\\}|(?<bare>[^\\s\"'=<>`{}]+))/gu;\n// Commented-out markup renders nothing; matched across lines once the\n// scannable lines are joined back together. Shared with the search\n// extractor so both agree on what a comment is.\nexport const HTML_COMMENT = /<!--[\\s\\S]*?-->/gu;\nexport const INLINE_CODE = /`[^`]*`/gu;\n\n/** A heading whose trailing `{#id}` marker is unescaped — see `BARE_CURLY_MARKER`. */\nexport interface CurlyMarker {\n id: string;\n /** 1-based line of the heading (a setext heading's first text line) in the body. */\n line: number;\n}\n\n/** Scanner state: the open fence plus the paragraph lines accumulated so far. */\ninterface HeadingScanState {\n /**\n * Lines eligible to hold an HTML `id` — outside fences and `<Prompt>`\n * regions, inline code masked — collected for one `HTML_ID` pass at the\n * end so a tag wrapped over several lines still matches.\n */\n anchorLines: string[];\n curlyMarkers: CurlyMarker[];\n fence: FenceState;\n /** 1-based body line of the line being scanned. */\n line: number;\n /** Where each heading in `headings` sits, index-aligned. */\n sites: HeadingSite[];\n /** Consecutive paragraph lines — the candidate text for a setext underline. */\n paragraph: string[];\n /** Body line of the first line in `paragraph`. */\n paragraphStart: number;\n /** Nesting depth inside `<Prompt>...</Prompt>` — 0 when outside one. */\n promptDepth: number;\n /** True inside a multi-line `<Prompt` opening tag, awaiting its `>`. */\n promptTag: boolean;\n}\n\n/**\n * Consume the rest of a `<Prompt` opening tag, scanning a trimmed line from\n * `start`. The tag's attributes may spread over several lines\n * (`state.promptTag` carries the search onto the next one), and until the\n * terminating `>` arrives it isn't known whether the tag even has children —\n * so the depth only rises once that `>` is found, and not when it turns out\n * to be `/>` or when the element also closes on the same line\n * (`<Prompt ...>copy this</Prompt>`). Attribute values containing `>` are not\n * parsed: the first `>` ends the tag, which errs toward opening a region a\n * real close tag will still exit.\n */\nconst finishPromptTag = (\n line: string,\n start: number,\n state: HeadingScanState\n): void => {\n const end = line.indexOf(\">\", start);\n if (end === -1) {\n state.promptTag = true;\n return;\n }\n state.promptTag = false;\n if (line[end - 1] === \"/\" || line.includes(\"</Prompt>\", end)) {\n return;\n }\n state.promptDepth += 1;\n};\n\n/**\n * Extract ATX and setext headings from a markdown body, skipping fenced code\n * blocks and `<Prompt>` children, exactly as the renderer sees them: ATX\n * headings may be indented up to 3 spaces, and a paragraph underlined with\n * `=`/`-` is a level 1/2 setext heading. Each heading's anchor slug comes\n * from a per-document\n * `github-slugger` — the exact slugger the renderer uses\n * (`markdown/heading-anchors`) — advanced over every heading in document\n * order. Matching it (rather than a hand-rolled slugify) keeps the manifest's\n * anchor ids identical to the rendered ones, so `blume validate` stops\n * false-flagging links like `#the-read--write-fallback` (a hand slugify\n * collapses `--`; github-slugger keeps it) and resolves repeated headings the\n * same way (`setup`, `setup-1`).\n */\n// CommonMark's escapable ASCII punctuation. The renderer only ever sees\n// heading text *after* the Markdown parser has resolved backslash escapes, so\n// `\\[toc]` reaches the hast as plain `[toc]` and the marker still applies;\n// resolving escapes here keeps the two pipelines identical (there is no\n// inline way to write a literal trailing marker — use inline code instead).\nconst ESCAPED_PUNCTUATION = /\\\\(?<char>[!-/:-@[-`{-~])/gu;\n\n// The start of a link-reference definition, as the renderer accepts it:\n// `[label]:` after up to 3 leading spaces, optionally inside block-quote or\n// list-item containers (`> [label]: /url`, `- [label]: /url`) — a definition\n// nested in either still defines the label document-wide. `rest` is whatever\n// follows the colon on the same line.\n//\n// Every container iteration begins with its marker and ends with the\n// whitespace that follows it, so a whitespace run belongs to exactly one\n// iteration. Letting an iteration start with optional whitespace as well\n// gave each run two homes and backtracked exponentially on `>\\t>\\t>…` and\n// `*\\t\\t*\\t\\t*…` lines (CodeQL js/redos).\nconst REF_DEFINITION =\n /^(?: {0,3}|[ \\t]*(?:(?:>|(?:[-*+]|\\d{1,9}[.)])[ \\t])[ \\t]*)+)\\[(?<label>[^\\]]+)\\]:[ \\t]*(?<rest>.*)$/u;\n\n/**\n * The normalized labels of every link-reference definition in the body\n * (outside fenced code). A trailing heading bracket whose label is defined is\n * a CommonMark shortcut link, not a marker — the renderer leaves it in the\n * heading as an `<a>`, so the marker parse must skip it too. Labels match\n * case-insensitively with collapsed internal whitespace (CommonMark).\n *\n * Only a *valid* definition defines a label: the label must contain a\n * non-whitespace character, and a destination must follow — on the same line\n * or, as CommonMark allows, alone on the next. A bare `[toc]:` with nothing\n * after it is paragraph text, and the renderer still treats the heading's\n * `[toc]` as literal — which Blume reads as a marker — so it must not be\n * recorded here.\n */\nconst refDefinitionLabels = (lines: readonly string[]): Set<string> => {\n const labels = new Set<string>();\n let fence: FenceState = null;\n for (const [index, line] of lines.entries()) {\n const next = nextFenceState(line, fence);\n if (fence !== null || next !== null) {\n fence = next;\n continue;\n }\n const groups = line.match(REF_DEFINITION)?.groups;\n if (groups?.label === undefined || groups.label.trim() === \"\") {\n continue;\n }\n const destination = groups.rest ?? \"\";\n if (destination === \"\" && (lines[index + 1] ?? \"\").trim() === \"\") {\n continue;\n }\n labels.add(groups.label.trim().replaceAll(/\\s+/gu, \" \").toLowerCase());\n }\n return labels;\n};\n\n/**\n * A heading record from raw heading text: escapes resolved and trailing\n * markers stripped, exactly as the renderer sees them. A `[#custom-id]` pin\n * becomes the slug verbatim and — matching the renderer — occupies its id in\n * the slugger, so a later heading whose auto-slug collides disambiguates\n * (`setup` → `setup-1`). `[!toc]`/`[toc]` headings stay in the record: their\n * ids exist in the rendered page, so links to them are valid anchors\n * regardless of TOC visibility. A heading that is nothing but markers keeps\n * them as literal text, mirroring the renderer.\n */\n/** A scanned heading plus whether its id came from an author pin. */\ninterface ScannedHeading {\n heading: Heading;\n pinned: boolean;\n}\n\nconst toHeading = (\n depth: number,\n raw: string,\n slugger: GithubSlugger,\n isRefDefined: (label: string) => boolean\n): ScannedHeading => {\n const unescaped = raw.replaceAll(ESCAPED_PUNCTUATION, \"$<char>\");\n const markers = parseHeadingMarkers(unescaped, isRefDefined);\n const text = markers.text.trim();\n if (text === \"\" && (markers.id !== undefined || markers.toc !== undefined)) {\n return {\n heading: { depth, slug: slugger.slug(unescaped), text: unescaped },\n pinned: false,\n };\n }\n if (markers.id !== undefined) {\n occupySlug(slugger, markers.id);\n return { heading: { depth, slug: markers.id, text }, pinned: true };\n }\n return { heading: { depth, slug: slugger.slug(text), text }, pinned: false };\n};\n\n/** Record a heading and where a trailing marker would be written for it. */\nconst pushHeading = (\n headings: Heading[],\n state: HeadingScanState,\n scanned: ScannedHeading,\n line: number\n): void => {\n headings.push(scanned.heading);\n state.sites.push({ line, pinned: scanned.pinned });\n};\n\n/** Record a heading's unescaped trailing `{#id}` so `.mdx` pages can be warned. */\nconst noteCurlyMarker = (\n text: string,\n line: number,\n state: HeadingScanState\n): void => {\n const id = text.match(BARE_CURLY_MARKER)?.groups?.id;\n if (id !== undefined) {\n state.curlyMarkers.push({ id, line });\n }\n};\n\n/** Scan a line outside fences and prompts: an anchor host, a heading, or prose. */\nconst scanContentLine = (\n line: string,\n state: HeadingScanState,\n slugger: GithubSlugger,\n headings: Heading[],\n isRefDefined: (label: string) => boolean\n): void => {\n // Inline code is masked so a documented `<a id=\"…\">` isn't an anchor.\n state.anchorLines.push(line.replaceAll(INLINE_CODE, \"\"));\n const atx = line.match(ATX_HEADING);\n if (atx?.groups) {\n const depth = atx.groups.hashes?.length ?? 1;\n const text = (atx.groups.text ?? \"\").trim();\n pushHeading(\n headings,\n state,\n toHeading(depth, text, slugger, isRefDefined),\n state.line\n );\n noteCurlyMarker(text, state.line, state);\n state.paragraph = [];\n return;\n }\n const setext = line.match(SETEXT_UNDERLINE);\n if (setext?.groups && state.paragraph.length > 0) {\n // Setext wins over thematic break when it closes a paragraph (CommonMark);\n // a multi-line paragraph renders as one heading, soft breaks as spaces.\n const depth = setext.groups.marker?.startsWith(\"=\") ? 1 : 2;\n const text = state.paragraph.join(\" \").trim();\n // A setext heading's markers trail its last text line, just above the\n // underline — that is where a pin is appended.\n pushHeading(\n headings,\n state,\n toHeading(depth, text, slugger, isRefDefined),\n state.line - 1\n );\n noteCurlyMarker(text, state.paragraphStart, state);\n state.paragraph = [];\n return;\n }\n if (\n line.trim() === \"\" ||\n THEMATIC_BREAK.test(line) ||\n PARAGRAPH_INTERRUPT.test(line)\n ) {\n state.paragraph = [];\n return;\n }\n if (state.paragraph.length === 0) {\n state.paragraphStart = state.line;\n }\n state.paragraph.push(line.trim());\n};\n\n/** Scan one line for a heading, advancing the fence/paragraph state. */\nconst scanHeadingLine = (\n line: string,\n state: HeadingScanState,\n slugger: GithubSlugger,\n headings: Heading[],\n isRefDefined: (label: string) => boolean\n): void => {\n const next = nextFenceState(line, state.fence);\n // Skip fence delimiter lines themselves and anything inside a fence. A fence\n // also ends any open paragraph, so no underline can reach across it.\n if (state.fence !== null || next !== null) {\n state.fence = next;\n state.paragraph = [];\n return;\n }\n // Prompt tags may be indented arbitrarily (MDX has no indented code\n // blocks), so they match against the trimmed line. A tag line can't also\n // be a heading, so each just updates the state and moves on, same as a\n // fence delimiter line. Outside a prompt, a `</Prompt>` line is plain text.\n const trimmed = line.trimStart();\n if (state.promptTag) {\n finishPromptTag(trimmed, 0, state);\n state.paragraph = [];\n return;\n }\n if (PROMPT_OPEN.test(trimmed)) {\n finishPromptTag(trimmed, \"<Prompt\".length, state);\n state.paragraph = [];\n return;\n }\n if (state.promptDepth > 0) {\n if (PROMPT_CLOSE.test(line)) {\n state.promptDepth -= 1;\n }\n state.paragraph = [];\n return;\n }\n scanContentLine(line, state, slugger, headings, isRefDefined);\n};\n\n/** Where a heading's text ends in the scanned text, for appending a marker. */\nexport interface HeadingSite {\n /** 1-based line (of the text passed to `scanBody`) that any trailing marker ends. */\n line: number;\n /** True when the heading already pins its id with `[#id]`/`{#id}`. */\n pinned: boolean;\n}\n\n/** Everything one walk over a body yields for the anchor index. */\nexport interface BodyScan {\n /**\n * Raw HTML element ids (`<a id=\"…\">`) outside headings, fences, inline\n * code, comments, and `<Prompt>` regions — fragment-link targets that\n * `blume validate` accepts alongside heading slugs. Deduplicated, in\n * document order.\n */\n anchors: string[];\n /** Headings whose trailing `{#id}` marker is unescaped, for `.mdx` pages. */\n curlyMarkers: CurlyMarker[];\n headings: Heading[];\n /** Index-aligned with `headings`: where each one's markers would go. */\n sites: HeadingSite[];\n}\n\n/**\n * Scan a body for its headings, explicit HTML anchors, and unescaped `{#id}`\n * markers in one fence-aware walk (the same walk `extractHeadings` exposes for\n * headings alone).\n */\nexport const scanBody = (body: string): BodyScan => {\n const headings: Heading[] = [];\n const slugger = new GithubSlugger();\n const state: HeadingScanState = {\n anchorLines: [],\n curlyMarkers: [],\n fence: null,\n line: 0,\n paragraph: [],\n paragraphStart: 0,\n promptDepth: 0,\n promptTag: false,\n sites: [],\n };\n\n const { lines, offset } = linesWithoutFrontMatter(body);\n const definedLabels = refDefinitionLabels(lines);\n const isRefDefined = (label: string): boolean =>\n definedLabels.has(label.toLowerCase());\n for (const [index, line] of lines.entries()) {\n state.line = index + offset + 1;\n scanHeadingLine(line, state, slugger, headings, isRefDefined);\n }\n\n const anchors = new Set<string>();\n // Replaced with a space rather than removed: dropping a comment outright\n // can splice its neighbors into a new `<!--` (`<!-<!-- x -->->`), and a\n // space keeps a tag from fusing with an `id=` that only a comment separated.\n const markup = state.anchorLines.join(\"\\n\").replaceAll(HTML_COMMENT, \" \");\n for (const match of markup.matchAll(HTML_ID)) {\n const id = match.groups?.quoted ?? match.groups?.jsx ?? match.groups?.bare;\n if (id !== undefined) {\n anchors.add(id);\n }\n }\n return {\n anchors: [...anchors],\n curlyMarkers: state.curlyMarkers,\n headings,\n sites: state.sites,\n };\n};\n\nexport const extractHeadings = (body: string): Heading[] =>\n scanBody(body).headings;\n\n// The label admits one level of nested brackets so an image-wrapped link\n// (`[](/target)`) matches as the *outer* link — with a flat\n// `[^\\]]*` label the match stopped at the image's `]` and the outer target was\n// never seen. The target admits one level of balanced parens so a Wikipedia-\n// style URL (`/wiki/Foo_(bar)`) isn't truncated at its first `)`.\nconst MD_LINK =\n /\\[(?<label>(?:[^[\\]]|\\[[^\\]]*\\])*)\\]\\((?<target>(?:[^()\\s]|\\([^()\\s]*\\))+)(?<title>\\s+\"[^\"]*\")?\\)/gu;\n// An image inside a link label; its target was matched (and so validated) as a\n// link of its own before labels admitted nesting, and still should be.\nexport const MD_IMAGE =\n /!\\[[^\\]]*\\]\\((?<target>(?:[^()\\s]|\\([^()\\s]*\\))+)(?<title>\\s+\"[^\"]*\")?\\)/gu;\n\n/** Column (0-based, within `matched`) where a link/image match's target starts. */\nexport const targetOffsetIn = (\n matched: string,\n target: string,\n title: string | undefined\n): number => matched.length - 1 - (title?.length ?? 0) - target.length;\n\n/**\n * Extract link targets from a markdown body for later validation, recording the\n * 1-based line/column of each target. Skips fenced code blocks and inline code.\n * `lineOffset` shifts every recorded line: the body is frontmatter-stripped, so\n * diagnostics that point into the raw file must add the stripped block's height.\n */\n/** Scan one line for link targets; returns the next fenced-block state. */\nconst scanLinkLine = (\n line: string,\n lineNumber: number,\n fence: FenceState,\n links: PageLink[]\n): FenceState => {\n const next = nextFenceState(line, fence);\n // Skip fence delimiter lines themselves and anything inside a fence.\n if (fence !== null || next !== null) {\n return next;\n }\n // Blank out inline code spans (`[label](/x)` shown as syntax, not a link)\n // with same-length padding so recorded columns stay accurate.\n const masked = line.replaceAll(INLINE_CODE, (span) =>\n \" \".repeat(span.length)\n );\n for (const match of masked.matchAll(MD_LINK)) {\n const target = match.groups?.target;\n if (target === undefined || match.index === undefined) {\n continue;\n }\n // Locate the target by arithmetic from the match end rather than searching\n // for its text — a label that contains the same text (e.g. `[/a/b](/a/b)`)\n // would otherwise report the column inside the label.\n const targetOffset = targetOffsetIn(match[0], target, match.groups?.title);\n const entry: PageLink = {\n column: match.index + targetOffset + 1,\n line: lineNumber,\n target,\n };\n // `MD_LINK` matches the `[label](target)` tail of an image embed too; the\n // preceding `!` is what marks the target as going through the image\n // pipeline rather than resolving as a site route.\n if (masked[match.index - 1] === \"!\") {\n entry.image = true;\n }\n links.push(entry);\n // An image nested in the label (`[](/target)`) carries its\n // own target; surface it too so a missing image is still caught.\n const label = match[0].slice(0, targetOffset - \"](\".length);\n for (const image of label.matchAll(MD_IMAGE)) {\n const imageTarget = image.groups?.target;\n if (imageTarget === undefined || image.index === undefined) {\n continue;\n }\n links.push({\n column:\n match.index +\n image.index +\n targetOffsetIn(image[0], imageTarget, image.groups?.title) +\n 1,\n image: true,\n line: lineNumber,\n target: imageTarget,\n });\n }\n }\n return next;\n};\n\n/**\n * A component's string `href` (`<Card href=\"./install\" />`): the attribute\n * may sit on a later line than the tag name, where a formatter wraps a long\n * element, so the gap between them spans lines. An expression-valued\n * `href={…}` isn't a literal target, and a lowercase tag is raw HTML in a\n * `.md` page, so neither is matched.\n */\nconst COMPONENT_HREF =\n /<[A-Z][\\w.]*(?=[\\s/>])[^<>]*?\\shref=(?:\"(?<double>[^\"]*)\"|'(?<single>[^']*)')/gu;\n\n/** The body with fenced blocks and inline code blanked, shape preserved. */\nconst maskCode = (lines: readonly string[]): string => {\n let fence: FenceState = null;\n const masked = lines.map((line) => {\n const next = nextFenceState(line, fence);\n const inFence = fence !== null || next !== null;\n fence = next;\n return inFence\n ? \" \".repeat(line.length)\n : line.replaceAll(INLINE_CODE, (span) => \" \".repeat(span.length));\n });\n return masked.join(\"\\n\");\n};\n\n/** Every component `href` target in `body`, with its 1-based position. */\nconst componentHrefs = (\n lines: readonly string[],\n lineOffset: number\n): PageLink[] => {\n const links: PageLink[] = [];\n const text = maskCode(lines);\n for (const match of text.matchAll(COMPONENT_HREF)) {\n const target = match.groups?.double ?? match.groups?.single ?? \"\";\n // The value ends one character (its closing quote) before the match does.\n const at = match.index + match[0].length - target.length - 1;\n const before = text.slice(0, at);\n const lineStart = before.lastIndexOf(\"\\n\") + 1;\n links.push({\n column: at - lineStart + 1,\n line: lineOffset + before.split(\"\\n\").length,\n target,\n });\n }\n return links;\n};\n\nexport const extractLinks = (body: string, lineOffset = 0): PageLink[] => {\n const links: PageLink[] = [];\n let fence: FenceState = null;\n let lineNumber = lineOffset;\n\n const lines = body.split(\"\\n\");\n for (const line of lines) {\n lineNumber += 1;\n fence = scanLinkLine(line, lineNumber, fence, links);\n }\n\n return body.includes(\"href=\")\n ? [...links, ...componentHrefs(lines, lineOffset)]\n : links;\n};\n\n// Double-quoted strings hold JSX attribute values and JSON in `{...}` props; a\n// `<Tag>` written inside prose there (e.g. an \"Astro <Font> integration\" note)\n// isn't a real usage. Single quotes are left alone so prose apostrophes don't\n// swallow a real tag between two words.\nconst DOUBLE_QUOTED = /\"[^\"]*\"/gu;\nconst JSX_OPEN = /<(?<tag>[A-Z][A-Za-z0-9]*)/gu;\n\n/**\n * Capitalized JSX component tags used in an `.mdx` body (`<Callout>`,\n * `<Tree.File>` → `Tree`). Skips fenced code, inline code, and double-quoted\n * strings so code samples and prose don't count. Powers the missing-component\n * diagnostic.\n */\n/** Scan one line for JSX component tags; returns the next fenced-block state. */\nconst scanTagLine = (\n line: string,\n fence: FenceState,\n tags: Set<string>\n): FenceState => {\n const next = nextFenceState(line, fence);\n // Skip fence delimiter lines themselves and anything inside a fence.\n if (fence !== null || next !== null) {\n return next;\n }\n const clean = line.replaceAll(INLINE_CODE, \"\").replaceAll(DOUBLE_QUOTED, \"\");\n for (const match of clean.matchAll(JSX_OPEN)) {\n const tag = match.groups?.tag;\n if (tag) {\n tags.add(tag);\n }\n }\n return next;\n};\n\nexport const extractComponentTags = (body: string): string[] => {\n const tags = new Set<string>();\n let fence: FenceState = null;\n for (const line of body.split(\"\\n\")) {\n fence = scanTagLine(line, fence, tags);\n }\n return [...tags];\n};\n\n/**\n * Height of the frontmatter block stripped from `raw` to produce `body` (0\n * when the raw text is unknown or nothing was stripped). Link positions are\n * extracted from the stripped body, but diagnostics point into the raw\n * document — recorded lines must shift by this offset to match it.\n */\nexport const strippedLineOffset = (\n raw: string | undefined,\n body: string\n): number =>\n raw ? Math.max(0, raw.split(\"\\n\").length - body.split(\"\\n\").length) : 0;\n\n/**\n * Map links extracted from include-expanded text back to the file and raw\n * line each expanded line came from, so a broken link inside a partial is\n * reported against the partial. Links whose origin is the page's own source\n * carry no `file` override (origins already hold raw-file lines).\n */\nconst remapExpandedLinks = (\n links: PageLink[],\n origins: { file: string; line: number }[],\n sourcePath: string | undefined\n): PageLink[] =>\n links.map((link) => {\n const origin = origins[link.line - 1];\n if (!origin) {\n return link;\n }\n const remapped: PageLink = { ...link, line: origin.line };\n if (origin.file !== sourcePath) {\n remapped.file = origin.file;\n }\n return remapped;\n });\n\n/** The entry's transitively included files, when the scan expanded any. */\nconst entryIncludes = (entry: SourceEntry): string[] | undefined =>\n entry.expanded && entry.expanded.includes.length > 0\n ? entry.expanded.includes\n : undefined;\n\n/**\n * Extract an entry's links for validation. When the scan expanded includes,\n * extraction runs over the expanded text (origins already hold raw-file\n * lines); otherwise over the stripped body, shifted by the stripped front\n * matter block's height.\n */\nconst entryLinks = (entry: SourceEntry): PageLink[] =>\n entry.expanded\n ? remapExpandedLinks(\n extractLinks(entry.expanded.text),\n entry.expanded.origins,\n entry.sourcePath\n )\n : extractLinks(\n entry.body.text,\n strippedLineOffset(entry.raw, entry.body.text)\n );\n\n/**\n * Diagnostics for `{#id}` heading markers in an `.mdx` page. The MDX parser\n * reads a bare `{…}` as a JSX expression, so the page fails to compile —\n * reported here, at the marker's source line, instead of as a raw acorn error\n * at render time. An included `.md` partial is spliced into the including\n * page and parsed in *its* format (see `markdown/include.ts`), so a partial's\n * markers count too and are reported against the partial via the expansion's\n * origins. `.md` pages render the marker as text and get no diagnostic.\n */\nconst curlyMarkerDiagnostics = (\n entry: SourceEntry,\n markers: CurlyMarker[],\n sourceName: string\n): Diagnostic[] =>\n markers.map(({ id, line }) => {\n const origin = entry.expanded?.origins[line - 1];\n const page = entry.sourcePath ?? `${sourceName}:${entry.ref}`;\n const inPartial = origin !== undefined && origin.file !== entry.sourcePath;\n return {\n code: \"BLUME_MDX_CURLY_ANCHOR\",\n file: origin?.file ?? page,\n line:\n origin?.line ?? line + strippedLineOffset(entry.raw, entry.body.text),\n message: inPartial\n ? `\\`{#${id}}\\` is a JSX expression once this partial is included in ${page} (.mdx), so that page fails to compile.`\n : `\\`{#${id}}\\` is a JSX expression in .mdx, so this page fails to compile.`,\n severity: \"error\",\n suggestion: `Write \\`[#${id}]\\` or escape it as \\`\\\\{#${id}\\\\}\\` — both pin the same anchor in .md and .mdx.`,\n };\n });\n\nconst deriveTitle = (\n meta: PageMeta,\n headings: Heading[],\n id: string\n): string => {\n if (meta.title) {\n return meta.title;\n }\n const firstHeading = headings.find((h) => h.depth === 1) ?? headings[0];\n if (firstHeading) {\n return firstHeading.text;\n }\n const base = id.split(\"/\").pop() ?? id;\n return titleCase(stripNumericPrefix(base.replace(extname(base), \"\")));\n};\n\n/** Strip habitual leading/trailing slashes (`/getting-started`, `guides/`). */\nconst trimSlashes = (value: string): string => trimChar(value, \"/\");\n\n/** Whether a raw frontmatter value is a string (e.g. the `type` override). */\nexport const isStringValue = (\n value: SourceEntry[\"data\"][string]\n): value is string => typeof value === \"string\";\n\n/** Mount a source-relative path under the source's route prefix. */\nconst withPrefix = (prefix: string | undefined, path: string): string => {\n const clean = prefix ? trimSlashes(prefix) : \"\";\n return clean ? `${clean}/${path}` : path;\n};\n\n/** What a route resolution needs from the owning source and the config. */\nexport type RouteContext = Pick<NormalizeContext, \"i18n\" | \"versions\"> & {\n /** The source's route prefix (`NormalizeContext[\"source\"][\"prefix\"]`). */\n prefix?: string;\n};\n\n/** Where an entry's ref places it once its directories are read off. */\nexport interface EntryPlacement {\n /**\n * The locale codes the entry publishes in: `[\"\"]` without i18n, one code for\n * a placed file, every configured code for a shared `$` file.\n */\n locales: string[];\n /** The ref with its version and locale directories stripped, prefix-less. */\n navPath: string;\n /** The version snapshot the entry belongs to (`\"\"` for current). */\n version: string;\n}\n\n/**\n * Read the version and locale directories off an entry's ref. The version is\n * detected first: a snapshot directory is outermost on disk\n * (`v1.0/fr/page.mdx`), so the locale parser must see a version-stripped ref.\n * The current version is `\"\"` and lives at the root. Locale placement comes\n * from the ref (a leading dir, or a filename suffix under the `dot` parser),\n * never the slug — the slug is the logical, locale-agnostic path within a\n * locale. A shared `$` file maps to every locale; a source without i18n\n * placement maps to one.\n */\nexport const placeEntryRef = (\n ref: string,\n ext: string,\n ctx: Pick<RouteContext, \"i18n\" | \"versions\">\n): EntryPlacement => {\n const { version, rest } = ctx.versions\n ? detectVersionRef(ref, ctx.versions)\n : { rest: ref, version: \"\" };\n const { navPath, locales } = ctx.i18n\n ? localePlacement(rest, ext, ctx.i18n)\n : { locales: [\"\"], navPath: rest };\n return { locales, navPath, version };\n};\n\n/** Everything `normalizeEntry` derives from an entry's ref and slug. */\nexport interface EntryRoute extends Pick<\n EntryPlacement,\n \"locales\" | \"version\"\n> {\n groups: string[];\n /**\n * The version-prefixed, locale-agnostic route — the translation key. Pass it\n * through {@link localizedRoute} for the route one locale publishes at.\n */\n logicalRoute: string;\n /** The prefixed, locale- and version-stripped nav path. */\n navPath: string;\n segments: string[];\n /** The version-agnostic mapped route. */\n versionKey: string;\n}\n\n/**\n * The canonical route resolution, shared by {@link normalizeEntry} and any\n * source that must predict the route an entry will publish at — the Obsidian\n * source turns `[[Note]]` into a real href, and a second derivation of a route\n * is a second answer.\n *\n * A frontmatter `slug` wins, then the adapter-supplied `entry.slug` (the typed\n * SPI's \"logical route input; defaults to ref if omitted\"), then the ref. The\n * extension is re-appended so `mapRoute`'s extname strip can't eat a dotted\n * slug segment (`v1.2`). A slug that trims to nothing falls back. The version\n * prefixes the mapped route *after* `mapRoute` runs: the mapped route is the\n * version-agnostic key, the config id is prepended verbatim (never\n * numeric-prefix-stripped), a frontmatter `slug` gets versionized so snapshots\n * can't collide with the live page, and `translationKey` becomes\n * version-specific for free. `basePath` is not applied here — it is outermost,\n * after locale prefixing — so the result reads `{locale?}/{prefix?}/…`.\n */\nexport const resolveEntryRoute = (\n entry: Pick<SourceEntry, \"ref\" | \"slug\">,\n ext: string,\n frontmatterSlug: string | undefined,\n ctx: RouteContext\n): EntryRoute => {\n const { locales, navPath, version } = placeEntryRef(entry.ref, ext, ctx);\n const slugInput = frontmatterSlug ?? entry.slug;\n const slug = slugInput ? trimSlashes(slugInput) : \"\";\n const routeInput = withPrefix(ctx.prefix, slug ? `${slug}${ext}` : navPath);\n const { segments, groups, route: versionKey } = mapRoute(routeInput);\n return {\n groups,\n locales,\n logicalRoute: versionizeRoute(versionKey, version),\n navPath: withPrefix(ctx.prefix, navPath),\n segments,\n version,\n versionKey,\n };\n};\n\n/** The route a logical route publishes at in one locale, base path excluded. */\nexport const localizedRoute = (\n logicalRoute: string,\n locale: string,\n i18n: ResolvedI18nConfig | undefined\n): string => (i18n ? localizeRoute(logicalRoute, locale, i18n) : logicalRoute);\n\n/** A custom-key validation failure, lowered to a joinable diagnostic path. */\ninterface CustomKeyIssue {\n message: string;\n path: (string | number)[];\n}\n\n/** The validated custom keys (if any survived) plus every failure found. */\ninterface CustomKeyValidation {\n custom?: PageRecord[\"custom\"];\n issues: CustomKeyIssue[];\n}\n\n/** Whether a Standard Schema path segment is the wrapped `{ key }` form. */\nconst isKeyCarrier = (\n segment: PropertyKey | { readonly key: PropertyKey }\n): segment is { readonly key: PropertyKey } =>\n typeof segment === \"object\" && segment !== null;\n\nconst isSymbolKey = (key: PropertyKey): key is symbol =>\n typeof key === \"symbol\";\n\n/** Lower a Standard Schema path segment (`key` or `{ key }`) for joining. */\nconst segmentKey = (\n segment: PropertyKey | { readonly key: PropertyKey }\n): string | number => {\n const key = isKeyCarrier(segment) ? segment.key : segment;\n return isSymbolKey(key) ? String(key) : key;\n};\n\n/**\n * Validate the opt-in custom frontmatter keys (`frontmatter.extend` and\n * `content.types.<type>.frontmatter`) through the Standard Schema contract —\n * the consumer's own Zod (any version), Valibot, or ArkType, never Blume's\n * bundled zod (see `standard-schema.ts`). Every declared key is checked,\n * absent ones included, so a required schema enforces its key on every page\n * it applies to. Async schemas are rejected with a diagnostic: this funnel is\n * synchronous, and frontmatter validation has no business awaiting I/O.\n */\nconst validateCustomKeys = (\n data: SourceEntry[\"data\"],\n extend: FrontmatterExtend\n): CustomKeyValidation => {\n const custom: NonNullable<PageRecord[\"custom\"]> = {};\n const issues: CustomKeyIssue[] = [];\n for (const [key, schema] of Object.entries(extend)) {\n const outcome = schema[\"~standard\"].validate(data[key]);\n if (outcome instanceof Promise) {\n issues.push({\n message: \"Async schemas are not supported for custom frontmatter keys.\",\n path: [key],\n });\n continue;\n }\n if (outcome.issues !== undefined) {\n issues.push(\n ...outcome.issues.map((issue) => ({\n message: issue.message,\n path: [key, ...(issue.path ?? []).map(segmentKey)],\n }))\n );\n continue;\n }\n // Preserve the validated (schema-output) value; skip keys that are absent\n // and stay absent, so `.optional()` extras don't materialize as undefined.\n if (outcome.value !== undefined || Object.hasOwn(data, key)) {\n custom[key] = outcome.value;\n }\n }\n return {\n custom: Object.keys(custom).length > 0 ? custom : undefined,\n issues,\n };\n};\n\n/**\n * Parse an entry's frontmatter: built-in keys through the strict page schema,\n * custom keys (`frontmatter.extend` plus the page type's\n * `content.types.<type>.frontmatter`) through their user-supplied schemas.\n * The custom keys are carved out before the strict parse, so the page schema\n * stays strict for everything else and unknown-key typo catching is unchanged\n * — a key declared only for some other type stays unknown here.\n * Returns diagnostics instead of meta when either side rejects.\n */\nconst parseEntryMeta = (\n entry: SourceEntry,\n ctx: NormalizeContext\n):\n | { meta: PageMeta; custom?: PageRecord[\"custom\"]; diagnostics?: never }\n | { meta?: never; diagnostics: Diagnostic[] } => {\n // Resolved the same way `contentType` is after parsing (`meta.type` falling\n // back to `defaultType`); a non-string `type` fails the strict parse below,\n // so which per-type map was merged for that entry never matters.\n const entryType = isStringValue(entry.data.type)\n ? entry.data.type\n : ctx.defaultType;\n const typeExtend = ctx.typeFrontmatter?.[entryType];\n // Config validation rejects a key declared both site-wide and per-type, so\n // this merge never has to pick a winner.\n const extend =\n ctx.frontmatterExtend || typeExtend\n ? { ...ctx.frontmatterExtend, ...typeExtend }\n : undefined;\n const known = extend\n ? Object.fromEntries(\n Object.entries(entry.data).filter(\n ([key]) => !Object.hasOwn(extend, key)\n )\n )\n : entry.data;\n\n const result = pageMetaSchema.safeParse(known);\n const customResult = extend ? validateCustomKeys(entry.data, extend) : null;\n\n if (result.success && (customResult?.issues.length ?? 0) === 0) {\n return { custom: customResult?.custom, meta: result.data };\n }\n\n // Source text lets the error carry a line/column into the frontmatter block:\n // `entry.raw` for non-filesystem sources, else the file itself (read only on\n // this rare error path, so filesystem entries stay cheap in the happy path).\n const source =\n entry.raw ??\n (entry.sourcePath && existsSync(entry.sourcePath)\n ? readFileSync(entry.sourcePath, \"utf-8\")\n : undefined);\n const location = {\n code: \"BLUME_FRONTMATTER_INVALID\",\n file: entry.sourcePath ?? `${ctx.source.name}:${entry.ref}`,\n source,\n };\n return {\n diagnostics: [\n ...(result.success ? [] : diagnosticsFromZod(result.error, location)),\n ...(customResult\n ? diagnosticsFromIssues(customResult.issues, location)\n : []),\n ],\n };\n};\n\n/** The per-locale page records and diagnostics from one source entry. */\nexport interface NormalizedEntry {\n pages: PageRecord[];\n diagnostics: Diagnostic[];\n}\n\n/**\n * Normalize one source entry into per-locale `PageRecord`s. This is the single\n * funnel every adapter's entries pass through, so route mapping, heading/link\n * extraction, and meta validation are identical regardless of origin.\n */\nexport const normalizeEntry = (\n entry: SourceEntry,\n ctx: NormalizeContext\n): NormalizedEntry => {\n const { format } = entry.body;\n const ext = format === \"mdx\" ? \".mdx\" : \".md\";\n\n const parsed = parseEntryMeta(entry, ctx);\n if (parsed.diagnostics) {\n return { diagnostics: parsed.diagnostics, pages: [] };\n }\n\n const { meta } = parsed;\n\n // Top-level `hidden`/`noindex` are accepted as shorthands for their nested\n // equivalents — the schema declares them, so silently ignoring them would\n // strand authors with no diagnostic.\n if (meta.hidden) {\n meta.sidebar.hidden = true;\n }\n if (meta.noindex) {\n meta.seo.noindex = true;\n }\n\n const {\n groups,\n locales,\n logicalRoute,\n navPath,\n segments,\n version,\n versionKey,\n } = resolveEntryRoute(entry, ext, meta.slug, {\n i18n: ctx.i18n,\n prefix: ctx.source.prefix,\n versions: ctx.versions,\n });\n // Extraction runs on the include-expanded body when the scan expanded one,\n // so a partial's headings anchor-index and TOC under every including page\n // and its components register for the runtime import map.\n const bodyText = entry.expanded?.text ?? entry.body.text;\n const { anchors, curlyMarkers, headings } = scanBody(bodyText);\n const { staged } = ctx.source;\n\n const base = {\n anchors,\n body: staged ? { format, text: entry.raw ?? entry.body.text } : undefined,\n collection: staged ? \"staged\" : undefined,\n componentsUsed:\n format === \"mdx\" ? extractComponentTags(bodyText) : undefined,\n contentType: meta.type ?? ctx.defaultType,\n custom: parsed.custom,\n description: meta.description,\n editUrl: entry.editUrl,\n entryId: staged ? `${ctx.source.name}/${entry.ref}` : undefined,\n format,\n groups,\n headings,\n id: `${ctx.source.name}:${entry.ref}`,\n includes: entryIncludes(entry),\n lastModified: meta.lastModified ?? entry.lastModified,\n links: entryLinks(entry),\n meta,\n monolingual: ctx.source.monolingual,\n navPath,\n segments,\n source: { name: ctx.source.name, ref: entry.ref },\n sourcePath: entry.sourcePath,\n title: deriveTitle(meta, headings, navPath),\n translationKey: logicalRoute,\n version,\n versionKey,\n } satisfies Omit<PageRecord, \"locale\" | \"route\">;\n\n // One record per locale this entry maps to (one normally; every locale for a\n // shared `$` file). All share the same id, source ref, and translation key.\n // `basePath` is applied outermost — after locale prefixing — so the route\n // reads `{basePath}/{locale?}/{prefix?}/…`; `navPath` and `translationKey`\n // stay base-less so the nav tree and translation matching are unaffected.\n const pages = locales.map((locale) => ({\n ...base,\n locale,\n route: withBasePath(\n ctx.basePath ?? \"\",\n localizedRoute(logicalRoute, locale, ctx.i18n)\n ),\n }));\n\n return {\n diagnostics:\n format === \"mdx\"\n ? curlyMarkerDiagnostics(entry, curlyMarkers, ctx.source.name)\n : [],\n pages,\n };\n};\n",
|
|
55
|
+
"/**\n * Trailing heading markers, matching Fumadocs' syntax so migrated content works\n * verbatim: `## Heading [#custom-id]` pins the anchor id, `## Heading [!toc]`\n * keeps the heading on the page but out of the table of contents, and\n * `## Heading [toc]` shows it only in the table of contents. Markers chain in\n * any order (`## Heading [toc] [#id]`). The `{#id}` pin of Pandoc, kramdown,\n * and Markdown-based specification toolchains is accepted as an equivalent of\n * `[#id]` — in `.md` verbatim, in `.mdx` only as the escape `\\{#id\\}` (a bare\n * `{…}` there is a JSX expression; the scan-time scanner reports one as\n * `BLUME_MDX_CURLY_ANCHOR`). Both pipelines resolve escapes before parsing\n * markers, so the escaped and bare spellings reach this parser identically.\n *\n * Both heading pipelines share this parser — the render-time hast plugin\n * (`markdown/heading-anchors.ts`) and the scan-time source scanner\n * (`core/sources/normalize.ts`) — so the rendered `id`, the TOC entry, and the\n * anchor index `blume validate` checks against always agree.\n */\n\nimport type GithubSlugger from \"github-slugger\";\n\n/**\n * Frontmatter key carrying the slugs of `[!toc]` headings out of a render. The\n * hast plugin pushes onto it and the generated page template reads it back via\n * `remarkPluginFrontmatter` to filter the TOC.\n */\nexport const TOC_HIDDEN_KEY = \"__blumeTocHidden\";\n\n/**\n * Register a pinned `[#id]` with the document slugger, the way\n * `GithubSlugger#slug` registers the slugs it returns — so a later heading\n * whose auto-slug collides disambiguates (`setup` → `setup-1`) instead of\n * silently duplicating the anchor id. An id that is already taken is left\n * untouched (the pin still uses it verbatim; duplicate pins are the author's\n * explicit choice).\n */\nexport const occupySlug = (slugger: GithubSlugger, id: string): void => {\n slugger.occurrences[id] ??= 0;\n};\n\n/** One trailing marker: `[#id]`, `{#id}`, `[toc]`, or `[!toc]`. */\nconst MARKER =\n /\\s*(?:\\{#(?<curlyId>[^\\s}]+)\\}|\\[(?:#(?<id>[^\\s\\]]+)|(?<hide>!)?toc)\\])\\s*$/u;\n\nexport interface HeadingMarkers {\n /** Author-pinned anchor id from `[#id]` or `{#id}`, used verbatim (never re-slugged). */\n id?: string;\n /** The heading text with every trailing marker stripped. */\n text: string;\n /** `[!toc]` hides the heading from the TOC; `[toc]` shows it only there. */\n toc?: \"hide\" | \"only\";\n}\n\n/**\n * Split trailing markers off a heading's text. Only markers at the very end of\n * the heading count (mid-text brackets are ordinary prose); when a marker kind\n * repeats, the last one written wins.\n *\n * `isRefDefined` reports whether a link-reference definition exists for a\n * bracket's label (`toc`, `!toc`, `#id`): a defined bracket is a CommonMark\n * shortcut link, not a marker — the renderer sees a resolved `<a>` element\n * there and strips nothing at or before it, so the parse stops the same way.\n * The render-time hast plugin never passes it (resolved links are already\n * elements by the time it runs); the raw-source scanner does.\n */\nexport const parseHeadingMarkers = (\n text: string,\n isRefDefined?: (label: string) => boolean\n): HeadingMarkers => {\n let remaining = text;\n let id: string | undefined;\n let toc: HeadingMarkers[\"toc\"];\n for (\n let match = MARKER.exec(remaining);\n match?.groups;\n match = MARKER.exec(remaining)\n ) {\n const explicitId = match.groups.curlyId ?? match.groups.id;\n const label =\n explicitId === undefined\n ? `${match.groups.hide ?? \"\"}toc`\n : `#${explicitId}`;\n // A `{#id}` is never a shortcut link, whatever the definitions say.\n if (match.groups.curlyId === undefined && isRefDefined?.(label)) {\n break;\n }\n remaining = remaining.slice(0, match.index);\n if (explicitId === undefined) {\n // Stripping runs right-to-left, so keeping the first capture of each\n // kind makes the rightmost occurrence win.\n toc ??= match.groups.hide === undefined ? \"only\" : \"hide\";\n } else {\n id ??= explicitId;\n }\n }\n return { id, text: remaining, toc };\n};\n",
|
|
56
|
+
"import type { AstroIntegration } from \"astro\";\nimport { z } from \"zod\";\n\nimport {\n askAdapterSchema,\n askMovedFieldsHint,\n DEFAULT_ASK_PROVIDER,\n} from \"../ai/ask.ts\";\nimport type { ComponentMarkdown } from \"../ai/component-markdown.ts\";\nimport { analyticsConfigSchema } from \"../analytics/schema.ts\";\nimport { resolvedDeploymentSchema } from \"../deploy/adapters/registry.ts\";\nimport type { CodeTheme } from \"../markdown/themes.ts\";\nimport { normalizeRoute } from \"../openapi/references.ts\";\nimport {\n referenceConfigSchema,\n removedReferenceKeysHint,\n} from \"../reference/schema.ts\";\nimport { orama } from \"../search/adapters/orama.ts\";\nimport {\n NONE_SEARCH_ADAPTER,\n resolvedSearchAdapterSchema,\n} from \"../search/adapters/registry.ts\";\nimport type { SearchAdapterInput } from \"../search/adapters/registry.ts\";\nimport { normalizeXHandle } from \"../seo/x-handle.ts\";\nimport { filesystem } from \"../sources/filesystem.ts\";\nimport {\n contentSourcesSchema,\n resolvedSourceAdapterSchema,\n} from \"../sources/registry.ts\";\nimport { FONT_SLUGS, isFontSlug } from \"../theme/fonts.ts\";\nimport { normalizeBasePath } from \"./base-path.ts\";\nimport { PUBLIC_HOST_URL } from \"./github.ts\";\nimport { uiLocaleOverridesSchema } from \"./i18n-ui.ts\";\nimport { openInChatProviders } from \"./open-in-chat.ts\";\nimport { isStandardSchema } from \"./standard-schema.ts\";\nimport type { StandardSchema } from \"./standard-schema.ts\";\nimport { trimEnd } from \"./trim.ts\";\nimport { unrecognizedKeysMessage } from \"./unrecognized-keys.ts\";\n\n/**\n * An absolute HTTP(S) URL, for any field that lands verbatim in an `href` —\n * the header repo mark, the GitHub instance origin. Zod's bare `z.url()` also\n * admits `javascript:` and `data:`, which would render as a script link on\n * every page.\n */\nconst httpUrlSchema = z.url({ protocol: /^https?$/u });\n\n/**\n * Public Blume schemas.\n *\n * These are exported from `blume/schema` so migration tools, editor\n * integrations, and the runtime share a single source of validation truth.\n */\n\n// ---------------------------------------------------------------------------\n// Shared primitives\n// ---------------------------------------------------------------------------\n\n// `typeof` checks live in named predicates (the form the oxlint anti-slop\n// config sanctions); generic so each site keeps its own union narrowing.\nconst isString = <Value>(value: Value): value is Value & string =>\n typeof value === \"string\";\n\nconst isBoolean = <Value>(value: Value): value is Value & boolean =>\n typeof value === \"boolean\";\n\nconst isObjectLike = <Value>(value: Value): value is Value & object =>\n typeof value === \"object\" && value !== null;\n\n/** Icon inputs in serializable contexts (frontmatter, meta files). */\nconst iconName = z.string().min(1);\n\n/**\n * Error params for a strict object whose keys were removed or moved in a\n * major release. A config still carrying one of `hints`' keys fails with\n * the message that names its replacement, instead of Zod's bare\n * \"Unrecognized key\"; any other unknown key keeps the default message.\n */\nconst removedKeysHint = (hints: Record<string, string>) => ({\n error: (issue: z.core.$ZodRawIssue): string | undefined => {\n if (issue.code !== \"unrecognized_keys\") {\n return;\n }\n const messages = issue.keys.flatMap((key) =>\n Object.hasOwn(hints, key) ? [hints[key]] : []\n );\n if (messages.length === 0) {\n return;\n }\n // A hinted key beside a plain unknown one: keep Zod's wording for the\n // latter so it isn't silently dropped from the diagnostic.\n const others = issue.keys.filter((key) => !Object.hasOwn(hints, key));\n if (others.length > 0) {\n messages.push(unrecognizedKeysMessage(others));\n }\n return messages.join(\" \");\n },\n});\n\n/** Default include glob for filesystem-backed content sources. */\nconst hydrationMode = z.enum([\"load\", \"idle\", \"visible\", \"media\", \"only\"]);\nexport type HydrationMode = z.infer<typeof hydrationMode>;\n\n/**\n * A publish date in frontmatter. YAML auto-parses an unquoted `2026-01-01` into\n * a `Date`, so accept either form and normalize to an ISO string.\n */\nconst dateSchema = z\n .union([z.string(), z.date()])\n .transform((value) => (value instanceof Date ? value.toISOString() : value));\n\n/**\n * How a sidebar group renders:\n * - `flat`: a non-collapsible header with its items listed beneath (default).\n * - `group`: a collapsible `<details>` disclosure.\n * - `page`: a single row that drills into a sub-panel showing only this group's\n * items, with a back arrow at the top.\n */\nconst sidebarDisplaySchema = z.enum([\"flat\", \"group\", \"page\"]);\nexport type SidebarDisplay = z.infer<typeof sidebarDisplaySchema>;\n\n// ---------------------------------------------------------------------------\n// Page frontmatter\n// ---------------------------------------------------------------------------\n\nconst sidebarMetaSchema = z.strictObject({\n badge: z.string().optional(),\n /**\n * Render mode for this page's folder group. Only meaningful on a folder's\n * `index` page — it configures the group, not the page. Overrides the\n * folder's `meta.ts` `display` and the global `navigation.sidebar.display`.\n */\n display: sidebarDisplaySchema.optional(),\n hidden: z.boolean().default(false),\n icon: iconName.optional(),\n label: z.string().optional(),\n order: z.number().optional(),\n});\n\n/**\n * An X handle, normalized to a leading `@` — `twitter:site`/`twitter:creator`\n * require it, and a handle configured without one is the obvious typo to absorb\n * rather than reject. The layouts normalize again on the way out, since a page's\n * `seo.x.creator` reaches them straight from unvalidated frontmatter.\n */\nconst xHandleSchema = z.string().transform(normalizeXHandle).optional();\n\nconst seoMetaSchema = z.strictObject({\n canonical: z.url().optional(),\n description: z.string().optional(),\n image: z.string().optional(),\n noindex: z.boolean().default(false),\n title: z.string().optional(),\n /** Per-page X attribution — a guest post credits its own author. */\n x: z.strictObject({ creator: xHandleSchema }).optional(),\n});\n\nconst searchMetaSchema = z.strictObject(\n {\n exclude: z.boolean().default(false),\n tags: z.array(z.string()).optional(),\n },\n removedKeysHint({\n boost:\n \"search.boost was removed: search never read it, so the page ranked the same without it. Delete the field.\",\n })\n);\n\nconst aiMetaSchema = z.strictObject({\n /** Exclude this page from llms.txt and llms-full.txt. */\n exclude: z.boolean().default(false),\n});\n\nconst changelogMetaSchema = z.strictObject({\n category: z.string().optional(),\n date: dateSchema.optional(),\n version: z.string().optional(),\n});\n\n/**\n * A post author: a bare name/handle, or an object with a name plus optional\n * avatar/URL. The object is passthrough so richer author metadata (social\n * handles, roles) survives untouched — Blume doesn't render authors yet, so\n * this exists to preserve the field (common on blog/changelog pages) rather\n * than have a strict scan reject it.\n */\nconst authorSchema = z.union([\n z.string(),\n z\n .object({\n avatar: z.string().optional(),\n image: z.string().optional(),\n name: z.string(),\n url: z.string().optional(),\n })\n .catchall(z.unknown()),\n]);\n\n// Shorthand defaults use `.prefault()`, not `.default()`, wherever the value\n// must still be parsed — Zod 4's `.default()` returns the value as-is, so a\n// `.default({})` on an object with inner defaults (or a transform) would\n// resolve to a bare `{}` instead of the fully-defaulted shape.\n\n/** Frontmatter accepted on any content page. */\nconst pageMetaBaseSchema = z.strictObject({\n ai: aiMetaSchema.prefault({}),\n /** Post author(s) for blog/changelog content; preserved, not yet rendered. */\n authors: z.union([authorSchema, z.array(authorSchema)]).optional(),\n changelog: changelogMetaSchema.optional(),\n /** Publish date for feed-backed content like blog/changelog. */\n date: dateSchema.optional(),\n deprecated: z.boolean().default(false),\n description: z.string().optional(),\n draft: z.boolean().default(false),\n hidden: z.boolean().default(false),\n icon: iconName.optional(),\n /** Overrides the git-derived last-modified date when `lastModified` is on. */\n lastModified: dateSchema.optional(),\n noindex: z.boolean().default(false),\n search: searchMetaSchema.prefault({}),\n seo: seoMetaSchema.prefault({}),\n sidebar: sidebarMetaSchema.prefault({}),\n slug: z.string().optional(),\n title: z.string().optional(),\n // No default: an absent `type` must fall through to `content.defaultType`.\n type: z.string().optional(),\n});\n\nexport const pageMetaSchema = pageMetaBaseSchema;\n\nexport type PageMeta = z.infer<typeof pageMetaBaseSchema>;\nexport type PageMetaInput = z.input<typeof pageMetaBaseSchema>;\n\n/** The fully-defaulted front matter of a page that declares nothing. */\nconst EMPTY_PAGE_META: PageMeta = pageMetaBaseSchema.parse({});\n\n/**\n * The page schema as the generated content collections declare it, so\n * `entry.data` is typed and normalized (dates as ISO strings, X handles with\n * their `@`) the same way the scan's `PageMeta` is. Two deliberate loosenings\n * over {@link pageMetaSchema}: custom keys (`frontmatter.extend`, per-type\n * maps) pass through instead of failing the strict parse, and a page the\n * strict parse rejects resolves to the empty defaults instead of throwing.\n * The scan has already dropped such a page with a `BLUME_FRONTMATTER_INVALID`\n * diagnostic — Blume continues without it unless `--strict` — so the\n * collection must not turn that dropped page into a failed content sync.\n */\nexport const pageCollectionSchema = pageMetaBaseSchema\n .loose()\n // oxlint-disable-next-line promise/prefer-await-to-then -- zod's catch, not a promise\n .catch(() => EMPTY_PAGE_META);\n\n/** Built-in page frontmatter keys; custom keys must never redeclare one. */\nconst BUILT_IN_PAGE_META_KEYS = new Set<string>(\n pageMetaBaseSchema.keyof().options\n);\n\n/**\n * A map of custom frontmatter keys to user-supplied validation schemas,\n * consumed through the Standard Schema `~standard` contract — never Zod's own\n * API — so the consumer's zod (any version), Valibot, or ArkType all work\n * (see `standard-schema.ts`). Shared by the site-wide `frontmatter.extend`\n * and the per-type `content.types.<type>.frontmatter` maps. Built-in\n * frontmatter fields can't be redeclared — they're load-bearing (routing,\n * sidebar, SEO), and shadowing one would silently change its semantics.\n */\nconst customKeySchemaRecord = (where: string) =>\n z\n .record(\n z.string(),\n z.custom<StandardSchema>(isStandardSchema, {\n message:\n \"Expected a Standard Schema (e.g. a Zod schema — any Zod version works).\",\n })\n )\n .default({})\n .superRefine((value, ctx) => {\n for (const key of Object.keys(value)) {\n if (BUILT_IN_PAGE_META_KEYS.has(key)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `\"${key}\" is a built-in frontmatter field and cannot be redeclared via ${where}.`,\n path: [key],\n });\n }\n }\n });\n\n// ---------------------------------------------------------------------------\n// Folder meta (meta.ts)\n// ---------------------------------------------------------------------------\n\nexport const folderMetaSchema = z.strictObject({\n collapsed: z.boolean().optional(),\n /** Render mode for this group; overrides `navigation.sidebar.display`. */\n display: sidebarDisplaySchema.optional(),\n icon: iconName.optional(),\n order: z.number().optional(),\n /** Explicit child ordering by slug segment (without numeric prefix). */\n pages: z.array(z.string()).optional(),\n title: z.string().optional(),\n});\n\nexport type FolderMeta = z.infer<typeof folderMetaSchema>;\n\n// ---------------------------------------------------------------------------\n// Project config (blume.config.ts)\n// ---------------------------------------------------------------------------\n\n/** The logo mark: a single image path/URL, or light/dark variants with alt text. */\nconst logoImageSchema = z.union([\n z.string(),\n z.strictObject({\n alt: z.string().optional(),\n dark: z.string().optional(),\n light: z.string().optional(),\n }),\n]);\n\n/**\n * Site logo. A bare string is the image shorthand. The object form splits the\n * brand into an optional `image` mark and optional wordmark `text` so a site can\n * show an image-only logo (a mark with the wordmark baked in), a text-only logo,\n * or both. Omit `text` to fall back to the site title; set `text: \"\"` to render\n * the mark alone. `href` overrides the brand link (defaults to `/`).\n */\nconst logoConfigSchema = z.union([\n z.string(),\n z.strictObject({\n href: z.string().optional(),\n image: logoImageSchema.optional(),\n text: z.string().optional(),\n }),\n]);\n\n/** Site-wide announcement banner: a string, or text with an optional link. */\nconst bannerConfigSchema = z.union([\n z.string(),\n z.strictObject({\n content: z.string(),\n /** Show a dismiss button; the choice is remembered per visitor. */\n dismissible: z.boolean().default(false),\n /** Stable key for remembering dismissal; defaults to the content. */\n id: z.string().optional(),\n link: z.strictObject({ href: z.string(), text: z.string() }).optional(),\n }),\n]);\n\n/** A validated `content.sources` entry: an adapter descriptor from `blume/sources`. */\nexport type { ContentSourceAdapter } from \"../sources/registry.ts\";\n\n/**\n * Per-type content definition. An object (rather than a bare frontmatter map)\n * so type-scoped concerns added later — search facets, templates — have a\n * home without a breaking config change.\n */\nconst contentTypeConfigSchema = z.strictObject({\n /**\n * Custom frontmatter keys whose values become filterable facets for pages\n * of this type — surfaced in search documents and filterable through the\n * MCP tools' `filters` input. Each name must be a custom key declared for\n * the type (in its `frontmatter` map or the site-wide `frontmatter.extend`),\n * checked at the config level where both maps are visible. Only string\n * (or number/boolean, stringified) values ever facet.\n */\n facets: z.array(z.string()).default([]),\n /**\n * Custom frontmatter keys for pages of this type, layered on top of the\n * site-wide `frontmatter.extend`. Every declared key is validated on every\n * page of the type — absent ones included — so a required schema enforces\n * the key type-wide while leaving other types untouched.\n */\n frontmatter: customKeySchemaRecord(\"content.types\"),\n});\n\n/** The top-level fields that are shorthand for a single `filesystem()` source. */\nconst FILESYSTEM_SHORTHAND_KEYS = [\"exclude\", \"include\", \"root\"] as const;\n\n/**\n * `content`: where pages come from. `sources` lists adapters from\n * `blume/sources`; the top-level `root`/`include`/`exclude` are zero-config\n * shorthand that desugars to exactly one `filesystem()` entry when `sources`\n * is absent, and are rejected beside it — so after parse, `sources` is the\n * one source of truth and nothing downstream picks between the two.\n */\nconst contentConfigSchema = z\n .strictObject({\n defaultType: z.string().default(\"doc\"),\n exclude: z.array(z.string()).optional(),\n include: z.array(z.string()).optional(),\n pages: z.string().default(\"pages\"),\n root: z.string().optional(),\n sources: contentSourcesSchema.optional(),\n /**\n * Per-type content definitions, keyed by the frontmatter `type` they apply\n * to (including `defaultType`, for pages that set none).\n */\n types: z.record(z.string(), contentTypeConfigSchema).default({}),\n })\n .superRefine((value, ctx) => {\n if (!value.sources) {\n return;\n }\n for (const key of FILESYSTEM_SHORTHAND_KEYS) {\n if (value[key] !== undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `content.${key} is shorthand for a single filesystem() source and can't be combined with content.sources — move it into a filesystem({ ${key} }) entry in content.sources.`,\n path: [key],\n });\n }\n }\n })\n .transform(({ exclude, include, root, sources, ...rest }) => ({\n ...rest,\n sources: sources ?? [\n // The shorthand's defaults are the adapter's own, applied by its schema.\n resolvedSourceAdapterSchema.parse(filesystem({ exclude, include, root })),\n ],\n }));\n\n/**\n * A header label that may localize: a plain string, or a map of locale code to\n * label (`{ en: \"Docs\", ja: \"ドキュメント\" }`). Resolved when each locale's\n * navigation is built — the active locale's entry wins, then the default\n * locale's, then the map's first entry — so a single-locale site can keep\n * plain strings and an i18n site can translate its header without forking the\n * config.\n */\nconst localizableLabelSchema = z.union([\n z.string(),\n z\n .record(z.string(), z.string())\n .refine((value) => Object.keys(value).length > 0, {\n message: \"Provide at least one locale's label.\",\n }),\n]);\n\nexport type LocalizableLabel = z.infer<typeof localizableLabelSchema>;\n\nconst navTabSchema = z.strictObject({\n // Rejected empty rather than accepted: an empty `href` would render a link to\n // nowhere, and it can't mean \"resolve it for me\" either — that's what\n // omitting the field does.\n href: z.string().min(1).optional(),\n icon: iconName.optional(),\n items: z\n .array(\n z.strictObject({\n description: z.string().optional(),\n icon: iconName.optional(),\n label: localizableLabelSchema,\n path: z.string(),\n tag: z.string().optional(),\n })\n )\n .optional(),\n label: localizableLabelSchema,\n path: z.string(),\n});\n\nconst navSelectorItemSchema = z.strictObject({\n description: z.string().optional(),\n icon: iconName.optional(),\n label: z.string(),\n path: z.string(),\n tag: z.string().optional(),\n});\n\nconst navSelectorSchema = z.strictObject({\n items: z.array(navSelectorItemSchema).default([]),\n kind: z.enum([\"dropdown\", \"language\", \"product\", \"version\"]),\n label: z.string(),\n});\n\nconst directoryModeSchema = z.enum([\"accordion\", \"card\", \"none\"]);\nexport type DirectoryMode = z.infer<typeof directoryModeSchema>;\n\n/** A node in an explicit sidebar config: a page reference or a group/link. */\nexport type SidebarItemConfig =\n | string\n | {\n label: string;\n badge?: string;\n directory?: DirectoryMode;\n display?: SidebarDisplay;\n href?: string;\n icon?: string;\n collapsed?: boolean;\n items?: SidebarItemConfig[];\n root?: string;\n };\n\n// Zod 4's `ZodType` defaults its Input parameter to `unknown` (it no longer\n// mirrors Output), so the recursive annotation names both — otherwise\n// `z.input` of anything containing this schema degrades to `unknown`.\nconst sidebarItemSchema: z.ZodType<SidebarItemConfig, SidebarItemConfig> =\n z.lazy(() =>\n z.union([\n z.string(),\n z.strictObject({\n badge: z.string().optional(),\n collapsed: z.boolean().optional(),\n directory: directoryModeSchema.optional(),\n display: sidebarDisplaySchema.optional(),\n href: z.string().optional(),\n icon: iconName.optional(),\n items: z.array(sidebarItemSchema).optional(),\n label: z.string(),\n root: z.string().optional(),\n }),\n ])\n );\n\nconst fontFallbackSchema = z.enum([\"sans\", \"serif\", \"mono\"]);\n\n/** Any family from a zero-config Astro provider, by name. */\nconst remoteFontSchema = z.strictObject({\n fallback: fontFallbackSchema.optional(),\n name: z.string().min(1),\n provider: z\n .enum([\"google\", \"fontsource\", \"bunny\", \"fontshare\"])\n .default(\"google\"),\n /** Character subsets to load; defaults to `latin` plus the locales' scripts. */\n subsets: z.array(z.string().min(1)).nonempty().optional(),\n weights: z\n .array(\n z.union([z.number().int().positive(), z.string().regex(/^\\d+\\.\\.\\d+$/u)])\n )\n .nonempty()\n .optional(),\n});\n\n/** One local `@font-face`: a file plus optional weight/style (else inferred). */\nconst localFontVariantSchema = z.strictObject({\n src: z.string().min(1),\n style: z.enum([\"normal\", \"italic\", \"oblique\"]).optional(),\n weight: z\n .union([\n z.number().int().positive(),\n z.string().regex(/^\\d+(?:\\.\\.\\d+)?$/u),\n ])\n .optional(),\n});\n\n/** A self-hosted family loaded from font files in the project. */\nconst localFontSchema = z.strictObject({\n fallback: fontFallbackSchema.optional(),\n name: z.string().min(1),\n variants: z.array(localFontVariantSchema).nonempty(),\n});\n\n/**\n * A role's font: a curated Google Font slug (see `theme/fonts.ts`), a\n * remote-provider family, or local font files. Bare strings must be curated\n * slugs so a typo fails with the supported list instead of a provider error.\n */\nconst fontValueSchema = z\n .union([z.string(), remoteFontSchema, localFontSchema])\n .superRefine((value, ctx) => {\n if (isString(value) && !isFontSlug(value)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Unknown font \"${value}\". Supported fonts: ${FONT_SLUGS.join(\", \")}. For any other family, use the object form: { name: \"...\" } (remote provider) or { name: \"...\", variants: [...] } (local files).`,\n });\n }\n });\n\n/**\n * An optional per-mode theme value: a string applies to both color modes; a\n * `{ light, dark }` object sets each mode individually (either may be\n * omitted to override a single mode).\n */\nconst perModeValueSchema = z\n .union([\n z.string(),\n z.strictObject({\n dark: z.string().optional(),\n light: z.string().optional(),\n }),\n ])\n .optional()\n .transform((value) =>\n isString(value) ? { dark: value, light: value } : value\n );\n\nconst themeConfigFields = {\n accent: z\n .union([\n z.string(),\n z.strictObject({ dark: z.string(), light: z.string() }),\n ])\n .default(\"blue\")\n .transform((value) =>\n isString(value) ? { dark: value, light: value } : value\n ),\n action: z.string().optional(),\n background: perModeValueSchema,\n backgroundImage: perModeValueSchema,\n fonts: z\n .strictObject({\n body: fontValueSchema.default(\"inter\"),\n display: fontValueSchema.default(\"inter\"),\n mono: fontValueSchema.default(\"ibm-plex-mono\"),\n })\n .prefault({}),\n mode: z.enum([\"system\", \"light\", \"dark\"]).default(\"system\"),\n radius: z.enum([\"none\", \"sm\", \"md\", \"lg\"]).default(\"md\"),\n};\n\nconst themeConfigSchema = z.strictObject(\n themeConfigFields,\n removedKeysHint({\n layout:\n \"theme.layout was removed: the sidebar layout is the only one, so delete the field.\",\n })\n);\n\n/** Curated link for the search dialog empty state (internal route or external URL). */\nconst searchPopularLinkSchema = z.strictObject({\n href: z.string(),\n icon: iconName.optional(),\n label: z.string(),\n});\n\n/**\n * The search backend: an adapter descriptor from `blume/search` (`algolia({…})`,\n * `orama()`, …) or `false` to disable search. Resolves to a descriptor either\n * way — `false` becomes the `none` adapter — so consumers read `kind`,\n * `runtimeDeps`, and `requiredSecrets` without a special case.\n */\nconst searchProviderSchema = z\n .custom<false | SearchAdapterInput>(\n // A 1.x provider name (`\"algolia\"`, `\"none\"`) fails here with the adapter\n // that replaces it, rather than the pipe's bare \"expected object\".\n (value) => value === false || isObjectLike(value),\n {\n message:\n 'search.provider takes an adapter from \"blume/search\" — algolia({…}), pagefind(), … — not a provider name. The 1.x provider string was removed, and \"none\" is now `search: false`.',\n }\n )\n .transform((value) => (value === false ? NONE_SEARCH_ADAPTER : value))\n .pipe(resolvedSearchAdapterSchema);\n\n/** Indexing behavior shared by every source-built index. */\nconst searchIndexingSchema = z\n .strictObject({\n includeCodeBlocks: z.boolean().default(false),\n includeHiddenPages: z.boolean().default(false),\n })\n .prefault({});\n\n/** The object form of `search`: the adapter plus its adapter-independent settings. */\nconst searchOptionsSchema = z.strictObject(\n {\n indexing: searchIndexingSchema,\n /** Curated links for the Cmd+K empty state; defaults to the first sidebar pages. */\n popular: z.array(searchPopularLinkSchema).default([]),\n provider: searchProviderSchema.default(() => orama()),\n },\n // The 1.x credential blocks, each now its adapter's options.\n removedKeysHint({\n algolia:\n 'search.algolia moved into its adapter: `search: algolia({ appId, indexName, apiKey })` from \"blume/search\", where the 1.x `searchApiKey` is now `apiKey`.',\n mixedbread:\n 'search.mixedbread moved into its adapter: `search: mixedbread({ storeId })` from \"blume/search\".',\n oramaCloud:\n 'search.oramaCloud moved into its adapter: `search: oramaCloud({ endpoint, apiKey, indexId })` from \"blume/search\".',\n typesense:\n 'search.typesense moved into its adapter: `search: typesense({ host, collection, apiKey })` from \"blume/search\", where the 1.x `searchApiKey` is now `apiKey`.',\n })\n);\n\ntype SearchOptionsInput = z.input<typeof searchOptionsSchema>;\n\n/** What `search` accepts: an adapter (or `false`) directly, or the object form. */\ntype SearchConfigInput = false | SearchAdapterInput | SearchOptionsInput;\n\n/**\n * `search` takes an adapter directly (`search: algolia({…})`, or `false`) as\n * shorthand for the object form (`search: { provider: algolia({…}), popular,\n * indexing }`). The shorthand is lifted into `provider` before the object\n * schema validates, rather than through a union: a union reports whichever\n * branch fails \"softest\", which for a descriptor missing an option is the\n * object form's \"unrecognized keys\" — pointing at the wrong problem. A\n * descriptor is recognized by its `kind`; the object form never has one.\n */\nconst searchConfigSchema = z\n .custom<SearchConfigInput>(\n // Anything else (a 1.x provider string, null, true) must become a\n // diagnostic here: the `in` check below would throw a TypeError on it.\n (value) => value === false || isObjectLike(value),\n {\n message:\n 'search must be an adapter from \"blume/search\" (orama(), algolia({…}), …), false, or { provider, popular, indexing }. The 1.x provider string was removed.',\n }\n )\n .transform((value): SearchOptionsInput =>\n value === false || \"kind\" in value ? { provider: value } : value\n )\n .pipe(searchOptionsSchema);\n\n/**\n * JWK parameters that carry private or secret key material (RFC 7518): the\n * private exponent/scalar, the RSA CRT parameters, and the symmetric key.\n * A directory is public by definition, so any of these in a configured key is\n * a leaked credential, not a config style choice — reject loudly.\n */\nconst PRIVATE_JWK_PARAMS = [\"d\", \"p\", \"q\", \"dp\", \"dq\", \"qi\", \"oth\", \"k\"];\n\n/**\n * A public JWK for the Web Bot Auth signature directory. Shape is left to the\n * signing setup (Ed25519 `OKP` keys in current deployments) — validation only\n * requires the mandatory `kty` and refuses private key material.\n */\nconst publicJwkSchema = z\n .record(z.string(), z.unknown())\n .superRefine((jwk, ctx) => {\n if (!isString(jwk.kty) || jwk.kty.length === 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'A JWK must declare its key type (\"kty\").',\n });\n }\n const leaked = PRIVATE_JWK_PARAMS.filter((param) => param in jwk);\n if (leaked.length > 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `The JWK contains private key material (\"${leaked.join('\", \"')}\") — the signatures directory is public, so list only public keys and keep the private key where the signing agent runs.`,\n });\n }\n });\n\nconst mcpConfigSchema = z.strictObject({\n enabled: z.boolean().default(false),\n /** Optional system hint passed to connecting agents. */\n instructions: z.string().optional(),\n /** Server name shown to clients; defaults to the site title. */\n name: z.string().optional(),\n /**\n * Normalized like `openapi.route`: a slash-less value would otherwise be\n * string-concatenated onto the site origin (`https://acme.comdocs-mcp`).\n */\n route: z.string().default(\"/mcp\").transform(normalizeRoute),\n});\n\nconst askEndpointSchema = z\n .string()\n .trim()\n .min(1)\n .refine(\n (value) => {\n if (value.startsWith(\"/\") && !value.startsWith(\"//\")) {\n return true;\n }\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n },\n {\n message:\n \"ai.ask.endpoint must be an HTTP(S) URL or a root-relative path.\",\n }\n );\n\n/** The object form of `agents.llmsTxt`; a bare boolean normalizes onto it. */\nconst llmsTxtObjectSchema = z.strictObject({\n /**\n * Markdown inserted after the title and summary, before the page sections:\n * the llms.txt spec's \"details\" slot. The place to tell agents when to use\n * the product and how to call it; trimmed, and dropped when blank.\n */\n details: z.string().trim().min(1).optional(),\n enabled: z.boolean().default(true),\n openapi: z.boolean().default(true),\n});\n\ntype LlmsTxtResolved = z.output<typeof llmsTxtObjectSchema>;\n\n/** The object form of `agents.catalog`; a bare boolean normalizes onto it. */\nconst aiCatalogObjectSchema = z.strictObject({\n enabled: z.boolean().default(true),\n /**\n * Representative queries per catalog entry, keyed by the entry's\n * `<namespace>:<name>` (the identifier minus its `urn:air:<host>:` prefix,\n * e.g. `mcp:docs`, `skill:blume`, `api:docs`). Replaces the generated\n * defaults for that entry; 2–5 short natural-language questions the\n * resource can answer, which registries embed for semantic search.\n */\n queries: z\n .record(z.string().min(1), z.array(z.string().trim().min(1)).min(1))\n .default({}),\n});\n\ntype AiCatalogResolved = z.output<typeof aiCatalogObjectSchema>;\n\n/**\n * The keys that moved from `ai` to `agents`: `ai` now holds only what faces a\n * model at read time (Ask AI, Open in chat), and the machine-readable surface\n * agents consume lives under `agents`.\n */\nconst MOVED_TO_AGENTS = [\n \"api\",\n \"catalog\",\n \"llmsTxt\",\n \"markdownComponents\",\n \"mcp\",\n \"skills\",\n \"webBotAuth\",\n \"webmcp\",\n] as const;\n\nconst movedToAgentsHints = (from: string): Record<string, string> =>\n Object.fromEntries(\n MOVED_TO_AGENTS.map((key) => [\n key,\n `${from}.${key} moved to agents.${key}.`,\n ])\n );\n\n/** Model-facing config: the Ask AI assistant and the \"Open in chat\" action. */\nconst aiConfigFields = {\n ask: z\n .strictObject(\n {\n // Origins allowed to call the generated `/api/ask` from another site (a\n // marketing page that embeds an ask box, say), or `\"*\"` for every\n // origin. Each URL is reduced to its origin so a trailing slash or path\n // can't defeat the exact match the route performs. Read by the\n // generated route only; an external `endpoint` owns its own CORS.\n cors: z\n .array(\n z.union([\n z.literal(\"*\"),\n z\n .url({ protocol: /^https?$/u })\n .transform((value) => new URL(value).origin),\n ])\n )\n .optional(),\n enabled: z.boolean().default(false),\n // Optional external endpoint for projects that keep their docs static\n // and host Ask AI in an existing backend. Absolute URLs and root-relative\n // paths are both valid; the built-in request/stream contract is unchanged.\n endpoint: askEndpointSchema.optional(),\n // Extra system-prompt text (identity, language, tone) appended to the\n // built-in instructions, so the grounding contract — answer from the\n // retrieved excerpts, cite pages as Markdown links — stays intact.\n instructions: z.string().trim().min(1).optional(),\n // The adapter descriptor a `gateway()`/`openrouter()`/... factory\n // returns; each adapter validates its own options (model, key env var,\n // reasoning mapping, `providerOptions` passthrough) in `ai/ask.ts`.\n // Unset means the gateway with its default model, so zero-config Ask AI\n // is unchanged.\n provider: askAdapterSchema.prefault(DEFAULT_ASK_PROVIDER),\n // How much documentation each question carries. Injected characters are\n // the dominant term in time-to-first-token on a self-hosted backend, so\n // these trade recall for latency. No zod defaults here: only what the\n // user set reaches the generated (and ejected) endpoint, so omitted\n // fields keep tracking the installed package's built-in defaults in\n // `ai/ask-context.ts` instead of pinning today's numbers as literals.\n retrieval: z\n .strictObject({\n contextBudget: z.number().int().positive().optional(),\n excerptChars: z.number().int().positive().optional(),\n maxResults: z.number().int().positive().optional(),\n })\n .optional(),\n // Empty-state prompts shown before the first question. Each renders as a\n // clickable suggestion; `icon` is an optional Lucide name beside it.\n suggestions: z\n .array(\n z.strictObject({\n icon: iconName.optional(),\n label: z.string().min(1),\n })\n )\n .default([]),\n },\n askMovedFieldsHint\n )\n .superRefine((value, ctx) => {\n // `cors` configures the generated route, which an external `endpoint`\n // replaces; accepting both would silently do nothing.\n if (value.cors && value.endpoint) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message:\n \"ai.ask.cors only applies to the generated route; with ai.ask.endpoint, CORS is that backend's job.\",\n path: [\"cors\"],\n });\n }\n })\n .optional(),\n /**\n * The \"Open in chat\" page action. `true` (the default) lists every\n * provider, `false` hides the action entirely, and an array of provider\n * keys shows just that subset, in the given order. Normalized to the\n * provider list so consumers read a plain array.\n */\n openInChat: z\n .union([\n z.boolean(),\n z\n .array(z.enum(openInChatProviders))\n .refine((value) => new Set(value).size === value.length, {\n message: \"ai.openInChat must not repeat a provider.\",\n }),\n ])\n .default(true)\n .transform((value) => {\n if (isBoolean(value)) {\n return value ? [...openInChatProviders] : [];\n }\n return value;\n }),\n};\n\nconst aiConfigSchema = z.strictObject(\n aiConfigFields,\n removedKeysHint(movedToAgentsHints(\"ai\"))\n);\n\n/**\n * A pinned link rendered above the sidebar sections — a blog, changelog, or\n * contact page that should always be reachable, regardless of the active tab.\n * `href` may be an external URL or an internal route.\n */\nconst featuredLinkSchema = z.strictObject({\n href: z.string(),\n icon: iconName.optional(),\n label: z.string(),\n});\n\n/**\n * A header link: a plain one (`Log in`, `Status`), or the single call to\n * action. Same shape as a featured link minus the icon — the header row is\n * text, not iconography.\n */\nconst headerActionSchema = z.strictObject({\n href: z.string(),\n label: z.string(),\n});\n\nconst navigationConfigSchema = z.strictObject({\n /** Plain links in the header, left of the icon buttons. */\n actions: z.array(headerActionSchema).default([]),\n /**\n * The one primary call to action in the header, as a filled button.\n *\n * Singular on purpose: a docs header has room for exactly one thing a\n * reader is being asked to do, a row of buttons asks for nothing, and\n * `featured` already takes the secondary links.\n */\n cta: headerActionSchema.optional(),\n /** Pinned links shown above the generated sidebar sections. */\n featured: z.array(featuredLinkSchema).default([]),\n /**\n * The GitHub link in the header. `true` derives it from `github`, `false`\n * hides it, and an absolute URL points it anywhere on GitHub — an\n * organization, say, when the docs repo itself is private and `github` has\n * to stay unset. The mark stays the GitHub one, so a URL elsewhere belongs in\n * `actions`.\n */\n repo: z.union([z.boolean(), httpUrlSchema]).default(true),\n selectors: z.array(navSelectorSchema).default([]),\n /**\n * Sidebar behavior. `display` sets how every group renders (a group in an\n * explicit `items` config may still override it); `items` is an explicit\n * sidebar — when omitted the sidebar is generated from the content tree.\n * A bare array is shorthand for `{ items }`.\n */\n sidebar: z\n .union([\n z.array(sidebarItemSchema),\n z.strictObject({\n display: sidebarDisplaySchema.default(\"flat\"),\n items: z.array(sidebarItemSchema).optional(),\n }),\n ])\n .prefault({})\n .transform((value) =>\n Array.isArray(value) ? { display: \"flat\" as const, items: value } : value\n ),\n tabs: z.array(navTabSchema).default([]),\n});\n\nexport { askReasoningLevels } from \"../ai/ask.ts\";\nexport type { AskReasoning } from \"../ai/ask.ts\";\nexport type AskAiConfig = NonNullable<z.infer<typeof aiConfigSchema>[\"ask\"]>;\nexport { openInChatProviders } from \"./open-in-chat.ts\";\nexport type { OpenInChatProvider } from \"./open-in-chat.ts\";\n\n// Reader-facing \"Export\" page action (PDF via print, EPUB via client-side\n// generation). Off by default. Accepts a shorthand boolean to toggle both\n// formats, or an object to enable them individually; both normalize to\n// `{ epub, pdf }` so consumers read plain booleans.\nconst exportConfigSchema = z\n .union([\n z.boolean(),\n z.strictObject({\n epub: z.boolean().default(false),\n pdf: z.boolean().default(false),\n }),\n ])\n .transform((value) =>\n isBoolean(value) ? { epub: value, pdf: value } : value\n );\n\n/** A configured locale: ISO-ish code plus display metadata for the switcher. */\nconst localeSchema = z.strictObject({\n code: z.string().min(1),\n /** Text direction; drives `<html dir>` and a future RTL pass. */\n dir: z.enum([\"ltr\", \"rtl\"]).default(\"ltr\"),\n label: z.string(),\n /**\n * Freeform style guidance for `blume translate`, e.g. \"Brazilian\n * Portuguese, informal você\". Pins register and dialect from the first\n * translation and wins over an existing translation's style on reruns.\n */\n style: z.string().optional(),\n});\n\n/**\n * Internationalization. Opt-in: when absent, Blume is single-locale and behaves\n * exactly as before. The default locale lives at the content root; other locales\n * are top-level directories named by `code` (the `dir` parser).\n */\nconst i18nConfigSchema = z\n .strictObject({\n defaultLocale: z.string().default(\"en\"),\n /** Locale rendered for a missing translation; `null` disables fallback. */\n fallbackLocale: z.string().nullable().optional(),\n /** Drop the URL prefix for the default locale (`/`, `/fr/…`). Static-safe. */\n hideDefaultLocalePrefix: z.boolean().default(true),\n locales: z.array(localeSchema).min(1),\n /** `\"dir\"`: locale directories (`fr/page.mdx`). `\"dot\"`: filename suffix (`page.fr.mdx`). */\n parser: z.enum([\"dir\", \"dot\"]).default(\"dir\"),\n /** Per-locale UI string overrides: `{ fr: { search: { button: \"…\" } } }`. */\n ui: uiLocaleOverridesSchema.optional(),\n })\n .superRefine((value, ctx) => {\n const codes = new Set(value.locales.map((locale) => locale.code));\n if (!codes.has(value.defaultLocale)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `i18n.defaultLocale \"${value.defaultLocale}\" must match one of i18n.locales.`,\n path: [\"defaultLocale\"],\n });\n }\n if (\n value.fallbackLocale !== null &&\n value.fallbackLocale !== undefined &&\n !codes.has(value.fallbackLocale)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `i18n.fallbackLocale \"${value.fallbackLocale}\" must match one of i18n.locales.`,\n path: [\"fallbackLocale\"],\n });\n }\n });\n\n/**\n * Version ids must start with a letter (`v1.0`, not `1.0`): the id doubles as\n * the snapshot directory name, and a leading digit would collide with the\n * numeric-prefix ordering convention (`01-intro.mdx`), which strips `1.0/` to\n * `0/`. The rest allows word characters, dots, and hyphens — URL-safe as-is.\n */\nexport const VERSION_ID = /^[A-Za-z][\\w.-]*$/u;\n\n/** A frozen documentation snapshot: a directory under the content root. */\nconst archivedVersionSchema = z.strictObject({\n /**\n * The \"you're viewing an old version\" notice: `true` for the built-in\n * message, a string for custom copy, `false` to hide it.\n */\n banner: z.union([z.boolean(), z.string()]).default(true),\n /**\n * Where this version's pages point their canonical URL: `latest` targets the\n * same page in the current docs when it still exists (self otherwise), so\n * search engines treat the live page as authoritative without deindexing\n * version-only content. `self` keeps every page authoritative.\n */\n canonical: z.enum([\"latest\", \"self\"]).default(\"latest\"),\n /** Directory name under the content root, and the URL segment. */\n id: z\n .string()\n .regex(\n VERSION_ID,\n 'Version ids must start with a letter (e.g. \"v1.0\") and contain only letters, digits, dots, hyphens, and underscores.'\n ),\n /** Switcher label; defaults to the id. */\n label: z.string().optional(),\n /** Emit `noindex` on every page of this version. */\n noindex: z.boolean().default(false),\n});\n\n/**\n * Docs versioning. Opt-in: the latest docs live at the content root with\n * unprefixed URLs, and each archived version is a frozen snapshot directory\n * (`content/docs/<id>/`) cut with `blume version <id>`. Archived means frozen:\n * snapshots carry their own translations and are never retranslated.\n */\nconst versionsConfigSchema = z\n .strictObject({\n /** Frozen snapshots, newest first — this order is the switcher order. */\n archived: z.array(archivedVersionSchema).default([]),\n /** Labels the unprefixed tree (the latest docs) in the switcher. */\n current: z.strictObject({\n /** Small tag rendered next to the label (e.g. `Latest`). */\n badge: z.string().optional(),\n label: z.string(),\n }),\n switcher: z\n .strictObject({\n /**\n * Where switching lands when the page has no equivalent in the target\n * version: `same-page` goes to the equivalent when it exists (version\n * root otherwise); `root` always goes to the version root.\n */\n redirect: z.enum([\"same-page\", \"root\"]).default(\"same-page\"),\n })\n .prefault({}),\n })\n .superRefine((value, ctx) => {\n const seen = new Set<string>();\n for (const [position, version] of value.archived.entries()) {\n if (seen.has(version.id)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `versions.archived declares \"${version.id}\" more than once.`,\n path: [\"archived\", position, \"id\"],\n });\n }\n seen.add(version.id);\n }\n });\n\n/**\n * A pattern segment in a redirect path: a named `:param` segment or a `*`\n * splat. `from` is matched as an exact path, and hosts disagree on patterns —\n * a static build would even write a literal `:slug` folder — so both ends are\n * checked. An absolute `to` URL's own scheme and host are skipped.\n */\nconst REDIRECT_PATTERN = /(?:^|\\/):[A-Za-z_]|\\*/u;\nconst URL_ORIGIN = /^[a-z][\\d+.a-z-]*:\\/\\/[^/]*/iu;\n\nconst exactRedirectPath = (end: \"from\" | \"to\") =>\n z\n .string()\n .refine((path) => !REDIRECT_PATTERN.test(path.replace(URL_ORIGIN, \"\")), {\n message: `redirects take exact paths: \\`${end}\\` can't hold a \\`:param\\` segment or a \\`*\\` wildcard. Add one redirect per path, or put pattern rules in your host's redirect config (vercel.json, _redirects).`,\n });\n\nconst redirectSchema = z.strictObject({\n from: exactRedirectPath(\"from\"),\n status: z\n .union([z.literal(301), z.literal(302), z.literal(307), z.literal(308)])\n .default(301),\n to: exactRedirectPath(\"to\"),\n});\n\n/**\n * One authorized remote image source, passed through to Astro's\n * `image.remotePatterns`. Wildcards follow Astro's rules: `hostname` accepts\n * `**.example.com` (any depth) or `*.example.com` (one level), `pathname`\n * accepts `/dir/**` or `/dir/*` the same way.\n */\nconst imageRemotePatternSchema = z.strictObject({\n hostname: z.string().optional(),\n pathname: z.string().optional(),\n port: z.string().optional(),\n protocol: z.string().optional(),\n});\n\n/**\n * Image optimization (`image`). Local images referenced by relative path\n * (``) are optimized at build time automatically —\n * compressed, converted to WebP, and stamped with intrinsic dimensions.\n * Remote images are only optimized when their host is authorized here;\n * both fields map directly onto Astro's `image` config.\n */\nconst imageConfigSchema = z.strictObject({\n /** Hosts whose remote images may be optimized, e.g. `[\"cdn.example.com\"]`. */\n domains: z.array(z.string()).default([]),\n /** Pattern-based host authorization, for wildcards `domains` can't express. */\n remotePatterns: z.array(imageRemotePatternSchema).default([]),\n});\n\n/**\n * X (Twitter) attribution. The account fields feed `twitter:site` (the site's\n * account) and `twitter:creator` (the author's), which is the one piece of X\n * card metadata with no Open Graph equivalent to fall back to — everything else\n * on the card is read from `og:*`.\n */\nconst xConfigSchema = z.strictObject({\n /** The author's account, overridable per page via `seo.x.creator`. */\n creator: xHandleSchema,\n /** The site's own account, e.g. `@blume`. */\n handle: xHandleSchema,\n});\n\n/**\n * Any CSS color. Takumi parses the full grammar, so this stays unvalidated\n * here and a bad value fails the OG prerender with a parse error naming it —\n * the same fail-fast the card's accent relies on. Validating hex-only here\n * would reject `oklch(…)`, which `theme.accent` (the card's default accent)\n * already accepts.\n */\nconst ogColorSchema = z.string();\n\nconst ogPaletteSchema = z.strictObject({\n accent: ogColorSchema.optional(),\n background: ogColorSchema.optional(),\n border: ogColorSchema.optional(),\n foreground: ogColorSchema.optional(),\n muted: ogColorSchema.optional(),\n});\n\n/**\n * A font to load into the OG card renderer. A bare string is a Google Fonts\n * family name; the name-only object form pins the weight (a number, a list, or\n * a variable range like `\"100..900\"`) and style, fetched from Google Fonts at\n * build. The `src` form reads a local font file from the project instead.\n * Either way Takumi does per-glyph fallback, so a family covering a script\n * (e.g. Noto Sans JP for CJK) fixes tofu without touching how Latin renders.\n */\nconst ogFontWeightSchema = z.union([\n z.number().int().positive(),\n z.array(z.number().int().positive()),\n z.string().regex(/^\\d+\\.\\.\\d+$/u),\n]);\nconst ogFontStyleSchema = z.enum([\"normal\", \"italic\"]);\nconst ogFontSchema = z.union([\n z.string(),\n z.strictObject({\n name: z.string(),\n style: z.union([ogFontStyleSchema, z.array(ogFontStyleSchema)]).optional(),\n weight: ogFontWeightSchema.optional(),\n }),\n /** A local font file, read from the project at build. */\n z.strictObject({\n name: z.string(),\n src: z.string().min(1),\n style: ogFontStyleSchema.optional(),\n weight: z.number().int().positive().optional(),\n }),\n]);\n\nconst ogConfigSchema = z.strictObject({\n /**\n * Site-wide card subtitle, shown on pages without their own description.\n * Defaults to the site description; a string overrides it, `false` renders\n * every card without a subtitle (page descriptions included).\n */\n description: z.union([z.string(), z.literal(false)]).optional(),\n /**\n * Generate a per-page Open Graph image. Defaults to on once a deployment\n * site URL is known (set or auto-detected) and off otherwise, since\n * `og:image` must be absolute to be useful to crawlers — resolved in\n * `loadConfig`. An explicit value here always wins.\n */\n enabled: z.boolean().optional(),\n /**\n * Google Font families for the generated card, extending Takumi's Latin-only\n * default so non-Latin titles (CJK, and so on) render instead of tofu.\n * Fetched from Google Fonts at build.\n */\n fonts: z.array(ogFontSchema).optional(),\n /**\n * Local SVG used in the generated card instead of the site logo; `false`\n * renders the card without any brand mark.\n */\n logo: z.union([z.string(), z.literal(false)]).optional(),\n /** Optional generated-card colors. */\n palette: ogPaletteSchema.optional(),\n /**\n * Footer site text. Defaults to the deployment site's host plus\n * `deployment.base` (`docs.acme.com`, `user.github.io/repo`); a string\n * overrides it, `false` hides it.\n */\n site: z.union([z.string(), z.literal(false)]).optional(),\n /**\n * Card headlines for custom `.astro` pages, keyed by route (`\"/\"`, `\"/cli\"`).\n * A custom page has no frontmatter to read, so its card is otherwise titled\n * by humanizing its last URL segment (`/cli` → \"Cli\"); an entry here wins.\n * Content pages always take their card headline from the page title.\n */\n titles: z.record(z.string(), z.string()).optional(),\n});\n\nconst rssConfigSchema = z.strictObject({\n enabled: z.boolean().default(true),\n /** Max items per feed, newest first. */\n limit: z.number().int().positive().default(50),\n /** Content types that each get a feed at `/<type>/rss.xml`. */\n types: z.array(z.string()).default([\"blog\", \"changelog\"]),\n});\n\n/**\n * robots.txt `Content-Signal` preferences — the emerging content-usage\n * declaration for how crawlers may reuse the site. Each field maps to one\n * signal:\n * - `search` → `search` (traditional and AI search indexing)\n * - `aiInput` → `ai-input` (grounding / RAG use at answer time)\n * - `aiTrain` → `ai-train` (model training)\n */\nconst contentSignalsObjectSchema = z.strictObject({\n aiInput: z.boolean().default(true),\n aiTrain: z.boolean().default(true),\n search: z.boolean().default(true),\n});\n\n/**\n * Content signals accept a boolean shorthand or a per-signal object, and\n * normalize to `{ search, aiInput, aiTrain }` — or `null` when disabled, so\n * robots.txt omits the declaration entirely. On by default (`true`): Blume\n * declares the docs open to search and agents. `false` opts out; an object\n * restricts individual signals (unset signals stay `yes`).\n */\nconst contentSignalsSchema = z\n .union([z.boolean(), contentSignalsObjectSchema])\n .transform((value) => {\n if (value === true) {\n return contentSignalsObjectSchema.parse({});\n }\n if (value === false) {\n return null;\n }\n return value;\n });\n\n/** A schema.org `PostalAddress`, any part of which may be given. */\nconst postalAddressSchema = z.strictObject({\n addressCountry: z.string().optional(),\n addressLocality: z.string().optional(),\n addressRegion: z.string().optional(),\n postalCode: z.string().optional(),\n streetAddress: z.string().optional(),\n});\n\n/**\n * `seo.organization`: the organization behind the site, emitted on every page\n * as a schema.org `Organization` node (see `seo/jsonld.ts`). Name and URL\n * default to the site's; contact details become a `ContactPoint`, the address\n * a `PostalAddress` — what agents check to verify a business.\n */\nconst organizationConfigSchema = z.strictObject({\n address: postalAddressSchema.optional(),\n contactType: z.string().default(\"customer support\"),\n email: z.email().optional(),\n logo: z.string().optional(),\n name: z.string().optional(),\n sameAs: z.array(z.url()).default([]),\n telephone: z.string().optional(),\n url: z.url().optional(),\n});\n\n/**\n * `seo.software`: the product the site documents, emitted on the homepage as\n * a schema.org `SoftwareApplication` node. `true` takes every default (name\n * and description from the site, category `DeveloperApplication`).\n */\nconst softwareConfigSchema = z.strictObject({\n applicationCategory: z.string().default(\"DeveloperApplication\"),\n description: z.string().optional(),\n license: z.string().optional(),\n name: z.string().optional(),\n operatingSystem: z.string().optional(),\n price: z.union([z.number().nonnegative(), z.string()]).optional(),\n priceCurrency: z.string().default(\"USD\"),\n sameAs: z.array(z.url()).default([]),\n});\n\ntype SoftwareResolved = z.output<typeof softwareConfigSchema>;\n\n/** Discoverability features: OG images, feeds, sitemap, structured data. */\nconst seoConfigFields = {\n og: ogConfigSchema.default({}),\n /** The organization behind the site, as an `Organization` JSON-LD node. */\n organization: organizationConfigSchema.optional(),\n /** Generate robots.txt (with a Sitemap reference when available). */\n robots: z.boolean().default(true),\n rss: rssConfigSchema.prefault({}),\n /** Generate sitemap.xml (requires deployment.site). */\n sitemap: z.boolean().default(true),\n /** The documented product, as a homepage `SoftwareApplication` node. */\n software: z\n .union([z.boolean(), softwareConfigSchema])\n .optional()\n .transform((value): SoftwareResolved | undefined => {\n if (value === true) {\n return softwareConfigSchema.parse({});\n }\n return value === false ? undefined : value;\n }),\n /** Emit schema.org JSON-LD in each page's <head>. */\n structuredData: z.boolean().default(true),\n /** X (Twitter) account attribution for share cards. */\n x: xConfigSchema.default({}),\n};\n\nconst seoConfigSchema = z.strictObject(\n seoConfigFields,\n removedKeysHint({\n agentReadability: \"seo.agentReadability moved to agents.agentReadability.\",\n contentSignals: \"seo.contentSignals moved to agents.contentSignals.\",\n })\n);\n\n/**\n * The machine-readable surface agents consume: the JSON API, `llms.txt`, the\n * MCP server, published skills, discovery manifests, and the robots.txt\n * usage policy. Everything reader-facing that talks to a model (Ask AI, Open\n * in chat) stays under `ai`.\n */\nconst agentsConfigSchema = z.strictObject({\n /**\n * Emit `agent-readability.json` at the site root: a manifest that indexes\n * the agent-facing surface (llms.txt, Markdown mirrors, MCP server, feeds)\n * so agents can discover it without scraping HTML.\n */\n agentReadability: z.boolean().default(true),\n /**\n * The JSON docs API: the page index, per-page JSON, and navigation under\n * `/api/docs/` (prerendered, so a static site serves them from files), the\n * live search endpoint on server output, and the OpenAPI description of\n * the whole machine-readable surface at `/openapi.json`. On by default.\n */\n api: z.boolean().default(true),\n /**\n * The AI Catalog / ARD manifest at `/.well-known/ai-catalog.json` (mirrored\n * at `/.well-known/ard.json`): one entry per agent-facing resource the site\n * publishes — the MCP server card, each agent skill, the JSON docs API's\n * OpenAPI document, each rendered API reference, and llms.txt — so agent\n * registries can index the site from its domain alone. Needs a\n * `deployment.site` (identifiers are domain-anchored URNs). On by default;\n * the object form overrides the generated representative queries.\n */\n catalog: z\n .union([z.boolean(), aiCatalogObjectSchema])\n .default(true)\n .transform((value): AiCatalogResolved =>\n isBoolean(value) ? { enabled: value, queries: {} } : value\n ),\n /** robots.txt `Content-Signal` usage declaration (on by default). */\n contentSignals: contentSignalsSchema.prefault(true),\n /**\n * `llms.txt`/`llms-full.txt` emission. A bare boolean toggles it; the object\n * form adds `openapi: false` to keep generated API reference pages out of\n * both files (e.g. when the configured spec is example content) and\n * `details`, free-form Markdown placed after the summary — the llms.txt\n * spec's details block, where a site tells agents when to reach for it.\n */\n llmsTxt: z\n .union([z.boolean(), llmsTxtObjectSchema])\n .default(true)\n .transform((value): LlmsTxtResolved =>\n isBoolean(value) ? { enabled: value, openapi: true } : value\n ),\n // Serializers for the agent-facing Markdown downlevel (the `.md` mirror,\n // llms-full.txt, MCP get_page), keyed by JSX name. Functions live here —\n // not in components.tsx — because the config file is executed at build\n // time while the components file is only statically analyzed. A same-name\n // entry replaces the built-in serializer.\n // Two-argument `z.record` — the single-argument form throws at\n // schema-construction time under Zod 4 (see uiStringsOverrideSchema).\n markdownComponents: z\n .record(\n z.string(),\n z.custom<ComponentMarkdown>(\n (value): value is ComponentMarkdown => typeof value === \"function\",\n {\n message: \"Expected a serializer function.\",\n }\n )\n )\n .default({}),\n /** Expose the docs as an MCP server for connecting agents. */\n mcp: mcpConfigSchema.prefault({}),\n /**\n * Publish Agent Skills for discovery: a directory (resolved against the\n * project root) whose subdirectories each hold a `SKILL.md`. The build\n * copies each skill under `/.well-known/agent-skills/` — a lone `SKILL.md`\n * verbatim, a skill with supporting files as a `.tar.gz` — and emits the\n * discovery index (`index.json`) with SHA-256 digests per the Agent Skills\n * Discovery RFC.\n */\n skills: z.string().min(1).optional(),\n /**\n * Web Bot Auth (IETF `webbotauth`): publish the org's HTTP Message\n * Signature public keys at `/.well-known/http-message-signatures-directory`\n * so sites receiving requests from the org's agents can verify them.\n * Opt-in and public-keys-only — the private keys live wherever the signing\n * agents run, never in the site.\n */\n webBotAuth: z\n .strictObject({\n keys: z.array(publicJwkSchema).default([]),\n })\n .prefault({}),\n /**\n * WebMCP: register in-page tools (search, page Markdown, the docs index)\n * on the browser's model context so agentic browsers can drive the docs\n * without a separate MCP connection. A tiny script that no-ops in browsers\n * without the API; on by default.\n */\n webmcp: z.boolean().default(true),\n});\n\n/**\n * The GitHub instance's origin, normalized. Repo, edit, and API URLs are all\n * built by appending to this, so it is reduced to a bare origin: a trailing\n * slash would double the separator, and a path, query, fragment, or embedded\n * credentials would land in the middle of every generated link.\n */\nconst githubOriginSchema = httpUrlSchema.transform(\n (value) => new URL(value).origin\n);\n\n/**\n * A REST API base: an origin plus an optional path, since Enterprise Server\n * serves the API from `/api/v3`. Anything past the path is dropped for the same\n * reason the host is reduced — `/repos/{owner}/{repo}` is appended as a string,\n * so a query would swallow the route and a fragment would strip it from the\n * request entirely, leaving a lookup that silently returns the wrong thing.\n */\nconst githubApiSchema = httpUrlSchema.transform((value) => {\n const { origin, pathname } = new URL(value);\n return trimEnd(`${origin}${pathname}`, \"/\");\n});\n\nconst githubConfigSchema = z.strictObject({\n /** REST API base. Derived from `host` when unset. */\n api: githubApiSchema.optional(),\n branch: z.string().default(\"main\"),\n /** Path from the repo root to the project root (for monorepos). */\n dir: z.string().optional(),\n /** Origin of the GitHub instance, for Enterprise installations. */\n host: githubOriginSchema.default(PUBLIC_HOST_URL),\n owner: z.string(),\n repo: z.string(),\n});\n\n/** The theme fields the structural code-theme check inspects. */\ninterface CodeThemeFields {\n colors?: unknown;\n settings?: unknown;\n tokenColors?: unknown;\n}\n\n/** A non-null, non-array object — the floor for a theme and its `colors` map. */\nconst isThemeObject = <Value>(value: Value): value is Value & CodeThemeFields =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst codeThemeSchema = z.custom<CodeTheme>((value) => {\n if (isString(value)) {\n return true;\n }\n if (!isThemeObject(value)) {\n return false;\n }\n // Token rules live in `settings` (Shiki's canonical field, also the TextMate\n // form themes like createCssVariablesTheme() produce) or `tokenColors` (the\n // VS Code spelling Shiki falls back to). A colors-only theme (editor fg/bg,\n // no token rules) is also valid — Shiki renders it from `colors` alone. Each\n // field present must have the right shape, and at least one must be present.\n const settingsValid =\n value.settings === undefined || Array.isArray(value.settings);\n const tokenColorsValid =\n value.tokenColors === undefined || Array.isArray(value.tokenColors);\n const colorsValid = value.colors === undefined || isThemeObject(value.colors);\n const hasContent =\n value.settings !== undefined ||\n value.tokenColors !== undefined ||\n value.colors !== undefined;\n return settingsValid && tokenColorsValid && colorsValid && hasContent;\n}, \"Expected a Shiki theme name or custom theme object\");\n\nconst codeBlockThemeSchema = z.strictObject({\n dark: codeThemeSchema.default(\"github-dark\"),\n light: codeThemeSchema.default(\"github-light\"),\n});\n\n/**\n * `<Component />` example previews. A string is shorthand for `{ source }`:\n * where examples live, relative to the project root (default `examples`).\n * `source` may be a glob (anything with `*`/`?`/`[]`/`{}`/`!`), in which case\n * only matching files are discovered and each `<Component path>` key is\n * relative to the glob's static prefix — use this for a registry layout that\n * colocates component sources with their examples\n * (`registry/<pkg>/**\\/examples/*`), leaving the sources (which have no\n * default export to wrap) out.\n *\n * `css` names a stylesheet (relative to the project root) injected into every\n * preview frame after Blume's default tokens. Previews render in an isolated\n * iframe that the site's docs styles never reach, so this is where design\n * tokens for the previewed components live — e.g. shadcn variables and\n * `@theme` mappings. Tailwind itself is already provided; the file should\n * hold tokens and custom styles, not another `@import \"tailwindcss\"`.\n */\nconst examplesConfigSchema = z\n .union([\n z.string(),\n z.strictObject({\n css: z.string().optional(),\n source: z.string().default(\"examples\"),\n }),\n ])\n .transform((value): { css?: string; source: string } =>\n isString(value) ? { source: value } : value\n );\n\n/**\n * \"Last updated\" timestamps for content pages. `false` (default) disables the\n * feature; `\"git\"` derives each page's date from the repository history;\n * `\"frontmatter\"` never runs git and reads only the page's own field. A page's\n * `lastModified` frontmatter always wins. The 1.x `true` and `{ type }` forms\n * fail with the hint below.\n */\nconst lastModifiedConfigSchema = z.union(\n [z.literal(false), z.enum([\"git\", \"frontmatter\"])],\n {\n error: (issue) =>\n issue.code === \"invalid_union\"\n ? 'lastModified takes false, \"git\", or \"frontmatter\": `true` became \"git\" and `{ type: \"…\" }` became the bare string.'\n : undefined,\n }\n);\n\n/**\n * How the \"last updated\" stamp and the changelog timeline render their dates —\n * a curated pass-through to `Intl.DateTimeFormat`, shared by both surfaces so\n * they read alike. Defaults to `{ dateStyle: \"long\" }`. Both stamps format in\n * UTC unless a `timeZone` is given, so a date reads the same regardless of the\n * build machine's zone. `dateStyle` is a preset that can't be combined with the\n * individual component fields (`year`, `month`, …), matching `Intl`'s own rule.\n */\nconst dateFormatConfigSchema = z\n .strictObject({\n /** Calendar system (e.g. `japanese`, `buddhist`). */\n calendar: z.string().optional(),\n /** Preset date length; mutually exclusive with the component fields. */\n dateStyle: z.enum([\"full\", \"long\", \"medium\", \"short\"]).optional(),\n /** Day representation. */\n day: z.enum([\"numeric\", \"2-digit\"]).optional(),\n /** Era representation (e.g. the Japanese imperial era). */\n era: z.enum([\"long\", \"short\", \"narrow\"]).optional(),\n /** Month representation. */\n month: z.enum([\"numeric\", \"2-digit\", \"long\", \"short\", \"narrow\"]).optional(),\n /** Numbering system (e.g. `latn`, `arab`). */\n numberingSystem: z.string().optional(),\n /** IANA time zone (e.g. `Asia/Tokyo`). Defaults to `UTC`. */\n timeZone: z.string().optional(),\n /** Weekday representation. */\n weekday: z.enum([\"long\", \"short\", \"narrow\"]).optional(),\n /** Year representation. */\n year: z.enum([\"numeric\", \"2-digit\"]).optional(),\n })\n .refine(\n (value) =>\n value.dateStyle === undefined ||\n (value.weekday === undefined &&\n value.era === undefined &&\n value.year === undefined &&\n value.month === undefined &&\n value.day === undefined),\n {\n message:\n \"dateFormat.dateStyle can't be combined with weekday/era/year/month/day; use one or the other.\",\n }\n );\n\n/** Code rendering options (`markdown.code`). */\nconst codeConfigSchema = z.strictObject({\n /**\n * Show a brand language icon in the code-block header (TypeScript, Python,\n * …). On by default; recognized languages only.\n */\n icons: z.boolean().default(true),\n /**\n * Light/dark Shiki themes for every code surface: fenced blocks, inline\n * `` `code`{:lang} ``, `<CodeBlock>`, and `<Diff>`.\n */\n theme: codeBlockThemeSchema.prefault({}),\n /**\n * Wrap long lines instead of scrolling horizontally. Off by default, so\n * code keeps its original line breaks and overflows into a scroll area.\n */\n wrap: z.boolean().default(false),\n});\n\nconst markdownConfigFields = {\n /** Code rendering: language icons, syntax themes, and line wrapping. */\n code: codeConfigSchema.prefault({}),\n /**\n * Open external Markdown links (absolute `http(s)://` and `//host` URLs) in\n * a new tab, like Blume's own header and sidebar links: `target=\"_blank\"`,\n * `rel=\"noreferrer\"`, an arrow icon, and a screen-reader \"Opens in a new\n * tab\" hint. Off by default; site routes, fragments, and `mailto:`/`tel:`\n * links are never affected.\n */\n externalLinks: z.boolean().default(false),\n /**\n * Wrap each `##`–`######` heading in a link to its own anchor so readers can\n * click to copy, bookmark, or share a permalink to that section. On by\n * default; set to `false` to render plain headings.\n */\n headingAnchors: z.boolean().default(true),\n /**\n * Make content images click-to-zoom (open in a lightbox). On by default;\n * opt a single image out with `data-no-zoom`.\n */\n imageZoom: z.boolean().default(true),\n};\n\nconst markdownConfigSchema = z.strictObject(\n markdownConfigFields,\n removedKeysHint({\n codeBlocks:\n \"markdown.codeBlocks was merged into markdown.code: move theme: { light, dark } under markdown.code.\",\n })\n);\n\n/** React island behavior (`react`). */\nconst reactConfigSchema = z.strictObject({\n /**\n * Auto-memoize React components/hooks with the React Compiler\n * (`babel-plugin-react-compiler`). On by default whenever React is enabled\n * (a project `.tsx`/`.jsx`, a React island/example/override, or Ask AI); set\n * to `false` to skip the compiler's babel pass.\n */\n compiler: z.boolean().default(true),\n});\n\n/**\n * Opt-in custom frontmatter keys. `extend` maps each extra key a project's\n * pages may carry (e.g. `owner`, `reviewedAt`) to a validation schema; the\n * page schema stays strict for everything else, so typo-catching is preserved.\n * Schemas are consumed through the Standard Schema `~standard` contract —\n * never Zod's own API — so the consumer's zod (any version), Valibot, or\n * ArkType all work (see `standard-schema.ts`). Every declared key is validated\n * on every page, absent ones included, so a required schema enforces the key\n * site-wide; mark it `.optional()` to validate only when present. Built-in\n * frontmatter fields can't be redeclared — they're load-bearing (routing,\n * sidebar, SEO), and shadowing one would silently change its semantics.\n */\nconst frontmatterConfigSchema = z.strictObject({\n extend: customKeySchemaRecord(\"frontmatter.extend\"),\n});\n\n/** Full user-facing config schema. All fields optional with defaults. */\n/**\n * Table-of-contents config. `true`/`false` toggles it; an object narrows the\n * heading range. Normalized to `{ enabled, minLevel, maxLevel }` (default: on,\n * H2–H3, matching the historical hardcoded range).\n */\nconst tocConfigSchema = z\n .union([\n z.boolean(),\n z.strictObject({\n maxHeadingLevel: z.number().int().min(1).max(6).optional(),\n minHeadingLevel: z.number().int().min(1).max(6).optional(),\n }),\n ])\n .default(true)\n .transform((value) => {\n if (isBoolean(value)) {\n return { enabled: value, maxLevel: 3, minLevel: 2 };\n }\n return {\n enabled: true,\n maxLevel: value.maxHeadingLevel ?? 3,\n minLevel: value.minHeadingLevel ?? 2,\n };\n })\n // Checked after defaults apply, so `{ minHeadingLevel: 5 }` (default max 3)\n // is caught too — an inverted range would silently render an empty TOC.\n .refine((value) => value.minLevel <= value.maxLevel, {\n message:\n \"toc.minHeadingLevel must be less than or equal to toc.maxHeadingLevel.\",\n });\n\nexport const blumeConfigSchema = z\n .strictObject(\n {\n agents: agentsConfigSchema.prefault({}),\n ai: aiConfigSchema.prefault({}),\n // Adapters from `blume/analytics`, each a serializable descriptor.\n analytics: analyticsConfigSchema,\n banner: bannerConfigSchema.optional(),\n /**\n * Site-wide mount point prepended to every generated route (e.g. `/docs`),\n * while staying invisible to the sidebar/nav tree. Distinct from a per-source\n * `prefix` (which creates a group) and from `deployment.base` (Astro's\n * host-subdirectory base); the two compose. Normalized to `\"\"` or `/seg`.\n */\n basePath: z\n .string()\n .optional()\n .transform((value) => normalizeBasePath(value)),\n content: contentConfigSchema.prefault({}),\n /**\n * Date presentation for the \"last updated\" stamp and the changelog timeline.\n * Pass-through `Intl.DateTimeFormat` options; defaults to `{ dateStyle: \"long\" }`.\n */\n dateFormat: dateFormatConfigSchema.default({ dateStyle: \"long\" }),\n /**\n * A host adapter from `blume/deploy` (`vercel()`, `netlify()`,\n * `cloudflare()`, `node()`) for a server build on that host, or the plain\n * `{ site, base }` form for a static build anywhere. Resolves to the\n * adapter's descriptor with `output` filled in; `static` when unset.\n */\n deployment: resolvedDeploymentSchema.prefault({}),\n description: z.string().optional(),\n /**\n * Where `<Component path>` resolves live previews and their source from.\n * A string is shorthand for `{ source }` — the directory (or glob, for\n * colocated registry layouts) under the project root that holds example\n * files. The object form adds `css`: a stylesheet injected into every\n * preview frame (design tokens, shadcn variables, `@theme` mappings).\n */\n examples: examplesConfigSchema.prefault(\"examples\"),\n export: exportConfigSchema.prefault(false),\n feedback: z.boolean().default(true),\n /** Opt-in custom frontmatter keys, validated by user-supplied schemas. */\n frontmatter: frontmatterConfigSchema.prefault({}),\n github: githubConfigSchema.optional(),\n i18n: i18nConfigSchema.optional(),\n image: imageConfigSchema.prefault({}),\n integrations: z.array(z.custom<AstroIntegration>()).default([]),\n lastModified: lastModifiedConfigSchema.default(false),\n logo: logoConfigSchema.optional(),\n markdown: markdownConfigSchema.prefault({}),\n navigation: navigationConfigSchema.prefault({}),\n react: reactConfigSchema.prefault({}),\n redirects: z.array(redirectSchema).default([]),\n /** API references: adapters from `blume/reference`, each a serializable descriptor. */\n reference: referenceConfigSchema,\n search: searchConfigSchema.prefault({}),\n seo: seoConfigSchema.prefault({}),\n theme: themeConfigSchema.prefault({}),\n title: z.string().default(\"Documentation\"),\n toc: tocConfigSchema,\n versions: versionsConfigSchema.optional(),\n },\n {\n // The 1.x `openapi`/`asyncapi`/`graphql` blocks name the `reference` list\n // that replaced them, alongside every other issue in the config.\n error: (issue) =>\n issue.code === \"unrecognized_keys\"\n ? removedReferenceKeysHint(issue.keys)\n : undefined,\n }\n )\n .superRefine((config, ctx) => {\n // A version id that is also a configured locale code would make a leading\n // `<id>/` directory ambiguous between the two axes — refuse it outright so\n // detection order (version first, then locale) never has to guess.\n if (config.versions && config.i18n) {\n const localeCodes = new Set(\n config.i18n.locales.map((locale) => locale.code.toLowerCase())\n );\n for (const [position, version] of config.versions.archived.entries()) {\n if (localeCodes.has(version.id.toLowerCase())) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Version id \"${version.id}\" is also a configured locale code — rename the version (e.g. \"v${version.id}\").`,\n path: [\"versions\", \"archived\", position, \"id\"],\n });\n }\n }\n }\n // A custom key is declared site-wide (`frontmatter.extend`) or per-type\n // (`content.types`), never both — two schemas for one key would make\n // precedence on pages of that type ambiguous.\n for (const [typeName, typeConfig] of Object.entries(config.content.types)) {\n for (const key of Object.keys(typeConfig.frontmatter)) {\n if (Object.hasOwn(config.frontmatter.extend, key)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `\"${key}\" is already declared in frontmatter.extend and cannot be redeclared for type \"${typeName}\".`,\n path: [\"content\", \"types\", typeName, \"frontmatter\", key],\n });\n }\n }\n // A facet with no declared key could never carry a value — pages can't\n // even set the key — so it's a config mistake, caught here where both\n // the per-type map and the site-wide extend are visible.\n for (const [position, facet] of typeConfig.facets.entries()) {\n if (\n !(\n Object.hasOwn(typeConfig.frontmatter, facet) ||\n Object.hasOwn(config.frontmatter.extend, facet)\n )\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Facet \"${facet}\" for type \"${typeName}\" is not a declared custom frontmatter key — add it to the type's frontmatter map or frontmatter.extend.`,\n path: [\"content\", \"types\", typeName, \"facets\", position],\n });\n }\n }\n }\n });\n\n/** Resolved config: every field present after defaults are applied. */\nexport type ResolvedConfig = z.infer<typeof blumeConfigSchema>;\n/** Resolved `dateFormat`: the `Intl.DateTimeFormat` options both date stamps share. */\nexport type ResolvedDateFormat = z.infer<typeof dateFormatConfigSchema>;\n/** Resolved `frontmatter.extend`: custom key → user-supplied schema. */\nexport type FrontmatterExtend = Record<string, StandardSchema>;\n/** Resolved i18n block (present only when the project opts into i18n). */\nexport type ResolvedI18nConfig = z.infer<typeof i18nConfigSchema>;\n/** A configured locale with display metadata. */\nexport type LocaleConfig = z.infer<typeof localeSchema>;\n/** Resolved versions block (present only when the project opts into versioning). */\nexport type ResolvedVersionsConfig = z.infer<typeof versionsConfigSchema>;\n/** A configured archived (frozen) version. */\nexport type ArchivedVersionConfig = z.infer<typeof archivedVersionSchema>;\n/**\n * User-authored config, straight off the schema. The public, hand-documented\n * authoring type is `BlumeConfig` in `./config-input.ts`, which a compile-time\n * guard keeps structurally identical to this.\n */\nexport type BlumeConfigInput = z.input<typeof blumeConfigSchema>;\n/** The resolved search backend: an adapter descriptor, or `none`. */\nexport type { ResolvedSearchAdapter } from \"../search/adapters/registry.ts\";\n/** Resolved robots.txt `Content-Signal` preferences (`null` when disabled). */\nexport type ContentSignals = z.infer<typeof contentSignalsSchema>;\n/** The resolved per-signal policy object (present when signals are enabled). */\nexport type ContentSignalPolicy = NonNullable<ContentSignals>;\n",
|
|
57
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport { unrecognizedKeysMessage } from \"../core/unrecognized-keys.ts\";\n\n/**\n * The `reasoning` levels the adapters accept: the AI SDK's top-level\n * `reasoning` values minus `provider-default`, which is what omitting the\n * option means.\n */\nexport const askReasoningLevels = [\n \"none\",\n \"minimal\",\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n] as const;\n\n/** How much the model reasons before answering (an adapter's `reasoning`). */\nexport type AskReasoning = (typeof askReasoningLevels)[number];\n\n/**\n * The AI SDK's `providerOptions` shape, forwarded to `streamText` verbatim:\n * `{ [provider]: { [option]: value } }`. The escape hatch for model controls\n * Blume doesn't name, so a new provider knob never needs a Blume field.\n */\nexport type AskProviderOptions = Record<string, Record<string, JsonValue>>;\n\n/** The AI SDK provider package the OpenAI-compatible adapters install. */\nconst OPENAI_COMPATIBLE_DEP = \"@ai-sdk/openai-compatible\";\n\n// ---------------------------------------------------------------------------\n// Shared options\n// ---------------------------------------------------------------------------\n\n/** The options every Ask AI adapter accepts. */\nexport interface AskAdapterOptions {\n /**\n * Name of the env var holding the provider's API key. Each adapter has its\n * own default; set this only to point at a different variable.\n */\n apiKeyEnv?: string;\n /**\n * Static request headers sent to the provider on every call — a\n * caller-identifying header for a shared backend, for example. Values are\n * written into the generated route as literals, so keep secrets in\n * `apiKeyEnv` rather than here.\n */\n headers?: Record<string, string>;\n /**\n * Options passed to `streamText` as its `providerOptions`, untouched, in the\n * AI SDK's own shape (`{ openai: { textVerbosity: \"low\" } }`, say).\n */\n providerOptions?: AskProviderOptions;\n}\n\n/**\n * `providerOptions`, forwarded to `streamText` verbatim. JSON-only, because\n * the generated and ejected routes inline it as a literal.\n */\nconst providerOptionsSchema = z.record(\n z.string(),\n z.record(z.string(), z.json())\n);\n\n/** The shared option schema, with the adapter's own key env var default. */\nconst sharedOptions = (apiKeyEnv: string) => ({\n apiKeyEnv: z.string().min(1).default(apiKeyEnv),\n headers: z.record(z.string(), z.string()).optional(),\n providerOptions: providerOptionsSchema.optional(),\n});\n\nconst reasoningOption = z.enum(askReasoningLevels).optional();\n\n// ---------------------------------------------------------------------------\n// gateway()\n// ---------------------------------------------------------------------------\n\nconst GATEWAY_API_KEY_ENV = \"AI_GATEWAY_API_KEY\";\n/** The model the gateway adapter uses when none is configured. */\nconst DEFAULT_GATEWAY_MODEL = \"openai/gpt-5.5\";\n\n/** Options for {@link gateway}. */\nexport interface AskGatewayOptions extends AskAdapterOptions {\n /** A `provider/model` id routed by the gateway. Defaults to `openai/gpt-5.5`. */\n model?: string;\n /**\n * How much the model reasons before answering. Sent as the AI SDK's\n * top-level `reasoning` option, which the gateway maps to the model's own\n * control (OpenAI's `reasoning_effort`, for example); the model has to\n * offer the level you pick. Omitted keeps the model's default.\n */\n reasoning?: AskReasoning;\n}\n\nconst gatewayOptionsSchema = z.strictObject({\n ...sharedOptions(GATEWAY_API_KEY_ENV),\n model: z.string().min(1).default(DEFAULT_GATEWAY_MODEL),\n reasoning: reasoningOption,\n});\n\nexport type AskGatewayAdapter = AdapterDescriptor<\"gateway\", AskGatewayOptions>;\n\nexport const gatewayAdapterSchema = adapterDescriptorSchema(\n \"gateway\",\n gatewayOptionsSchema\n);\n\n/**\n * Route Ask AI through the Vercel AI Gateway (the default). `model` is a\n * `provider/model` string; the key is `AI_GATEWAY_API_KEY`, or Vercel's OIDC\n * token when deployed there. Needs no provider SDK beyond the `ai` package\n * Blume ships.\n */\nexport const gateway = (\n options: AskGatewayOptions = {}\n): AskGatewayAdapter => ({\n kind: \"gateway\",\n options,\n requiredSecrets: [options.apiKeyEnv ?? GATEWAY_API_KEY_ENV],\n runtimeDeps: [],\n});\n\n// ---------------------------------------------------------------------------\n// openrouter()\n// ---------------------------------------------------------------------------\n\nconst OPENROUTER_API_KEY_ENV = \"OPENROUTER_API_KEY\";\n\n/** Options for {@link openrouter}. */\nexport interface AskOpenRouterOptions extends AskAdapterOptions {\n /** The OpenRouter model id (`anthropic/claude-sonnet-4-5`). */\n model: string;\n /**\n * How much the model reasons before answering. Set on the model as\n * OpenRouter's `reasoning.effort`, because its provider ignores the AI\n * SDK's call-level option. Omitted keeps the model's default.\n */\n reasoning?: AskReasoning;\n}\n\nconst openrouterOptionsSchema = z.strictObject({\n ...sharedOptions(OPENROUTER_API_KEY_ENV),\n model: z.string().min(1),\n reasoning: reasoningOption,\n});\n\nexport type AskOpenRouterAdapter = AdapterDescriptor<\n \"openrouter\",\n AskOpenRouterOptions\n>;\n\nexport const openrouterAdapterSchema = adapterDescriptorSchema(\n \"openrouter\",\n openrouterOptionsSchema\n);\n\n/**\n * Route Ask AI through OpenRouter. Reads `OPENROUTER_API_KEY` and needs\n * `@openrouter/ai-sdk-provider` installed in the project.\n */\nexport const openrouter = (\n options: AskOpenRouterOptions\n): AskOpenRouterAdapter => ({\n kind: \"openrouter\",\n options,\n requiredSecrets: [options.apiKeyEnv ?? OPENROUTER_API_KEY_ENV],\n runtimeDeps: [\"@openrouter/ai-sdk-provider\"],\n});\n\n// ---------------------------------------------------------------------------\n// llmgateway()\n// ---------------------------------------------------------------------------\n\nconst LLMGATEWAY_API_KEY_ENV = \"LLMGATEWAY_API_KEY\";\n\n/** Options for {@link llmgateway}. */\nexport interface AskLlmGatewayOptions extends AskAdapterOptions {\n /** Overrides the preset endpoint (`https://api.llmgateway.io/v1`). */\n baseUrl?: string;\n /** The model id LLMGateway serves. */\n model: string;\n /**\n * How much the model reasons before answering, sent in the request as\n * `reasoning_effort`. Omitted keeps the model's default.\n */\n reasoning?: AskReasoning;\n}\n\nconst llmgatewayOptionsSchema = z.strictObject({\n ...sharedOptions(LLMGATEWAY_API_KEY_ENV),\n baseUrl: z.url().default(\"https://api.llmgateway.io/v1\"),\n model: z.string().min(1),\n reasoning: reasoningOption,\n});\n\nexport type AskLlmGatewayAdapter = AdapterDescriptor<\n \"llmgateway\",\n AskLlmGatewayOptions\n>;\n\nexport const llmgatewayAdapterSchema = adapterDescriptorSchema(\n \"llmgateway\",\n llmgatewayOptionsSchema\n);\n\n/**\n * Route Ask AI through LLMGateway's OpenAI-compatible endpoint. Reads\n * `LLMGATEWAY_API_KEY` and needs `@ai-sdk/openai-compatible` installed.\n */\nexport const llmgateway = (\n options: AskLlmGatewayOptions\n): AskLlmGatewayAdapter => ({\n kind: \"llmgateway\",\n options,\n requiredSecrets: [options.apiKeyEnv ?? LLMGATEWAY_API_KEY_ENV],\n runtimeDeps: [OPENAI_COMPATIBLE_DEP],\n});\n\n// ---------------------------------------------------------------------------\n// inkeep()\n// ---------------------------------------------------------------------------\n\nconst INKEEP_API_KEY_ENV = \"INKEEP_API_KEY\";\n\n/**\n * Options for {@link inkeep}. No `reasoning`: Inkeep runs its own QA pipeline\n * behind an OpenAI-compatible endpoint with no reasoning control.\n */\nexport interface AskInkeepOptions extends AskAdapterOptions {\n /** Overrides the preset endpoint (`https://api.inkeep.com/v1`). */\n baseUrl?: string;\n /** The Inkeep QA model id. */\n model: string;\n}\n\nconst inkeepOptionsSchema = z.strictObject({\n ...sharedOptions(INKEEP_API_KEY_ENV),\n baseUrl: z.url().default(\"https://api.inkeep.com/v1\"),\n model: z.string().min(1),\n});\n\nexport type AskInkeepAdapter = AdapterDescriptor<\"inkeep\", AskInkeepOptions>;\n\nexport const inkeepAdapterSchema = adapterDescriptorSchema(\n \"inkeep\",\n inkeepOptionsSchema\n);\n\n/**\n * Answer with Inkeep, which retrieves from the content indexed in its own\n * dashboard, so Blume leaves it ungrounded and it takes no `reasoning`.\n * Reads `INKEEP_API_KEY` and needs `@ai-sdk/openai-compatible` installed.\n */\nexport const inkeep = (options: AskInkeepOptions): AskInkeepAdapter => ({\n kind: \"inkeep\",\n options,\n requiredSecrets: [options.apiKeyEnv ?? INKEEP_API_KEY_ENV],\n runtimeDeps: [OPENAI_COMPATIBLE_DEP],\n});\n\n// ---------------------------------------------------------------------------\n// openaiCompatible()\n// ---------------------------------------------------------------------------\n\n/** Options for {@link openaiCompatible}. */\nexport interface AskOpenAICompatibleOptions extends AskAdapterOptions {\n /** Name of the env var holding the endpoint's API key. */\n apiKeyEnv: string;\n /** The endpoint's base URL (`https://my-gateway.example.com/v1`). */\n baseUrl: string;\n /** The model id the endpoint serves. */\n model: string;\n /** The provider name the AI SDK reports. Defaults to `openai-compatible`. */\n name?: string;\n /**\n * How much the model reasons before answering, sent in the request as\n * `reasoning_effort`, so the endpoint has to accept that parameter.\n * Omitted keeps the model's default.\n */\n reasoning?: AskReasoning;\n}\n\nconst openaiCompatibleOptionsSchema = z.strictObject({\n ...sharedOptions(\"API_KEY\"),\n // A generic endpoint has no preset, so the caller names the key env var.\n apiKeyEnv: z.string().min(1),\n baseUrl: z.url(),\n model: z.string().min(1),\n name: z.string().min(1).default(\"openai-compatible\"),\n reasoning: reasoningOption,\n});\n\nexport type AskOpenAICompatibleAdapter = AdapterDescriptor<\n \"openai-compatible\",\n AskOpenAICompatibleOptions\n>;\n\nexport const openaiCompatibleAdapterSchema = adapterDescriptorSchema(\n \"openai-compatible\",\n openaiCompatibleOptionsSchema\n);\n\n/**\n * Route Ask AI through any OpenAI-compatible endpoint: supply its `baseUrl`,\n * the `model` it serves, and the env var holding its key. Needs\n * `@ai-sdk/openai-compatible` installed.\n */\nexport const openaiCompatible = (\n options: AskOpenAICompatibleOptions\n): AskOpenAICompatibleAdapter => ({\n kind: \"openai-compatible\",\n options,\n requiredSecrets: [options.apiKeyEnv],\n runtimeDeps: [OPENAI_COMPATIBLE_DEP],\n});\n\n// ---------------------------------------------------------------------------\n// The `ai.ask.provider` schema\n// ---------------------------------------------------------------------------\n\n/** Which backend answers Ask AI: the value of `gateway()`, `openrouter()`, … */\nexport type AskAdapter =\n | AskGatewayAdapter\n | AskOpenRouterAdapter\n | AskLlmGatewayAdapter\n | AskInkeepAdapter\n | AskOpenAICompatibleAdapter;\n\n// ---------------------------------------------------------------------------\n// Blume 1 hints\n// ---------------------------------------------------------------------------\n\n/**\n * The 1.x `ai.ask.provider` names — also the adapters' `kind`s — each with the\n * `blume/ai` factory that replaced it.\n */\nconst FACTORY_BY_PROVIDER = new Map([\n [\"gateway\", \"gateway\"],\n [\"inkeep\", \"inkeep\"],\n [\"llmgateway\", \"llmgateway\"],\n [\"openai-compatible\", \"openaiCompatible\"],\n [\"openrouter\", \"openrouter\"],\n]);\n\n/** The 1.x flat `ai.ask` fields: each is now an option of the provider adapter. */\nconst MOVED_TO_PROVIDER: ReadonlySet<string> = new Set([\n \"apiKeyEnv\",\n \"baseUrl\",\n \"headers\",\n \"model\",\n \"reasoning\",\n]);\n\n/** The provider an `ai.ask` object names: a 1.x string or a descriptor's `kind`. */\nconst askProviderNameProbe = z.looseObject({\n provider: z.union([\n z.string(),\n z.looseObject({ kind: z.string() }).transform(({ kind }) => kind),\n ]),\n});\n\n/** The factory a failing `ai.ask` object's provider names, or the gateway. */\nconst providerFactory = (issue: z.core.$ZodRawIssue): string => {\n const probe = askProviderNameProbe.safeParse(issue.input);\n return (\n (probe.success && FACTORY_BY_PROVIDER.get(probe.data.provider)) || \"gateway\"\n );\n};\n\n/**\n * Error params for `ai.ask`: a 1.x flat provider field (`model`, `apiKeyEnv`,\n * `baseUrl`, `headers`, `reasoning`) names the adapter call it moves into —\n * the one the object's `provider` picks, 1.x string or descriptor — instead\n * of Zod's bare \"Unrecognized key\"; any other unknown key keeps its wording.\n */\nexport const askMovedFieldsHint = {\n error: (issue: z.core.$ZodRawIssue): string | undefined => {\n if (issue.code !== \"unrecognized_keys\") {\n return;\n }\n const moved = issue.keys.filter((key) => MOVED_TO_PROVIDER.has(key));\n if (moved.length === 0) {\n return;\n }\n const fields = moved.map((key) => `ai.ask.${key}`).join(\", \");\n const hint = `${fields} moved into the provider adapter: \\`provider: ${providerFactory(issue)}({ ${moved.join(\", \")} })\\`, imported from \"blume/ai\".`;\n const others = issue.keys.filter((key) => !MOVED_TO_PROVIDER.has(key));\n return others.length > 0\n ? `${hint} ${unrecognizedKeysMessage(others)}`\n : hint;\n },\n};\n\n/** A value that is a 1.x provider name, for the `ai.ask.provider` hint. */\nconst providerNameProbe = z.string();\n\n/**\n * The message for an `ai.ask.provider` that isn't a descriptor: a 1.x\n * provider name names the factory that replaced it; anything else lists them.\n */\nconst providerNotAdapterMessage = (issue: z.core.$ZodRawIssue): string => {\n const name = providerNameProbe.safeParse(issue.input);\n const factory = name.success ? FACTORY_BY_PROVIDER.get(name.data) : undefined;\n return factory\n ? `ai.ask.provider takes an adapter from \"blume/ai\", not a provider name: \\`provider: ${factory}({ model })\\`. The 1.x model, apiKeyEnv, baseUrl, headers, and reasoning fields move into the call.`\n : 'ai.ask.provider takes an adapter from \"blume/ai\": gateway(), openrouter(), llmgateway(), inkeep(), or openaiCompatible().';\n};\n\n/**\n * `ai.ask.provider`: the descriptor an adapter factory returned, validated\n * against that adapter's own option schema. A value that isn't a descriptor\n * at all (a 1.x provider name) names the factory that replaced it.\n */\nexport const askAdapterSchema = z.discriminatedUnion(\n \"kind\",\n [\n gatewayAdapterSchema,\n openrouterAdapterSchema,\n llmgatewayAdapterSchema,\n inkeepAdapterSchema,\n openaiCompatibleAdapterSchema,\n ],\n {\n // A non-object (a 1.x provider name) fails before any discriminator is\n // read — `invalid_type` at runtime, though Zod types the union's own\n // issues as `invalid_union` only; a bad `kind` keeps Zod's message.\n error: (issue) =>\n issue.code === \"invalid_union\"\n ? undefined\n : providerNotAdapterMessage(issue),\n }\n);\n\n/** A resolved (post-defaults) `ai.ask.provider` descriptor. */\nexport type AskAdapterConfig = z.output<typeof askAdapterSchema>;\nexport type AskAdapterKind = AskAdapterConfig[\"kind\"];\n\n/** The provider when `ai.ask.provider` is unset: the gateway with its defaults. */\nexport const DEFAULT_ASK_PROVIDER: AskAdapter = gateway();\n\n// ---------------------------------------------------------------------------\n// Resolved backend\n// ---------------------------------------------------------------------------\n\n/** The route fragments an adapter contributes to `askEndpointTemplate`. */\nexport interface AskBackendTemplate {\n /**\n * Extra `streamText` fields as `key: value` source lines: the adapter's\n * reasoning mapping (when it is a call option) and `providerOptions`.\n */\n fields: string[];\n /** Import lines after the shared `astro` and `astro:env/server` ones. */\n imports: string[];\n /**\n * The up-front credential guard: a statement that returns a 503, since the\n * endpoint exists but can't answer until the deployment sets its key.\n */\n keyCheck: string;\n /** The `model:` expression passed to `streamText`. */\n model: string;\n /** Module-level provider setup (the provider factory call). */\n setup: string;\n}\n\n/**\n * What the endpoint template and the diagnostics read from an adapter beyond\n * the descriptor itself (`kind`, `requiredSecrets`, `runtimeDeps` travel on\n * the descriptor; `generate`, `eject`, the required-secrets check, and the\n * runtime-dependency manifest read those directly).\n */\nexport interface AskBackend {\n /** Whether Blume grounds answers in the docs (Inkeep retrieves itself). */\n grounded: boolean;\n kind: AskAdapterKind;\n /** Human-readable adapter name for diagnostics (\"AI Gateway\"). */\n label: string;\n /** Appended to the missing-secret warning (an alternative credential, say). */\n secretNote?: string;\n template: AskBackendTemplate;\n}\n\nconst secretExpr = (env: string): string => `getSecret(${JSON.stringify(env)})`;\n\n/**\n * The `headers` line of a provider factory call. Every provider Blume\n * generates against takes the same option; the OpenAI-compatible provider\n * applies it after the `Authorization` header it derives from the API key, so\n * a custom header can't displace auth. An empty map is dropped so the route\n * only carries `headers` when there is something to send.\n */\nconst headersLine = (headers?: Record<string, string>): string =>\n headers && Object.keys(headers).length > 0\n ? `\\n headers: ${JSON.stringify(headers)},`\n : \"\";\n\n/** Refuse a request up front when the adapter's key env var is unset. */\nconst keyCheck = (env: string): string => ` if (!${secretExpr(env)}) {\n return new Response(\n ${JSON.stringify(`Ask AI is not configured: set ${env}.`)},\n { status: 503 }\n );\n }`;\n\n/**\n * The `streamText` fields shared by the adapters that take `reasoning` as the\n * AI SDK's top-level call option, plus the verbatim `providerOptions`.\n */\nconst callFields = (options: {\n providerOptions?: z.output<typeof providerOptionsSchema>;\n reasoning?: AskReasoning;\n}): string[] => {\n const fields: string[] = [];\n if (options.reasoning) {\n fields.push(`reasoning: ${JSON.stringify(options.reasoning)}`);\n }\n if (options.providerOptions) {\n fields.push(`providerOptions: ${JSON.stringify(options.providerOptions)}`);\n }\n return fields;\n};\n\nconst gatewayBackend = (\n options: z.output<typeof gatewayOptionsSchema>\n): AskBackend => ({\n grounded: true,\n kind: \"gateway\",\n label: \"AI Gateway\",\n secretNote: \"on Vercel the gateway can also authenticate via OIDC\",\n template: {\n // The gateway maps the AI SDK's top-level `reasoning` to the model's own\n // control (OpenAI's `reasoning_effort`, say).\n fields: callFields(options),\n // The gateway provider reads the key (or Vercel's OIDC token) from the\n // environment itself; passing the key explicitly lets a binding-backed\n // secret store reach it too.\n imports: [\n 'import { createGateway, createTextStreamResponse, streamText, toTextStream } from \"ai\";',\n ],\n keyCheck: ` // The AI Gateway authenticates with an API key or Vercel's OIDC token.\n if (!(${secretExpr(options.apiKeyEnv)} || getSecret(\"VERCEL_OIDC_TOKEN\"))) {\n return new Response(\n ${JSON.stringify(`Ask AI is not configured: set ${options.apiKeyEnv} (or deploy on Vercel with OIDC).`)},\n { status: 503 }\n );\n }`,\n model: `gateway(${JSON.stringify(options.model)})`,\n setup: `\\nconst gateway = createGateway({\n apiKey: ${secretExpr(options.apiKeyEnv)},${headersLine(options.headers)}\n});\\n`,\n },\n});\n\nconst openrouterBackend = (\n options: z.output<typeof openrouterOptionsSchema>\n): AskBackend => {\n // The OpenRouter provider ignores the AI SDK's top-level `reasoning` call\n // option and only reads its own model-level setting, so the level rides on\n // the model as `reasoning.effort` and nowhere else.\n const settings = options.reasoning\n ? `, { reasoning: { effort: ${JSON.stringify(options.reasoning)} } }`\n : \"\";\n return {\n grounded: true,\n kind: \"openrouter\",\n label: \"OpenRouter\",\n template: {\n fields: callFields({ providerOptions: options.providerOptions }),\n imports: [\n 'import { createTextStreamResponse, streamText, toTextStream } from \"ai\";',\n 'import { createOpenRouter } from \"@openrouter/ai-sdk-provider\";',\n ],\n keyCheck: keyCheck(options.apiKeyEnv),\n model: `openrouter(${JSON.stringify(options.model)}${settings})`,\n setup: `\\nconst openrouter = createOpenRouter({\n apiKey: ${secretExpr(options.apiKeyEnv)},${headersLine(options.headers)}\n});\\n`,\n },\n };\n};\n\n/**\n * The backend shared by the adapters that stream through the AI SDK's\n * OpenAI-compatible provider, which sends the top-level `reasoning` call\n * option as `reasoning_effort`.\n */\nconst openaiCompatibleBackend = (\n kind: AskAdapterKind,\n label: string,\n grounded: boolean,\n options: {\n apiKeyEnv: string;\n baseUrl: string;\n headers?: Record<string, string>;\n model: string;\n name: string;\n providerOptions?: z.output<typeof providerOptionsSchema>;\n reasoning?: AskReasoning;\n }\n): AskBackend => ({\n grounded,\n kind,\n label,\n template: {\n fields: callFields(options),\n imports: [\n 'import { createTextStreamResponse, streamText, toTextStream } from \"ai\";',\n 'import { createOpenAICompatible } from \"@ai-sdk/openai-compatible\";',\n ],\n keyCheck: keyCheck(options.apiKeyEnv),\n model: `provider(${JSON.stringify(options.model)})`,\n // `headers` sits between the key and the name so the API key's\n // `Authorization` header is applied first.\n setup: `\\nconst provider = createOpenAICompatible({\n apiKey: ${secretExpr(options.apiKeyEnv)},\n baseURL: ${JSON.stringify(options.baseUrl)},${headersLine(options.headers)}\n name: ${JSON.stringify(options.name)},\n});\\n`,\n },\n});\n\n/** Resolve a parsed `ai.ask.provider` descriptor into its backend. */\nexport const resolveAskBackend = (\n provider: AskAdapterConfig = askAdapterSchema.parse(DEFAULT_ASK_PROVIDER)\n): AskBackend => {\n switch (provider.kind) {\n case \"gateway\": {\n return gatewayBackend(provider.options);\n }\n case \"openrouter\": {\n return openrouterBackend(provider.options);\n }\n case \"llmgateway\": {\n return openaiCompatibleBackend(\"llmgateway\", \"LLMGateway\", true, {\n ...provider.options,\n name: \"llmgateway\",\n });\n }\n case \"inkeep\": {\n // Inkeep answers from the content indexed in its dashboard, so injected\n // excerpts would conflict with its own retrieval.\n return openaiCompatibleBackend(\"inkeep\", \"Inkeep\", false, {\n ...provider.options,\n name: \"inkeep\",\n });\n }\n default: {\n return openaiCompatibleBackend(\n \"openai-compatible\",\n \"OpenAI-compatible\",\n true,\n provider.options\n );\n }\n }\n};\n",
|
|
58
|
+
"/**\n * Zod's own wording for unknown keys no removed-key hint covers, appended to\n * a hint so an unrelated typo isn't silently dropped from the diagnostic\n * beside it. Shared by every config object that names a removed field's\n * replacement (the root config, `ai.ask`, `openapi()`/`asyncapi()`, …).\n */\nexport const unrecognizedKeysMessage = (keys: string[]): string =>\n `Unrecognized key${keys.length > 1 ? \"s\" : \"\"}: ${keys\n .map((key) => JSON.stringify(key))\n .join(\", \")}`;\n",
|
|
59
|
+
"import { z } from \"zod\";\n\nimport { adobeAdapterSchema } from \"./adobe.ts\";\nimport { amplitudeAdapterSchema } from \"./amplitude.ts\";\nimport { clarityAdapterSchema } from \"./clarity.ts\";\nimport { clearbitAdapterSchema } from \"./clearbit.ts\";\nimport { cloudflareAdapterSchema } from \"./cloudflare.ts\";\nimport { fathomAdapterSchema } from \"./fathom.ts\";\nimport { googleAnalyticsAdapterSchema } from \"./google-analytics.ts\";\nimport { googleTagManagerAdapterSchema } from \"./google-tag-manager.ts\";\nimport { heapAdapterSchema } from \"./heap.ts\";\nimport { hightouchAdapterSchema } from \"./hightouch.ts\";\nimport { hotjarAdapterSchema } from \"./hotjar.ts\";\nimport { logrocketAdapterSchema } from \"./logrocket.ts\";\nimport { mixpanelAdapterSchema } from \"./mixpanel.ts\";\nimport { pirschAdapterSchema } from \"./pirsch.ts\";\nimport { plausibleAdapterSchema } from \"./plausible.ts\";\nimport { posthogAdapterSchema } from \"./posthog.ts\";\nimport { scriptAdapterSchema } from \"./script.ts\";\nimport { segmentAdapterSchema } from \"./segment.ts\";\nimport { vercelAdapterSchema } from \"./vercel.ts\";\n\n/** One configured analytics adapter, as its factory returned it. */\nexport const analyticsAdapterSchema = z.discriminatedUnion(\"kind\", [\n adobeAdapterSchema,\n amplitudeAdapterSchema,\n clarityAdapterSchema,\n clearbitAdapterSchema,\n cloudflareAdapterSchema,\n fathomAdapterSchema,\n googleAnalyticsAdapterSchema,\n googleTagManagerAdapterSchema,\n heapAdapterSchema,\n hightouchAdapterSchema,\n hotjarAdapterSchema,\n logrocketAdapterSchema,\n mixpanelAdapterSchema,\n pirschAdapterSchema,\n plausibleAdapterSchema,\n posthogAdapterSchema,\n scriptAdapterSchema,\n segmentAdapterSchema,\n vercelAdapterSchema,\n]);\n\nexport type AnalyticsAdapter = z.output<typeof analyticsAdapterSchema>;\n\nconst ARRAY_HINT =\n 'analytics is a list of adapters — e.g. `analytics: [posthog({ key }), vercel(), plausible({ domain }), script({ src })]`, imported from \"blume/analytics\".';\n\n/**\n * `blume.config.analytics`: the adapters to emit, in order. Unset means none.\n * A non-array (the pre-adapter object form, say) fails with the list hint;\n * element errors keep their own messages.\n */\nexport const analyticsConfigSchema = z\n .array(analyticsAdapterSchema, {\n error: (issue) => (issue.code === \"invalid_type\" ? ARRAY_HINT : undefined),\n })\n .default([]);\n",
|
|
60
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** Options for {@link adobe}. */\nexport interface AdobeOptions {\n /**\n * The Launch (Adobe Experience Platform Tags) embed script URL for the\n * environment to load, e.g. `https://assets.adobedtm.com/…/launch-….min.js`.\n */\n url: string;\n}\n\nexport const adobeOptionsSchema = z.strictObject({\n url: z.string().min(1),\n});\n\nexport type AdobeAdapter = AdapterDescriptor<\"adobe\", AdobeOptions>;\n\nexport const adobeAdapterSchema = adapterDescriptorSchema(\n \"adobe\",\n adobeOptionsSchema\n);\n\n/**\n * Adobe Analytics through a Launch property: Blume loads the environment's\n * embed script, and the property's own rules decide what to track. Copy the\n * URL from the environment's install instructions in Data Collection.\n */\nexport const adobe = (options: AdobeOptions): AdobeAdapter => ({\n kind: \"adobe\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The async embed tag, as Launch's install instructions render it. Pageviews\n * on client-router navigations are the property's business: give it a rule on\n * history changes (or `_satellite.track` from a `script()` adapter).\n */\nexport const adobeHead = (options: AdobeOptions): HeadScript[] => [\n { attributes: { async: true, src: options.url }, content: null },\n];\n",
|
|
61
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** The options {@link amplitude} maps itself. */\nexport interface AmplitudeNamedOptions {\n /** Project API key. */\n key: string;\n}\n\n/**\n * Options for {@link amplitude}: the key plus any other Browser SDK\n * `amplitude.init` option, forwarded verbatim (`serverZone`, `autocapture`,\n * `defaultTracking`, …). JSON values only.\n */\nexport type AmplitudeOptions = AmplitudeNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const amplitudeOptionsSchema = z\n .object({\n key: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type AmplitudeAdapter = AdapterDescriptor<\"amplitude\", AmplitudeOptions>;\n\nexport const amplitudeAdapterSchema = adapterDescriptorSchema(\n \"amplitude\",\n amplitudeOptionsSchema\n);\n\n/**\n * Amplitude product analytics through the Browser SDK's script loader. The\n * project API key is public — it's what every browser event carries.\n */\nexport const amplitude = (options: AmplitudeOptions): AmplitudeAdapter => ({\n kind: \"amplitude\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/** The script loader's CDN; the key picks the bundle. */\nexport const AMPLITUDE_SCRIPT_ORIGIN = \"https://cdn.amplitude.com/script/\";\n\n/**\n * The init options the dashboard snippet ships with. `autocapture` covers page\n * views, sessions, and history changes, so client-router navigations count\n * without any extra hook; a passthrough option overrides either.\n */\nexport const AMPLITUDE_DEFAULT_INIT = {\n autocapture: true,\n fetchRemoteConfig: true,\n};\n\n/**\n * The two tags from the dashboard's install snippet: the keyed SDK bundle\n * (synchronous, so `window.amplitude` exists for the next tag) and the init\n * call, with `key` mapped and everything else forwarded to `init` verbatim.\n */\nexport const amplitudeHead = (options: AmplitudeOptions): HeadScript[] => {\n const { key, ...init } = options;\n return [\n {\n attributes: {\n src: `${AMPLITUDE_SCRIPT_ORIGIN}${encodeURIComponent(key)}.js`,\n },\n content: null,\n },\n {\n attributes: {},\n content: `window.amplitude.init(${inlineJson(key)},${inlineJson({ ...AMPLITUDE_DEFAULT_INIT, ...init })});`,\n },\n ];\n};\n",
|
|
62
|
+
"import type { JsonValue } from \"../core/adapter.ts\";\n\n/**\n * JSON for an inline `<script>` body. `JSON.stringify` leaves `<` alone, so a\n * value like `</script>` would end the script element early; escape it the way\n * the layouts do for their JSON.\n */\nexport const inlineJson = (value: JsonValue): string =>\n JSON.stringify(value).replaceAll(\"<\", \"\\\\u003c\");\n\n/**\n * A snippet that re-sends a pageview on every client-router navigation, for a\n * provider whose loader only counts real page loads. Keyed off\n * `astro:page-load` with a path-plus-query guard held in `window[slot]`, so the\n * initial load (which the loader already counted) and same-page hash moves\n * aren't double-counted, while a query-only navigation (`?tab=a` → `?tab=b`)\n * still is. Each adapter passes its own slot: two adapters sharing one would\n * see the second always match the first's update and never fire.\n */\nexport const spaPageviews = (slot: string, capture: string): string =>\n `document.addEventListener(\"astro:page-load\",function(){var p=window.${slot},c=location.pathname+location.search;window.${slot}=c;if(p!==undefined&&p!==c){${capture}}});`;\n",
|
|
63
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** Options for {@link clarity}. */\nexport interface ClarityOptions {\n /** Project ID, from the project's tracking code in the Clarity dashboard. */\n id: string;\n}\n\nexport const clarityOptionsSchema = z.strictObject({\n id: z.string().min(1),\n});\n\nexport type ClarityAdapter = AdapterDescriptor<\"clarity\", ClarityOptions>;\n\nexport const clarityAdapterSchema = adapterDescriptorSchema(\n \"clarity\",\n clarityOptionsSchema\n);\n\n/**\n * Microsoft Clarity session recordings and heatmaps. The project ID is public;\n * it only picks the project the tag reports to.\n */\nexport const clarity = (options: ClarityOptions): ClarityAdapter => ({\n kind: \"clarity\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The dashboard's tracking code: a `window.clarity` queue and the async tag\n * load. Clarity follows history changes itself, so client-router navigations\n * need no extra hook.\n */\nexport const clarityHead = (options: ClarityOptions): HeadScript[] => [\n {\n attributes: {},\n content: `(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};t=l.createElement(r);t.async=1;t.src=\"https://www.clarity.ms/tag/\"+i;y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);})(window,document,\"clarity\",\"script\",${inlineJson(encodeURIComponent(options.id))});`,\n },\n];\n",
|
|
64
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** Options for {@link clearbit}. */\nexport interface ClearbitOptions {\n /** Publishable API key (`pk_…`). */\n key: string;\n}\n\nexport const clearbitOptionsSchema = z.strictObject({\n key: z.string().min(1),\n});\n\nexport type ClearbitAdapter = AdapterDescriptor<\"clearbit\", ClearbitOptions>;\n\nexport const clearbitAdapterSchema = adapterDescriptorSchema(\n \"clearbit\",\n clearbitOptionsSchema\n);\n\n/**\n * Clearbit's website tag (Reveal and the Clearbit tags it manages). The\n * publishable key is meant for the browser.\n */\nexport const clearbit = (options: ClearbitOptions): ClearbitAdapter => ({\n kind: \"clearbit\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/** The tag origin; the key picks the tags bundle. */\nexport const CLEARBIT_TAG_ORIGIN = \"https://tag.clearbitscripts.com/v1/\";\n\n/** The tag as Clearbit's install snippet renders it. */\nexport const clearbitHead = (options: ClearbitOptions): HeadScript[] => [\n {\n attributes: {\n referrerpolicy: \"strict-origin-when-cross-origin\",\n src: `${CLEARBIT_TAG_ORIGIN}${encodeURIComponent(options.key)}/tags.js`,\n },\n content: null,\n },\n];\n",
|
|
65
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** The beacon script Cloudflare's dashboard snippet loads. */\nexport const CLOUDFLARE_BEACON_SRC =\n \"https://static.cloudflareinsights.com/beacon.min.js\";\n\n/** The options {@link cloudflare} maps itself. */\nexport interface CloudflareNamedOptions {\n /** Site token from the Web Analytics JS snippet (`data-cf-beacon`). */\n token: string;\n}\n\n/**\n * Options for {@link cloudflare}: the token plus any other `data-cf-beacon`\n * setting, forwarded verbatim (`spa`, …). JSON values only.\n */\nexport type CloudflareOptions = CloudflareNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const cloudflareOptionsSchema = z\n .object({\n token: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type CloudflareAdapter = AdapterDescriptor<\n \"cloudflare\",\n CloudflareOptions\n>;\n\nexport const cloudflareAdapterSchema = adapterDescriptorSchema(\n \"cloudflare\",\n cloudflareOptionsSchema\n);\n\n/**\n * Cloudflare Web Analytics in manual (JS snippet) mode, for a site Cloudflare\n * doesn't proxy. A proxied zone with automatic RUM injection on needs no\n * adapter at all — listing one there would count every pageview twice.\n */\nexport const cloudflare = (options: CloudflareOptions): CloudflareAdapter => ({\n kind: \"cloudflare\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The beacon tag exactly as the dashboard's snippet renders it, with the whole\n * option object as its `data-cf-beacon` JSON. The beacon tracks history\n * changes itself, so client-router navigations need no extra hook.\n */\nexport const cloudflareHead = (options: CloudflareOptions): HeadScript[] => [\n {\n attributes: {\n \"data-cf-beacon\": JSON.stringify(options),\n defer: true,\n src: CLOUDFLARE_BEACON_SRC,\n },\n content: null,\n },\n];\n",
|
|
66
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** The script Fathom's dashboard snippet loads. */\nexport const FATHOM_SCRIPT_SRC = \"https://cdn.usefathom.com/script.js\";\n\n/** The options {@link fathom} maps itself. */\nexport interface FathomNamedOptions {\n /** Site ID, from the site's script settings. */\n site: string;\n}\n\n/**\n * Options for {@link fathom}: the site ID plus any other script setting,\n * forwarded as a `data-` attribute on the tag (`spa` → `data-spa`,\n * `\"honor-dnt\"` → `data-honor-dnt`, `\"excluded-domains\"`, `canonical`, …).\n */\nexport type FathomOptions = FathomNamedOptions & {\n [setting: string]: string;\n};\n\nexport const fathomOptionsSchema = z\n .object({\n site: z.string().min(1),\n })\n .catchall(z.string());\n\nexport type FathomAdapter = AdapterDescriptor<\"fathom\", FathomOptions>;\n\nexport const fathomAdapterSchema = adapterDescriptorSchema(\n \"fathom\",\n fathomOptionsSchema\n);\n\n/**\n * Fathom Analytics. The site ID is public — it's in the tag on every page.\n */\nexport const fathom = (options: FathomOptions): FathomAdapter => ({\n kind: \"fathom\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The deferred tag from the dashboard, with `site` as `data-site` and every\n * other option as its own `data-` attribute. Fathom only tracks history\n * changes when the tag opts in, so `spa` defaults to `\"auto\"` — Blume's\n * client router navigates without full loads — and an explicit `spa` wins.\n */\nexport const fathomHead = (options: FathomOptions): HeadScript[] => {\n const { site, ...settings } = { spa: \"auto\", ...options };\n const attributes: HeadScript[\"attributes\"] = {};\n for (const [setting, value] of Object.entries(settings)) {\n attributes[`data-${setting}`] = value;\n }\n attributes[\"data-site\"] = site;\n attributes.defer = true;\n attributes.src = FATHOM_SCRIPT_SRC;\n return [{ attributes, content: null }];\n};\n",
|
|
67
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** The options {@link googleAnalytics} maps itself. */\nexport interface GoogleAnalyticsNamedOptions {\n /** Measurement ID of the GA4 web data stream (`G-…`). */\n id: string;\n}\n\n/**\n * Options for {@link googleAnalytics}: the measurement ID plus any other\n * `gtag('config', …)` parameter, forwarded verbatim (`send_page_view`,\n * `anonymize_ip`, `cookie_domain`, `debug_mode`, …). JSON values only.\n */\nexport type GoogleAnalyticsOptions = GoogleAnalyticsNamedOptions & {\n [parameter: string]: JsonValue;\n};\n\nexport const googleAnalyticsOptionsSchema = z\n .object({\n id: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type GoogleAnalyticsAdapter = AdapterDescriptor<\n \"google-analytics\",\n GoogleAnalyticsOptions\n>;\n\nexport const googleAnalyticsAdapterSchema = adapterDescriptorSchema(\n \"google-analytics\",\n googleAnalyticsOptionsSchema\n);\n\n/**\n * Google Analytics 4 through the Google tag (`gtag.js`). The measurement ID is\n * public; it names the data stream the tag reports to.\n */\nexport const googleAnalytics = (\n options: GoogleAnalyticsOptions\n): GoogleAnalyticsAdapter => ({\n kind: \"google-analytics\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/** The Google tag loader; the measurement ID travels in its query string. */\nexport const GOOGLE_TAG_SRC = \"https://www.googletagmanager.com/gtag/js\";\n\n/**\n * The two tags from the data stream's install instructions: the async loader\n * and the `dataLayer` bootstrap with the `config` call. Extra options ride on\n * the `config` call, and it is emitted bare when there are none, exactly as\n * the instructions print it. GA4's enhanced measurement counts history\n * changes as page views by default, so client-router navigations need no\n * extra hook here.\n */\nexport const googleAnalyticsHead = (\n options: GoogleAnalyticsOptions\n): HeadScript[] => {\n const { id, ...parameters } = options;\n const config =\n Object.keys(parameters).length === 0\n ? `gtag(\"config\",${inlineJson(id)});`\n : `gtag(\"config\",${inlineJson(id)},${inlineJson(parameters)});`;\n return [\n {\n attributes: {\n async: true,\n src: `${GOOGLE_TAG_SRC}?id=${encodeURIComponent(id)}`,\n },\n content: null,\n },\n {\n attributes: {},\n content: `window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag(\"js\",new Date());${config}`,\n },\n ];\n};\n",
|
|
68
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** Options for {@link googleTagManager}. */\nexport interface GoogleTagManagerOptions {\n /** Name of the data layer global the container reads. Defaults to `dataLayer`. */\n dataLayer?: string;\n /** Container ID (`GTM-…`). */\n id: string;\n}\n\nexport const googleTagManagerOptionsSchema = z.strictObject({\n dataLayer: z.string().min(1).optional(),\n id: z.string().min(1),\n});\n\nexport type GoogleTagManagerAdapter = AdapterDescriptor<\n \"google-tag-manager\",\n GoogleTagManagerOptions\n>;\n\nexport const googleTagManagerAdapterSchema = adapterDescriptorSchema(\n \"google-tag-manager\",\n googleTagManagerOptionsSchema\n);\n\n/**\n * Google Tag Manager. Blume loads the container; which tags fire, and on what,\n * is the container's configuration. The container ID is public.\n */\nexport const googleTagManager = (\n options: GoogleTagManagerOptions\n): GoogleTagManagerAdapter => ({\n kind: \"google-tag-manager\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The container snippet from the workspace's install instructions (the\n * `<head>` half; the `<noscript>` iframe is for browsers without JavaScript,\n * which never run analytics anyway). Client-router navigations reach the\n * container as history changes — fire pageview tags from a History Change\n * trigger rather than the page-load one. The snippet also keeps a reference\n * to its data layer on `window.__blumeGtmLayer`, so `track()` pushes custom\n * events into the layer this container reads rather than the default\n * `dataLayer`.\n */\nexport const googleTagManagerHead = (\n options: GoogleTagManagerOptions\n): HeadScript[] => [\n {\n attributes: {},\n content: `(function(w,d,s,l,i){w[l]=w[l]||[];w.__blumeGtmLayer=w[l];w[l].push({\"gtm.start\":new Date().getTime(),event:\"gtm.js\"});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!=\"dataLayer\"?\"&l=\"+l:\"\";j.async=true;j.src=\"https://www.googletagmanager.com/gtm.js?id=\"+i+dl;f.parentNode.insertBefore(j,f);})(window,document,\"script\",${inlineJson(options.dataLayer ?? \"dataLayer\")},${inlineJson(encodeURIComponent(options.id))});`,\n },\n];\n",
|
|
69
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** The options {@link heap} maps itself. */\nexport interface HeapNamedOptions {\n /** App ID (the environment ID), from the project's install settings. */\n id: string;\n}\n\n/**\n * Options for {@link heap}: the app ID plus any other `heap.load` config\n * option, forwarded verbatim (`disableTextCapture`, `secureCookie`, …). JSON\n * values only.\n */\nexport type HeapOptions = HeapNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const heapOptionsSchema = z\n .object({\n id: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type HeapAdapter = AdapterDescriptor<\"heap\", HeapOptions>;\n\nexport const heapAdapterSchema = adapterDescriptorSchema(\n \"heap\",\n heapOptionsSchema\n);\n\n/**\n * Heap autocapture analytics. The app ID is public — the tag carries it on\n * every page.\n */\nexport const heap = (options: HeapOptions): HeapAdapter => ({\n kind: \"heap\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n// The install snippet: a `window.heap` queue whose `load` injects the keyed\n// script and stubs the API until it arrives.\nconst HEAP_LOADER =\n 'window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=document.createElement(\"script\");r.type=\"text/javascript\",r.async=!0,r.src=\"https://cdn.heapanalytics.com/js/heap-\"+e+\".js\";var a=document.getElementsByTagName(\"script\")[0];a.parentNode.insertBefore(r,a);for(var n=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=[\"addEventProperties\",\"addUserProperties\",\"clearEventProperties\",\"identify\",\"resetIdentity\",\"removeEventProperty\",\"setEventProperties\",\"track\",\"unsetEventProperty\"],o=0;o<p.length;o++)heap[p[o]]=n(p[o])};';\n\n/**\n * The loader plus `heap.load` with `id` mapped and everything else forwarded\n * as the config object; the object is left off when there is nothing to pass,\n * as the install snippet prints it. Heap autocaptures history changes as\n * pageviews, so client-router navigations need no extra hook.\n */\nexport const heapHead = (options: HeapOptions): HeadScript[] => {\n const { id, ...config } = options;\n const load =\n Object.keys(config).length === 0\n ? `heap.load(${inlineJson(id)});`\n : `heap.load(${inlineJson(id)},${inlineJson(config)});`;\n return [{ attributes: {}, content: `${HEAP_LOADER}${load}` }];\n};\n",
|
|
70
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson, spaPageviews } from \"./inline.ts\";\n\n/** The events API host `hightouch()` uses when `host` is unset. */\nexport const HIGHTOUCH_DEFAULT_HOST = \"us-east-1.hightouch-events.com\";\n\n/** The options {@link hightouch} maps itself. */\nexport interface HightouchNamedOptions {\n /** Events API host, without a scheme. Defaults to the US East region. */\n host?: string;\n /** Write key of the event source. */\n key: string;\n}\n\n/**\n * Options for {@link hightouch}: the named options plus any other\n * `htevents.load` option, forwarded verbatim. JSON values only.\n */\nexport type HightouchOptions = HightouchNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const hightouchOptionsSchema = z\n .object({\n host: z.string().min(1).optional(),\n key: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type HightouchAdapter = AdapterDescriptor<\"hightouch\", HightouchOptions>;\n\nexport const hightouchAdapterSchema = adapterDescriptorSchema(\n \"hightouch\",\n hightouchOptionsSchema\n);\n\n/**\n * Hightouch Events. The write key is meant for the browser — it identifies\n * the event source the SDK reports to.\n */\nexport const hightouch = (options: HightouchOptions): HightouchAdapter => ({\n kind: \"hightouch\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n// The install snippet: a `window.htevents` queue whose `load` injects the SDK.\nconst HIGHTOUCH_LOADER =\n '!function(){var e=window.htevents=window.htevents||[];if(!e.initialize)if(e.invoked)window.console&&console.error&&console.error(\"Hightouch snippet included twice.\");else{e.invoked=!0,e.methods=[\"trackSubmit\",\"trackClick\",\"trackLink\",\"trackForm\",\"pageview\",\"identify\",\"reset\",\"group\",\"track\",\"ready\",\"alias\",\"debug\",\"page\",\"once\",\"off\",\"on\",\"addSourceMiddleware\",\"addIntegrationMiddleware\",\"setAnonymousId\",\"addDestinationMiddleware\"],e.factory=function(t){return function(){var r=Array.prototype.slice.call(arguments);return r.unshift(t),e.push(r),e}};for(var t=0;t<e.methods.length;t++){var r=e.methods[t];e[r]=e.factory(r)}e.load=function(t,r){var n=document.createElement(\"script\");n.type=\"text/javascript\",n.async=!0,n.src=\"https://cdn.hightouch-events.com/browser/release/v1-latest/events.min.js\";var o=document.getElementsByTagName(\"script\")[0];o.parentNode.insertBefore(n,o),e._loadOptions=r,e._writeKey=t},e.SNIPPET_VERSION=\"0.0.1\",';\n\n// The SDK sends one `page()` per real page load (the snippet's own call), so\n// client-router swaps are sent here.\nconst HIGHTOUCH_SPA_PAGEVIEWS = spaPageviews(\n \"__blumeHightouchPath\",\n \"htevents.page();\"\n);\n\n/**\n * The loader with `key` mapped to the write key and `host` to `apiHost`;\n * everything else lands in the load options verbatim, after the mapped host\n * so a raw `apiHost` still wins.\n */\nexport const hightouchHead = (options: HightouchOptions): HeadScript[] => {\n const { host, key, ...load } = options;\n const loadOptions = { apiHost: host ?? HIGHTOUCH_DEFAULT_HOST, ...load };\n return [\n {\n attributes: {},\n content: `${HIGHTOUCH_LOADER}e.load(${inlineJson(key)},${inlineJson(loadOptions)}),e.page()}}();${HIGHTOUCH_SPA_PAGEVIEWS}`,\n },\n ];\n};\n",
|
|
71
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** The tracking-code version (`hjsv`) `hotjar()` uses when `version` is unset. */\nexport const HOTJAR_DEFAULT_VERSION = 6;\n\n/** Options for {@link hotjar}. */\nexport interface HotjarOptions {\n /** Site ID (`hjid`), from the site's tracking code. */\n id: number;\n /** Tracking-code version (`hjsv`). Defaults to the current one. */\n version?: number;\n}\n\nexport const hotjarOptionsSchema = z.strictObject({\n id: z.number().int().positive(),\n version: z.number().int().positive().optional(),\n});\n\nexport type HotjarAdapter = AdapterDescriptor<\"hotjar\", HotjarOptions>;\n\nexport const hotjarAdapterSchema = adapterDescriptorSchema(\n \"hotjar\",\n hotjarOptionsSchema\n);\n\n/**\n * Hotjar heatmaps and recordings. The site ID is public — it's in the tracking\n * code on every page.\n */\nexport const hotjar = (options: HotjarOptions): HotjarAdapter => ({\n kind: \"hotjar\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/** The tracking code as the site's install instructions render it. */\nexport const hotjarHead = (options: HotjarOptions): HeadScript[] => [\n {\n attributes: {},\n content: `(function(h,o,t,j,a,r){h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};h._hjSettings={hjid:${options.id},hjsv:${options.version ?? HOTJAR_DEFAULT_VERSION}};a=o.getElementsByTagName(\"head\")[0];r=o.createElement(\"script\");r.async=1;r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;a.appendChild(r);})(window,document,\"https://static.hotjar.com/c/hotjar-\",\".js?sv=\");`,\n },\n];\n",
|
|
72
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** The SDK script LogRocket's install snippet loads. */\nexport const LOGROCKET_SCRIPT_SRC = \"https://cdn.logrocket.io/LogRocket.min.js\";\n\n/** The options {@link logrocket} maps itself. */\nexport interface LogrocketNamedOptions {\n /** App ID (`org/app`), from the project's settings. */\n id: string;\n}\n\n/**\n * Options for {@link logrocket}: the app ID plus any other `LogRocket.init`\n * option, forwarded verbatim (`release`, `console`, `network`, `dom`, …). JSON\n * values only; a sanitizer function can't travel through config — call\n * `LogRocket.init` yourself from a `script()` adapter for those.\n */\nexport type LogrocketOptions = LogrocketNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const logrocketOptionsSchema = z\n .object({\n id: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type LogrocketAdapter = AdapterDescriptor<\"logrocket\", LogrocketOptions>;\n\nexport const logrocketAdapterSchema = adapterDescriptorSchema(\n \"logrocket\",\n logrocketOptionsSchema\n);\n\n/**\n * LogRocket session replay. The app ID is public — it's what the SDK reports\n * under.\n */\nexport const logrocket = (options: LogrocketOptions): LogrocketAdapter => ({\n kind: \"logrocket\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The two tags from the install snippet: the SDK (synchronous, so\n * `window.LogRocket` exists for the next tag) and the guarded `init` call,\n * with `id` mapped and everything else forwarded to `init` verbatim; the\n * options object is left off when there is nothing to pass, as the snippet\n * prints it. A session spans client-router navigations on its own.\n */\nexport const logrocketHead = (options: LogrocketOptions): HeadScript[] => {\n const { id, ...init } = options;\n const call =\n Object.keys(init).length === 0\n ? `window.LogRocket.init(${inlineJson(id)})`\n : `window.LogRocket.init(${inlineJson(id)},${inlineJson(init)})`;\n return [\n {\n attributes: { crossorigin: \"anonymous\", src: LOGROCKET_SCRIPT_SRC },\n content: null,\n },\n { attributes: {}, content: `window.LogRocket&&${call};` },\n ];\n};\n",
|
|
73
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson } from \"./inline.ts\";\n\n/** Mixpanel's data residency regions and the ingestion host each one uses. */\nexport const MIXPANEL_REGION_HOSTS = {\n eu: \"https://api-eu.mixpanel.com\",\n in: \"https://api-in.mixpanel.com\",\n us: \"https://api.mixpanel.com\",\n} as const;\n\nexport type MixpanelRegion = keyof typeof MIXPANEL_REGION_HOSTS;\n\n/** The options {@link mixpanel} maps itself. */\nexport interface MixpanelNamedOptions {\n /** Data residency region of the project. Defaults to US. */\n region?: MixpanelRegion;\n /** Project token. */\n token: string;\n}\n\n/**\n * Options for {@link mixpanel}: the named options plus any other\n * `mixpanel.init` option, forwarded verbatim (`persistence`, `autocapture`,\n * `record_sessions_percent`, `debug`, …). JSON values only.\n */\nexport type MixpanelOptions = MixpanelNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const mixpanelOptionsSchema = z\n .object({\n region: z.enum([\"us\", \"eu\", \"in\"]).optional(),\n token: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type MixpanelAdapter = AdapterDescriptor<\"mixpanel\", MixpanelOptions>;\n\nexport const mixpanelAdapterSchema = adapterDescriptorSchema(\n \"mixpanel\",\n mixpanelOptionsSchema\n);\n\n/**\n * Mixpanel product analytics. The project token is public — it's what every\n * browser event carries.\n */\nexport const mixpanel = (options: MixpanelOptions): MixpanelAdapter => ({\n kind: \"mixpanel\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n// The official loader snippet: a `window.mixpanel` stub that queues calls and\n// injects the library.\nconst MIXPANEL_LOADER =\n '(function(f,b){if(!b.__SV){var e,g,i,h;window.mixpanel=b;b._i=[];b.init=function(e,f,c){function g(a,d){var b=d.split(\".\");2==b.length&&(a=a[b[0]],d=b[1]);a[d]=function(){a.push([d].concat(Array.prototype.slice.call(arguments,0)))}}var a=b;\"undefined\"!==typeof c?a=b[c]=[]:c=\"mixpanel\";a.people=a.people||[];a.toString=function(a){var d=\"mixpanel\";\"mixpanel\"!==c&&(d+=\".\"+c);a||(d+=\" (stub)\");return d};a.people.toString=function(){return a.toString(1)+\".people (stub)\"};i=\"disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking start_batch_senders people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove\".split(\" \");for(h=0;h<i.length;h++)g(a,i[h]);var j=\"set set_once union unset remove delete\".split(\" \");a.get_group=function(){function b(c){d[c]=function(){call2_args=arguments;call2=[c].concat(Array.prototype.slice.call(call2_args,0));a.push([e,call2])}}for(var d={},e=[\"get_group\"].concat(Array.prototype.slice.call(arguments,0)),c=0;c<j.length;c++)b(j[c]);return d};b._i.push([e,f,c])};b.__SV=1.2;e=f.createElement(\"script\");e.type=\"text/javascript\";e.async=!0;e.src=\"undefined\"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:\"file:\"===f.location.protocol&&\"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js\".match(/^\\\\/\\\\//)?\"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js\":\"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js\";g=f.getElementsByTagName(\"script\")[0];g.parentNode.insertBefore(e,g)}})(document,window.mixpanel||[]);';\n\n/**\n * The init options `mixpanel()` starts from. The library counts one pageview\n * per real page load with `track_pageview: true`; this mode has it track each\n * path-or-query change too, so client-router navigations count without any\n * extra hook. A passthrough option overrides it.\n */\nexport const MIXPANEL_DEFAULT_INIT = {\n track_pageview: \"url-with-path-and-query-string\",\n};\n\n/**\n * The loader plus `mixpanel.init` with `token` mapped and `region` mapped to\n * `api_host` (the US host when unset); everything else lands in the init\n * options verbatim, after the mapped host so a raw `api_host` still wins.\n */\nexport const mixpanelHead = (options: MixpanelOptions): HeadScript[] => {\n const { region, token, ...init } = options;\n const initOptions = {\n ...MIXPANEL_DEFAULT_INIT,\n api_host: MIXPANEL_REGION_HOSTS[region ?? \"us\"],\n ...init,\n };\n return [\n {\n attributes: {},\n content: `${MIXPANEL_LOADER}mixpanel.init(${inlineJson(token)},${inlineJson(initOptions)});`,\n },\n ];\n};\n",
|
|
74
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** The script Pirsch's dashboard snippet loads. */\nexport const PIRSCH_SCRIPT_SRC = \"https://api.pirsch.io/pa.js\";\n\n/** The options {@link pirsch} maps itself. */\nexport interface PirschNamedOptions {\n /** Identification code, from Settings → Developer → Identification Code. */\n code: string;\n}\n\n/**\n * Options for {@link pirsch}: the identification code plus any other script\n * setting, forwarded as a `data-` attribute on the tag (`dev` → `data-dev`,\n * `exclude`, `include`, `domain`, `endpoint`, …).\n */\nexport type PirschOptions = PirschNamedOptions & {\n [setting: string]: string;\n};\n\nexport const pirschOptionsSchema = z\n .object({\n code: z.string().min(1),\n })\n .catchall(z.string());\n\nexport type PirschAdapter = AdapterDescriptor<\"pirsch\", PirschOptions>;\n\nexport const pirschAdapterSchema = adapterDescriptorSchema(\n \"pirsch\",\n pirschOptionsSchema\n);\n\n/**\n * Pirsch Analytics. The identification code is public — it's in the tag on\n * every page.\n */\nexport const pirsch = (options: PirschOptions): PirschAdapter => ({\n kind: \"pirsch\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The deferred tag from the dashboard, with `code` as `data-code`, every other\n * option as its own `data-` attribute, and the `pianjs` id the script finds\n * itself by. Pirsch's script tracks history changes on its own, so\n * client-router navigations need no extra hook.\n */\nexport const pirschHead = (options: PirschOptions): HeadScript[] => {\n const { code, ...settings } = options;\n const attributes: HeadScript[\"attributes\"] = {};\n for (const [setting, value] of Object.entries(settings)) {\n attributes[`data-${setting}`] = value;\n }\n attributes[\"data-code\"] = code;\n attributes.defer = true;\n attributes.id = \"pianjs\";\n attributes.src = PIRSCH_SCRIPT_SRC;\n return [{ attributes, content: null }];\n};\n",
|
|
75
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** Plausible Cloud, the origin `plausible()` loads the script from when `host` is unset. */\nexport const PLAUSIBLE_DEFAULT_HOST = \"https://plausible.io\";\n\n/** The options {@link plausible} maps itself. */\nexport interface PlausibleNamedOptions {\n /** The site's domain as added in Plausible, e.g. `docs.example.com`. */\n domain: string;\n /**\n * Origin of a self-hosted (or proxied) Plausible instance, e.g.\n * `https://plausible.example.com`. Defaults to Plausible Cloud.\n */\n host?: string;\n}\n\n/**\n * Options for {@link plausible}: the named options plus any other script\n * setting, forwarded as a `data-` attribute on the tag (`api` → `data-api`,\n * `\"exclude\"`, `\"include\"`, …).\n */\nexport type PlausibleOptions = PlausibleNamedOptions & {\n [setting: string]: string;\n};\n\nexport const plausibleOptionsSchema = z\n .object({\n domain: z.string().min(1),\n host: z.string().min(1).optional(),\n })\n .catchall(z.string());\n\nexport type PlausibleAdapter = AdapterDescriptor<\"plausible\", PlausibleOptions>;\n\nexport const plausibleAdapterSchema = adapterDescriptorSchema(\n \"plausible\",\n plausibleOptionsSchema\n);\n\n/**\n * Plausible Analytics. Nothing here is secret: the tag names the site and\n * where to send events.\n */\nexport const plausible = (options: PlausibleOptions): PlausibleAdapter => ({\n kind: \"plausible\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/**\n * The queue stub from Plausible's custom-events guide: `plausible()` calls\n * made before the deferred script lands are buffered on `plausible.q` and\n * replayed once it loads, so an early `track()` isn't lost.\n */\nexport const PLAUSIBLE_QUEUE =\n \"window.plausible=window.plausible||function(){(window.plausible.q=window.plausible.q||[]).push(arguments)}\";\n\n/**\n * The deferred tag from the site's install instructions, with `domain` as\n * `data-domain`, `host` as the script origin, and every other option as its\n * own `data-` attribute, followed by the custom-event queue stub. Plausible's\n * script tracks history changes on its own, so client-router navigations\n * need no extra hook.\n */\nexport const plausibleHead = (options: PlausibleOptions): HeadScript[] => {\n const { domain, host, ...settings } = options;\n const attributes: HeadScript[\"attributes\"] = {};\n for (const [setting, value] of Object.entries(settings)) {\n attributes[`data-${setting}`] = value;\n }\n attributes[\"data-domain\"] = domain;\n attributes.defer = true;\n attributes.src = `${(host ?? PLAUSIBLE_DEFAULT_HOST).replace(/\\/+$/u, \"\")}/js/script.js`;\n return [\n { attributes, content: null },\n { attributes: {}, content: PLAUSIBLE_QUEUE },\n ];\n};\n",
|
|
76
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson, spaPageviews } from \"./inline.ts\";\n\n/** PostHog Cloud US, the ingestion host `posthog()` uses when `host` is unset. */\nexport const POSTHOG_DEFAULT_HOST = \"https://us.i.posthog.com\";\n\n/** The options {@link posthog} maps itself. */\nexport interface PosthogNamedOptions {\n /** API host (for self-hosted / EU). Defaults to PostHog Cloud US. */\n host?: string;\n /** Project API key. */\n key: string;\n}\n\n/**\n * Options for {@link posthog}: the named options plus any other `posthog.init`\n * option, forwarded verbatim (`persistence`, `capture_pageview`,\n * `autocapture`, …). JSON values only.\n */\nexport type PosthogOptions = PosthogNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const posthogOptionsSchema = z\n .object({\n host: z.string().optional(),\n key: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type PosthogAdapter = AdapterDescriptor<\"posthog\", PosthogOptions>;\n\nexport const posthogAdapterSchema = adapterDescriptorSchema(\n \"posthog\",\n posthogOptionsSchema\n);\n\n/**\n * PostHog product analytics. The project API key is public and write-only, so\n * it is safe to ship to the browser.\n */\nexport const posthog = (options: PosthogOptions): PosthogAdapter => ({\n kind: \"posthog\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n// The official array.js loader snippet.\nconst POSTHOG_LOADER =\n '!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(\".\");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement(\"script\")).type=\"text/javascript\",p.crossOrigin=\"anonymous\",p.async=!0,p.src=s.api_host.replace(\".i.posthog.com\",\"-assets.i.posthog.com\")+\"/static/array.js\",(r=t.getElementsByTagName(\"script\")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a=\"posthog\",u.people=u.people||[],u.toString=function(t){var e=\"posthog\";return\"posthog\"!==a&&(e+=\".\"+a),t||(e+=\" (stub)\"),e},u.people.toString=function(){return u.toString(1)+\".people (stub)\"},o=\"init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug getPageViewId captureTraceFeedback captureTraceMetric\".split(\" \"),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);';\n\n// PostHog's loader only captures a pageview per real page load, so the client\n// router's in-place swaps are captured here.\nconst POSTHOG_SPA_PAGEVIEWS = spaPageviews(\n \"__blumePosthogPath\",\n 'posthog.capture(\"$pageview\");'\n);\n\n/**\n * The inline loader-plus-init snippet. `key` and `host` are the options Blume\n * maps (`host` becomes `api_host`); everything else lands in `posthog.init`'s\n * options verbatim, after the mapped host so a raw `api_host` still wins.\n */\nexport const posthogHead = (options: PosthogOptions): HeadScript[] => {\n const { host, key, ...init } = options;\n const initOptions = { api_host: host ?? POSTHOG_DEFAULT_HOST, ...init };\n return [\n {\n attributes: {},\n content: `${POSTHOG_LOADER}posthog.init(${inlineJson(key)},${inlineJson(initOptions)});${POSTHOG_SPA_PAGEVIEWS}`,\n },\n ];\n};\n",
|
|
77
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\n\n/** Options for {@link script}; set exactly one of `src` or `content`. */\nexport interface ScriptOptions {\n /** Extra attributes spread onto the `<script>` (e.g. `data-domain`, `id`). */\n attributes?: Record<string, string>;\n /** Inline script body. Mutually exclusive with `src`. */\n content?: string;\n /** External script URL. Mutually exclusive with `content`. */\n src?: string;\n /** Load strategy for an external script. */\n strategy?: \"async\" | \"defer\";\n}\n\nexport const scriptOptionsSchema = z\n .strictObject({\n attributes: z.record(z.string(), z.string()).optional(),\n content: z.string().optional(),\n src: z.string().optional(),\n strategy: z.enum([\"async\", \"defer\"]).optional(),\n })\n .refine((value) => Boolean(value.src) !== Boolean(value.content), {\n message: \"An analytics script must set exactly one of `src` or `content`.\",\n });\n\nexport type ScriptAdapter = AdapterDescriptor<\"script\", ScriptOptions>;\n\nexport const scriptAdapterSchema = adapterDescriptorSchema(\n \"script\",\n scriptOptionsSchema\n);\n\n/**\n * Any other provider (Plausible, Fathom, GA, Umami, …) as one `<script>` tag:\n * external via `src`, inline via `content`. `attributes` is the verbatim\n * passthrough here — every entry lands on the tag as-is.\n */\nexport const script = (options: ScriptOptions): ScriptAdapter => ({\n kind: \"script\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n/** The tag. Explicit `src`/`strategy` win over a same-named spread attribute. */\nexport const scriptHead = (options: ScriptOptions): HeadScript[] => {\n const attributes: HeadScript[\"attributes\"] = { ...options.attributes };\n if (!options.src) {\n return [{ attributes, content: options.content ?? \"\" }];\n }\n if (options.strategy) {\n attributes[options.strategy] = true;\n }\n attributes.src = options.src;\n return [{ attributes, content: null }];\n};\n",
|
|
78
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { HeadScript } from \"./head.ts\";\nimport { inlineJson, spaPageviews } from \"./inline.ts\";\n\n/** Segment's CDN, where `segment()` loads analytics.js from when `cdn` is unset. */\nexport const SEGMENT_DEFAULT_CDN = \"https://cdn.segment.com\";\n\n/** The options {@link segment} maps itself. */\nexport interface SegmentNamedOptions {\n /**\n * Origin of a custom domain that proxies Segment's CDN, e.g.\n * `https://cdn.example.com`. Defaults to Segment's own.\n */\n cdn?: string;\n /** Write key of the JavaScript source. */\n key: string;\n}\n\n/**\n * Options for {@link segment}: the named options plus any other\n * `analytics.load` option, forwarded verbatim (`integrations`, …). JSON\n * values only.\n */\nexport type SegmentOptions = SegmentNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const segmentOptionsSchema = z\n .object({\n cdn: z.string().min(1).optional(),\n key: z.string().min(1),\n })\n .catchall(z.json());\n\nexport type SegmentAdapter = AdapterDescriptor<\"segment\", SegmentOptions>;\n\nexport const segmentAdapterSchema = adapterDescriptorSchema(\n \"segment\",\n segmentOptionsSchema\n);\n\n/**\n * Segment (Twilio Segment) analytics.js. The write key is meant for the\n * browser — it identifies the source the SDK reports to.\n */\nexport const segment = (options: SegmentOptions): SegmentAdapter => ({\n kind: \"segment\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n\n// The SDK sends one `page()` per real page load (the snippet's own call), so\n// client-router swaps are sent here.\nconst SEGMENT_SPA_PAGEVIEWS = spaPageviews(\n \"__blumeSegmentPath\",\n \"analytics.page();\"\n);\n\n/**\n * The install snippet, with `key` mapped to the write key, `cdn` mapped to\n * the script origin (and `analytics._cdn`, so the library fetches its\n * integrations from the same place), and everything else forwarded as the\n * load options; the object is left off when there is nothing to pass, as the\n * snippet prints it.\n */\nexport const segmentHead = (options: SegmentOptions): HeadScript[] => {\n const { cdn, key, ...load } = options;\n const origin = (cdn ?? SEGMENT_DEFAULT_CDN).replace(/\\/+$/u, \"\");\n const loadCall =\n Object.keys(load).length === 0\n ? `analytics.load(${inlineJson(key)});`\n : `analytics.load(${inlineJson(key)},${inlineJson(load)});`;\n const cdnAssign =\n cdn === undefined ? \"\" : `analytics._cdn=${inlineJson(origin)};`;\n return [\n {\n attributes: {},\n content: `!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error(\"Segment snippet included twice.\");else{analytics.invoked=!0;analytics.methods=[\"trackSubmit\",\"trackClick\",\"trackLink\",\"trackForm\",\"pageview\",\"identify\",\"reset\",\"group\",\"track\",\"ready\",\"alias\",\"debug\",\"page\",\"once\",\"off\",\"on\",\"addSourceMiddleware\",\"addIntegrationMiddleware\",\"setAnonymousId\",\"addDestinationMiddleware\"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement(\"script\");t.type=\"text/javascript\";t.async=!0;t.src=${inlineJson(`${origin}/analytics.js/v1/`)}+encodeURIComponent(key)+\"/analytics.min.js\";var n=document.getElementsByTagName(\"script\")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics._writeKey=${inlineJson(key)};${cdnAssign}analytics.SNIPPET_VERSION=\"4.15.3\";${loadCall}analytics.page();}}();${SEGMENT_SPA_PAGEVIEWS}`,\n },\n ];\n};\n",
|
|
79
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\n\n/** The props of `@vercel/analytics/astro` that {@link vercel} documents. */\nexport interface VercelNamedOptions {\n /** Log every event to the console. Defaults to the component's own rule (on outside production). */\n debug?: boolean;\n /** Force the script's environment instead of letting it detect one. */\n mode?: \"auto\" | \"development\" | \"production\";\n}\n\n/**\n * Options for {@link vercel}: the documented props plus any other prop of the\n * official component, forwarded verbatim (`endpoint`, `scriptSrc`, `dsn`, …).\n * JSON values only; `beforeSend` is a function and can't travel through\n * config — assign `window.webAnalyticsBeforeSend` from a `script()` adapter\n * listed before `vercel()` instead.\n */\nexport type VercelOptions = VercelNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport const vercelOptionsSchema = z\n .object({\n debug: z.boolean().optional(),\n mode: z.enum([\"auto\", \"development\", \"production\"]).optional(),\n })\n .catchall(z.json());\n\nexport type VercelAdapter = AdapterDescriptor<\"vercel\", VercelOptions>;\n\nexport const vercelAdapterSchema = adapterDescriptorSchema(\n \"vercel\",\n vercelOptionsSchema\n);\n\n/**\n * Vercel Web Analytics, rendered through the official Astro component, which\n * injects the first-party script Vercel serves at `/_vercel/insights` once Web\n * Analytics is enabled for the project. Needs no keys. `@vercel/analytics` is\n * one of Blume's own dependencies, so the adapter declares no runtime dep.\n */\nexport const vercel = (options: VercelOptions = {}): VercelAdapter => ({\n kind: \"vercel\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
80
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../../core/adapter.ts\";\nimport { cloudflare, cloudflareAdapterSchema } from \"./cloudflare.ts\";\nimport type { CloudflareAdapter } from \"./cloudflare.ts\";\nimport { netlify, netlifyAdapterSchema } from \"./netlify.ts\";\nimport type { NetlifyAdapter } from \"./netlify.ts\";\nimport { node, nodeAdapterSchema } from \"./node.ts\";\nimport type { NodeAdapter } from \"./node.ts\";\nimport type { DeployOutput, StaticDeployment } from \"./types.ts\";\nimport { vercel, vercelAdapterSchema } from \"./vercel.ts\";\nimport type { VercelAdapter } from \"./vercel.ts\";\n\n/** Every descriptor a host adapter factory can return. */\nexport type AnyDeployAdapter =\n | CloudflareAdapter\n | NetlifyAdapter\n | NodeAdapter\n | VercelAdapter;\n\n/** Every adapter identity, including the resolved `static` default. */\nexport type DeployAdapterKind = \"static\" | AnyDeployAdapter[\"kind\"];\n\n/**\n * A resolved deployment's options: `output` is always present (a host adapter\n * defaults to `server`, the static form is `static`), and anything else the\n * adapter was given rides along for the `@astrojs/*` constructor.\n */\nexport type ResolvedDeployOptions = {\n base?: string;\n output: DeployOutput;\n site?: string;\n} & { [option: string]: JsonValue };\n\n/**\n * What `config.deployment` resolves to: the descriptor the factory returned\n * with `output` filled in, or the `static` descriptor for the plain form.\n */\nexport type ResolvedDeployment = AdapterDescriptor<\n DeployAdapterKind,\n ResolvedDeployOptions\n>;\n\n/** What `blume.config.ts` accepts under `deployment`. */\nexport type DeploymentInput = AnyDeployAdapter | StaticDeployment;\n\nconst HINT =\n 'deployment takes a host adapter from \"blume/deploy\" — e.g. `deployment: vercel()`, `netlify({ output: \"static\" })`, `node({ site })` — or `{ site, base }` for a static build on any host. The 1.x `adapter`/`output` fields were removed.';\n\n/**\n * The static form, `{ site?, base? }`. Its discriminator is optional so the\n * union resolves a plain object (and `{}`) to it; the 1.x object form fails\n * here on its unrecognized `adapter`/`output` keys with the adapter hint.\n */\nconst staticDeploymentSchema = z.strictObject(\n {\n base: z.string().optional(),\n kind: z.literal(\"static\").optional(),\n site: z.url().optional(),\n },\n {\n error: (issue) => (issue.code === \"unrecognized_keys\" ? HINT : undefined),\n }\n);\n\n/** The union `deployment` is validated against, before resolution. */\nconst deploymentInputSchema = z.discriminatedUnion(\n \"kind\",\n [\n cloudflareAdapterSchema,\n netlifyAdapterSchema,\n nodeAdapterSchema,\n vercelAdapterSchema,\n staticDeploymentSchema,\n ],\n {\n error: (issue) =>\n issue.code === \"invalid_union\" || issue.code === \"invalid_type\"\n ? HINT\n : undefined,\n }\n);\n\n/** A host adapter with `output` resolved: unset means a server build. */\nconst resolveHost = (adapter: AnyDeployAdapter): ResolvedDeployment => ({\n ...adapter,\n options: { ...adapter.options, output: adapter.options.output ?? \"server\" },\n});\n\n/**\n * Validates what a factory returned (or the plain static form) and resolves\n * it to the canonical descriptor, re-derived through the factory so a\n * descriptor that went through JSON carries the same metadata Blume ships.\n * `static` is internal: `kind: \"static\"` is admitted but never needed.\n */\nexport const resolvedDeploymentSchema = deploymentInputSchema.transform(\n (value): ResolvedDeployment => {\n switch (value.kind) {\n case \"cloudflare\": {\n return resolveHost(cloudflare(value.options));\n }\n case \"netlify\": {\n return resolveHost(netlify(value.options));\n }\n case \"node\": {\n return resolveHost(node(value.options));\n }\n case \"vercel\": {\n return resolveHost(vercel(value.options));\n }\n default: {\n // The static form (`kind` unset or \"static\") is resolved after the\n // switch rather than in this block: Bun 1.4.0's line coverage never\n // credits the closing brace of a switch's final block.\n break;\n }\n }\n const options: ResolvedDeployOptions = { output: \"static\" };\n if (value.base !== undefined) {\n options.base = value.base;\n }\n if (value.site !== undefined) {\n options.site = value.site;\n }\n return { kind: \"static\", options, requiredSecrets: [], runtimeDeps: [] };\n }\n);\n",
|
|
81
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../../core/adapter.ts\";\n\n/** Build output mode: prerendered HTML only, or a server that can also answer requests. */\nexport type DeployOutput = \"static\" | \"server\";\n\n/** The options every host adapter maps itself. */\nexport interface DeployNamedOptions {\n /** Base path when the site is served from a subdirectory (`/docs`). */\n base?: string;\n /**\n * Build output mode. Defaults to `server`: naming a host adapter is how a\n * site opts into server rendering. Pass `\"static\"` to keep a static build\n * on that host, with its site detection and platform files.\n */\n output?: DeployOutput;\n /**\n * Canonical site URL. Needed for absolute links, the sitemap, and OG images;\n * detected from the platform's env at build time when unset.\n */\n site?: string;\n}\n\n/**\n * Options for a host adapter: the named options plus anything else, forwarded\n * verbatim to the underlying `@astrojs/*` adapter's constructor. JSON values\n * only — the descriptor is inlined into the generated `astro.config.mjs`.\n */\nexport type DeployOptions = DeployNamedOptions & {\n [option: string]: JsonValue;\n};\n\n/**\n * The descriptor a host adapter factory returns and `blume.config.ts` carries\n * under `deployment`: the shared {@link AdapterDescriptor} contract, with the\n * options a host takes. Plain data, never an Astro integration — the generated\n * config imports the real adapter package itself.\n */\nexport type DeployAdapter<\n Kind extends string,\n Options extends DeployOptions = DeployOptions,\n> = AdapterDescriptor<Kind, Options>;\n\n/**\n * A static build for any host — the form `deployment` takes when no adapter is\n * named: `{ site, base }`, or nothing at all. `kind` is the resolved\n * discriminator; leave it unset.\n */\nexport interface StaticDeployment {\n /** Base path when the site is served from a subdirectory (`/docs`). */\n base?: string;\n /** The resolved kind; never needed in a config. */\n kind?: \"static\";\n /**\n * Canonical site URL. Needed for absolute links, the sitemap, and OG images;\n * detected from the platform's env at build time when unset.\n */\n site?: string;\n}\n\n/** The named options' schema; every host adapter extends it with `z.json()` passthrough. */\nexport const deployOptionsSchema = z\n .object({\n base: z.string().optional(),\n output: z.enum([\"static\", \"server\"]).optional(),\n site: z.url().optional(),\n })\n .catchall(z.json());\n\nconst NAMED_OPTIONS = new Set([\"base\", \"output\", \"site\"]);\n\n/**\n * The options Blume does not name — what reaches the `@astrojs/*` adapter's\n * constructor verbatim.\n */\nexport const deployPassthrough = (\n options: DeployOptions\n): Record<string, JsonValue> =>\n Object.fromEntries(\n Object.entries(options).filter(([key]) => !NAMED_OPTIONS.has(key))\n );\n\n/**\n * The runtime dependency a host adapter declares: its `@astrojs/*` package,\n * which the generated `astro.config.mjs` imports for a server build and\n * nothing imports for a static one. Unset `output` means server.\n */\nexport const serverRuntimeDeps = (\n options: DeployNamedOptions,\n adapterPackage: string\n): string[] => (options.output === \"static\" ? [] : [adapterPackage]);\n",
|
|
82
|
+
"import { adapterDescriptorSchema } from \"../../core/adapter.ts\";\nimport type { DeployAdapter, DeployOptions } from \"./types.ts\";\nimport { deployOptionsSchema, serverRuntimeDeps } from \"./types.ts\";\n\n/** The Astro adapter package a Cloudflare server build imports. */\nexport const CLOUDFLARE_ADAPTER_PACKAGE = \"@astrojs/cloudflare\";\n\n/**\n * Options for {@link cloudflare}: `output`, `site`, and `base`, plus any\n * option of `@astrojs/cloudflare` forwarded verbatim (`platformProxy`,\n * `routes`, `cloudflareModules`, …). Blume sets `prerenderEnvironment`,\n * `imageService`, and `configPath` itself; an option you pass wins.\n */\nexport type CloudflareOptions = DeployOptions;\n\nexport type CloudflareAdapter = DeployAdapter<\"cloudflare\">;\n\nexport const cloudflareOptionsSchema = deployOptionsSchema;\n\nexport const cloudflareAdapterSchema = adapterDescriptorSchema(\n \"cloudflare\",\n cloudflareOptionsSchema\n);\n\n/**\n * Cloudflare Workers and Pages. A server build emits a Worker into\n * `dist/server` (with a generated wrapper that answers `Accept:\n * text/markdown`) and serves `dist/client` through the ASSETS binding.\n * `@astrojs/cloudflare` is an optional peer: install it in the project\n * (`npm install @astrojs/cloudflare`).\n */\nexport const cloudflare = (\n options: CloudflareOptions = {}\n): CloudflareAdapter => ({\n kind: \"cloudflare\",\n options,\n requiredSecrets: [],\n runtimeDeps: serverRuntimeDeps(options, CLOUDFLARE_ADAPTER_PACKAGE),\n});\n",
|
|
83
|
+
"import { adapterDescriptorSchema } from \"../../core/adapter.ts\";\nimport type { DeployAdapter, DeployOptions } from \"./types.ts\";\nimport { deployOptionsSchema, serverRuntimeDeps } from \"./types.ts\";\n\n/** The Astro adapter package a Netlify server build imports. */\nexport const NETLIFY_ADAPTER_PACKAGE = \"@astrojs/netlify\";\n\n/**\n * Options for {@link netlify}: `output`, `site`, and `base`, plus any option\n * of `@astrojs/netlify` forwarded verbatim (`edgeMiddleware`, `imageCDN`,\n * `cacheOnDemandPages`, …).\n */\nexport type NetlifyOptions = DeployOptions;\n\nexport type NetlifyAdapter = DeployAdapter<\"netlify\">;\n\nexport const netlifyOptionsSchema = deployOptionsSchema;\n\nexport const netlifyAdapterSchema = adapterDescriptorSchema(\n \"netlify\",\n netlifyOptionsSchema\n);\n\n/**\n * Netlify. A server build runs on Netlify Functions from the Frameworks API\n * tree the adapter writes to `.netlify/v1`. `@astrojs/netlify` is an optional\n * peer: install it in the project (`npm install @astrojs/netlify`).\n */\nexport const netlify = (options: NetlifyOptions = {}): NetlifyAdapter => ({\n kind: \"netlify\",\n options,\n requiredSecrets: [],\n runtimeDeps: serverRuntimeDeps(options, NETLIFY_ADAPTER_PACKAGE),\n});\n",
|
|
84
|
+
"import { adapterDescriptorSchema } from \"../../core/adapter.ts\";\nimport type { DeployAdapter, DeployOptions } from \"./types.ts\";\nimport { deployOptionsSchema, serverRuntimeDeps } from \"./types.ts\";\n\n/** The Astro adapter package a Node server build imports. */\nexport const NODE_ADAPTER_PACKAGE = \"@astrojs/node\";\n\n/**\n * Options for {@link node}: `output`, `site`, and `base`, plus any option of\n * `@astrojs/node` forwarded verbatim (`mode`, `host`, `port`, …). Blume\n * defaults `mode` to `\"standalone\"`; an option you pass wins.\n */\nexport type NodeOptions = DeployOptions;\n\nexport type NodeAdapter = DeployAdapter<\"node\">;\n\nexport const nodeOptionsSchema = deployOptionsSchema;\n\nexport const nodeAdapterSchema = adapterDescriptorSchema(\n \"node\",\n nodeOptionsSchema\n);\n\n/**\n * A self-hosted Node server (containers, VMs). The standalone server in\n * `dist/server/entry.mjs` serves `dist/client` itself. `@astrojs/node` is one\n * of Blume's own dependencies.\n */\nexport const node = (options: NodeOptions = {}): NodeAdapter => ({\n kind: \"node\",\n options,\n requiredSecrets: [],\n runtimeDeps: serverRuntimeDeps(options, NODE_ADAPTER_PACKAGE),\n});\n",
|
|
85
|
+
"import { adapterDescriptorSchema } from \"../../core/adapter.ts\";\nimport type { DeployAdapter, DeployOptions } from \"./types.ts\";\nimport { deployOptionsSchema, serverRuntimeDeps } from \"./types.ts\";\n\n/** The Astro adapter package a Vercel server build imports. */\nexport const VERCEL_ADAPTER_PACKAGE = \"@astrojs/vercel\";\n\n/**\n * Options for {@link vercel}: `output`, `site`, and `base`, plus any option of\n * `@astrojs/vercel` forwarded verbatim (`isr`, `maxDuration`, `imageService`,\n * `webAnalytics`, …).\n */\nexport type VercelOptions = DeployOptions;\n\nexport type VercelAdapter = DeployAdapter<\"vercel\">;\n\nexport const vercelOptionsSchema = deployOptionsSchema;\n\nexport const vercelAdapterSchema = adapterDescriptorSchema(\n \"vercel\",\n vercelOptionsSchema\n);\n\n/**\n * Vercel. A server build writes the Build Output tree to `.vercel/output`,\n * audits the function bundle for imports the platform's dependency trace\n * dropped, and wires `Accept: text/markdown` negotiation into the routing\n * config. `@astrojs/vercel` is one of Blume's own dependencies.\n */\nexport const vercel = (options: VercelOptions = {}): VercelAdapter => ({\n kind: \"vercel\",\n options,\n requiredSecrets: [],\n runtimeDeps: serverRuntimeDeps(options, VERCEL_ADAPTER_PACKAGE),\n});\n",
|
|
86
|
+
"import { normalizeRoute, withBasePath } from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { trimChar } from \"../core/trim.ts\";\nimport type { ScalarOptions } from \"../reference/scalar.ts\";\nimport type { ResolvedReferenceAdapter } from \"../reference/schema.ts\";\n\n// Re-exported from its home next to the other path helpers; `core/schema.ts`\n// and downstream consumers historically imported it from here.\nexport { normalizeRoute } from \"../core/base-path.ts\";\n\n/**\n * Pure resolution of the configured `reference` adapters into concrete routes\n * and labels — no file IO, so the content source, the\n * nav-target validation, the Scalar page generator, and the `blume:openapi`\n * data module all share one source of truth. Kept free of any Astro/template\n * imports so `core` can depend on it without a cycle.\n */\n\n/**\n * Which adapter a reference came from. `openapi`, `asyncapi`, and `graphql`\n * are rendered by Blume into real pages; `scalar` is the embedded Scalar SPA\n * on a single route.\n */\nexport type ReferenceKind = ResolvedReferenceAdapter[\"kind\"];\n\n/** The kinds Blume renders into pages itself — everything but the Scalar embed. */\nexport type BlumeReferenceKind = Exclude<ReferenceKind, \"scalar\">;\n\n/** Per-adapter display options for the Blume renderer. */\nexport interface ReferenceDisplay {\n /** Code-sample languages shown per operation. */\n codeSamples: string[];\n /** Whether nested schema rows start expanded. */\n expandSchemas: boolean;\n /**\n * The \"Try it\" playground: whether operation pages render it, and the CORS\n * proxy the Send button routes through (`false` off, a URL string, or\n * `true` for the built-in `/_api-proxy` endpoint).\n */\n playground: { enabled: boolean; proxy: string | boolean };\n}\n\n/** A spec source resolved to a concrete route and label. */\nexport interface ReferenceSource {\n kind: ReferenceKind;\n /** Unique token derived from the route; the `<Operation source>` / data key. */\n slug: string;\n /** Normalized route the reference mounts at, e.g. `/reference`. */\n route: string;\n /**\n * Site-wide `basePath` the rendered pages are mounted under (`\"\"` when\n * none). Kept separate from `route` — the content pipeline applies it to\n * staged entries itself — so consumers prefix only the URLs they emit.\n */\n basePath: string;\n label: string;\n /** Whether generated pages are included in llms.txt/llms-full.txt. */\n includeInLlms: boolean;\n /** Whether generated pages are included in site search. */\n includeInSearch: boolean;\n /** Whether generated pages emit noindex metadata and stay out of the sitemap. */\n noindex: boolean;\n /**\n * Whether operation meta descriptions end with the generated English\n * \"Reference for …\" sentence, or carry the spec's own prose alone.\n */\n seoDescriptionSuffix: boolean;\n /** Local path or `http(s)` URL, verbatim from config. */\n spec: string;\n /**\n * URL of the live GraphQL endpoint the playground and code samples target\n * (GraphQL only — a schema, unlike an OpenAPI document, names no server).\n */\n endpoint?: string;\n /**\n * The `scalar()` adapter's own options (`scalar` kind only): `theme` plus\n * any Scalar config forwarded verbatim to `<ScalarComponent>`, which takes\n * precedence over Blume's derived spec/theme config.\n */\n scalar?: ScalarOptions;\n /** Display options carried through to the Blume renderer. */\n display: ReferenceDisplay;\n /**\n * Warnings recorded while deduping — another source's route collided with\n * this one and was dropped. Surfaced as diagnostics when the source loads.\n */\n collisions?: string[];\n}\n\n/** A reference Blume renders itself: one the content pipeline stages pages for. */\nexport type BlumeReferenceSource = ReferenceSource & {\n kind: BlumeReferenceKind;\n};\n\nconst isBlumeReference = (ref: ReferenceSource): ref is BlumeReferenceSource =>\n ref.kind !== \"scalar\";\n\n// Keep Unicode letters/marks/numbers so diacritics stay in the slug (ASCII-only\n// stripping turned `Größe` into `gr-e`, which the nav humanizer rendered as\n// `Gr E`); `\\p{M}` keeps combining marks attached to their base letter, which\n// NFC cannot always compose away (Devanagari vowel signs, Turkish `İ`'s\n// lowercased combining dot).\nconst NON_SLUG = /[^\\p{L}\\p{M}\\p{N}]+/gu;\n// Format characters (ZWNJ, ZWJ, bidi controls) separate no words — hyphenating\n// them would split Persian/Indic compounds the way ASCII stripping split\n// `Größe` — so they are dropped, not replaced.\nconst FORMAT_CHARS = /\\p{Cf}/gu;\n// A combining mark at the start of the slug has no base letter to attach to\n// (it would glue onto the preceding `/` in a URL), and a marks-only slug must\n// come out empty so callers' fallbacks (`operations`, `reference`) fire.\nconst LEADING_MARKS = /^\\p{M}+/u;\n\n/**\n * Lowercase, hyphen-separated slug: `Add a Pet!` -> `add-a-pet`. Unicode\n * letters are kept (`Größe` -> `größe`), NFC-normalized so canonically\n * equivalent spellings (NFD input from macOS tooling) land on one slug.\n * Non-ASCII slugs rely on the emitter percent-encoding the URL where a raw\n * URI is required (sitemap, canonical).\n */\nexport const slugify = (text: string): string =>\n trimChar(\n text\n .normalize(\"NFC\")\n .toLowerCase()\n .replace(FORMAT_CHARS, \"\")\n .replace(NON_SLUG, \"-\"),\n \"-\"\n ).replace(LEADING_MARKS, \"\");\n\n/** A stable per-reference token from its route: `/api/events` -> `api-events`. */\nconst routeSlug = (route: string): string =>\n slugify(trimChar(route, \"/\")) || \"reference\";\n\n/** The label a source gets when it names none (numbered when there are several). */\nconst DEFAULT_LABELS: Record<ReferenceKind, string> = {\n asyncapi: \"Events\",\n graphql: \"GraphQL\",\n openapi: \"API Reference\",\n scalar: \"API Reference\",\n};\n\n/** The Blume renderer has nothing to show for a Scalar embed. */\nconst NO_DISPLAY: ReferenceDisplay = {\n codeSamples: [],\n expandSchemas: false,\n playground: { enabled: false, proxy: false },\n};\n\nconst displayOf = (adapter: ResolvedReferenceAdapter): ReferenceDisplay => {\n if (adapter.kind === \"scalar\") {\n return NO_DISPLAY;\n }\n return {\n codeSamples: adapter.options.codeSamples,\n // GraphQL field tables have no nesting, so `graphql()` takes no\n // `expandSchemas` toggle.\n expandSchemas:\n adapter.kind === \"graphql\" ? false : adapter.options.expandSchemas,\n playground: adapter.options.playground,\n };\n};\n\n/**\n * A `scalar()` adapter's options minus the ones Blume resolves itself\n * (`route`, `sources`): `theme` and the verbatim Scalar passthrough, which\n * the generated page inlines.\n */\nconst scalarOptionsOf = (\n options: Extract<ResolvedReferenceAdapter, { kind: \"scalar\" }>[\"options\"]\n): ScalarOptions =>\n Object.fromEntries(\n Object.entries(options).filter(\n ([key]) => key !== \"route\" && key !== \"sources\"\n )\n );\n\n/** A source row with every kind's fields reconciled onto one shape. */\ninterface SourceRow {\n endpoint?: string;\n includeInLlms: boolean;\n includeInSearch: boolean;\n label?: string;\n noindex: boolean;\n route?: string;\n seoDescriptionSuffix: boolean;\n spec: string;\n}\n\n/**\n * One row per source, with the kind-specific fields already reconciled: a\n * GraphQL source's `endpoint` falls back to the adapter-wide default (the\n * common single-schema case pairs it with the `spec` shorthand); the other\n * kinds have no endpoint at all. A Scalar source carries only `noindex` of\n * the per-source controls — the embed sits outside search and llms.txt, so\n * the other two read as off.\n */\nconst sourceRowsOf = (adapter: ResolvedReferenceAdapter): SourceRow[] => {\n if (adapter.kind === \"graphql\") {\n return adapter.options.sources.map((source) => ({\n ...source,\n endpoint: source.endpoint ?? adapter.options.endpoint,\n }));\n }\n if (adapter.kind === \"scalar\") {\n return adapter.options.sources.map((source) => ({\n ...source,\n includeInLlms: false,\n includeInSearch: false,\n seoDescriptionSuffix: false,\n }));\n }\n return adapter.options.sources;\n};\n\nconst referencesFor = (\n adapter: ResolvedReferenceAdapter,\n basePath: string\n): ReferenceSource[] => {\n const sources = sourceRowsOf(adapter);\n const base = normalizeRoute(adapter.options.route);\n const defaultLabel = DEFAULT_LABELS[adapter.kind];\n const display = displayOf(adapter);\n\n return sources.map((source, index) => {\n const label =\n source.label ??\n (sources.length > 1 ? `${defaultLabel} ${index + 1}` : defaultLabel);\n\n let route: string;\n if (source.route) {\n route = normalizeRoute(source.route);\n } else if (sources.length === 1) {\n route = base;\n } else {\n const suffix = source.label ? slugify(source.label) : \"\";\n route = normalizeRoute(`${base}/${suffix || index + 1}`);\n }\n\n const reference: ReferenceSource = {\n basePath,\n display,\n includeInLlms: source.includeInLlms,\n includeInSearch: source.includeInSearch,\n kind: adapter.kind,\n label,\n noindex: source.noindex,\n route,\n seoDescriptionSuffix: source.seoDescriptionSuffix,\n slug: routeSlug(route),\n spec: source.spec,\n };\n if (adapter.kind === \"scalar\") {\n reference.scalar = scalarOptionsOf(adapter.options);\n }\n if (source.endpoint !== undefined) {\n reference.endpoint = source.endpoint;\n }\n return reference;\n });\n};\n\n/**\n * Resolve every configured reference, in `reference` order: Blume's own pages\n * for `openapi()`, `asyncapi()`, and `graphql()`, and one embedded Scalar page\n * per `scalar()` source.\n */\nexport const resolveReferences = (config: ResolvedConfig): ReferenceSource[] =>\n config.reference.flatMap((adapter) =>\n referencesFor(adapter, config.basePath)\n );\n\n/**\n * Mounted route for every reference, regardless of kind. References no\n * longer add a header tab automatically — authors point a `navigation.tabs`\n * entry at one of these routes to surface it (and, for Blume-rendered specs, to\n * scope its operations sidebar). These routes are whitelisted as valid nav\n * targets so such a tab doesn't read as a broken link.\n */\nexport const referenceRoutes = (config: ResolvedConfig): string[] =>\n resolveReferences(config).map((ref) =>\n // Blume-rendered operation pages flow through the content pipeline and are\n // mounted under `basePath`. Scalar references are a single embedded page\n // injected at the raw `route`, left root-anchored.\n ref.kind === \"scalar\" ? ref.route : withBasePath(config.basePath, ref.route)\n );\n\n/**\n * Accept one resolved reference into the deduped Blume-rendered set, or return\n * null to skip it. Mutates `seen`/`usedSlugs` so repeated routes/slugs collapse.\n * A dropped route collision is recorded on the kept reference (mirroring the\n * Scalar path's warning) — losing a whole spec's pages must not be silent.\n */\nconst blumeReferenceOf = (\n ref: ReferenceSource,\n seen: Map<string, BlumeReferenceSource>,\n usedSlugs: Set<string>\n): BlumeReferenceSource | null => {\n if (!isBlumeReference(ref)) {\n return null;\n }\n const kept = seen.get(ref.route);\n if (kept) {\n (kept.collisions ??= []).push(\n `Two API reference sources resolve to ${ref.route}; keeping the first.`\n );\n return null;\n }\n // Distinct routes can slugify identically (`/api/v1` and `/api-v1` both\n // yield `api-v1`). The slug keys the `blume:openapi` data module, so a\n // collision would let one spec silently overwrite the other while the\n // loser's pages still point at the shared key — disambiguate.\n let { slug } = ref;\n let n = 2;\n while (usedSlugs.has(slug)) {\n slug = `${ref.slug}-${n}`;\n n += 1;\n }\n usedSlugs.add(slug);\n const accepted = slug === ref.slug ? ref : { ...ref, slug };\n // Keep the accepted object (not the original) so a later collision's warning\n // lands on the reference the caller actually receives.\n seen.set(ref.route, accepted);\n return accepted;\n};\n\n/** Blume-rendered references (every kind but Scalar), deduped by route (first wins). */\nexport const blumeReferences = (\n config: ResolvedConfig\n): BlumeReferenceSource[] => {\n const seen = new Map<string, BlumeReferenceSource>();\n const usedSlugs = new Set<string>();\n const result: BlumeReferenceSource[] = [];\n for (const ref of resolveReferences(config)) {\n const accepted = blumeReferenceOf(ref, seen, usedSlugs);\n if (accepted) {\n result.push(accepted);\n }\n }\n return result;\n};\n\n/** Whether any reference is Scalar-rendered (gates the Scalar pages). */\nexport const hasScalarReferences = (config: ResolvedConfig): boolean =>\n resolveReferences(config).some((ref) => ref.kind === \"scalar\");\n\n/**\n * The Blume-rendered references whose enabled playground opted into the\n * built-in CORS proxy with `proxy: true`. A proxy URL string points at an\n * external service, and `false` sends requests directly — neither routes\n * through the endpoint. AsyncAPI never does: an event composer's WebSocket\n * connect is direct, so its `proxy` has nothing to forward. Drawn from the\n * deduped set so the slugs match the `blume:openapi` data keys; the\n * generator's per-spec allowlist diagnostics key on this, so it shares one\n * definition with {@link needsPlaygroundProxy}.\n */\nexport const builtinProxyReferences = (\n config: ResolvedConfig\n): BlumeReferenceSource[] =>\n blumeReferences(config).filter(\n (ref) =>\n ref.kind !== \"asyncapi\" &&\n ref.display.playground.enabled &&\n ref.display.playground.proxy === true\n );\n\n/**\n * Whether the built-in playground CORS proxy endpoint (`/_api-proxy`) must be\n * generated: some Blume-rendered reference's playground opted into it with\n * `proxy: true`. Shared by the server feature gate and the generator so the\n * two can never disagree.\n */\nexport const needsPlaygroundProxy = (config: ResolvedConfig): boolean =>\n builtinProxyReferences(config).length > 0;\n",
|
|
87
|
+
"import { z } from \"zod\";\n\nimport { unrecognizedKeysMessage } from \"../core/unrecognized-keys.ts\";\nimport { asyncapiAdapterSchema } from \"./asyncapi.ts\";\nimport type { AsyncApiAdapter, ResolvedAsyncApiAdapter } from \"./asyncapi.ts\";\nimport { graphqlAdapterSchema } from \"./graphql.ts\";\nimport type { GraphqlAdapter, ResolvedGraphqlAdapter } from \"./graphql.ts\";\nimport { openapiAdapterSchema } from \"./openapi.ts\";\nimport type { OpenApiAdapter, ResolvedOpenApiAdapter } from \"./openapi.ts\";\nimport { SCALAR_RUNTIME_DEPS, scalarAdapterSchema } from \"./scalar.ts\";\nimport type { ResolvedScalarAdapter, ScalarAdapter } from \"./scalar.ts\";\n\n/** Every descriptor a `blume/reference` factory can return. */\nexport type ReferenceAdapter =\n | AsyncApiAdapter\n | GraphqlAdapter\n | OpenApiAdapter\n | ScalarAdapter;\n\n/** What `config.reference` holds: each descriptor with its options resolved. */\nexport type ResolvedReferenceAdapter =\n | ResolvedAsyncApiAdapter\n | ResolvedGraphqlAdapter\n | ResolvedOpenApiAdapter\n | ResolvedScalarAdapter;\n\n/**\n * One configured reference adapter, as its factory returned it. Only `kind`\n * and `options` carry information — the metadata lists are validated for\n * shape, then re-derived from the resolved options so a descriptor that went\n * through JSON resolves to the same canonical metadata the factory ships.\n */\nexport const referenceAdapterSchema = z\n .discriminatedUnion(\"kind\", [\n asyncapiAdapterSchema,\n graphqlAdapterSchema,\n openapiAdapterSchema,\n scalarAdapterSchema,\n ])\n .transform((value): ResolvedReferenceAdapter => ({\n ...value,\n requiredSecrets: [],\n // Blume's own renderer parses at generate time and needs nothing; the\n // Scalar embed is imported by its generated page.\n runtimeDeps: value.kind === \"scalar\" ? [...SCALAR_RUNTIME_DEPS] : [],\n }));\n\nconst LIST_HINT =\n 'reference is a list of adapters — e.g. `reference: [openapi({ spec }), asyncapi({ spec }), graphql({ spec, endpoint }), scalar({ spec })]`, imported from \"blume/reference\".';\n\n/**\n * `blume.config.reference`: the API references to render, in order. Unset\n * means none. A non-array fails with the list hint; element errors keep their\n * own messages.\n */\nexport const referenceConfigSchema = z\n .array(referenceAdapterSchema, {\n error: (issue) => (issue.code === \"invalid_type\" ? LIST_HINT : undefined),\n })\n .default([]);\n\n/** The top-level keys the `reference` list replaced. */\nconst REMOVED_KEYS: readonly string[] = [\"asyncapi\", \"graphql\", \"openapi\"];\n\n/**\n * The hint for a config still carrying the 1.x `openapi`/`asyncapi`/`graphql`\n * blocks, or `undefined` when none of the unrecognized keys is one of them\n * (so the default \"unrecognized key\" message applies). Wired into the root\n * config object's error hook: the keys are gone from the schema, so without\n * this a migrating site would see only \"Unrecognized key\". Any other unknown\n * key keeps Zod's wording beside the hint, and the rest of the config is\n * still validated in the same run.\n */\nexport const removedReferenceKeysHint = (\n keys: string[]\n): string | undefined => {\n const removed = REMOVED_KEYS.filter((key) => keys.includes(key));\n if (removed.length === 0) {\n return undefined;\n }\n const list = removed.map((key) => `\\`${key}\\``).join(\", \");\n const factories = removed.map((key) => `${key}({ … })`).join(\", \");\n const hint = `The top-level ${list} config was replaced by \\`reference\\`, a list of adapters imported from \"blume/reference\": \\`reference: [${factories}]\\`. Each block's options move onto its factory unchanged (\\`enabled\\` is gone — an adapter in the list is enabled), and a block with \\`renderer: \"scalar\"\\` becomes its own \\`scalar({ spec, theme, …scalar })\\` adapter in the list.`;\n const others = keys.filter((key) => !REMOVED_KEYS.includes(key));\n return others.length > 0\n ? `${hint} ${unrecognizedKeysMessage(others)}`\n : hint;\n};\n",
|
|
88
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport {\n liftSpec,\n referenceSourceSchema,\n hasSources,\n missingSourcesIssue,\n rendererRemovedHint,\n sharedOptions,\n} from \"./options.ts\";\nimport type { PlaygroundOptions, ReferenceSourceOptions } from \"./options.ts\";\n\n/** Options for {@link asyncapi}. */\nexport interface AsyncApiOptions {\n /**\n * Code-sample tools shown per operation (Blume renderer). Defaults to every\n * tool appropriate to the operation's protocol binding.\n */\n codeSamples?: string[];\n /** Start nested schema rows expanded rather than collapsed (Blume renderer). Defaults to `false`. */\n expandSchemas?: boolean;\n /**\n * The \"Try it\" message composer (Blume renderer). On by default; `false`\n * hides it. `proxy` is accepted for parity but doesn't apply to event\n * operations — a WebSocket connect goes straight from the browser.\n */\n playground?: PlaygroundOptions;\n /** Where the reference mounts. Defaults to `/events`. */\n route?: string;\n /** One or more specs; each renders on its own route by default. */\n sources?: ReferenceSourceOptions[];\n /** Shorthand for a single source: `sources: [{ spec }]`. */\n spec?: string;\n}\n\nexport const asyncapiOptionsSchema = z\n .strictObject(\n {\n // Empty `codeSamples` means every tool the operation's protocol binding\n // suggests.\n ...sharedOptions({ codeSamples: [], route: \"/events\" }),\n /** Start nested schema rows expanded rather than collapsed (Blume renderer). */\n expandSchemas: z.boolean().default(false),\n /** One or more specs; each renders on its own route by default. */\n sources: z.array(referenceSourceSchema).default([]),\n },\n rendererRemovedHint\n )\n .transform(liftSpec(referenceSourceSchema))\n .refine(hasSources, missingSourcesIssue(\"asyncapi\"));\n\n/** `asyncapi()` options with every default applied and `spec` folded into `sources`. */\nexport type ResolvedAsyncApiOptions = z.output<typeof asyncapiOptionsSchema>;\n\nexport type AsyncApiAdapter = AdapterDescriptor<\"asyncapi\", AsyncApiOptions>;\n\n/** An `asyncapi()` descriptor as the config schema resolves it. */\nexport type ResolvedAsyncApiAdapter = AdapterDescriptor<\n \"asyncapi\",\n ResolvedAsyncApiOptions\n>;\n\nexport const asyncapiAdapterSchema = adapterDescriptorSchema(\n \"asyncapi\",\n asyncapiOptionsSchema\n);\n\n/**\n * An AsyncAPI reference. Blume normalizes the spec to AsyncAPI 3.x and renders\n * its own UI — one real page per operation, in the sidebar, search, llms.txt,\n * and OG; a `scalar()` adapter is the embedded-SPA alternative. Only the\n * defaults differ from `openapi()`: the reference mounts at `/events`, and\n * empty `codeSamples` means every tool the operation's protocol binding\n * suggests.\n */\nexport const asyncapi = (options: AsyncApiOptions): AsyncApiAdapter => ({\n kind: \"asyncapi\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
89
|
+
"import { z } from \"zod\";\n\nimport { unrecognizedKeysMessage } from \"../core/unrecognized-keys.ts\";\n\n/**\n * The option pieces every reference adapter shares: a spec source, the \"Try\n * it\" playground normalization, and the `spec` shorthand that folds into\n * `sources` at parse. Kept apart from the kind modules so `openapi()`,\n * `asyncapi()`, and `graphql()` validate one definition of each.\n */\n\nconst isBoolean = <Value>(value: Value): value is Value & boolean =>\n typeof value === \"boolean\";\n\n/**\n * A single spec rendered by a reference. `spec` is a local path or an\n * `http(s)` URL (an OpenAPI document for `openapi()`, an AsyncAPI document\n * for `asyncapi()`, SDL or introspection JSON for `graphql()`).\n */\nexport const referenceSourceSchema = z.strictObject({\n /** Include generated pages from this spec in llms.txt/llms-full.txt. */\n includeInLlms: z.boolean().default(true),\n /** Include generated pages from this spec in site search. */\n includeInSearch: z.boolean().default(true),\n /** Nav/section label for this source. */\n label: z.string().optional(),\n /** Emit noindex metadata and omit generated pages from the sitemap. */\n noindex: z.boolean().default(false),\n /** Per-source route; defaults to the adapter's `route` (or a derived path). */\n route: z.string().optional(),\n /**\n * Append the English \"Reference for the … endpoint in the … API.\" sentence\n * to every generated operation page's meta description. On by default, so\n * terse specs still ship distinct, snippet-length descriptions; set to\n * `false` on a non-English site to describe pages with the spec's own prose\n * alone (falling back to the page title when an operation has none).\n */\n seoDescriptionSuffix: z.boolean().default(true),\n /** Local path or `http(s)` URL to the spec. */\n spec: z.string(),\n});\n\n/** One spec source, as `openapi()` and `asyncapi()` accept it. */\nexport interface ReferenceSourceOptions {\n /** Include generated pages from this spec in llms.txt/llms-full.txt. Defaults to `true`. */\n includeInLlms?: boolean;\n /** Include generated pages from this spec in site search. Defaults to `true`. */\n includeInSearch?: boolean;\n /** Nav/section label for this source. */\n label?: string;\n /** Emit noindex metadata and omit generated pages from the sitemap. Defaults to `false`. */\n noindex?: boolean;\n /** Per-source route; defaults to the adapter's `route` (or a derived path). */\n route?: string;\n /**\n * Append the generated English \"Reference for …\" sentence to every\n * operation page's meta description. Defaults to `true`; set `false` on a\n * non-English site to keep the spec's own prose alone.\n */\n seoDescriptionSuffix?: boolean;\n /** Local path or `http(s)` URL to the spec. */\n spec: string;\n}\n\n/** A spec source with every default applied. */\nexport type ResolvedReferenceSource = z.output<typeof referenceSourceSchema>;\n\n/**\n * A single GraphQL schema: the shared source shape plus `endpoint`, the live\n * GraphQL API URL the playground and code samples target (a schema, unlike an\n * OpenAPI document, names no server).\n */\nexport const graphqlSourceSchema = referenceSourceSchema.extend({\n /** URL of the live GraphQL endpoint (playground + code samples). */\n endpoint: z.string().optional(),\n});\n\n/** One schema source, as `graphql()` accepts it. */\nexport interface GraphqlSourceOptions extends ReferenceSourceOptions {\n /** URL of the live GraphQL endpoint (playground + code samples); wins over the adapter's `endpoint`. */\n endpoint?: string;\n}\n\n/** A GraphQL schema source with every default applied. */\nexport type ResolvedGraphqlSource = z.output<typeof graphqlSourceSchema>;\n\n/**\n * The interactive \"Try it\" panel on operation pages (Blume renderer). On by\n * default; `false` hides it. The object form keeps it on and sets `proxy`,\n * the CORS escape hatch the Send button routes requests through: a proxy URL,\n * or `true` for the built-in `/_api-proxy` endpoint (which needs server\n * output: a host adapter such as `vercel()` in `deployment`). Booleans\n * normalize to the object shape so consumers read `{ enabled, proxy }`\n * directly. `proxy` applies to the HTTP-posting playgrounds (OpenAPI, GraphQL)\n * — an event composer's WebSocket connect is direct. One schema for every\n * reference kind, so the normalization can never drift between them.\n */\nexport const playgroundSchema = z\n .union([\n z.boolean(),\n z.strictObject({\n enabled: z.boolean().default(true),\n proxy: z.union([z.boolean(), z.string()]).default(false),\n }),\n ])\n .default(true)\n .transform((value) =>\n isBoolean(value) ? { enabled: value, proxy: false } : value\n );\n\n/** The `playground` option as a factory accepts it. */\nexport type PlaygroundOptions =\n | boolean\n | {\n /** Render the panel. Defaults to `true`. */\n enabled?: boolean;\n /** CORS proxy: a URL, or `true` for the built-in `/_api-proxy` route. Defaults to `false`. */\n proxy?: boolean | string;\n };\n\n/** The playground with its booleans normalized: `{ enabled, proxy }`. */\nexport type ResolvedPlayground = z.output<typeof playgroundSchema>;\n\n/**\n * The message a config still passing `renderer` to `openapi()`/`asyncapi()`\n * gets: Scalar is its own adapter now, so the option has no home.\n */\nexport const RENDERER_REMOVED_HINT =\n '`renderer` was removed: the Scalar embed is its own adapter. Replace `openapi({ spec, renderer: \"scalar\", theme })` with a separate `scalar({ spec, theme })` entry in `reference`, imported from \"blume/reference\" — `route`, `sources`, `label`, and `noindex` carry over, and the native display options (`codeSamples`, `expandSchemas`, `playground`) don\\'t apply to the embed.';\n\n/**\n * Error params for the `openapi()`/`asyncapi()` option objects: a leftover\n * `renderer` key names its replacement instead of Zod's bare \"Unrecognized\n * key\"; any other unknown key keeps the default message, beside the hint.\n */\nexport const rendererRemovedHint = {\n error: (issue: z.core.$ZodRawIssue): string | undefined => {\n if (\n issue.code !== \"unrecognized_keys\" ||\n !issue.keys.includes(\"renderer\")\n ) {\n return;\n }\n const others = issue.keys.filter((key) => key !== \"renderer\");\n return others.length > 0\n ? `${RENDERER_REMOVED_HINT} ${unrecognizedKeysMessage(others)}`\n : RENDERER_REMOVED_HINT;\n },\n};\n\n/**\n * The options every kind shares, with that kind's defaults for the mount\n * route and code-sample set. `spec` is the single-source shorthand; the kind\n * schema folds it into `sources` with {@link liftSpec}.\n */\nexport const sharedOptions = (defaults: {\n codeSamples: string[];\n route: string;\n}) => ({\n /** Code-sample languages/tools shown per operation (Blume renderer). */\n codeSamples: z.array(z.string()).default(defaults.codeSamples),\n /** The \"Try it\" panel; see {@link playgroundSchema}. */\n playground: playgroundSchema,\n /** Where the reference mounts. */\n route: z.string().default(defaults.route),\n /** Shorthand for a single source: `sources: [{ spec }]`. */\n spec: z.string().optional(),\n});\n\n/**\n * Resolve the `spec` shorthand into `sources` so downstream code reads one\n * field: the shorthand becomes the first source (with the source defaults\n * applied through the source schema itself, so the two can never drift) and\n * the `spec` key is dropped. An adapter with neither renders nothing, which\n * is a config mistake rather than a choice — `refine` it away with\n * {@link hasSources}.\n */\nexport const liftSpec =\n <Source extends { spec: string }>(\n sourceSchema: z.ZodType<Source, { spec: string }>\n ) =>\n <Options extends { sources: Source[]; spec?: string }>({\n spec,\n ...options\n }: Options): Omit<Options, \"spec\"> => ({\n ...options,\n sources:\n spec === undefined\n ? options.sources\n : [sourceSchema.parse({ spec }), ...options.sources],\n });\n\n/** Whether an adapter has anything to render; pairs with {@link missingSourcesIssue}. */\nexport const hasSources = (options: { sources: { spec: string }[] }): boolean =>\n options.sources.length > 0;\n\n/** The refinement issue for a source-less adapter, naming its factory. */\nexport const missingSourcesIssue = (factory: string) => ({\n message: `${factory}() renders nothing without a spec — set \\`spec\\` or at least one \\`sources\\` entry.`,\n path: [\"sources\"],\n});\n",
|
|
90
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport {\n graphqlSourceSchema,\n liftSpec,\n hasSources,\n missingSourcesIssue,\n sharedOptions,\n} from \"./options.ts\";\nimport type { GraphqlSourceOptions, PlaygroundOptions } from \"./options.ts\";\n\n/** Options for {@link graphql}. */\nexport interface GraphqlOptions {\n /** Code-sample languages shown per operation. Defaults to `[\"curl\", \"js\", \"python\"]`. */\n codeSamples?: string[];\n /**\n * URL of the live GraphQL endpoint the playground and code samples target —\n * a schema, unlike an OpenAPI document, names no server. Applies to every\n * source; a per-source `endpoint` wins.\n */\n endpoint?: string;\n /**\n * The interactive \"Try it\" panel. On by default; `false` hides it. The\n * object form sets `proxy`, the CORS escape hatch the Send button routes\n * requests through: a proxy URL, or `true` for the built-in `/_api-proxy`\n * endpoint (which needs server output: a host adapter such as `vercel()` in\n * `deployment`).\n */\n playground?: PlaygroundOptions;\n /** Where the reference mounts. Defaults to `/graphql`. */\n route?: string;\n /** One or more schemas; each renders on its own route by default. */\n sources?: GraphqlSourceOptions[];\n /** Shorthand for a single source: `sources: [{ spec }]`. */\n spec?: string;\n}\n\n/**\n * No `expandSchemas` (GraphQL field tables have no nesting) — everything\n * else, the playground normalization included, is the shared reference\n * shape. There is no Scalar counterpart: the Scalar embed reads OpenAPI and\n * AsyncAPI documents only.\n */\nexport const graphqlOptionsSchema = z\n .strictObject({\n ...sharedOptions({\n codeSamples: [\"curl\", \"js\", \"python\"],\n route: \"/graphql\",\n }),\n /** Default live endpoint URL for every source (per-source `endpoint` wins). */\n endpoint: z.string().optional(),\n /** One or more schemas; each renders on its own route by default. */\n sources: z.array(graphqlSourceSchema).default([]),\n })\n .transform(liftSpec(graphqlSourceSchema))\n .refine(hasSources, missingSourcesIssue(\"graphql\"));\n\n/** `graphql()` options with every default applied and `spec` folded into `sources`. */\nexport type ResolvedGraphqlOptions = z.output<typeof graphqlOptionsSchema>;\n\nexport type GraphqlAdapter = AdapterDescriptor<\"graphql\", GraphqlOptions>;\n\n/** A `graphql()` descriptor as the config schema resolves it. */\nexport type ResolvedGraphqlAdapter = AdapterDescriptor<\n \"graphql\",\n ResolvedGraphqlOptions\n>;\n\nexport const graphqlAdapterSchema = adapterDescriptorSchema(\n \"graphql\",\n graphqlOptionsSchema\n);\n\n/**\n * A GraphQL reference. Blume lowers the schema (SDL or introspection JSON) to\n * one real page per root field — grouped as Queries/Mutations/Subscriptions —\n * plus one page per named type (Objects, Input Objects, Enums, Interfaces,\n * Unions, Scalars), all included in the sidebar, search, llms.txt, and OG.\n * Always Blume-rendered: the Scalar embed reads OpenAPI and AsyncAPI\n * documents only, so there is no `scalar()` counterpart.\n */\nexport const graphql = (options: GraphqlOptions): GraphqlAdapter => ({\n kind: \"graphql\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
91
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport {\n liftSpec,\n referenceSourceSchema,\n hasSources,\n missingSourcesIssue,\n rendererRemovedHint,\n sharedOptions,\n} from \"./options.ts\";\nimport type { PlaygroundOptions, ReferenceSourceOptions } from \"./options.ts\";\n\n/** Options for {@link openapi}. */\nexport interface OpenApiOptions {\n /** Code-sample languages shown per operation (Blume renderer). Defaults to `[\"curl\", \"js\", \"python\"]`. */\n codeSamples?: string[];\n /** Start nested schema rows expanded rather than collapsed (Blume renderer). Defaults to `false`. */\n expandSchemas?: boolean;\n /**\n * The interactive \"Try it\" panel (Blume renderer). On by default; `false`\n * hides it. The object form sets `proxy`, the CORS escape hatch the Send\n * button routes requests through: a proxy URL, or `true` for the built-in\n * `/_api-proxy` endpoint (which needs server output: a host adapter such as\n * `vercel()` in `deployment`).\n */\n playground?: PlaygroundOptions;\n /** Where the reference mounts. Defaults to `/reference`. */\n route?: string;\n /** One or more specs; each renders on its own route by default. */\n sources?: ReferenceSourceOptions[];\n /** Shorthand for a single source: `sources: [{ spec }]`. */\n spec?: string;\n}\n\nexport const openapiOptionsSchema = z\n .strictObject(\n {\n ...sharedOptions({\n codeSamples: [\"curl\", \"js\", \"python\"],\n route: \"/reference\",\n }),\n /** Start nested schema rows expanded rather than collapsed (Blume renderer). */\n expandSchemas: z.boolean().default(false),\n /** One or more specs; each renders on its own route by default. */\n sources: z.array(referenceSourceSchema).default([]),\n },\n rendererRemovedHint\n )\n .transform(liftSpec(referenceSourceSchema))\n .refine(hasSources, missingSourcesIssue(\"openapi\"));\n\n/** `openapi()` options with every default applied and `spec` folded into `sources`. */\nexport type ResolvedOpenApiOptions = z.output<typeof openapiOptionsSchema>;\n\nexport type OpenApiAdapter = AdapterDescriptor<\"openapi\", OpenApiOptions>;\n\n/** An `openapi()` descriptor as the config schema resolves it. */\nexport type ResolvedOpenApiAdapter = AdapterDescriptor<\n \"openapi\",\n ResolvedOpenApiOptions\n>;\n\nexport const openapiAdapterSchema = adapterDescriptorSchema(\n \"openapi\",\n openapiOptionsSchema\n);\n\n/**\n * An OpenAPI reference. Blume parses the spec with Scalar's parser and renders\n * its own UI: one real page per operation, grouped by tag in the sidebar and\n * included in site search, llms.txt, and OG. To embed the Scalar SPA instead\n * (a single self-contained route that doesn't weave into the sidebar or\n * search), list a `scalar()` adapter. Blume's renderer parses at generate\n * time and needs no runtime dependency.\n */\nexport const openapi = (options: OpenApiOptions): OpenApiAdapter => ({\n kind: \"openapi\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
92
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor, JsonValue } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport { hasSources, missingSourcesIssue } from \"./options.ts\";\n\n/**\n * What the generated Scalar page imports. Declared on every `scalar()`\n * descriptor so the generated project lists it, which is what lets Astro's\n * framework-package crawl bundle the embed.\n */\nexport const SCALAR_RUNTIME_DEPS: readonly string[] = [\"@scalar/astro\"];\n\n/**\n * A single document rendered by a `scalar()` reference. Scalar reads OpenAPI\n * and AsyncAPI documents and detects which it was given, so there is one\n * source shape for both. The embed sits outside Blume's search and llms.txt,\n * so of the native per-source controls only `noindex` applies here.\n */\nexport const scalarSourceSchema = z.strictObject({\n /** Nav/section label for this source. */\n label: z.string().optional(),\n /** Emit noindex metadata and omit the page from the sitemap. */\n noindex: z.boolean().default(false),\n /** Per-source route; defaults to the adapter's `route` (or a derived path). */\n route: z.string().optional(),\n /** Local path or `http(s)` URL to the OpenAPI or AsyncAPI document. */\n spec: z.string(),\n});\n\n/** One document source, as `scalar()` accepts it. */\nexport interface ScalarSourceOptions {\n /** Nav/section label for this source. */\n label?: string;\n /** Emit noindex metadata and omit the page from the sitemap. Defaults to `false`. */\n noindex?: boolean;\n /** Per-source route; defaults to the adapter's `route` (or a derived path). */\n route?: string;\n /** Local path or `http(s)` URL to the OpenAPI or AsyncAPI document. */\n spec: string;\n}\n\n/** A source with every default applied. */\nexport type ResolvedScalarSource = z.output<typeof scalarSourceSchema>;\n\n/**\n * `scalar()` options with every default applied and `spec` folded into\n * `sources`; every key beyond the named ones is forwarded Scalar config.\n */\nexport type ResolvedScalarOptions = {\n route: string;\n sources: ResolvedScalarSource[];\n theme?: string;\n} & { [option: string]: JsonValue };\n\n/** The options {@link scalar} maps itself. */\nexport interface ScalarNamedOptions {\n /** Where the reference mounts. Defaults to `/reference`. */\n route?: string;\n /** One or more documents; each renders on its own route by default. */\n sources?: ScalarSourceOptions[];\n /** Shorthand for a single source: `sources: [{ spec }]`. */\n spec?: string;\n /** A Scalar theme name (`purple`, `moon`, …). Unset keeps Scalar's default theme with Blume's accent and radius layered on top. */\n theme?: string;\n}\n\n/**\n * Options for {@link scalar}: the source, route, and `theme` Blume maps, plus\n * any other [Scalar configuration](https://github.com/scalar/scalar/blob/main/documentation/configuration.md)\n * key, forwarded verbatim to the embedded `<ScalarComponent>` (`localization`,\n * `agent`, `hideTestRequestButton`, `orderSchemaPropertiesBy`, …). Blume\n * doesn't mirror Scalar's config surface, so this is a full escape hatch: a\n * forwarded key wins over Blume's own derived spec/theme config. JSON values\n * only — the configuration is inlined into the generated page. `sources` is\n * Blume's (one page per document); Scalar's own multi-document `sources`\n * can't be forwarded.\n */\nexport type ScalarOptions = ScalarNamedOptions & {\n [option: string]: JsonValue;\n};\n\n/**\n * `spec` is the single-source shorthand and folds into `sources` at parse\n * (through the source schema, so the two can never drift); every key beyond\n * the named ones is Scalar configuration and passes through untouched.\n */\nexport const scalarOptionsSchema = z\n .object({\n /** Where the reference mounts. */\n route: z.string().default(\"/reference\"),\n /** One or more documents; each renders on its own route by default. */\n sources: z.array(scalarSourceSchema).default([]),\n /** Shorthand for a single source: `sources: [{ spec }]`. */\n spec: z.string().optional(),\n /** A Scalar theme name; unset layers Blume's accent and radius on Scalar's default theme. */\n theme: z.string().optional(),\n })\n .catchall(z.json())\n .transform(({ spec, sources, ...options }): ResolvedScalarOptions => ({\n ...options,\n sources:\n spec === undefined\n ? sources\n : [scalarSourceSchema.parse({ spec }), ...sources],\n }))\n .refine(hasSources, missingSourcesIssue(\"scalar\"));\n\nexport type ScalarAdapter = AdapterDescriptor<\"scalar\", ScalarOptions>;\n\n/** A `scalar()` descriptor as the config schema resolves it. */\nexport type ResolvedScalarAdapter = AdapterDescriptor<\n \"scalar\",\n ResolvedScalarOptions\n>;\n\nexport const scalarAdapterSchema = adapterDescriptorSchema(\n \"scalar\",\n scalarOptionsSchema\n);\n\n/**\n * An API reference rendered by [Scalar](https://scalar.com)'s self-contained\n * UI — its own sidebar, search, theme, and request client on a single route —\n * instead of Blume's native operation pages. Takes an OpenAPI or AsyncAPI\n * document (Scalar detects which); a GraphQL schema has no Scalar embed.\n * Blume's per-page controls don't apply: the embed doesn't weave into the\n * sidebar, search, or llms.txt, and it brings its own request client in place\n * of the Try it playground.\n */\nexport const scalar = (options: ScalarOptions): ScalarAdapter => ({\n kind: \"scalar\",\n options,\n requiredSecrets: [],\n runtimeDeps: [...SCALAR_RUNTIME_DEPS],\n});\n",
|
|
93
|
+
"import { z } from \"zod\";\n\nimport type { KeylessSearchOptions, SearchAdapter } from \"./types.ts\";\n\n/** Orama takes no options; unknown keys fail config validation. */\nexport type OramaOptions = KeylessSearchOptions;\n\nexport type OramaAdapter = SearchAdapter<\"orama\", \"static\", OramaOptions>;\n\nexport const oramaOptionsSchema = z.strictObject({});\n\n/**\n * Blume's default search: a JSON index built from the source files, served\n * at `/blume-search.json` and queried in the browser. Keyless, and live in\n * `blume dev`. The tokenizer follows `i18n.defaultLocale`, so non-Latin\n * scripts are word-segmented.\n */\nexport const orama = (options: OramaOptions = {}): OramaAdapter => ({\n kind: \"orama\",\n mode: \"static\",\n options,\n requiredSecrets: [],\n runtimeDeps: [\"@orama/orama\"],\n});\n",
|
|
94
|
+
"import { z } from \"zod\";\n\nimport { adapterDescriptorSchema } from \"../../core/adapter.ts\";\nimport { algolia, algoliaOptionsSchema } from \"./algolia.ts\";\nimport type { AlgoliaAdapter } from \"./algolia.ts\";\nimport { flexsearch, flexsearchOptionsSchema } from \"./flexsearch.ts\";\nimport type { FlexsearchAdapter } from \"./flexsearch.ts\";\nimport { mixedbread, mixedbreadOptionsSchema } from \"./mixedbread.ts\";\nimport type { MixedbreadAdapter } from \"./mixedbread.ts\";\nimport { oramaCloud, oramaCloudOptionsSchema } from \"./orama-cloud.ts\";\nimport type { OramaCloudAdapter } from \"./orama-cloud.ts\";\nimport { orama, oramaOptionsSchema } from \"./orama.ts\";\nimport type { OramaAdapter } from \"./orama.ts\";\nimport { pagefind, pagefindOptionsSchema } from \"./pagefind.ts\";\nimport type { PagefindAdapter } from \"./pagefind.ts\";\nimport type {\n KeylessSearchOptions,\n SearchAdapter,\n SearchAdapterMode,\n} from \"./types.ts\";\nimport { typesense, typesenseOptionsSchema } from \"./typesense.ts\";\nimport type { TypesenseAdapter } from \"./typesense.ts\";\n\n/** Every descriptor a factory can return. */\nexport type AnySearchAdapter =\n | AlgoliaAdapter\n | FlexsearchAdapter\n | MixedbreadAdapter\n | OramaAdapter\n | OramaCloudAdapter\n | PagefindAdapter\n | TypesenseAdapter;\n\n/** The resolved form of `search: false`: search is disabled. */\nexport type NoneSearchAdapter = SearchAdapter<\n \"none\",\n \"none\",\n KeylessSearchOptions\n>;\n\n/** What `config.search.provider` resolves to: an adapter, or `none`. */\nexport type ResolvedSearchAdapter = AnySearchAdapter | NoneSearchAdapter;\n\n/** Every adapter identity, including the resolved `none`. */\nexport type SearchAdapterKind = ResolvedSearchAdapter[\"kind\"];\n\nexport const NONE_SEARCH_ADAPTER: NoneSearchAdapter = {\n kind: \"none\",\n mode: \"none\",\n options: {},\n requiredSecrets: [],\n runtimeDeps: [],\n};\n\n/**\n * The descriptor shape a factory returns: the shared adapter contract plus\n * the search-specific `mode`. Only `kind` and `options` carry information —\n * the metadata lists are validated for shape, then re-derived from the\n * factory below so a descriptor that went through JSON resolves to the same\n * canonical metadata Blume ships.\n */\nconst descriptor = <\n Kind extends string,\n Mode extends SearchAdapterMode,\n Options extends z.ZodType,\n>(\n kind: Kind,\n mode: Mode,\n options: Options\n) => adapterDescriptorSchema(kind, options).extend({ mode: z.literal(mode) });\n\n/** One variant per public adapter factory. */\nconst adapterVariants = [\n descriptor(\"algolia\", \"hosted\", algoliaOptionsSchema),\n descriptor(\"flexsearch\", \"static\", flexsearchOptionsSchema),\n descriptor(\"mixedbread\", \"server\", mixedbreadOptionsSchema),\n descriptor(\"orama\", \"static\", oramaOptionsSchema),\n descriptor(\"orama-cloud\", \"hosted\", oramaCloudOptionsSchema),\n descriptor(\"pagefind\", \"pagefind\", pagefindOptionsSchema),\n descriptor(\"typesense\", \"hosted\", typesenseOptionsSchema),\n] as const;\n\n/** What a public factory returns, as the config schema accepts it. */\nexport type SearchAdapterInput = z.input<(typeof adapterVariants)[number]>;\n\n/**\n * Validates a descriptor — one a factory returned, or the `none` descriptor\n * the config schema substitutes for `false` — and resolves it to the\n * canonical form, so every consumer reads `mode`, `runtimeDeps`, and\n * `requiredSecrets` straight off the descriptor. `none` is internal: it is\n * not part of {@link SearchAdapterInput}, so `search: { kind: \"none\" }` is a\n * type error even though the runtime schema admits it.\n */\nexport const resolvedSearchAdapterSchema = z\n .discriminatedUnion(\"kind\", [\n ...adapterVariants,\n descriptor(\"none\", \"none\", z.strictObject({})),\n ])\n .transform((value): ResolvedSearchAdapter => {\n switch (value.kind) {\n case \"algolia\": {\n return algolia(value.options);\n }\n case \"flexsearch\": {\n return flexsearch(value.options);\n }\n case \"mixedbread\": {\n return mixedbread(value.options);\n }\n case \"none\": {\n return NONE_SEARCH_ADAPTER;\n }\n case \"orama\": {\n return orama(value.options);\n }\n case \"orama-cloud\": {\n return oramaCloud(value.options);\n }\n case \"pagefind\": {\n return pagefind(value.options);\n }\n default: {\n // Only Typesense is left, and TypeScript has narrowed `value` to it.\n // It returns after the switch rather than from a last case block:\n // Bun 1.4.0's line coverage never credits the closing brace of a\n // switch's final block, which would fail the 100% gate in CI.\n break;\n }\n }\n return typesense(value.options);\n });\n",
|
|
95
|
+
"import { z } from \"zod\";\n\nimport type { JsonValue } from \"../../core/adapter.ts\";\nimport type { SearchAdapter } from \"./types.ts\";\n\n/**\n * Public Algolia credentials. The browser queries the index with the\n * search-only `apiKey`; the build-time sync replaces the index with the admin\n * key from `ALGOLIA_ADMIN_API_KEY`, which never enters the config.\n */\nexport interface AlgoliaNamedOptions {\n appId: string;\n /** The search-only API key (public — it ships to the browser). */\n apiKey: string;\n indexName: string;\n}\n\n/**\n * Options for {@link algolia}: the named options plus any other client\n * option, forwarded to the browser verbatim. JSON values only.\n */\nexport type AlgoliaOptions = AlgoliaNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport type AlgoliaAdapter = SearchAdapter<\"algolia\", \"hosted\", AlgoliaOptions>;\n\nexport const algoliaOptionsSchema = z\n .object({\n apiKey: z.string(),\n appId: z.string(),\n indexName: z.string(),\n })\n .catchall(z.json());\n\n/**\n * Hosted search on Algolia. Each `blume build` replaces the whole index with\n * the current records, so deleted or renamed pages don't linger as stale hits.\n */\nexport const algolia = (options: AlgoliaOptions): AlgoliaAdapter => ({\n kind: \"algolia\",\n mode: \"hosted\",\n options,\n requiredSecrets: [],\n runtimeDeps: [\"algoliasearch\"],\n});\n",
|
|
96
|
+
"import { z } from \"zod\";\n\nimport type { KeylessSearchOptions, SearchAdapter } from \"./types.ts\";\n\n/** FlexSearch takes no options; unknown keys fail config validation. */\nexport type FlexsearchOptions = KeylessSearchOptions;\n\nexport type FlexsearchAdapter = SearchAdapter<\n \"flexsearch\",\n \"static\",\n FlexsearchOptions\n>;\n\nexport const flexsearchOptionsSchema = z.strictObject({});\n\n/**\n * A second keyless, client-side engine. It loads the same `/blume-search.json`\n * index Orama ships and builds a FlexSearch document index in the browser.\n * No locale-aware tokenizer, so prefer Orama for non-Latin scripts.\n */\nexport const flexsearch = (\n options: FlexsearchOptions = {}\n): FlexsearchAdapter => ({\n kind: \"flexsearch\",\n mode: \"static\",\n options,\n requiredSecrets: [],\n runtimeDeps: [\"flexsearch\"],\n});\n",
|
|
97
|
+
"import { z } from \"zod\";\n\nimport type { JsonValue } from \"../../core/adapter.ts\";\nimport type { SearchAdapter } from \"./types.ts\";\n\n/**\n * The Mixedbread store the generated `/api/search` endpoint queries, plus any\n * other option, forwarded to the endpoint verbatim. JSON values only.\n */\nexport interface MixedbreadOptions {\n storeId: string;\n [option: string]: JsonValue;\n}\n\nexport type MixedbreadAdapter = SearchAdapter<\n \"mixedbread\",\n \"server\",\n MixedbreadOptions\n>;\n\nexport const mixedbreadOptionsSchema = z\n .object({\n storeId: z.string(),\n })\n .catchall(z.json());\n\n/**\n * Semantic search on Mixedbread. Queries go through a generated `/api/search`\n * endpoint that holds `MIXEDBREAD_API_KEY`, so the adapter requires server\n * output. Content is synced to the store out-of-band with the `mxbai` CLI,\n * not by the build.\n */\nexport const mixedbread = (options: MixedbreadOptions): MixedbreadAdapter => ({\n kind: \"mixedbread\",\n mode: \"server\",\n options,\n requiredSecrets: [\"MIXEDBREAD_API_KEY\"],\n runtimeDeps: [\"@mixedbread/sdk\"],\n});\n",
|
|
98
|
+
"import { z } from \"zod\";\n\nimport type { JsonValue } from \"../../core/adapter.ts\";\nimport type { SearchAdapter } from \"./types.ts\";\n\n/**\n * Public Orama Cloud credentials. The browser queries `endpoint` with the\n * public `apiKey`; the build-time sync pushes records to `indexId` with\n * `ORAMA_PRIVATE_API_KEY`, which never enters the config.\n */\nexport interface OramaCloudNamedOptions {\n /** The public API key (it ships to the browser). */\n apiKey: string;\n endpoint: string;\n /** Index id used by the build-time sync; omit to skip syncing. */\n indexId?: string;\n}\n\n/**\n * Options for {@link oramaCloud}: the named options plus any other client\n * option, forwarded to the browser verbatim. JSON values only.\n */\nexport type OramaCloudOptions = OramaCloudNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport type OramaCloudAdapter = SearchAdapter<\n \"orama-cloud\",\n \"hosted\",\n OramaCloudOptions\n>;\n\nexport const oramaCloudOptionsSchema = z\n .object({\n apiKey: z.string(),\n endpoint: z.string(),\n indexId: z.string().optional(),\n })\n .catchall(z.json());\n\n/**\n * Hosted Orama. The browser queries your index endpoint directly; each\n * `blume build` snapshots the records into the index and deploys it.\n */\nexport const oramaCloud = (options: OramaCloudOptions): OramaCloudAdapter => ({\n kind: \"orama-cloud\",\n mode: \"hosted\",\n options,\n requiredSecrets: [],\n runtimeDeps: [\"@oramacloud/client\"],\n});\n",
|
|
99
|
+
"import { z } from \"zod\";\n\nimport type { KeylessSearchOptions, SearchAdapter } from \"./types.ts\";\n\n/** Pagefind takes no options; unknown keys fail config validation. */\nexport type PagefindOptions = KeylessSearchOptions;\n\nexport type PagefindAdapter = SearchAdapter<\n \"pagefind\",\n \"pagefind\",\n PagefindOptions\n>;\n\nexport const pagefindOptionsSchema = z.strictObject({});\n\n/**\n * Pagefind indexes the built HTML after `blume build` and loads the index in\n * shards on demand, so the initial payload stays small on very large sites.\n * The index only exists in the production build, not in `blume dev`.\n */\nexport const pagefind = (options: PagefindOptions = {}): PagefindAdapter => ({\n kind: \"pagefind\",\n mode: \"pagefind\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
100
|
+
"import { z } from \"zod\";\n\nimport type { JsonValue } from \"../../core/adapter.ts\";\nimport type { SearchAdapter } from \"./types.ts\";\n\n/**\n * Connection details for a self-hosted or cloud Typesense node. The browser\n * queries the collection with the search-only `apiKey`; the build-time sync\n * recreates the collection with `TYPESENSE_ADMIN_API_KEY`, which never enters\n * the config.\n */\nexport interface TypesenseNamedOptions {\n /** The search-only API key (public — it ships to the browser). */\n apiKey: string;\n collection: string;\n host: string;\n /** Defaults to 443. */\n port?: number;\n /** Defaults to `https`. */\n protocol?: \"http\" | \"https\";\n}\n\n/**\n * Options for {@link typesense}: the named options plus any other client\n * option, forwarded to the browser verbatim. JSON values only.\n */\nexport type TypesenseOptions = TypesenseNamedOptions & {\n [option: string]: JsonValue;\n};\n\nexport type TypesenseAdapter = SearchAdapter<\n \"typesense\",\n \"hosted\",\n TypesenseOptions\n>;\n\nexport const typesenseOptionsSchema = z\n .object({\n apiKey: z.string(),\n collection: z.string(),\n host: z.string(),\n port: z.number().int().positive().optional(),\n protocol: z.enum([\"http\", \"https\"]).optional(),\n })\n .catchall(z.json());\n\n/**\n * Hosted search on Typesense. Each `blume build` drops and recreates the\n * collection so deleted or renamed pages don't linger as stale hits.\n */\nexport const typesense = (options: TypesenseOptions): TypesenseAdapter => ({\n kind: \"typesense\",\n mode: \"hosted\",\n options,\n requiredSecrets: [],\n runtimeDeps: [\"typesense\"],\n});\n",
|
|
101
|
+
"/** Frontmatter defense in depth: only a real string can carry a handle. */\nconst isString = <Value>(value: Value): value is Value & string =>\n typeof value === \"string\";\n\n/**\n * Normalize an X account to the leading `@` that `twitter:site`/`twitter:creator`\n * require, so `acme`, `@acme`, and ` @acme ` all land on `@acme`. Empty or\n * blank input yields undefined, which renders no tag at all.\n *\n * The layouts call this on values that never passed through the config schema:\n * Astro's collections carry no schema here, so a page's `seo.x.creator` reaches\n * them as raw frontmatter, and the schema's own transform never runs on it.\n * (Blume's page pipeline does reject a non-string `creator` before the page is\n * built, so the string guard is defense in depth rather than the expected\n * path.)\n */\nexport const normalizeXHandle = <Value>(value: Value): string | undefined => {\n if (!isString(value)) {\n return;\n }\n const handle = value.trim().replace(/^@+/u, \"\");\n return handle ? `@${handle}` : undefined;\n};\n",
|
|
102
|
+
"import { z } from \"zod\";\n\nimport { contentful, contentfulAdapterSchema } from \"./contentful.ts\";\nimport type { ContentfulAdapter } from \"./contentful.ts\";\nimport { custom, customAdapterSchema } from \"./custom.ts\";\nimport type { CustomAdapter } from \"./custom.ts\";\nimport { filesystem, filesystemAdapterSchema } from \"./filesystem.ts\";\nimport type { FilesystemAdapter } from \"./filesystem.ts\";\nimport {\n githubReleases,\n githubReleasesAdapterSchema,\n} from \"./github-releases.ts\";\nimport type { GithubReleasesAdapter } from \"./github-releases.ts\";\nimport { mdxRemote, mdxRemoteAdapterSchema } from \"./mdx-remote.ts\";\nimport type { MdxRemoteAdapter } from \"./mdx-remote.ts\";\nimport { notion, notionAdapterSchema } from \"./notion.ts\";\nimport type { NotionAdapter } from \"./notion.ts\";\nimport { obsidian, obsidianAdapterSchema } from \"./obsidian.ts\";\nimport type { ObsidianAdapter } from \"./obsidian.ts\";\nimport { payload, payloadAdapterSchema } from \"./payload.ts\";\nimport type { PayloadAdapter } from \"./payload.ts\";\nimport { sanity, sanityAdapterSchema } from \"./sanity.ts\";\nimport type { SanityAdapter } from \"./sanity.ts\";\nimport { strapi, strapiAdapterSchema } from \"./strapi.ts\";\nimport type { StrapiAdapter } from \"./strapi.ts\";\n\n/** Every descriptor a `blume/sources` factory can return. */\nexport type AnySourceAdapter =\n | FilesystemAdapter\n | MdxRemoteAdapter\n | GithubReleasesAdapter\n | SanityAdapter\n | NotionAdapter\n | ContentfulAdapter\n | PayloadAdapter\n | StrapiAdapter\n | ObsidianAdapter\n | CustomAdapter;\n\n/** Every adapter identity. */\nexport type SourceAdapterKind = AnySourceAdapter[\"kind\"];\n\n/** One variant per public adapter factory. */\nconst adapterVariants = [\n filesystemAdapterSchema,\n mdxRemoteAdapterSchema,\n githubReleasesAdapterSchema,\n sanityAdapterSchema,\n notionAdapterSchema,\n contentfulAdapterSchema,\n payloadAdapterSchema,\n strapiAdapterSchema,\n obsidianAdapterSchema,\n customAdapterSchema,\n] as const;\n\nconst sourceAdapterUnion = z.discriminatedUnion(\"kind\", adapterVariants);\n\n/** What a public factory returns, as the config schema accepts it. */\nexport type SourceAdapterInput = z.input<typeof sourceAdapterUnion>;\n\n/**\n * A validated descriptor: the adapter's options with their defaults applied\n * (a `filesystem()` entry always carries `root`/`include`/`exclude`), and the\n * metadata lists re-derived from the factory so every consumer reads the\n * `runtimeDeps` and `requiredSecrets` this version of Blume ships.\n */\nexport type ContentSourceAdapter = z.output<typeof sourceAdapterUnion>;\n\n/** The factory name the 1.x `type` discriminator maps to, for the hint below. */\nconst FACTORY_FOR_TYPE = new Map([\n [\"custom\", \"custom\"],\n [\"filesystem\", \"filesystem\"],\n [\"github-releases\", \"githubReleases\"],\n [\"mdx-remote\", \"mdxRemote\"],\n [\"notion\", \"notion\"],\n [\"obsidian\", \"obsidian\"],\n [\"sanity\", \"sanity\"],\n]);\n\nconst FACTORIES_HINT =\n 'content.sources takes adapters imported from \"blume/sources\" — filesystem({ root }), mdxRemote({ github }), githubReleases({ owner, repo }), sanity({ projectId, dataset, query }), notion({ database }), contentful({ space, contentType }), payload({ url, collection }), strapi({ url, contentType }), obsidian({ vault }), or custom(source).';\n\nconst ARRAY_HINT = `content.sources is a list of adapters — e.g. \\`sources: [filesystem({ root: \"docs\" }), githubReleases({ owner, repo, prefix: \"changelog\" })]\\`, imported from \"blume/sources\".`;\n\nconst isObjectLike = (value: unknown): value is object =>\n typeof value === \"object\" && value !== null;\n\n/** The 1.x object form's discriminator, when an entry carries one. */\nconst legacyEntrySchema = z.looseObject({ type: z.string() });\n\n/**\n * The message for an entry that is not a descriptor. A 1.x `{ type: \"…\" }`\n * object names the factory that replaces it, so the fix is a rename plus\n * moving the remaining fields into the call.\n */\nconst entryHint = (type: string | undefined): string => {\n if (type === undefined) {\n return FACTORIES_HINT;\n }\n const factory = FACTORY_FOR_TYPE.get(type);\n if (!factory) {\n return `${FACTORIES_HINT} The 1.x { type: \"${type}\" } object form was removed.`;\n }\n const call =\n type === \"custom\"\n ? \"custom(source) with the source you passed as `source`\"\n : `${factory}({ … }) with the other fields as its options`;\n return `${FACTORIES_HINT} The 1.x { type: \"${type}\", … } object was removed: replace it with ${call}.`;\n};\n\n/**\n * Validates a descriptor a factory returned and resolves it to the canonical\n * form, so a descriptor that went through JSON (or was edited by hand)\n * resolves to the same metadata Blume ships.\n */\nexport const resolvedSourceAdapterSchema = sourceAdapterUnion.transform(\n (value): ContentSourceAdapter => {\n switch (value.kind) {\n case \"filesystem\": {\n return { ...filesystem(value.options), options: value.options };\n }\n case \"github-releases\": {\n return { ...githubReleases(value.options), options: value.options };\n }\n case \"mdx-remote\": {\n return { ...mdxRemote(value.options), options: value.options };\n }\n case \"notion\": {\n return { ...notion(value.options), options: value.options };\n }\n case \"contentful\": {\n return { ...contentful(value.options), options: value.options };\n }\n case \"payload\": {\n return { ...payload(value.options), options: value.options };\n }\n case \"strapi\": {\n return { ...strapi(value.options), options: value.options };\n }\n case \"obsidian\": {\n return { ...obsidian(value.options), options: value.options };\n }\n case \"sanity\": {\n return { ...sanity(value.options), options: value.options };\n }\n default: {\n // Only `custom` is left, and TypeScript has narrowed `value` to it.\n // It returns after the switch rather than from a last case block:\n // Bun 1.4.0's line coverage never credits the closing brace of a\n // switch's final block, which would fail the 100% gate in CI.\n break;\n }\n }\n return custom(value.options);\n }\n);\n\n/**\n * One `content.sources` entry. Anything without a `kind` — the 1.x `{ type }`\n * object, a string, `null` — fails here with the factory hint instead of the\n * union's opaque \"invalid discriminator\" message.\n */\nconst sourceEntrySchema = z\n .custom<SourceAdapterInput>(\n (value) => isObjectLike(value) && \"kind\" in value,\n {\n error: (issue) => {\n const legacy = legacyEntrySchema.safeParse(issue.input);\n return entryHint(legacy.success ? legacy.data.type : undefined);\n },\n }\n )\n .pipe(resolvedSourceAdapterSchema);\n\n/**\n * `content.sources`: the adapters to read, in order. A non-array (the 1.x\n * object form, say) fails with the list hint; entry errors keep their own.\n */\nexport const contentSourcesSchema = z.array(sourceEntrySchema, {\n error: (issue) => (issue.code === \"invalid_type\" ? ARRAY_HINT : undefined),\n});\n",
|
|
103
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions, SourceFieldMap } from \"./shared.ts\";\nimport {\n queryParamsSchema,\n sharedSourceOptionsSchema,\n sourceFieldMapSchema,\n} from \"./shared.ts\";\n\n/** Options for {@link contentful}. */\nexport interface ContentfulOptions extends SharedSourceOptions {\n /** The content type id whose entries become pages. */\n contentType: string;\n /** Environment id. Defaults to `master`. */\n environment?: string;\n /**\n * Field ids mapping an entry onto Blume meta + body; `sys.<key>` reaches\n * the entry's `sys`. Defaults to `title` / `description` / `slug` / `body`\n * / `sys.updatedAt`.\n */\n fields?: SourceFieldMap;\n /** Locale code to fetch; omit for the space's default locale. */\n locale?: string;\n /** Extra query parameters for the entries request (`\"fields.section\": \"sdk\"`). */\n params?: Record<string, string>;\n /** Space id. */\n space: string;\n}\n\nexport const contentfulOptionsSchema = sharedSourceOptionsSchema.extend({\n contentType: z.string(),\n environment: z.string().optional(),\n fields: sourceFieldMapSchema.optional(),\n locale: z.string().optional(),\n params: queryParamsSchema.optional(),\n space: z.string(),\n});\n\nexport type ContentfulAdapter = AdapterDescriptor<\n \"contentful\",\n ContentfulOptions\n>;\n\nexport const contentfulAdapterSchema = adapterDescriptorSchema(\n \"contentful\",\n contentfulOptionsSchema\n);\n\n/**\n * A Contentful content type read through the Delivery API; rich text bodies\n * become Markdown. The Delivery token comes from `CONTENTFUL_ACCESS_TOKEN`,\n * and `--preview` reads drafts through the Preview API with\n * `CONTENTFUL_PREVIEW_TOKEN`. Nothing to install: the adapter speaks the\n * REST API directly.\n */\nexport const contentful = (options: ContentfulOptions): ContentfulAdapter => ({\n kind: \"contentful\",\n options,\n requiredSecrets: [\"CONTENTFUL_ACCESS_TOKEN\"],\n runtimeDeps: [],\n});\n",
|
|
104
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { ContentSource } from \"../core/sources/types.ts\";\n\n/** A user-provided {@link ContentSource} instance, validated for `name` + `load`. */\nexport const customOptionsSchema = z.custom<ContentSource>(\n (value): value is ContentSource =>\n typeof value === \"object\" &&\n value !== null &&\n \"load\" in value &&\n typeof value.load === \"function\" &&\n \"name\" in value &&\n typeof value.name === \"string\",\n { message: \"custom() takes a ContentSource (an object with name + load)\" }\n);\n\nexport type CustomAdapter = AdapterDescriptor<\"custom\", ContentSource>;\n\nexport const customAdapterSchema = adapterDescriptorSchema(\n \"custom\",\n customOptionsSchema\n);\n\n/**\n * Any object implementing the {@link ContentSource} interface, passed straight\n * through. This is the extension point for adapters with custom serializers or\n * any other backend, without their SDKs touching core. Unlike the built-in\n * adapters the descriptor carries a live instance, so it never travels through\n * the generated project's data snapshot — the CLI consumes it at scan time.\n */\nexport const custom = (source: ContentSource): CustomAdapter => ({\n kind: \"custom\",\n options: source,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
105
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions } from \"./shared.ts\";\nimport { sharedSourceOptionsSchema } from \"./shared.ts\";\n\n/** Options for {@link githubReleases}. */\nexport interface GithubReleasesOptions extends SharedSourceOptions {\n /** Include draft releases (needs a token with repo write access). */\n drafts?: boolean;\n /** Cap the number of releases materialized, newest-first. Defaults to 100. */\n limit?: number;\n /** Repository owner (user or org). */\n owner: string;\n /** Include prereleases. */\n prereleases?: boolean;\n /** Repository name. */\n repo: string;\n}\n\nexport const githubReleasesOptionsSchema = sharedSourceOptionsSchema.extend({\n drafts: z.boolean().optional(),\n limit: z.number().positive().optional(),\n owner: z.string(),\n prereleases: z.boolean().optional(),\n repo: z.string(),\n});\n\nexport type GithubReleasesAdapter = AdapterDescriptor<\n \"github-releases\",\n GithubReleasesOptions\n>;\n\nexport const githubReleasesAdapterSchema = adapterDescriptorSchema(\n \"github-releases\",\n githubReleasesOptionsSchema\n);\n\n/**\n * A repo's GitHub Releases, materialized as `type: changelog` entries — release\n * notes become the changelog with no files to maintain. A private repo reads a\n * token from `GITHUB_TOKEN`; it is never inlined here.\n */\nexport const githubReleases = (\n options: GithubReleasesOptions\n): GithubReleasesAdapter => ({\n kind: \"github-releases\",\n options,\n requiredSecrets: [\"GITHUB_TOKEN\"],\n runtimeDeps: [],\n});\n",
|
|
106
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions } from \"./shared.ts\";\nimport { DEFAULT_CONTENT_GLOB, sharedSourceOptionsSchema } from \"./shared.ts\";\n\n/** Options for {@link mdxRemote}. */\nexport interface MdxRemoteOptions extends SharedSourceOptions {\n /** Explicit list of source-relative file paths to fetch from `url`. */\n files?: string[];\n /** Enumerate a GitHub repo subtree via the git-trees API. */\n github?: {\n /** Repository owner (user or org). */\n owner: string;\n /** Subpath within the repo. Defaults to the repo root. */\n path?: string;\n /** Git ref (branch, tag, or SHA). Defaults to `main`. */\n ref?: string;\n /** Repository name. */\n repo: string;\n };\n /** Glob patterns applied to enumerated refs. Defaults to `[\"**\\/*.{md,mdx}\"]`. */\n include?: string[];\n /** Raw base URL, e.g. `https://raw.githubusercontent.com/acme/sdk/main/docs`. */\n url?: string;\n}\n\nexport const mdxRemoteOptionsSchema = sharedSourceOptionsSchema.extend({\n files: z.array(z.string()).optional(),\n github: z\n .strictObject({\n owner: z.string(),\n path: z.string().default(\"\"),\n ref: z.string().default(\"main\"),\n repo: z.string(),\n })\n .optional(),\n include: z.array(z.string()).default([DEFAULT_CONTENT_GLOB]),\n url: z.string().optional(),\n});\n\nexport type MdxRemoteAdapter = AdapterDescriptor<\n \"mdx-remote\",\n MdxRemoteOptions\n>;\n\nexport const mdxRemoteAdapterSchema = adapterDescriptorSchema(\n \"mdx-remote\",\n mdxRemoteOptionsSchema\n);\n\n// The hosts the source ever sends `GITHUB_TOKEN` to (the same set the fetch\n// in core/sources/mdx-remote.ts checks), so only an adapter reading from\n// GitHub declares the variable.\nconst GITHUB_HOSTS = new Set([\"api.github.com\", \"raw.githubusercontent.com\"]);\n\nconst readsFromGithub = (options: MdxRemoteOptions): boolean =>\n options.github !== undefined ||\n (options.url !== undefined &&\n URL.canParse(options.url) &&\n GITHUB_HOSTS.has(new URL(options.url).hostname));\n\n/**\n * Remote Markdown/MDX fetched over HTTP. Enumerate files explicitly against a\n * raw `url` base, or from a GitHub repo subtree via `github`. A private repo's\n * token comes from `GITHUB_TOKEN` — never inline it here. The adapter declares\n * the variable only when it reads from GitHub, since a `url` on any other host\n * is never sent the token.\n */\nexport const mdxRemote = (options: MdxRemoteOptions): MdxRemoteAdapter => ({\n kind: \"mdx-remote\",\n options,\n requiredSecrets: readsFromGithub(options) ? [\"GITHUB_TOKEN\"] : [],\n runtimeDeps: [],\n});\n",
|
|
107
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions } from \"./shared.ts\";\nimport { sharedSourceOptionsSchema } from \"./shared.ts\";\n\n/** Options for {@link notion}. */\nexport interface NotionOptions extends SharedSourceOptions {\n /** Max concurrent Notion API requests; default 3 (Notion's per-integration pace). */\n concurrency?: number;\n /** Notion database id. */\n database: string;\n /** Notion property names mapped onto Blume meta. */\n properties?: {\n /** Property holding the page description. */\n description?: string;\n /** Property holding the sort order. */\n order?: string;\n /** Property holding the page slug. */\n slug?: string;\n /** Property holding the publish status. */\n status?: string;\n /** Property holding the page title. */\n title?: string;\n };\n /** Status value treated as published; others map to `draft`. Defaults to `Published`. */\n publishedValue?: string;\n}\n\nexport const notionOptionsSchema = sharedSourceOptionsSchema.extend({\n concurrency: z.number().positive().optional(),\n database: z.string(),\n properties: z\n .strictObject({\n description: z.string().optional(),\n order: z.string().optional(),\n slug: z.string().optional(),\n status: z.string().optional(),\n title: z.string().optional(),\n })\n .optional(),\n publishedValue: z.string().optional(),\n});\n\nexport type NotionAdapter = AdapterDescriptor<\"notion\", NotionOptions>;\n\nexport const notionAdapterSchema = adapterDescriptorSchema(\n \"notion\",\n notionOptionsSchema\n);\n\n/**\n * A Notion database; pages become entries, blocks become MDX. `@notionhq/client`\n * is the declared runtime dependency, and the integration token comes from\n * `NOTION_TOKEN`.\n */\nexport const notion = (options: NotionOptions): NotionAdapter => ({\n kind: \"notion\",\n options,\n requiredSecrets: [\"NOTION_TOKEN\"],\n runtimeDeps: [\"@notionhq/client\"],\n});\n",
|
|
108
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions } from \"./shared.ts\";\nimport { sharedSourceOptionsSchema } from \"./shared.ts\";\n\n/** Options for {@link obsidian}. */\nexport interface ObsidianOptions extends SharedSourceOptions {\n /** Vault folder names to skip at any depth, in addition to dot-folders. */\n exclude?: string[];\n /** Vault directory, absolute or relative to the project root. */\n vault: string;\n}\n\nexport const obsidianOptionsSchema = sharedSourceOptionsSchema.extend({\n exclude: z.array(z.string()).optional(),\n vault: z.string().min(1),\n});\n\nexport type ObsidianAdapter = AdapterDescriptor<\"obsidian\", ObsidianOptions>;\n\nexport const obsidianAdapterSchema = adapterDescriptorSchema(\n \"obsidian\",\n obsidianOptionsSchema\n);\n\n/**\n * An Obsidian vault, read in place. Wikilinks become route links and\n * `%%comments%%` are stripped at load time, so the vault stays the source of\n * truth — no export step and no generated notes in the repo.\n */\nexport const obsidian = (options: ObsidianOptions): ObsidianAdapter => ({\n kind: \"obsidian\",\n options,\n requiredSecrets: [],\n runtimeDeps: [],\n});\n",
|
|
109
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions, SourceFieldMap } from \"./shared.ts\";\nimport {\n queryParamsSchema,\n sharedSourceOptionsSchema,\n sourceFieldMapSchema,\n} from \"./shared.ts\";\n\n/** Options for {@link payload}. */\nexport interface PayloadOptions extends SharedSourceOptions {\n /**\n * The auth-enabled collection the API key belongs to. Defaults to `users`;\n * it names the scheme in the `Authorization` header (`users API-Key <key>`).\n */\n authCollection?: string;\n /** The collection slug whose documents become pages. */\n collection: string;\n /** Relationship depth to populate. Defaults to `1`, enough for upload URLs. */\n depth?: number;\n /**\n * Field paths mapping a document onto Blume meta + body. Defaults to\n * `title` / `description` / `slug` / `content` / `updatedAt`.\n */\n fields?: SourceFieldMap;\n /** Extra query parameters for the collection request (`\"where[status][equals]\": \"live\"`). */\n params?: Record<string, string>;\n /** The Payload app's origin (`https://cms.acme.dev`); its REST API is at `/api`. */\n url: string;\n}\n\nexport const payloadOptionsSchema = sharedSourceOptionsSchema.extend({\n authCollection: z.string().optional(),\n collection: z.string(),\n depth: z.number().int().nonnegative().optional(),\n fields: sourceFieldMapSchema.optional(),\n params: queryParamsSchema.optional(),\n url: z.string(),\n});\n\nexport type PayloadAdapter = AdapterDescriptor<\"payload\", PayloadOptions>;\n\nexport const payloadAdapterSchema = adapterDescriptorSchema(\n \"payload\",\n payloadOptionsSchema\n);\n\n/**\n * A Payload collection read through its REST API; Lexical bodies become\n * Markdown. The API key comes from `PAYLOAD_API_KEY`, and `--preview` reads\n * drafts. Nothing to install: the adapter speaks the REST API directly.\n */\nexport const payload = (options: PayloadOptions): PayloadAdapter => ({\n kind: \"payload\",\n options,\n requiredSecrets: [\"PAYLOAD_API_KEY\"],\n runtimeDeps: [],\n});\n",
|
|
110
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions } from \"./shared.ts\";\nimport { sharedSourceOptionsSchema } from \"./shared.ts\";\n\n/** Options for {@link sanity}. */\nexport interface SanityOptions extends SharedSourceOptions {\n /** Sanity API version (a date). Defaults to `2024-01-01`. */\n apiVersion?: string;\n /** Dataset name to query. */\n dataset: string;\n /** Field paths mapping a document onto Blume meta + body. */\n fields?: {\n /** Field holding the renderable body (Portable Text or Markdown). */\n body?: string;\n /** Field holding the page description. */\n description?: string;\n /** Field holding the last-modified date. */\n lastModified?: string;\n /** Field holding the page slug. */\n slug?: string;\n /** Field holding the page title. */\n title?: string;\n };\n /** Sanity project id. */\n projectId: string;\n /** GROQ query selecting the documents to import. */\n query: string;\n}\n\nexport const sanityOptionsSchema = sharedSourceOptionsSchema.extend({\n apiVersion: z.string().optional(),\n dataset: z.string(),\n fields: z\n .strictObject({\n body: z.string().optional(),\n description: z.string().optional(),\n lastModified: z.string().optional(),\n slug: z.string().optional(),\n title: z.string().optional(),\n })\n .optional(),\n projectId: z.string(),\n query: z.string(),\n});\n\nexport type SanityAdapter = AdapterDescriptor<\"sanity\", SanityOptions>;\n\nexport const sanityAdapterSchema = adapterDescriptorSchema(\n \"sanity\",\n sanityOptionsSchema\n);\n\n/**\n * A Sanity dataset queried with GROQ; Portable Text bodies become Markdown.\n * `@sanity/client` is the declared runtime dependency, and a private dataset's\n * read token comes from `SANITY_TOKEN`.\n */\nexport const sanity = (options: SanityOptions): SanityAdapter => ({\n kind: \"sanity\",\n options,\n requiredSecrets: [\"SANITY_TOKEN\"],\n runtimeDeps: [\"@sanity/client\"],\n});\n",
|
|
111
|
+
"import { z } from \"zod\";\n\nimport type { AdapterDescriptor } from \"../core/adapter.ts\";\nimport { adapterDescriptorSchema } from \"../core/adapter.ts\";\nimport type { SharedSourceOptions, SourceFieldMap } from \"./shared.ts\";\nimport {\n queryParamsSchema,\n sharedSourceOptionsSchema,\n sourceFieldMapSchema,\n} from \"./shared.ts\";\n\n/** Options for {@link strapi}. */\nexport interface StrapiOptions extends SharedSourceOptions {\n /** The content type's plural API id (`articles`). */\n contentType: string;\n /**\n * Field paths mapping an entry onto Blume meta + body. Defaults to\n * `title` / `description` / `slug` / `content` / `updatedAt`.\n */\n fields?: SourceFieldMap;\n /** Locale code to fetch, for a localized content type. */\n locale?: string;\n /** Extra query parameters for the request (`\"filters[section][$eq]\": \"sdk\"`). */\n params?: Record<string, string>;\n /** The `populate` parameter. Defaults to `*`, which fills media and relations. */\n populate?: string;\n /** The Strapi origin (`https://cms.acme.dev`); its REST API is at `/api`. */\n url: string;\n}\n\nexport const strapiOptionsSchema = sharedSourceOptionsSchema.extend({\n contentType: z.string(),\n fields: sourceFieldMapSchema.optional(),\n locale: z.string().optional(),\n params: queryParamsSchema.optional(),\n populate: z.string().optional(),\n url: z.string(),\n});\n\nexport type StrapiAdapter = AdapterDescriptor<\"strapi\", StrapiOptions>;\n\nexport const strapiAdapterSchema = adapterDescriptorSchema(\n \"strapi\",\n strapiOptionsSchema\n);\n\n/**\n * A Strapi content type read through its REST API; Blocks bodies become\n * Markdown. The API token comes from `STRAPI_API_TOKEN`, and `--preview`\n * reads drafts. Nothing to install: the adapter speaks the REST API\n * directly.\n */\nexport const strapi = (options: StrapiOptions): StrapiAdapter => ({\n kind: \"strapi\",\n options,\n requiredSecrets: [\"STRAPI_API_TOKEN\"],\n runtimeDeps: [],\n});\n",
|
|
112
|
+
"/**\n * Fonts exposed through `theme.fonts`.\n *\n * Each role accepts a curated Google Font slug, a remote-provider family (any\n * Google/Fontsource/Bunny/Fontshare family by name), or local font files. All\n * forms resolve to entries for Astro's built-in Fonts API, which self-hosts\n * and optimizes them; this module only resolves config values into the data\n * that drives it.\n */\n\nexport type FontCategory = \"sans\" | \"serif\" | \"mono\";\n\n/** The three configurable roles in `theme.fonts`. */\nexport type FontSlot = \"display\" | \"body\" | \"mono\";\n\n/** Zero-config Astro font providers usable from `theme.fonts`. */\nexport type RemoteFontProvider =\n | \"google\"\n | \"fontsource\"\n | \"bunny\"\n | \"fontshare\";\n\n/** A remote-provider family: any family name the provider knows. */\nexport interface RemoteFontConfig {\n /** Family name as the provider lists it, e.g. `\"Noto Sans JP\"`. */\n name: string;\n /** Which provider serves the family. Defaults to `\"google\"`. */\n provider?: RemoteFontProvider;\n /** Weights (or variable ranges like `\"100..900\"`) to load. Defaults to `[400, 500, 600, 700]`. */\n weights?: (number | string)[];\n /**\n * Character subsets to load (`\"latin\"`, `\"vietnamese\"`, `\"cyrillic\"`, …).\n * Defaults to `latin` plus whatever the site's configured locales need.\n */\n subsets?: string[];\n /** Fallback stack category. Defaults to `\"mono\"` for the mono role, `\"sans\"` otherwise. */\n fallback?: FontCategory;\n}\n\n/** One `@font-face` declaration for a local font. */\nexport interface LocalFontVariant {\n /** Font file path, relative to the project root. */\n src: string;\n /** Face weight; inferred from the file when omitted. */\n weight?: number | string;\n /** Face style; inferred from the file when omitted. */\n style?: \"normal\" | \"italic\" | \"oblique\";\n}\n\n/** A self-hosted family loaded from files in the project. */\nexport interface LocalFontConfig {\n /** Family name used in CSS and the OG card. */\n name: string;\n /** The faces to declare (at least one). */\n variants: LocalFontVariant[];\n /** Fallback stack category. Defaults to `\"mono\"` for the mono role, `\"sans\"` otherwise. */\n fallback?: FontCategory;\n}\n\n/** A role's font: curated slug, remote family, or local files. */\nexport type FontValue = string | RemoteFontConfig | LocalFontConfig;\n\ninterface FontDef {\n category: FontCategory;\n family: string;\n /**\n * Discrete weights, or one `\"min..max\"` range for a family Google Fonts\n * serves as a variable font: the range loads the same variable file the\n * discrete weights did, declared as one `@font-face` per style instead of\n * one per weight (16 rules down to 4 for Inter on every page). The three\n * static families in the table keep discrete weights.\n */\n weights: (number | string)[];\n}\n\n/** Resolved theme fonts (a validated value per role, all optional). */\nexport type FontsConfig = Partial<Record<FontSlot, FontValue>> | undefined;\n\n/** A single Astro `fonts:` entry (sans the literal `fontProviders.*()` call). */\nexport type FontEntry =\n | {\n kind: \"remote\";\n provider: RemoteFontProvider;\n cssVariable: string;\n fallbacks: string[];\n name: string;\n subsets: string[];\n weights: (number | string)[];\n }\n | {\n kind: \"local\";\n cssVariable: string;\n fallbacks: string[];\n name: string;\n variants: LocalFontVariant[];\n };\n\nconst FALLBACKS = {\n mono: [\"ui-monospace\", \"SF Mono\", \"Menlo\", \"monospace\"],\n sans: [\"ui-sans-serif\", \"system-ui\", \"sans-serif\"],\n serif: [\"ui-serif\", \"Georgia\", \"serif\"],\n} satisfies Record<FontCategory, string[]>;\n\n/** Slug -> Google family + weights + fallback category. Keep keys alphabetical. */\nexport const GOOGLE_FONTS = {\n \"dm-sans\": { category: \"sans\", family: \"DM Sans\", weights: [\"400..700\"] },\n figtree: {\n category: \"sans\",\n family: \"Figtree\",\n weights: [\"400..700\"],\n },\n \"fira-code\": {\n category: \"mono\",\n family: \"Fira Code\",\n weights: [\"400..700\"],\n },\n geist: { category: \"sans\", family: \"Geist\", weights: [\"400..700\"] },\n \"geist-mono\": {\n category: \"mono\",\n family: \"Geist Mono\",\n weights: [\"400..600\"],\n },\n \"ibm-plex-mono\": {\n category: \"mono\",\n family: \"IBM Plex Mono\",\n weights: [400, 500, 600],\n },\n \"ibm-plex-sans\": {\n category: \"sans\",\n family: \"IBM Plex Sans\",\n weights: [\"400..700\"],\n },\n \"ibm-plex-serif\": {\n category: \"serif\",\n family: \"IBM Plex Serif\",\n weights: [400, 500, 600],\n },\n inter: { category: \"sans\", family: \"Inter\", weights: [\"400..700\"] },\n \"inter-tight\": {\n category: \"sans\",\n family: \"Inter Tight\",\n weights: [\"400..700\"],\n },\n \"jetbrains-mono\": {\n category: \"mono\",\n family: \"JetBrains Mono\",\n weights: [\"400..700\"],\n },\n lora: { category: \"serif\", family: \"Lora\", weights: [\"400..700\"] },\n manrope: {\n category: \"sans\",\n family: \"Manrope\",\n weights: [\"400..700\"],\n },\n merriweather: {\n category: \"serif\",\n family: \"Merriweather\",\n weights: [\"400..700\"],\n },\n \"open-sans\": {\n category: \"sans\",\n family: \"Open Sans\",\n weights: [\"400..700\"],\n },\n \"playfair-display\": {\n category: \"serif\",\n family: \"Playfair Display\",\n weights: [\"400..700\"],\n },\n \"plus-jakarta-sans\": {\n category: \"sans\",\n family: \"Plus Jakarta Sans\",\n weights: [\"400..700\"],\n },\n roboto: { category: \"sans\", family: \"Roboto\", weights: [\"400..700\"] },\n \"roboto-mono\": {\n category: \"mono\",\n family: \"Roboto Mono\",\n weights: [\"400..700\"],\n },\n \"source-code-pro\": {\n category: \"mono\",\n family: \"Source Code Pro\",\n weights: [\"400..600\"],\n },\n \"source-sans-3\": {\n category: \"sans\",\n family: \"Source Sans 3\",\n weights: [\"400..700\"],\n },\n \"source-serif-4\": {\n category: \"serif\",\n family: \"Source Serif 4\",\n weights: [\"400..700\"],\n },\n \"space-grotesk\": {\n category: \"sans\",\n family: \"Space Grotesk\",\n weights: [\"400..700\"],\n },\n \"space-mono\": { category: \"mono\", family: \"Space Mono\", weights: [400, 700] },\n \"work-sans\": {\n category: \"sans\",\n family: \"Work Sans\",\n weights: [\"400..600\"],\n },\n} satisfies Record<string, FontDef>;\n\nexport type FontSlug = keyof typeof GOOGLE_FONTS;\n\n/** All supported slugs, for schema validation and error messages. */\nexport const FONT_SLUGS = Object.keys(GOOGLE_FONTS);\n\n/** Type guard: is `value` a supported font slug? */\nexport const isFontSlug = (value: string): value is FontSlug =>\n Object.hasOwn(GOOGLE_FONTS, value);\n\n/** Weights loaded for a remote family when the config does not pin them. */\nconst DEFAULT_REMOTE_WEIGHTS: (number | string)[] = [400, 500, 600, 700];\n\n/**\n * The subsets a language needs beyond `latin`, keyed by BCP 47 language\n * subtag. Names are Google Fonts subsets (Bunny and Fontsource use the same\n * ones). Languages whose alphabet fits Latin-1 — English, French, German,\n * Spanish, … — need only `latin` and are absent. Keep keys alphabetical.\n */\nconst LOCALE_SUBSETS = {\n az: [\"latin-ext\"],\n ba: [\"cyrillic\", \"cyrillic-ext\"],\n be: [\"cyrillic\"],\n bg: [\"cyrillic\"],\n bs: [\"latin-ext\"],\n cs: [\"latin-ext\"],\n cv: [\"cyrillic\", \"cyrillic-ext\"],\n cy: [\"latin-ext\"],\n el: [\"greek\"],\n eo: [\"latin-ext\"],\n et: [\"latin-ext\"],\n ha: [\"latin-ext\"],\n hr: [\"latin-ext\"],\n hu: [\"latin-ext\"],\n ig: [\"latin-ext\"],\n kk: [\"cyrillic\", \"cyrillic-ext\"],\n ku: [\"latin-ext\"],\n ky: [\"cyrillic\", \"cyrillic-ext\"],\n lt: [\"latin-ext\"],\n lv: [\"latin-ext\"],\n mk: [\"cyrillic\"],\n mn: [\"cyrillic\", \"cyrillic-ext\"],\n mt: [\"latin-ext\"],\n pl: [\"latin-ext\"],\n ro: [\"latin-ext\"],\n ru: [\"cyrillic\"],\n sk: [\"latin-ext\"],\n sl: [\"latin-ext\"],\n sr: [\"cyrillic\", \"latin-ext\"],\n tg: [\"cyrillic\", \"cyrillic-ext\"],\n tk: [\"latin-ext\"],\n tr: [\"latin-ext\"],\n tt: [\"cyrillic\", \"cyrillic-ext\"],\n uk: [\"cyrillic\"],\n uz: [\"cyrillic\", \"latin-ext\"],\n vi: [\"vietnamese\"],\n yo: [\"latin-ext\"],\n} satisfies Record<string, string[]>;\n\n/** Type guard: does `language` have an entry in the subset table? */\nconst isSubsetLanguage = (\n language: string\n): language is keyof typeof LOCALE_SUBSETS =>\n Object.hasOwn(LOCALE_SUBSETS, language);\n\n/**\n * Subsets a script subtag (`sr-Latn`, `az-Cyrl`) asks for on its own, so a\n * locale written in a script its language doesn't default to still loads it.\n */\nconst SCRIPT_SUBSETS = {\n cyrl: [\"cyrillic\"],\n latn: [\"latin-ext\"],\n} satisfies Record<string, string[]>;\n\n/** Type guard: does `script` have an entry in the script table? */\nconst isSubsetScript = (\n script: string\n): script is keyof typeof SCRIPT_SUBSETS =>\n Object.hasOwn(SCRIPT_SUBSETS, script);\n\n/** Google's listing order; keeps generated configs stable across runs. */\nconst SUBSET_ORDER = [\n \"latin\",\n \"latin-ext\",\n \"vietnamese\",\n \"cyrillic\",\n \"cyrillic-ext\",\n \"greek\",\n \"greek-ext\",\n];\n\n/** The shape of a config's `i18n` block the font builders read. */\nexport interface FontLocaleSource {\n locales: { code: string }[];\n}\n\n/** The locale codes an optional `i18n` block declares (none when absent). */\nexport const fontLocaleCodes = (i18n: FontLocaleSource | undefined): string[] =>\n i18n?.locales.map((locale) => locale.code) ?? [];\n\n/**\n * The subsets the site's locales need: `latin` always, plus each locale's\n * script. A site with no `i18n` block (or only Latin-1 languages) gets just\n * `latin` — Astro's own default — so its CSS and preloads don't change.\n */\nexport const localeFontSubsets = (locales: string[]): string[] => {\n const wanted = new Set([\"latin\"]);\n for (const locale of locales) {\n const [language = \"\", ...subtags] = locale.toLowerCase().split(\"-\");\n if (isSubsetLanguage(language)) {\n for (const subset of LOCALE_SUBSETS[language]) {\n wanted.add(subset);\n }\n }\n for (const subtag of subtags) {\n if (isSubsetScript(subtag)) {\n for (const subset of SCRIPT_SUBSETS[subtag]) {\n wanted.add(subset);\n }\n }\n }\n }\n return SUBSET_ORDER.filter((subset) => wanted.has(subset));\n};\n\n/**\n * Providers whose faces carry subset metadata, so `<Font preload>` can be\n * filtered by subset. Fontshare serves whole files with no subset split; a\n * subset filter there would match nothing and drop every preload.\n */\nconst SUBSET_PROVIDERS = new Set<RemoteFontProvider>([\n \"google\",\n \"bunny\",\n \"fontsource\",\n]);\n\n/** Kebab-case a family name into a slug (`\"Noto Sans JP\"` -> `\"noto-sans-jp\"`). */\nexport const slugifyFontName = (name: string): string =>\n name\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/gu, \"-\")\n // The collapse above leaves only single dashes, so no quantifiers needed\n // (an unanchored `-+$` backtracks quadratically on long dash runs).\n .replaceAll(/^-|-$/gu, \"\");\n\n/** The CSS variable Astro populates for a given font (shared across roles). */\nconst fontVar = (slug: string): string => `--blume-ff-${slug}`;\n\nconst SLOTS: FontSlot[] = [\"display\", \"body\", \"mono\"];\n\n/** The fallback category a role uses when a custom font does not pick one. */\nconst slotCategory = (slot: FontSlot): FontCategory =>\n slot === \"mono\" ? \"mono\" : \"sans\";\n\n/** Whether a slot value is the slug-string form (vs a custom font object). */\nconst isSlugValue = (value: FontValue): value is string =>\n typeof value === \"string\";\n\n/**\n * A slot value normalized into an entry, or null for an unknown slug string.\n * `subsets` is the locale-derived default a remote family loads when the\n * config does not pin its own.\n */\nconst resolveFontValue = (\n slot: FontSlot,\n value: FontValue,\n subsets: string[]\n): FontEntry | null => {\n if (isSlugValue(value)) {\n if (!isFontSlug(value)) {\n return null;\n }\n const def = GOOGLE_FONTS[value];\n return {\n cssVariable: fontVar(value),\n fallbacks: FALLBACKS[def.category],\n kind: \"remote\",\n name: def.family,\n provider: \"google\",\n subsets,\n weights: def.weights,\n };\n }\n const slug = slugifyFontName(value.name);\n const fallbacks = FALLBACKS[value.fallback ?? slotCategory(slot)];\n if (\"variants\" in value) {\n return {\n cssVariable: fontVar(slug),\n fallbacks,\n kind: \"local\",\n name: value.name,\n variants: value.variants,\n };\n }\n return {\n cssVariable: fontVar(slug),\n fallbacks,\n kind: \"remote\",\n name: value.name,\n provider: value.provider ?? \"google\",\n subsets: value.subsets ?? subsets,\n weights: value.weights ?? DEFAULT_REMOTE_WEIGHTS,\n };\n};\n\n/**\n * Merge two entries that resolved to the same CSS variable. The same remote\n * family configured twice unions its weights (so a custom `{ name: \"Inter\" }`\n * coexists with the curated `inter` default in another role); identical local\n * definitions collapse. Anything else is a config conflict worth failing on.\n */\nconst mergeFontEntries = (current: FontEntry, next: FontEntry): FontEntry => {\n if (\n current.kind === \"remote\" &&\n next.kind === \"remote\" &&\n current.provider === next.provider &&\n current.name === next.name\n ) {\n return {\n ...current,\n subsets: [...new Set([...current.subsets, ...next.subsets])],\n weights: [...new Set([...current.weights, ...next.weights])],\n };\n }\n if (\n current.kind === \"local\" &&\n next.kind === \"local\" &&\n current.name === next.name &&\n JSON.stringify(current.variants) === JSON.stringify(next.variants)\n ) {\n return current;\n }\n throw new Error(\n `theme.fonts: \"${next.name}\" conflicts with \"${current.name}\" — both resolve to the CSS variable \"${current.cssVariable}\" with different definitions. Rename one family or align their definitions.`\n );\n};\n\n/**\n * The unique Astro `fonts:` entries for the configured roles (deduped).\n * `locales` are the site's configured locale codes; they pick the subsets a\n * remote family loads unless its config pins `subsets` itself.\n */\nexport const buildFontEntries = (\n fonts: FontsConfig,\n locales: string[] = []\n): FontEntry[] => {\n if (!fonts) {\n return [];\n }\n const subsets = localeFontSubsets(locales);\n const entries = new Map<string, FontEntry>();\n for (const slot of SLOTS) {\n const value = fonts[slot];\n if (value === undefined) {\n continue;\n }\n const entry = resolveFontValue(slot, value, subsets);\n if (!entry) {\n continue;\n }\n const current = entries.get(entry.cssVariable);\n entries.set(\n entry.cssVariable,\n current ? mergeFontEntries(current, entry) : entry\n );\n }\n return [...entries.values()];\n};\n\n/** The slug backing a slot's CSS variable, or null for an unknown slug string. */\nconst slotSlug = (value: FontValue): string | null => {\n if (isSlugValue(value)) {\n return isFontSlug(value) ? value : null;\n }\n return slugifyFontName(value.name);\n};\n\n/**\n * The config-token CSS that points each role's `--blume-font-<role>-src` at the\n * Astro-populated family variable. Concatenated into the generated entry's\n * config tokens; empty when no fonts are set so defaults stay the system stacks.\n */\nexport const buildFontsCss = (fonts: FontsConfig): string => {\n if (!fonts) {\n return \"\";\n }\n const lines = SLOTS.flatMap((slot) => {\n const value = fonts[slot];\n if (value === undefined) {\n return [];\n }\n const slug = slotSlug(value);\n return slug ? [` --blume-font-${slot}-src: var(${fontVar(slug)});`] : [];\n });\n return lines.length > 0\n ? `/* Generated by Blume from theme.fonts. */\\n:root {\\n${lines.join(\"\\n\")}\\n}\\n`\n : \"\";\n};\n\n/**\n * Weights worth preloading per role — the faces above-the-fold text actually\n * renders in: body copy and UI chrome at 400/500, headings at 500/600, code at\n * 400. Every other face still loads on demand through its `@font-face` rule\n * (and `font-display: swap` never blocks text on it), so preloading the long\n * tail only competes with the critical CSS for bandwidth and pushes LCP out.\n */\nconst PRELOAD_WEIGHTS = {\n body: [400, 500],\n display: [500, 600],\n mono: [400],\n} satisfies Record<FontSlot, number[]>;\n\n/**\n * One `<Font>` render in the head: its CSS variable + the weights (and, for\n * providers that split faces by subset, the subsets) to preload. Local and\n * Fontshare faces carry no subset, so those entries leave `preloadSubsets`\n * unset and preload by weight alone.\n */\nexport interface FontHead {\n cssVariable: string;\n preloadSubsets?: string[];\n preloadWeights: number[];\n}\n\n/** The weights an entry's faces declare (`undefined` = inferred from files). */\nconst entryWeights = (entry: FontEntry): (number | string | undefined)[] =>\n entry.kind === \"remote\"\n ? entry.weights\n : entry.variants.map((variant) => variant.weight);\n\n/**\n * The role's preferred preload weights, narrowed to faces the family loads.\n * Variable ranges (`\"100..900\"`) and weight-inferred local files can serve any\n * weight, so they keep the preferred list; a family whose numeric weights miss\n * the preferred ones entirely preloads all of its faces instead — those are\n * what its text renders in.\n */\nconst preloadWeightsFor = (slot: FontSlot, entry: FontEntry): number[] => {\n const preferred = PRELOAD_WEIGHTS[slot];\n const weights = entryWeights(entry);\n const numeric = weights.filter(\n (weight): weight is number => typeof weight === \"number\"\n );\n const hits = preferred.filter((weight) => numeric.includes(weight));\n if (hits.length > 0) {\n return hits;\n }\n return numeric.length === weights.length ? numeric : preferred;\n};\n\n/**\n * The fonts to feed Astro's `<Font>` component in the document head, deduped\n * by CSS variable with preload weights unioned across the roles that share a\n * family (so `display` and `body` both set to Inter preload 400/500/600 once).\n */\nexport const configuredFonts = (\n fonts: FontsConfig,\n locales: string[] = []\n): FontHead[] => {\n if (!fonts) {\n return [];\n }\n const defaultSubsets = localeFontSubsets(locales);\n const heads = new Map<\n string,\n { subsets: Set<string> | null; weights: Set<number> }\n >();\n for (const slot of SLOTS) {\n const value = fonts[slot];\n if (value === undefined) {\n continue;\n }\n const entry = resolveFontValue(slot, value, defaultSubsets);\n if (!entry) {\n continue;\n }\n const head = heads.get(entry.cssVariable) ?? {\n subsets: null,\n weights: new Set<number>(),\n };\n for (const weight of preloadWeightsFor(slot, entry)) {\n head.weights.add(weight);\n }\n if (entry.kind === \"remote\" && SUBSET_PROVIDERS.has(entry.provider)) {\n head.subsets ??= new Set();\n for (const subset of entry.subsets) {\n head.subsets.add(subset);\n }\n }\n heads.set(entry.cssVariable, head);\n }\n return [...heads].map(([cssVariable, head]) => {\n const font: FontHead = {\n cssVariable,\n preloadWeights: [...head.weights].toSorted((a, b) => a - b),\n };\n if (head.subsets) {\n font.preloadSubsets = [...head.subsets];\n }\n return font;\n });\n};\n",
|
|
113
|
+
"/**\n * Repository URL derivation for `config.github`.\n *\n * Every repo-derived link — the header mark, per-page edit links, the agent\n * manifest's `repository` — is built from `host`, which defaults to github.com\n * but accepts a GitHub Enterprise origin so self-hosted and data-resident\n * installations get working links instead of ones pointing at the public site.\n *\n * The REST base is derived from the host unless `api` is set explicitly, since\n * the two Enterprise flavors expose it differently: Enterprise Cloud with data\n * residency serves it from an `api.` subdomain of the same host, Enterprise\n * Server from `/api/v3` on the host itself.\n *\n * `host` arrives as a bare origin and `api` as an origin plus path, both with\n * no trailing slash — the config schema normalizes them — so nothing here\n * re-trims user input.\n */\n\nimport type { ResolvedConfig } from \"./schema.ts\";\n\n/** The resolved `github` block, which the config leaves optional. */\nexport type GithubTarget = NonNullable<ResolvedConfig[\"github\"]>;\n\n/** The public instance every `host` defaults to. */\nexport const PUBLIC_HOST_URL = \"https://github.com\";\n/** The public instance's REST base. */\nexport const PUBLIC_API_URL = \"https://api.github.com\";\nconst PUBLIC_HOSTNAME = \"github.com\";\n/** Enterprise Cloud with data residency: `<tenant>.ghe.com`. */\nconst DATA_RESIDENCY_SUFFIX = \".ghe.com\";\n\n/** `owner/repo` — the bare slug, with no origin attached. */\nconst repoSlug = (github: Pick<GithubTarget, \"owner\" | \"repo\">): string =>\n `${github.owner}/${github.repo}`;\n\n/** The repository's web URL, e.g. `https://github.com/acme/docs`. */\nexport const repoUrl = (\n github: Pick<GithubTarget, \"host\" | \"owner\" | \"repo\">\n): string => `${github.host}/${repoSlug(github)}`;\n\n/** The base every edit link extends with a repo-relative path. */\nexport const editBaseUrl = (\n github: Pick<GithubTarget, \"branch\" | \"host\" | \"owner\" | \"repo\">\n): string => `${repoUrl(github)}/edit/${github.branch}`;\n\n/**\n * The REST API base for `host`. An explicit `api` always wins; otherwise\n * github.com (and any subdomain of it, `www.` say) maps to api.github.com, a\n * data-residency tenant to its `api.` subdomain, and anything else is treated\n * as Enterprise Server (`/api/v3`).\n */\nexport const apiUrl = (github: Pick<GithubTarget, \"api\" | \"host\">): string => {\n if (github.api) {\n return github.api;\n }\n const url = new URL(github.host);\n const { hostname } = url;\n if (\n hostname === PUBLIC_HOSTNAME ||\n hostname.endsWith(`.${PUBLIC_HOSTNAME}`)\n ) {\n return PUBLIC_API_URL;\n }\n if (hostname.endsWith(DATA_RESIDENCY_SUFFIX)) {\n // Rebuilt through the URL so a non-default port survives alongside the\n // subdomain rather than being dropped from the API base alone.\n url.hostname = `api.${hostname}`;\n return url.origin;\n }\n return `${github.host}/api/v3`;\n};\n",
|
|
114
|
+
"import { z } from \"zod\";\n\nimport { UI_PACKS } from \"./ui-packs/index.ts\";\n\n/**\n * Translatable UI chrome strings.\n *\n * The schema is the single source of truth: each field's `.default()` is the\n * English baseline, so `EN_UI = uiStringsSchema.parse({})`. Shipped packs and\n * user overrides merge on top (see {@link resolveUIStrings}). Grouped by surface\n * to keep the runtime payload and component props readable.\n */\nconst uiStringsObject = z.object({\n actions: z\n .object({\n addToCursor: z.string().default(\"Add to Cursor\"),\n addToVscode: z.string().default(\"Add to VS Code\"),\n askAI: z.string().default(\"Ask AI about this page\"),\n connectMcp: z.string().default(\"Connect to MCP\"),\n copied: z.string().default(\"Copied!\"),\n copyClaudeCode: z.string().default(\"Copy Claude Code command\"),\n copyCode: z.string().default(\"Copy code\"),\n copyCodex: z.string().default(\"Copy Codex command\"),\n copyFailed: z.string().default(\"Copy failed\"),\n copyMarkdown: z.string().default(\"Copy as Markdown\"),\n copyServerUrl: z.string().default(\"Copy server URL\"),\n edit: z.string().default(\"Edit on GitHub\"),\n export: z.string().default(\"Export\"),\n exportEpub: z.string().default(\"Export to EPUB\"),\n exportPdf: z.string().default(\"Export to PDF\"),\n generating: z.string().default(\"Generating…\"),\n // `{name}` is replaced with the provider's brand name at render time.\n openIn: z.string().default(\"Open in {name}\"),\n openInChat: z.string().default(\"Open in chat\"),\n // The prompt handed to the chat provider; `{url}` is replaced with the\n // page's raw-Markdown URL at load time.\n openInChatPrompt: z\n .string()\n .default(\"Read {url} so I can ask you questions about this page.\"),\n scrollToTop: z.string().default(\"Scroll to top\"),\n })\n .prefault({}),\n ask: z\n .object({\n ai: z.string().default(\"AI\"),\n clear: z.string().default(\"Clear conversation\"),\n close: z.string().default(\"Close\"),\n copy: z.string().default(\"Copy conversation\"),\n empty: z.string().default(\"Ask a question about the docs.\"),\n error: z.string().default(\"Sorry, something went wrong.\"),\n label: z.string().default(\"Ask a question\"),\n placeholder: z.string().default(\"Ask a question…\"),\n send: z.string().default(\"Send\"),\n tip: z.string().default(\"Tip: You can open and close chat with\"),\n title: z.string().default(\"Ask AI\"),\n you: z.string().default(\"You\"),\n })\n .prefault({}),\n banner: z\n .object({\n dismiss: z.string().default(\"Dismiss announcement\"),\n })\n .prefault({}),\n changelog: z\n .object({\n description: z\n .string()\n .default(\n \"Product updates, new features, and fixes from every release.\"\n ),\n title: z.string().default(\"Changelog\"),\n })\n .prefault({}),\n content: z\n .object({\n // A `<Color.Item>` swatch's accessible name; `{name}` and `{value}` are\n // replaced with the color's name and the value it shows.\n copyColor: z.string().default(\"Copy {name} color {value}\"),\n copyPrompt: z.string().default(\"Copy prompt\"),\n diagramError: z.string().default(\"Could not render this diagram.\"),\n })\n .prefault({}),\n feedback: z\n .object({\n no: z.string().default(\"No\"),\n question: z.string().default(\"Was this page helpful?\"),\n thanks: z.string().default(\"Thanks for your feedback!\"),\n yes: z.string().default(\"Yes\"),\n })\n .prefault({}),\n languageSwitcher: z\n .object({\n label: z.string().default(\"Language\"),\n untranslated: z.string().default(\"Not translated\"),\n })\n .prefault({}),\n nav: z\n .object({\n back: z.string().default(\"Back\"),\n breadcrumb: z.string().default(\"Breadcrumb\"),\n closeNavigation: z.string().default(\"Close navigation\"),\n deprecated: z.string().default(\"deprecated\"),\n featured: z.string().default(\"Featured\"),\n githubRepository: z.string().default(\"GitHub repository\"),\n navigation: z.string().default(\"Navigation\"),\n // The screen-reader description every new-tab link points at.\n opensInNewTab: z.string().default(\"Opens in a new tab\"),\n primary: z.string().default(\"Primary\"),\n sections: z.string().default(\"Sections\"),\n toggleNavigation: z.string().default(\"Toggle navigation\"),\n toggleTheme: z.string().default(\"Toggle color theme\"),\n })\n .prefault({}),\n notFound: z\n .object({\n /** Label of the OpenAPI description link on the Markdown/JSON 404. */\n api: z.string().default(\"JSON API description (openapi.json)\"),\n description: z\n .string()\n .default(\"We couldn't find the page you're looking for.\"),\n home: z.string().default(\"Back to home\"),\n /** Label of the llms.txt link on the 404 page. */\n llms: z.string().default(\"Docs index for AI agents (llms.txt)\"),\n /** Label of the sitemap link on the 404 page. */\n sitemap: z.string().default(\"Sitemap\"),\n /** Heading over the recovery links (sections, sitemap, llms.txt). */\n suggestions: z.string().default(\"Where to look next\"),\n title: z.string().default(\"Page not found\"),\n })\n .prefault({}),\n page: z\n .object({\n lastUpdated: z.string().default(\"Last updated on\"),\n next: z.string().default(\"Next\"),\n pagination: z.string().default(\"Pagination\"),\n previous: z.string().default(\"Previous\"),\n skipToContent: z.string().default(\"Skip to content\"),\n })\n .prefault({}),\n search: z\n .object({\n all: z.string().default(\"All\"),\n allLanguages: z.string().default(\"All languages\"),\n allVersions: z.string().default(\"All versions\"),\n askAi: z.string().default(\"Ask AI\"),\n askAiHint: z.string().default(\"Get an instant answer from AI\"),\n button: z.string().default(\"Search\"),\n devOnly: z\n .string()\n .default(\"Search is available in the production build.\"),\n error: z.string().default(\"Something went wrong. Please try again.\"),\n label: z.string().default(\"Search docs\"),\n navigate: z.string().default(\"navigate\"),\n noResults: z.string().default(\"No results found.\"),\n open: z.string().default(\"open\"),\n placeholder: z.string().default(\"Search documentation…\"),\n popular: z.string().default(\"Popular\"),\n preview: z.string().default(\"preview\"),\n results: z.string().default(\"Results\"),\n })\n .prefault({}),\n toc: z\n .object({\n title: z.string().default(\"On this page\"),\n })\n .prefault({}),\n versions: z\n .object({\n latest: z.string().default(\"Go to latest\"),\n // `{version}` is replaced with the archived version's label at render time.\n notice: z\n .string()\n .default(\n \"You're viewing documentation for {version}. It may be out of date.\"\n ),\n switcher: z.string().default(\"Version\"),\n })\n .prefault({}),\n});\n\nexport const uiStringsSchema = uiStringsObject.prefault({});\n\n/** A fully-resolved dictionary; every key present. */\nexport type UIStrings = z.infer<typeof uiStringsObject>;\n\n/**\n * The English baseline, derived from the schema defaults. The groups use\n * `.prefault({})` (not `.default({})`) so an absent group is still parsed\n * through its inner type and every field default applies — under Zod 4's\n * `.default()` semantics a bare `parse({})` would collapse each group to a\n * literal `{}` and the runtime would silently render blank chrome.\n */\nexport const EN_UI: UIStrings = uiStringsObject.parse({});\n\n/**\n * A partial override: `{ group: { key: \"translation\" } }`. Validated loosely\n * (object of objects of strings) so packs and user config can supply only the\n * keys they translate. Unknown groups/keys merge harmlessly.\n */\nexport const uiStringsOverrideSchema = z.record(\n z.string(),\n z.record(z.string(), z.string())\n);\n\nexport type UIStringsOverride = z.infer<typeof uiStringsOverrideSchema>;\n\n/** Per-locale UI overrides supplied in `i18n.ui`. */\nexport const uiLocaleOverridesSchema = z.record(\n z.string(),\n uiStringsOverrideSchema\n);\n\n/** Merge an override's string leaves onto a base dictionary (two levels deep). */\nconst mergeUI = (base: UIStrings, override?: UIStringsOverride): UIStrings => {\n if (!override) {\n return base;\n }\n const out: UIStrings = structuredClone(base);\n for (const [group, values] of Object.entries(override)) {\n // SAFETY: UIStrings is exactly two levels of string leaves, and the\n // override schema mirrors its groups, so `group` indexes a string map.\n const target = (out as Record<string, Record<string, string>>)[group];\n if (target && values) {\n Object.assign(target, values);\n }\n }\n return out;\n};\n\n/**\n * Built-in translation packs, one module per locale under {@link ./ui-packs}.\n * English is the schema baseline (no pack); every other locale ships a starter\n * pack so adopters get translated chrome out of the box. Re-exported here so the\n * resolver and existing imports keep a single entry point.\n */\nexport { UI_PACKS } from \"./ui-packs/index.ts\";\n\n/** Case-insensitive index for region-variant lookup (`pt-br` -> `pt-BR`). */\nconst PACKS_BY_LOWER: Record<string, UIStringsOverride> = Object.fromEntries(\n Object.entries(UI_PACKS).map(([code, pack]) => [code.toLowerCase(), pack])\n);\n\n/**\n * Find the built-in pack for a locale code, tolerating case and region subtags:\n * an exact match wins, then a case-insensitive match (`pt-br` -> `pt-BR`), then\n * the base language (`fr-CA` -> `fr`). So any reasonable code gets sensible\n * chrome without the project having to match our exact casing.\n */\nconst packFor = (code: string): UIStringsOverride | undefined => {\n const lower = code.toLowerCase();\n return (\n UI_PACKS[code] ??\n PACKS_BY_LOWER[lower] ??\n PACKS_BY_LOWER[lower.split(/[-_]/u)[0] ?? lower]\n );\n};\n\n/**\n * Resolve the active dictionary for a locale. Layers, in order:\n * English baseline ← default-locale pack ← default-locale override ←\n * locale pack ← locale override. So a missing key falls back to the default\n * locale's translation, then to English.\n */\nexport const resolveUIStrings = (\n locale: string,\n options: {\n defaultLocale: string;\n overrides?: Record<string, UIStringsOverride>;\n }\n): UIStrings => {\n const { defaultLocale, overrides } = options;\n let dict = EN_UI;\n dict = mergeUI(dict, packFor(defaultLocale));\n dict = mergeUI(dict, overrides?.[defaultLocale]);\n if (locale !== defaultLocale) {\n dict = mergeUI(dict, packFor(locale));\n dict = mergeUI(dict, overrides?.[locale]);\n }\n return dict;\n};\n",
|
|
115
|
+
"/**\n * Providers for the \"Open in chat\" page action, in display order. Shared by\n * the config schema (`ai.openInChat` subsets validate against this list) and\n * the PageActions menu (which renders the full list when the config is `true`).\n * Lives outside `schema.ts` so the component can import the list without\n * pulling the whole config schema into the layout module graph.\n */\nexport const openInChatProviders = [\n \"v0\",\n \"chatgpt\",\n \"claude\",\n \"t3\",\n \"scira\",\n \"cursor\",\n] as const;\n\nexport type OpenInChatProvider = (typeof openInChatProviders)[number];\n",
|
|
116
|
+
"/**\n * The Standard Schema interface (https://standardschema.dev), the minimal\n * `~standard` surface shared by Zod 3.24+, Zod 4, Valibot, ArkType, and\n * friends. Blume accepts user-supplied validation schemas (e.g.\n * `frontmatter.extend`) through this interface instead of Zod's own types:\n * `blume.config.ts` imports zod from the *consumer's* node_modules, which may\n * be a different major version than the zod Blume bundles, and calling Zod\n * methods (`.extend()`, `.safeParse()`) across instances is unsupported. The\n * `~standard.validate` contract is version- and library-agnostic.\n */\n\n/** One validation failure, with an optional path into the checked value. */\nexport interface StandardSchemaIssue {\n readonly message: string;\n readonly path?:\n | readonly (PropertyKey | { readonly key: PropertyKey })[]\n | undefined;\n}\n\n/** A passing validation: the (possibly transformed) output value. */\nexport interface StandardSchemaSuccess<Output> {\n readonly value: Output;\n readonly issues?: undefined;\n}\n\n/** A failing validation: one or more issues. */\nexport interface StandardSchemaFailure {\n readonly issues: readonly StandardSchemaIssue[];\n}\n\nexport type StandardSchemaResult<Output> =\n | StandardSchemaSuccess<Output>\n | StandardSchemaFailure;\n\n/** A validation schema exposing the Standard Schema `~standard` contract. */\nexport interface StandardSchema<Input = unknown, Output = Input> {\n readonly \"~standard\": {\n readonly version: 1;\n readonly vendor: string;\n readonly validate: (\n value: Input\n ) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;\n readonly types?:\n | { readonly input: Input; readonly output: Output }\n | undefined;\n };\n}\n\n/**\n * Whether a config-supplied value implements the `~standard` contract. Generic\n * so it can decode any input at the config boundary (`z.custom` hands it the\n * raw config value) while narrowing whatever type the caller holds.\n */\nexport const isStandardSchema = <T>(value: T): value is T & StandardSchema =>\n typeof value === \"object\" &&\n value !== null &&\n // SAFETY: the assertion only widens the checked object for property probing;\n // the trailing typeof check is what verifies `~standard.validate` exists.\n typeof (value as { \"~standard\"?: { validate?: unknown } })[\"~standard\"]\n ?.validate === \"function\";\n",
|
|
117
|
+
"import { localizeRoute } from \"./i18n.ts\";\nimport type {\n ArchivedVersionConfig,\n ResolvedConfig,\n ResolvedI18nConfig,\n ResolvedVersionsConfig,\n} from \"./schema.ts\";\nimport type { Diagnostic, PageRecord } from \"./types.ts\";\n\n/**\n * Version logic, centralized. Every seam that needs to reason about docs\n * versions (content discovery, navigation, manifest, runtime generation, the\n * catch-all) goes through these helpers so the routing rules live in exactly\n * one place — the same contract `./i18n.ts` holds for locales.\n *\n * The current version is the empty string `\"\"`: the latest docs live at the\n * content root with unprefixed URLs, and only archived snapshots have a\n * directory and a URL segment.\n */\n\n/**\n * Top-level folders that look like a version (`v1`, `V2.0`) — used by the\n * unconfigured-snapshot diagnostic and by `blume version` to keep such folders\n * out of new snapshots.\n */\nexport const VERSION_LIKE = /^v\\d/iu;\n\n/** True when the project opts into versioning. */\nexport const versionsEnabled = (\n config: ResolvedConfig\n): config is ResolvedConfig & { versions: ResolvedVersionsConfig } =>\n config.versions !== undefined;\n\n/** All archived version ids, in configured (switcher) order. */\nexport const archivedIds = (versions: ResolvedVersionsConfig): string[] =>\n versions.archived.map((version) => version.id);\n\n/** Switcher label for a version: the current label for `\"\"`, else per config. */\nexport const versionLabel = (\n id: string,\n versions: ResolvedVersionsConfig\n): string => {\n if (id === \"\") {\n return versions.current.label;\n }\n const archived = versions.archived.find((version) => version.id === id);\n return archived?.label ?? id;\n};\n\n/** The archived version config for an id (`undefined` for current/unknown). */\nexport const archivedVersion = (\n id: string,\n versions: ResolvedVersionsConfig\n): ArchivedVersionConfig | undefined =>\n versions.archived.find((version) => version.id === id);\n\n/** A resolved version (`\"\"` for current) and the version-stripped remainder. */\nexport interface DetectedVersion {\n version: string;\n rest: string[];\n}\n\n/** {@link DetectedVersion} for a slash-joined source ref. */\nexport interface DetectedVersionRef {\n version: string;\n rest: string;\n}\n\n/**\n * Detect a leading archived-version directory in a path's segments. The\n * current version lives at the content root, so only archived ids are matched\n * as a leading segment. Returns the resolved version (`\"\"` for current) and\n * the remaining (version-stripped) segments. Runs BEFORE locale detection —\n * the snapshot directory is outermost on disk, so the locale parser must see\n * a version-stripped path.\n */\nexport const detectVersion = (\n parts: string[],\n versions: ResolvedVersionsConfig\n): DetectedVersion => {\n const [first] = parts;\n if (first && versions.archived.some((version) => version.id === first)) {\n return { rest: parts.slice(1), version: first };\n }\n return { rest: parts, version: \"\" };\n};\n\n/**\n * {@link detectVersion} over a slash-joined source ref (`v1.0/fr/x.mdx`):\n * returns the version and the version-stripped ref for the locale parser and\n * route mapping to consume.\n */\nexport const detectVersionRef = (\n ref: string,\n versions: ResolvedVersionsConfig\n): DetectedVersionRef => {\n const { version, rest } = detectVersion(ref.split(\"/\"), versions);\n return { rest: rest.join(\"/\"), version };\n};\n\n/**\n * Prefix a version-agnostic logical route with its version: `/guides/x`\n * becomes `/v1.0/guides/x`, `/` becomes `/v1.0`. The current version (`\"\"`)\n * is the identity.\n */\nexport const versionizeRoute = (\n logicalRoute: string,\n version: string\n): string => {\n if (!version) {\n return logicalRoute;\n }\n return logicalRoute === \"/\" ? `/${version}` : `/${version}${logicalRoute}`;\n};\n\n/**\n * The localized root route of a version: `/`, `/fr`, `/v1.0`, or `/fr/v1.0`.\n * The locale prefix stays outermost, matching how page routes compose\n * (`localizeRoute(versionizeRoute(...))`).\n */\nexport const versionRoot = (\n version: string,\n locale?: string,\n i18n?: ResolvedI18nConfig\n): string => {\n const logical = versionizeRoute(\"/\", version);\n if (i18n && locale !== undefined) {\n return localizeRoute(logical, locale, i18n);\n }\n return logical;\n};\n\n/**\n * Warn about top-level content folders shaped like a version (`v1`, `v2.0`)\n * that aren't declared in `versions.archived`. Without this they're silently\n * treated as current-version content under a `/<folder>/…` route — usually a\n * snapshot that wasn't registered in config.\n */\nexport const versionsDiagnostics = (\n pages: PageRecord[],\n versions: ResolvedVersionsConfig\n): Diagnostic[] => {\n // Exact-id comparison, matching `detectVersion`: a folder that differs from\n // a configured id only by case (`V1.0/` vs `v1.0`) is NOT routed as that\n // snapshot, so it must still warn. `VERSION_LIKE` is case-insensitive on\n // its own.\n const configured = new Set(versions.archived.map((version) => version.id));\n const seen = new Set<string>();\n const diagnostics: Diagnostic[] = [];\n for (const page of pages) {\n // The version-looking folder is the first segment of the source-local ref\n // (e.g. `v1.0/guide.md`), not the namespaced id (`filesystem:v1.0/guide.md`).\n const [first] = page.source.ref.split(\"/\");\n if (\n first &&\n !seen.has(first) &&\n VERSION_LIKE.test(first) &&\n !configured.has(first)\n ) {\n seen.add(first);\n diagnostics.push({\n code: \"BLUME_VERSIONS_UNCONFIGURED_VERSION\",\n message: `Folder \"${first}/\" looks like a version, but \"${first}\" is not in versions.archived — its pages are treated as current-version content at /${first}/….`,\n severity: \"warning\",\n suggestion: `Add { id: \"${first}\" } to versions.archived, or rename the folder if it isn't a snapshot.`,\n });\n }\n }\n return diagnostics;\n};\n",
|
|
118
|
+
"import { readFile } from \"node:fs/promises\";\n\nimport { expandIncludes, hasIncludeStatements } from \"../includes.ts\";\nimport type { PageRecord } from \"../types.ts\";\nimport type { ContentSource } from \"./types.ts\";\n\n/** The subset of a scanned project the entry reader needs. */\nexport interface EntryReadContext {\n /** The instantiated sources, keyed for `read()` lookups. */\n sources?: ContentSource[];\n}\n\n/**\n * Read an entry's raw body text without assuming a filesystem path. Prefers the\n * body captured at scan time (staged sources), then the owning source's lazy\n * `read()`, then the back-compat `sourcePath` (any local file). Returns `\"\"` when an\n * entry can't be resolved, so callers degrade gracefully.\n */\nexport const readEntryText = async (\n ctx: EntryReadContext,\n page: PageRecord\n): Promise<string> => {\n if (page.body) {\n return page.body.text;\n }\n const name = page.source?.name;\n const source = name\n ? ctx.sources?.find((candidate) => candidate.name === name)\n : undefined;\n if (source?.read) {\n return await source.read(page.source.ref);\n }\n if (page.sourcePath) {\n return await readFile(page.sourcePath, \"utf-8\");\n }\n return \"\";\n};\n\n/**\n * Read an entry's raw body with `<include>` statements expanded — what search\n * indexing, the `.md`/`.mdx` mirrors, and llms-full.txt should see, matching\n * the spliced content the rendered page shows. Filesystem entries only\n * (includes resolve as filesystem paths); everything else passes through\n * verbatim. Expansion errors were already surfaced as scan diagnostics, so\n * unresolvable statements simply stay verbatim here.\n */\nexport const readExpandedEntryText = async (\n ctx: EntryReadContext,\n page: PageRecord\n): Promise<string> => {\n const raw = await readEntryText(ctx, page);\n if (!(page.sourcePath && hasIncludeStatements(raw))) {\n return raw;\n }\n const source = ctx.sources?.find(\n (candidate) => candidate.name === page.source.name\n );\n // Mirror the scan's expansion gate exactly (`!staged && contentRoot`): a\n // staged/custom source's entries were never expanded at scan time, so no\n // headings/links/diagnostics exist for the spliced content — expanding only\n // here would splice text the rest of the pipeline never validated, with no\n // content-root bound on resolution.\n if (!source || source.staged || !source.contentRoot) {\n return raw;\n }\n const expansion = await expandIncludes(raw, {\n contentRoot: source.contentRoot,\n sourcePath: page.sourcePath,\n });\n return expansion.text;\n};\n",
|
|
119
|
+
"import { readFile } from \"node:fs/promises\";\n\nimport { dirname, extname, join, relative, resolve } from \"pathe\";\n\nimport { nextFenceState } from \"./code-fences.ts\";\nimport type { FenceState } from \"./code-fences.ts\";\nimport matter from \"./frontmatter.ts\";\nimport { INLINE_CODE, MD_IMAGE, targetOffsetIn } from \"./sources/normalize.ts\";\nimport type { Diagnostic } from \"./types.ts\";\n\n/**\n * Content includes: `<include>./relative.mdx</include>` on a line of its own\n * splices another file into the page at build time — the syntax Fumadocs\n * ships, so migrated content works unchanged. Markdown/MDX targets are\n * spliced as content (front matter stripped, nested includes resolved, cycle\n * detection); any other extension — or an explicit `lang` attribute — embeds\n * the file as a fenced code block, with optional `meta` for the fence meta\n * string (e.g. `title=\"config.ts\"`).\n *\n * This module is the single owner of include semantics. The string-level\n * {@link expandIncludes} powers every surface that reads raw markdown source\n * (heading/link extraction, search indexing, the `/route.md` mirrors,\n * llms-full.txt), while {@link expandIncludeTarget} powers the Sätteri render\n * plugin, so what renders and what's indexed can't drift apart.\n */\n\n/** Docs page targets: `.md`/`.mdx` splice as content; anything else is code. */\nconst CONTENT_EXTENSIONS = new Set([\".md\", \".mdx\"]);\n\n/**\n * A full include statement occupying one (trimmed) line: optional lowercase\n * attributes, then the target path as the element's text. Attribute values\n * accept both quote styles; a bare attribute (no `=`) is allowed so future\n * boolean flags parse rather than break the statement match.\n *\n * The target is anchored to non-space characters on both ends (rather than a\n * lazy run trimmed by the following `\\s*`): a lazy `[^<>]*?` overlapping that\n * `\\s*` backtracks quadratically on inputs like `<include>x` plus a long run\n * of spaces with no closing tag (CodeQL js/polynomial-redos). With both ends\n * pinned, a trailing space run is consumed by `\\s*` alone and a failed match\n * stays linear.\n */\nconst INCLUDE_STATEMENT =\n /^<include(?<attrs>(?:\\s+[a-z][\\w-]*(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'))?)*)\\s*>\\s*(?<target>[^<>\\s](?:[^<>]*[^<>\\s])?)\\s*<\\/include\\s*>$/u;\n\n/** One attribute within a statement's attrs run. */\nconst INCLUDE_ATTRIBUTE =\n /(?<name>[a-z][\\w-]*)(?:\\s*=\\s*(?:\"(?<double>[^\"]*)\"|'(?<single>[^']*)'))?/gu;\n\n/**\n * Cheap pre-filter so include-free content (the overwhelmingly common case)\n * skips the line scan and file reads entirely.\n */\nexport const hasIncludeStatements = (text: string): boolean =>\n text.includes(\"<include\");\n\n/** A line indented four spaces (or a tab) — an indented code block in `.md`,\n * where the renderer shows a statement literally instead of splicing it. */\nconst INDENTED_CODE = /^(?: {4}|\\t)/u;\n\n/** A setext underline (`===`/`---`, up to 3 leading spaces): directly under a\n * statement line it folds the statement into a heading instead of a splice. */\nconst SETEXT_UNDERLINE = /^ {0,3}(?:=+|-+)\\s*$/u;\n\n/** Comment delimiters per format: `.md` uses HTML comments, `.mdx` JSX ones. */\nconst COMMENT_DELIMITERS = {\n md: { close: \"-->\", open: \"<!--\" },\n mdx: { close: \"*/}\", open: \"{/*\" },\n} as const;\n\n/**\n * Advance the comment state across one line: each open/close marker toggles\n * it, left to right. A line that *matches* a statement can't contain a marker\n * (the statement regex spans the whole trimmed line), so per-line state at the\n * line's start is all the statement scan needs.\n */\nconst advanceCommentState = (\n line: string,\n delimiters: { open: string; close: string },\n inComment: boolean\n): boolean => {\n let inside = inComment;\n let cursor = 0;\n for (;;) {\n const marker = inside ? delimiters.close : delimiters.open;\n const index = line.indexOf(marker, cursor);\n if (index === -1) {\n return inside;\n }\n inside = !inside;\n cursor = index + marker.length;\n }\n};\n\n/** The attributes an include statement supports. */\nexport interface IncludeAttributes {\n /** Force code-block mode with this language (even for `.md`/`.mdx`). */\n lang?: string;\n /** Fence meta string in code-block mode (e.g. `title=\"lib.ts\"`). */\n meta?: string;\n}\n\n/** A parsed include statement. */\nexport interface IncludeStatement {\n target: string;\n attributes: IncludeAttributes;\n}\n\n/**\n * Parse one trimmed line as an include statement, or `null` when it isn't\n * one. Only `lang` and `meta` are meaningful; unknown attributes parse and\n * are ignored so a future attribute degrades gracefully on older versions.\n */\nexport const parseIncludeStatement = (\n line: string\n): IncludeStatement | null => {\n const match = INCLUDE_STATEMENT.exec(line);\n if (!match?.groups) {\n return null;\n }\n const attributes: IncludeAttributes = {};\n for (const attr of (match.groups.attrs ?? \"\").matchAll(INCLUDE_ATTRIBUTE)) {\n const name = attr.groups?.name;\n const value = attr.groups?.double ?? attr.groups?.single;\n if (name === \"lang\" && value) {\n attributes.lang = value;\n }\n if (name === \"meta\" && value) {\n attributes.meta = value;\n }\n }\n return { attributes, target: match.groups.target ?? \"\" };\n};\n\n/**\n * Parse one raw `.md` source line as an include statement, applying the\n * line-level rules the renderer sees: a line indented like code (4 spaces or\n * a tab) is an indented code block, shown literally rather than spliced. The\n * render plugin's `.md` visitors share this so the two halves can't drift.\n */\nexport const parseIncludeLine = (line: string): IncludeStatement | null =>\n INDENTED_CODE.test(line) ? null : parseIncludeStatement(line.trim());\n\n/** A line that opens an include statement: `<include`, then a space, `>`, or its end. */\nconst INCLUDE_OPEN = /^<include(?:[\\s>]|$)/u;\n\n/** A line that closes one. */\nconst INCLUDE_CLOSE = /<\\/include\\s*>$/u;\n\n/**\n * How many lines a wrapped statement may span: room for a formatter that puts\n * every attribute on its own line, short enough that an unclosed `<include`\n * can't reach across a page.\n */\nconst MAX_STATEMENT_LINES = 8;\n\n/** What a line that may open an include statement turned out to be. */\nexport type IncludeMatch =\n /** A statement, ending on line `end` (the same line when it isn't wrapped). */\n | { kind: \"statement\"; end: number; statement: IncludeStatement }\n /** A line that opens `<include` but no statement Blume can read. */\n | { kind: \"malformed\" }\n /** Not an include statement at all. */\n | { kind: \"none\" };\n\n/**\n * Read the include statement opening at `lines[index]`, if any. A statement\n * sits on a line of its own, or — as a formatter wraps a long one — runs from a\n * line opening `<include` to the next line closing `</include>`, with no blank\n * line between (the path on its own line, attributes on one line or several):\n *\n * ```mdx\n * <include lang=\"ts\" meta='title=\"config.ts\"'>\n * ./examples/config.ts\n * </include>\n * ```\n *\n * The lines' trimmed text joins into the one-line form, so both parse by the\n * same rules. In `.md` a first line indented like code is a code block, never\n * a statement. A line that opens `<include` but doesn't close into a\n * statement is `malformed`, so the author hears about it instead of the page\n * rendering the raw tag. Shared by the string-level scanner and the render\n * plugin so they splice exactly the same statements.\n */\nexport const matchIncludeStatement = (\n lines: readonly string[],\n index: number,\n format: \"md\" | \"mdx\"\n): IncludeMatch => {\n const first = lines[index] ?? \"\";\n if (format === \"md\" && INDENTED_CODE.test(first)) {\n return { kind: \"none\" };\n }\n const opening = first.trim();\n if (!INCLUDE_OPEN.test(opening)) {\n return { kind: \"none\" };\n }\n const single = parseIncludeStatement(opening);\n if (single) {\n return { end: index, kind: \"statement\", statement: single };\n }\n const parts = [opening];\n const last = Math.min(lines.length, index + MAX_STATEMENT_LINES) - 1;\n for (let end = index + 1; end <= last; end += 1) {\n const part = (lines[end] ?? \"\").trim();\n if (part === \"\") {\n break;\n }\n parts.push(part);\n if (INCLUDE_CLOSE.test(part)) {\n const statement = parseIncludeStatement(parts.join(\" \"));\n return statement\n ? { end, kind: \"statement\", statement }\n : { kind: \"malformed\" };\n }\n }\n return { kind: \"malformed\" };\n};\n\n/**\n * The warning for a line that opens `<include` but isn't a statement Blume can\n * read — it renders as written, so a silent miss would ship a raw tag.\n */\nexport const malformedIncludeDiagnostic = (\n file: string,\n line: number\n): Diagnostic => ({\n code: \"BLUME_INCLUDE_MALFORMED\",\n file,\n line,\n message:\n \"This <include> isn't a statement Blume can read, so the page shows it as written.\",\n severity: \"warning\",\n suggestion:\n \"Write <include>./path.mdx</include> on a line of its own, or wrap it with the path on its own line and no blank lines; only lang and meta attributes are read.\",\n});\n\n/**\n * Advance the HTML comment state across one `.md` line — the render plugin's\n * half of the comment rule (a statement inside `<!-- -->` never splices),\n * sharing the same tracking the string-level scanner uses.\n */\nexport const advanceHtmlCommentState = (\n line: string,\n inComment: boolean\n): boolean => advanceCommentState(line, COMMENT_DELIMITERS.md, inComment);\n\n/** Provenance of one line of expanded output. */\nexport interface LineOrigin {\n /** Absolute path of the file the line came from. */\n file: string;\n /** 1-based line number within that file's raw source. */\n line: number;\n}\n\n/** The result of expanding a document's include statements. */\nexport interface IncludeExpansion {\n /** The document with every include statement replaced by its content. */\n text: string;\n /** Per output line: the source file and raw-file line it came from. */\n origins: LineOrigin[];\n /** Absolute paths of every file included, transitively. */\n includes: string[];\n /** Structured errors (missing target, cycle, escape); statements with an\n * error stay verbatim in the output. */\n errors: Diagnostic[];\n}\n\ninterface ExpandContext {\n /** The owning source's content root; bounds resolution when set. */\n contentRoot?: string;\n includes: Set<string>;\n errors: Diagnostic[];\n}\n\nconst DOCS_SUGGESTION =\n \"Include paths resolve relative to the including file; paths starting with / resolve from the content root.\";\n\nconst includeError = (\n code: string,\n message: string,\n file: string,\n line: number,\n suggestion: string\n): Diagnostic => ({ code, file, line, message, severity: \"error\", suggestion });\n\n/**\n * Whether `path` lies outside `root`. The relative path must be `..` itself or\n * start with a `../` *segment* — a bare `.startsWith(\"..\")` would also reject\n * a legal in-root directory whose name begins with two dots (`..archive/`).\n */\nconst escapesRoot = (root: string, path: string): boolean => {\n const rel = relative(root, path);\n return rel === \"..\" || rel.startsWith(\"../\");\n};\n\n/**\n * Resolve a statement's target to an absolute path, or an error when it can't\n * be resolved safely. `/`-leading targets resolve from the content root;\n * everything else resolves from the including file's directory. Targets must\n * stay within the content root — a partial outside it would be silently\n * dropped from version snapshots and ejects (and an escaping path could\n * splice arbitrary files into published pages). Both branches enforce the\n * bound: a root-relative target can still climb out through `..` segments.\n */\nconst resolveIncludePath = (\n target: string,\n filePath: string,\n ctx: ExpandContext,\n line: number\n): { path: string } | { error: Diagnostic } => {\n if (target.startsWith(\"/\")) {\n if (!ctx.contentRoot) {\n return {\n error: includeError(\n \"BLUME_INCLUDE_OUTSIDE_ROOT\",\n `Include target ${target} is root-relative, but no content root is configured here.`,\n filePath,\n line,\n \"Use a path relative to the including file instead.\"\n ),\n };\n }\n const path = join(ctx.contentRoot, target);\n if (escapesRoot(ctx.contentRoot, path)) {\n return {\n error: includeError(\n \"BLUME_INCLUDE_OUTSIDE_ROOT\",\n `Include target ${target} resolves outside the content root.`,\n filePath,\n line,\n \"Root-relative include paths resolve from the content root and cannot climb above it.\"\n ),\n };\n }\n return { path };\n }\n const path = resolve(dirname(filePath), target);\n if (ctx.contentRoot && escapesRoot(ctx.contentRoot, path)) {\n return {\n error: includeError(\n \"BLUME_INCLUDE_OUTSIDE_ROOT\",\n `Include target ${target} resolves outside the content root.`,\n filePath,\n line,\n \"Move the included file under the content root so builds, version snapshots, and ejects all see it.\"\n ),\n };\n }\n return { path };\n};\n\n/**\n * Rewrite one line's relative image targets from the included file's\n * directory to the including file's, so a partial's colocated\n * `` still resolves once its markdown lives in the\n * includer. Mirrors `rewriteLine` in `content-assets.ts`: matches run on an\n * inline-code-masked copy while replacements splice into the real line.\n */\nconst rebaseImageLine = (\n line: string,\n fromDir: string,\n toDir: string\n): string => {\n const masked = line.replaceAll(INLINE_CODE, (span) =>\n \" \".repeat(span.length)\n );\n let out = \"\";\n let cursor = 0;\n for (const match of masked.matchAll(MD_IMAGE)) {\n const target = match.groups?.target ?? \"\";\n // Only filesystem-relative targets move with the file: URLs, public-dir\n // absolutes, and anchors mean the same thing from either directory.\n if (\n target.startsWith(\"/\") ||\n target.startsWith(\"#\") ||\n URL.canParse(target)\n ) {\n continue;\n }\n const rebased = relative(toDir, resolve(fromDir, target));\n const url = rebased.startsWith(\".\") ? rebased : `./${rebased}`;\n const offset =\n (match.index ?? 0) +\n targetOffsetIn(match[0], target, match.groups?.title);\n out += line.slice(cursor, offset) + url;\n cursor = offset + target.length;\n }\n return out + line.slice(cursor);\n};\n\n/** Rebase every relative image target in expanded lines, skipping fences. */\nconst rebaseImages = (\n lines: string[],\n fromDir: string,\n toDir: string\n): string[] => {\n if (fromDir === toDir) {\n return lines;\n }\n let fence: FenceState = null;\n return lines.map((line) => {\n const next = nextFenceState(line, fence);\n const inFence = fence !== null || next !== null;\n fence = next;\n return inFence ? line : rebaseImageLine(line, fromDir, toDir);\n });\n};\n\n/** Wrap raw file content as a fenced code block that can't be broken by the\n * content's own backtick runs. */\nconst codeBlockLines = (\n content: string,\n path: string,\n attributes: IncludeAttributes\n): string[] => {\n const body = content.replace(/\\n$/u, \"\");\n let longestRun = 0;\n for (const run of body.match(/`+/gu) ?? []) {\n longestRun = Math.max(longestRun, run.length);\n }\n const fence = \"`\".repeat(Math.max(3, longestRun + 1));\n const ext = extname(path);\n const lang = attributes.lang ?? (ext ? ext.slice(1) : \"text\");\n const meta = attributes.meta ? ` ${attributes.meta}` : \"\";\n return [`${fence}${lang}${meta}`, ...body.split(\"\\n\"), fence];\n};\n\n/** Lines-with-origins pair every splice step produces. */\ninterface ExpandedLines {\n lines: string[];\n origins: LineOrigin[];\n}\n\n/**\n * Resolve one include statement to its expanded lines. Content targets are\n * front-matter-stripped, recursively expanded, and image-rebased into the\n * includer's directory; code targets are fence-wrapped verbatim.\n */\nconst expandStatement = async (\n statement: IncludeStatement,\n filePath: string,\n line: number,\n ctx: ExpandContext,\n stack: readonly string[]\n): Promise<ExpandedLines | { error: Diagnostic }> => {\n const resolved = resolveIncludePath(statement.target, filePath, ctx, line);\n if (\"error\" in resolved) {\n return resolved;\n }\n const { path } = resolved;\n if (stack.includes(path)) {\n return {\n error: includeError(\n \"BLUME_INCLUDE_CYCLE\",\n `Circular include: ${[...stack, path]\n .map((entry) => relative(ctx.contentRoot ?? dirname(path), entry))\n .join(\" -> \")}.`,\n filePath,\n line,\n \"Remove the include statement that closes the loop.\"\n ),\n };\n }\n let content: string;\n try {\n content = await readFile(path, \"utf-8\");\n } catch (error) {\n return {\n error: includeError(\n \"BLUME_INCLUDE_NOT_FOUND\",\n `Include target ${statement.target} was not found (looked at ${path}): ${\n error instanceof Error ? error.message : String(error)\n }.`,\n filePath,\n line,\n DOCS_SUGGESTION\n ),\n };\n }\n ctx.includes.add(path);\n\n const asContent =\n !statement.attributes.lang &&\n CONTENT_EXTENSIONS.has(extname(path).toLowerCase());\n if (!asContent) {\n const lines = codeBlockLines(content, path, statement.attributes);\n // Fence delimiters are synthetic; anchor them (and the verbatim body,\n // which link extraction skips as fenced code anyway) to the target file.\n return {\n lines,\n origins: lines.map((_, i) => ({ file: path, line: Math.max(1, i) })),\n };\n }\n\n const parsed = matter(content);\n const body = parsed.content;\n const strippedOffset = Math.max(\n 0,\n content.split(\"\\n\").length - body.split(\"\\n\").length\n );\n // The stack is copied per branch (never mutated) so sibling statements can\n // expand concurrently without seeing each other's frames as cycles.\n // oxlint-disable-next-line no-use-before-define -- mutual recursion: a partial expands its own includes\n const expanded = await expandLines(body, path, strippedOffset, ctx, [\n ...stack,\n path,\n ]);\n // Blank edge lines (the file's trailing newline, cosmetic leading gaps)\n // carry no markdown meaning; trimming them keeps splices tight and the\n // padding in `expandLines` the only blank-line authority.\n const lines = [...expanded.lines];\n const origins = [...expanded.origins];\n while (lines.at(-1)?.trim() === \"\") {\n lines.pop();\n origins.pop();\n }\n while (lines[0]?.trim() === \"\") {\n lines.shift();\n origins.shift();\n }\n return {\n lines: rebaseImages(lines, dirname(path), dirname(filePath)),\n origins,\n };\n};\n\n/**\n * Pass 1 of {@link expandLines}: find each include statement (outside fenced\n * code, comments, and — in `.md` — indented code blocks), indexed by the line\n * it opens on. A commented-out statement never renders, so expanding it would\n * leak the partial into search/mirror surfaces the page doesn't show.\n * Indented code and setext underlines only exist in `.md` (MDX has neither,\n * and an indented `<include>` there is still JSX flow the renderer splices).\n */\nconst scanStatements = (\n sourceLines: string[],\n isMdx: boolean\n): (IncludeMatch | null)[] => {\n const delimiters = COMMENT_DELIMITERS[isMdx ? \"mdx\" : \"md\"];\n const format = isMdx ? \"mdx\" : \"md\";\n const matches: (IncludeMatch | null)[] = sourceLines.map(() => null);\n let fence: FenceState = null;\n let inComment = false;\n for (let index = 0; index < sourceLines.length; index += 1) {\n const line = sourceLines[index] ?? \"\";\n if (inComment) {\n inComment = advanceCommentState(line, delimiters, true);\n continue;\n }\n const next = nextFenceState(line, fence);\n const inFence = fence !== null || next !== null;\n fence = next;\n if (inFence) {\n continue;\n }\n inComment = advanceCommentState(line, delimiters, false);\n if (inComment || !hasIncludeStatements(line)) {\n continue;\n }\n const match = matchIncludeStatement(sourceLines, index, format);\n // A setext underline directly below folds the statement into a heading —\n // the renderer shows a heading, not a splice, so skip it.\n if (\n match.kind === \"statement\" &&\n !isMdx &&\n SETEXT_UNDERLINE.test(sourceLines[match.end + 1] ?? \"\")\n ) {\n continue;\n }\n matches[index] = match;\n if (match.kind === \"statement\") {\n // A wrapped statement's remaining lines belong to it.\n index = match.end;\n }\n }\n return matches;\n};\n\n/**\n * Walk a document's lines, replacing each include statement (outside fenced\n * code, comments, and — in `.md` — indented code blocks) with the target's\n * expanded lines. Statements that error stay verbatim so downstream surfaces\n * show what the author wrote; a blank line is padded around each splice so a\n * partial can't merge into an adjacent paragraph.\n */\nconst expandLines = async (\n body: string,\n filePath: string,\n lineOffset: number,\n ctx: ExpandContext,\n stack: readonly string[]\n): Promise<ExpandedLines> => {\n const sourceLines = body.split(\"\\n\");\n const isMdx = extname(filePath).toLowerCase() === \".mdx\";\n const matches = scanStatements(sourceLines, isMdx);\n\n // Pass 2: expand every statement concurrently — reads are independent, and\n // each branch carries its own cycle stack.\n const expansions = await Promise.all(\n matches.map((match, index) =>\n match?.kind === \"statement\"\n ? expandStatement(\n match.statement,\n filePath,\n lineOffset + index + 1,\n ctx,\n stack\n )\n : null\n )\n );\n\n // Pass 3: assemble sequentially — the blank-line padding depends on the\n // accumulated output, and error order should follow document order.\n const lines: string[] = [];\n const origins: LineOrigin[] = [];\n for (let index = 0; index < sourceLines.length; index += 1) {\n const line = sourceLines[index] ?? \"\";\n const rawLine = lineOffset + index + 1;\n const match = matches[index];\n const expanded = expansions[index];\n if (match?.kind === \"malformed\") {\n ctx.errors.push(malformedIncludeDiagnostic(filePath, rawLine));\n }\n if (!expanded || \"error\" in expanded) {\n if (expanded) {\n ctx.errors.push(expanded.error);\n }\n lines.push(line);\n origins.push({ file: filePath, line: rawLine });\n continue;\n }\n const pad = (): void => {\n lines.push(\"\");\n origins.push({ file: filePath, line: rawLine });\n };\n if (lines.at(-1)?.trim()) {\n pad();\n }\n lines.push(...expanded.lines);\n origins.push(...expanded.origins);\n // A wrapped statement's remaining lines were spliced with it.\n if (match?.kind === \"statement\") {\n index = match.end;\n }\n if (sourceLines[index + 1]?.trim()) {\n pad();\n }\n }\n return { lines, origins };\n};\n\n/**\n * Expand a document's include statements at the string level. `lineOffset`\n * shifts the includer's own recorded origin lines — pass the stripped front\n * matter block's height when `body` is the stripped text, so origins point at\n * real file lines. Never throws: unresolvable statements stay verbatim and\n * surface through `errors`.\n */\nexport const expandIncludes = async (\n body: string,\n options: {\n /** Absolute path of the file being expanded. */\n sourcePath: string;\n /** The owning source's content root; bounds include resolution. */\n contentRoot?: string;\n /** Raw-file line of `body`'s first line, minus one (default `0`). */\n lineOffset?: number;\n }\n): Promise<IncludeExpansion> => {\n const ctx: ExpandContext = {\n contentRoot: options.contentRoot,\n errors: [],\n includes: new Set(),\n };\n const { lines, origins } = await expandLines(\n body,\n options.sourcePath,\n options.lineOffset ?? 0,\n ctx,\n [options.sourcePath]\n );\n return {\n errors: ctx.errors,\n includes: [...ctx.includes],\n origins,\n text: lines.join(\"\\n\"),\n };\n};\n\n/**\n * Resolve one include statement to its fully-expanded markdown text — the\n * render plugin's entry point (it finds the statements as AST nodes and only\n * needs each target spliced). Shares every semantic with\n * {@link expandIncludes}.\n */\nexport const expandIncludeTarget = async (\n statement: IncludeStatement,\n options: { sourcePath: string; contentRoot?: string }\n): Promise<{ text: string; errors: Diagnostic[] } | { error: Diagnostic }> => {\n const ctx: ExpandContext = {\n contentRoot: options.contentRoot,\n errors: [],\n includes: new Set(),\n };\n const expanded = await expandStatement(\n statement,\n options.sourcePath,\n 0,\n ctx,\n [options.sourcePath]\n );\n if (\"error\" in expanded) {\n return { error: expanded.error };\n }\n // Nested statements that errored stay verbatim inside the splice (matching\n // the string-level surfaces); they're reported so the render can warn.\n return { errors: ctx.errors, text: expanded.lines.join(\"\\n\") };\n};\n\n/**\n * Invert the scan's page → included-partials edges into the partial →\n * including-pages map `includeHmrPlugin` reads (`generated/includes.json`),\n * so editing a partial invalidates every page that splices it. Localized\n * pages share a source path, hence the dedupe. Shared by `generateRuntime`\n * and `eject`, whose configs both wire the plugin at the same path.\n */\nexport const buildIncludeGraph = (\n pages: { sourcePath?: string; includes?: string[] }[]\n) => {\n const graph: Record<string, string[]> = {};\n for (const page of pages) {\n const { sourcePath } = page;\n if (!sourcePath) {\n continue;\n }\n for (const partial of page.includes ?? []) {\n const includers = graph[partial] ?? [];\n graph[partial] = includers;\n if (!includers.includes(sourcePath)) {\n includers.push(sourcePath);\n }\n }\n }\n return graph;\n};\n",
|
|
120
|
+
"import baseMatter from \"gray-matter\";\nimport { dump, load } from \"js-yaml\";\n\nimport { YAML_SCHEMA } from \"./yaml.ts\";\n\n// gray-matter@4 binds js-yaml 3's `safeLoad`/`safeDump` as its default YAML\n// engine. In a workspace that resolves a newer js-yaml for gray-matter — v4\n// replaced those functions with throwing stubs, v5 dropped them — parsing\n// front matter throws \"Function yaml.safeLoad is removed in js-yaml 4.\" Every\n// Blume front-matter call routes through this `matter` wrapper, which supplies\n// an explicit engine built on Blume's own `load`/`dump`, so Blume is immune to\n// whichever version the consumer's install resolves for gray-matter.\n\ntype MatterInput = Parameters<typeof baseMatter>[0];\ntype MatterOptions = Parameters<typeof baseMatter>[1];\ntype ReadArgs = Parameters<typeof baseMatter.read>;\ntype StringifyArgs = Parameters<typeof baseMatter.stringify>;\n\n/** Front matter data as gray-matter types it (`GrayMatterFile[\"data\"]`). */\ntype FrontMatterData = ReturnType<typeof baseMatter>[\"data\"];\n\nconst yamlEngine = {\n // SAFETY: gray-matter's engine contract expects an object; a front matter\n // block is a YAML mapping, and js-yaml returns a scalar only for degenerate\n // input, which gray-matter treats the same way its bundled engine's output\n // is treated.\n parse: (input: string): object =>\n (load(input, { schema: YAML_SCHEMA }) ?? {}) as object,\n stringify: (data: FrontMatterData): string => dump(data),\n};\n\nconst withYamlEngine = <O extends { engines?: object } | undefined>(\n options: O\n): O =>\n // SAFETY: the spread keeps every field of `options`; adding a default yaml\n // engine (overridden by any caller-supplied `engines`) stays within O's\n // shape — TS just can't prove a spread of a generic re-satisfies O.\n ({\n ...options,\n engines: {\n yaml: yamlEngine,\n ...options?.engines,\n },\n }) as O;\n\n/**\n * True when a document's leading `---` line is a CommonMark thematic break,\n * not a front matter fence. Two shapes qualify (mirroring\n * `linesWithoutFrontMatter` in `sources/normalize.ts`):\n * - the next line is blank (or absent) — YAML metadata starts on the very\n * next line, so a gap means the body *opens* with a divider (e.g. a\n * Notion page whose first block is one);\n * - no closing `---` line follows — gray-matter would swallow the whole\n * document as one unclosed YAML block and hand it to js-yaml, which\n * crashes on ordinary Markdown (`> quote` → \"a line break is expected\").\n */\nconst opensWithThematicBreak = (input: string): boolean => {\n const [first = \"\", second] = input.split(/\\r?\\n/u, 2);\n if (!/^-{3}\\s*$/u.test(first)) {\n return false;\n }\n if (second === undefined || second.trim() === \"\") {\n return true;\n }\n // gray-matter closes the block at the next line-leading `---`; matching its\n // search exactly keeps this guard from firing on any document it parses.\n return !input.includes(\"\\n---\", 1);\n};\n\n/**\n * gray-matter's runtime result carries `isEmpty`, which its declared\n * GrayMatterFile type omits.\n */\ninterface MatterResult extends ReturnType<typeof baseMatter> {\n isEmpty: boolean;\n}\n\n/**\n * The parse result for a document with no front matter: the input passes\n * through as content, untouched. Shaped like gray-matter's own no-matter\n * result (every Blume call site reads only `content` and `data`).\n */\nconst passthrough = (input: string): ReturnType<typeof baseMatter> => {\n const file: MatterResult = {\n content: input,\n data: {},\n excerpt: \"\",\n isEmpty: false,\n language: \"\",\n matter: \"\",\n orig: input,\n // Recomposing a file with no matter and empty data is the content itself.\n stringify: (): string => input,\n };\n return file;\n};\n\n/** Narrows gray-matter's input union to the raw-string form. */\nconst isStringInput = (input: MatterInput): input is string =>\n typeof input === \"string\";\n\n// Every helper that parses or emits YAML (`read`, `stringify`) must be\n// re-wrapped here — Object.assign copies gray-matter's own helpers, which use\n// its default `safeLoad` engine and would reintroduce the crash. `test` only\n// checks for a delimiter, so the copied original is safe.\nconst matter = Object.assign(\n (input: MatterInput, options?: MatterOptions) =>\n isStringInput(input) && opensWithThematicBreak(input)\n ? passthrough(input)\n : baseMatter(input, withYamlEngine(options)),\n baseMatter,\n {\n read: (filepath: ReadArgs[0], options?: ReadArgs[1]) =>\n baseMatter.read(filepath, withYamlEngine(options)),\n // A string is the body to emit, not a document to parse: gray-matter\n // would otherwise run `matter()` over it, and a body that opens with a\n // `---` divider reads as a second front matter block — js-yaml either\n // throws or swallows the opening paragraph into the YAML header.\n stringify: (\n file: StringifyArgs[0],\n data: StringifyArgs[1],\n options?: StringifyArgs[2]\n ): string =>\n baseMatter.stringify(\n isStringInput(file) ? { content: file } : file,\n data,\n withYamlEngine(options)\n ),\n }\n);\n\nexport default matter;\n",
|
|
121
|
+
"import {\n binaryTag,\n CORE_SCHEMA,\n mergeTag,\n omapTag,\n pairsTag,\n setTag,\n timestampTag,\n} from \"js-yaml\";\n\n/**\n * The schema js-yaml 4 loaded with by default: YAML 1.2 core scalars plus the\n * `!!timestamp`, `!!merge`, `!!binary`, `!!omap`, `!!pairs`, and `!!set` tags.\n * js-yaml 5 loads with the bare core schema instead, which turns\n * `date: 2024-01-01` into a string and leaves `<<:` merge keys unresolved — a\n * silent change to every page's front matter. Every Blume `load` call passes\n * this schema so parsing stays identical across the upgrade.\n */\nexport const YAML_SCHEMA = CORE_SCHEMA.withTags(\n timestampTag,\n mergeTag,\n binaryTag,\n omapTag,\n pairsTag,\n setTag\n);\n",
|
|
122
|
+
"import {\n isInternalPath,\n normalizePath,\n stripBasePath,\n withBasePath,\n} from \"./base-path.ts\";\nimport { localePrefix, localizeRoute } from \"./i18n.ts\";\nimport type { LocaleRouting } from \"./i18n.ts\";\n\n/**\n * Locale-aware resolution of content links.\n *\n * Authors write internal links as if mounted at the default locale's root\n * (`[x](/guide)`, `<Card href=\"/guide\">`), and translated pages are usually\n * copies of the source with the same links — so read on `/fr/…`, a link would\n * otherwise drop the reader back into the default language. These helpers move\n * such a link to the reader's locale (`/fr/guide`) when that route is served\n * (a real translation or a materialized fallback page), and leave it alone\n * otherwise: an explicit cross-locale link (`/de/guide`), a custom `.astro`\n * page or generated route that has no per-locale variant, or a missing\n * translation on a site with fallbacks disabled all keep their authored\n * target rather than pointing at a 404.\n *\n * The rewrite runs at render time (`components/layout/LocaleLinks.astro`)\n * because content is compiled once per file but served per route: a fallback\n * route renders the fallback locale's file under the missing locale's URL, and\n * a shared `page.$.mdx` renders under every locale. The link checker applies\n * the same resolution so anchors are validated against the page a reader lands\n * on.\n */\n\n/** A route set, as the runtime (`Set`) or the checker (a predicate) sees it. */\nexport interface RouteSet {\n has: (route: string) => boolean;\n}\n\nexport interface LocalizeLinkOptions {\n /** Site-wide route mount point (`\"\"` or `/seg`); routes carry it. */\n basePath: string;\n i18n: LocaleRouting;\n /** Locale of the page the link is rendered on. */\n locale: string;\n /** Every served route, base-prefixed like `path` (no `deployment.base`). */\n routes: RouteSet;\n}\n\n/**\n * Mirrors the asset heuristic in `markdown/base-links.ts`: a path whose final\n * segment carries a file extension is a `public/` asset (or a raw `.md` twin),\n * served at the site root and never localized.\n */\nconst ASSET_PATH = /\\.[a-z0-9]+$/iu;\n\n/** Decode a percent-encoded path for a route lookup; leave junk as-is. */\nconst decodePercent = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\n/** Whether `path` (base-stripped) already sits under some locale's prefix. */\nconst hasLocalePrefix = (path: string, i18n: LocaleRouting): boolean =>\n i18n.locales.some((locale) => {\n const prefix = localePrefix(locale.code, i18n);\n return prefix !== \"\" && (path === prefix || path.startsWith(`${prefix}/`));\n });\n\n/**\n * Move a base-prefixed, fragment-less internal path into `locale` when that\n * route is served, else return it unchanged. Idempotent: a path already under\n * any configured locale prefix is never re-prefixed.\n */\nexport const localizeLinkPath = (\n path: string,\n options: LocalizeLinkOptions\n): string => {\n const { basePath, i18n, locale, routes } = options;\n if (localePrefix(locale, i18n) === \"\") {\n return path;\n }\n const rest = normalizePath(stripBasePath(basePath, path));\n if (hasLocalePrefix(rest, i18n)) {\n return path;\n }\n const localized = withBasePath(basePath, localizeRoute(rest, locale, i18n));\n // Routes are stored decoded; a browser-copied `/caf%C3%A9` must still find\n // its translation, but the emitted href keeps the author's encoding.\n return routes.has(localized) || routes.has(decodePercent(localized))\n ? localized\n : path;\n};\n\nexport interface LocalizeHrefOptions extends LocalizeLinkOptions {\n /** `deployment.base` (Astro's `BASE_URL`), layered over `basePath` in hrefs. */\n deployBase: string;\n}\n\n/**\n * Localize a rendered `href`: external URLs, relative paths, bare fragments, and\n * asset links pass through; a root-relative page link keeps its `?query` and\n * `#fragment` and its `deployment.base` layer around the localized path.\n */\nexport const localizeHref = (\n href: string,\n options: LocalizeHrefOptions\n): string => {\n if (!isInternalPath(href)) {\n return href;\n }\n const suffixAt = href.search(/[#?]/u);\n const path = suffixAt === -1 ? href : href.slice(0, suffixAt);\n const suffix = suffixAt === -1 ? \"\" : href.slice(suffixAt);\n if (ASSET_PATH.test(path)) {\n return href;\n }\n const based = stripBasePath(options.deployBase, path);\n const localized = localizeLinkPath(based, options);\n if (localized === based) {\n return href;\n }\n return `${withBasePath(options.deployBase, localized)}${suffix}`;\n};\n\n/** Every `<a …>` opening tag; `\\s` keeps `<abbr>`/`<astro-island>` out. */\nconst ANCHOR_TAG = /<a\\s[^>]*>/giu;\n/** The tag's `href` attribute, double- or single-quoted. */\nconst HREF_ATTR = /(?<attr>\\shref=)(?:\"(?<dq>[^\"]*)\"|'(?<sq>[^']*)')/iu;\n\n/**\n * Rewrite every `<a href>` in rendered content HTML through `rewrite`. Code\n * blocks are HTML-escaped (`<a`), and island props live on\n * `<astro-island>`, so neither is touched.\n */\nexport const localizeContentLinks = (\n html: string,\n rewrite: (href: string) => string\n): string =>\n html.replace(ANCHOR_TAG, (tag) =>\n tag.replace(HREF_ATTR, (_match, attr: string, dq?: string, sq?: string) => {\n const quote = dq === undefined ? \"'\" : '\"';\n return `${attr}${quote}${rewrite(dq ?? sq ?? \"\")}${quote}`;\n })\n );\n\n/**\n * The served route set for `blume:data`'s routes, built once per routes array\n * (the virtual module is evaluated once, so every page render shares it).\n */\nconst routeSets = new WeakMap<readonly { path: string }[], Set<string>>();\n\nexport const routeSetFor = (\n routes: readonly { path: string }[]\n): Set<string> => {\n const cached = routeSets.get(routes);\n if (cached) {\n return cached;\n }\n const built = new Set(routes.map((route) => route.path));\n routeSets.set(routes, built);\n return built;\n};\n",
|
|
123
|
+
"import pMap from \"p-map\";\n\nimport type { DiagnosticSeverity } from \"./types.ts\";\n\nexport const PROBE_CONCURRENCY = 8;\nexport const PROBE_TIMEOUT_MS = 10_000;\n\nconst STATUS_NOT_FOUND = 404;\nconst STATUS_GONE = 410;\nconst STATUS_METHOD_NOT_ALLOWED = 405;\nconst STATUS_NOT_IMPLEMENTED = 501;\n\n/** The outcome of a single HTTP probe, with failures normalized rather than thrown. */\nexport interface ProbeResult {\n ok: boolean;\n status?: number;\n timedOut?: boolean;\n error?: string;\n /** Whether the request was redirected before landing on `status`. */\n redirected?: boolean;\n /** The URL finally landed on, after following redirects. */\n finalUrl?: string;\n /** `Content-Encoding` of the response, when the server set one. */\n encoding?: string | null;\n /** Wall-clock milliseconds for the request. */\n ms?: number;\n /** `X-Robots-Tag` of the response, when the server set one. */\n robotsTag?: string | null;\n}\n\n/** Probe a URL with the given method, normalizing failures to a result. */\nconst request = async (\n url: string,\n method: \"GET\" | \"HEAD\",\n timeoutMs: number\n): Promise<ProbeResult> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const started = performance.now();\n try {\n const response = await fetch(url, {\n method,\n redirect: \"follow\",\n signal: controller.signal,\n });\n return {\n encoding: response.headers.get(\"content-encoding\"),\n finalUrl: response.url,\n ms: Math.round(performance.now() - started),\n ok: response.ok,\n redirected: response.redirected,\n robotsTag: response.headers.get(\"x-robots-tag\"),\n status: response.status,\n };\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return { ok: false, timedOut: true };\n }\n return {\n error: error instanceof Error ? error.message : String(error),\n ok: false,\n };\n } finally {\n clearTimeout(timer);\n }\n};\n\n/**\n * Probe a single URL: HEAD first, falling back to GET.\n *\n * Plenty of servers reject HEAD outright (405/501) or drop the connection, so a\n * HEAD-only probe would report healthy pages as dead.\n */\nexport const probe = async (\n url: string,\n options: { timeoutMs?: number } = {}\n): Promise<ProbeResult> => {\n const timeoutMs = options.timeoutMs ?? PROBE_TIMEOUT_MS;\n const head = await request(url, \"HEAD\", timeoutMs);\n const unreachable = !head.ok && head.status === undefined && !head.timedOut;\n const retry =\n head.status === STATUS_METHOD_NOT_ALLOWED ||\n head.status === STATUS_NOT_IMPLEMENTED ||\n unreachable;\n return retry ? await request(url, \"GET\", timeoutMs) : head;\n};\n\n/** Grade a probe result into a severity + detail, or null when the URL is fine. */\nexport const gradeExternal = (\n result: ProbeResult\n): { severity: DiagnosticSeverity; detail: string } | null => {\n if (result.ok) {\n return null;\n }\n if (result.timedOut) {\n return { detail: \"request timed out\", severity: \"warning\" };\n }\n if (result.status === undefined) {\n return { detail: result.error ?? \"unreachable\", severity: \"error\" };\n }\n // A 404/410 is definitively dead. A 403/429/5xx may well be rate limiting or a\n // transient blip, which is not the author's bug to fix.\n if (result.status === STATUS_NOT_FOUND || result.status === STATUS_GONE) {\n return { detail: `HTTP ${result.status}`, severity: \"error\" };\n }\n return { detail: `HTTP ${result.status}`, severity: \"warning\" };\n};\n\n/**\n * Probe many URLs with bounded concurrency, deduplicating first. Returns a map\n * from URL to its result — the caller decides what each one means.\n */\nexport const probeAll = async (\n urls: readonly string[],\n options: { concurrency?: number; timeoutMs?: number } = {}\n): Promise<Map<string, ProbeResult>> => {\n const unique = [...new Set(urls)];\n const entries = await pMap(\n unique,\n async (url) => [url, await probe(url, options)] as const,\n { concurrency: Math.max(1, options.concurrency ?? PROBE_CONCURRENCY) }\n );\n return new Map(entries);\n};\n",
|
|
124
|
+
"import { existsSync, readFileSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport { detect } from \"package-manager-detector/detect\";\nimport { basename, dirname, isAbsolute, join, relative } from \"pathe\";\n\nimport { blumePackageJson, toPackageName } from \"../../core/package-json.ts\";\nimport { contentful } from \"../../sources/contentful.ts\";\nimport { githubReleases } from \"../../sources/github-releases.ts\";\nimport { mdxRemote } from \"../../sources/mdx-remote.ts\";\nimport { notion } from \"../../sources/notion.ts\";\nimport { obsidian } from \"../../sources/obsidian.ts\";\nimport { payload } from \"../../sources/payload.ts\";\nimport type { AnySourceAdapter } from \"../../sources/registry.ts\";\nimport { sanity } from \"../../sources/sanity.ts\";\nimport { strapi } from \"../../sources/strapi.ts\";\n\nexport const TEMPLATES = [\"docs\", \"api\", \"sdk\", \"changelog\"] as const;\nexport type Template = (typeof TEMPLATES)[number];\n\nexport const PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\n/** The content-source kinds `init` can scaffold a config block for. */\nexport const SOURCE_KINDS = [\n \"filesystem\",\n \"obsidian\",\n \"github-releases\",\n \"notion\",\n \"sanity\",\n \"contentful\",\n \"payload\",\n \"strapi\",\n \"mdx-remote\",\n] as const;\nexport type SourceKind = (typeof SOURCE_KINDS)[number];\n\n/** Everything the scaffolder needs, whether prompted or derived from flags. */\nexport interface InitAnswers {\n contentDir: string;\n /** Target directory as the user gave it (`.` = current directory). */\n directory: string;\n packageManager: PackageManager;\n sources: SourceKind[];\n template: Template;\n title: string;\n}\n\n/** One file the scaffold plan will write; `path` is absolute. */\nexport interface ScaffoldFile {\n content: string;\n path: string;\n}\n\n/** Log sink for scaffold output — satisfied by both consola and clack's `log`. */\nexport interface ScaffoldLog {\n info: (message: string) => void;\n success: (message: string) => void;\n}\n\n/** A starter: a config fragment plus seed content files (paths relative to root). */\ninterface Starter {\n configExtra: string;\n /** Import lines the fragment needs, placed after the `defineConfig` import. */\n configImports: string[];\n files: (contentDir: string) => { content: string; path: string }[];\n}\n\nconst page = (title: string, description: string, body: string): string =>\n `---\\ntitle: ${title}\\ndescription: ${description}\\n---\\n\\n${body}\\n`;\n\nexport const STARTERS = {\n api: {\n configExtra: `\n reference: [\n openapi({\n route: \"/api\",\n sources: [\n {\n label: \"Petstore\",\n spec: \"https://petstore3.swagger.io/api/v3/openapi.json\",\n },\n ],\n }),\n ],`,\n configImports: ['import { openapi } from \"blume/reference\";'],\n files: (dir) => [\n {\n content: page(\n \"API Reference\",\n \"Reference documentation for the API, generated from its OpenAPI spec, with every endpoint, its parameters, request bodies, and responses.\",\n \"Your OpenAPI spec renders at [`/api`](/api). Point `openapi()` at your own spec in `blume.config.ts`.\"\n ),\n path: join(dir, \"index.mdx\"),\n },\n ],\n },\n changelog: {\n configExtra: `\n navigation: {\n tabs: [\n { label: \"Docs\", path: \"/\" },\n { label: \"Changelog\", path: \"/changelog\" },\n ],\n },`,\n configImports: [],\n files: (dir) => [\n {\n content: page(\n \"Introduction\",\n \"Welcome to your new documentation site. Write guides as Markdown pages here, and log each release as an entry in the changelog folder.\",\n \"Write your docs here, and log releases under `changelog/`: each entry joins the [changelog](/changelog), newest first.\"\n ),\n path: join(dir, \"index.mdx\"),\n },\n {\n content: `---\\ntitle: v1.0.0\\ndescription: The first release of the project. Replace this entry with your own release notes, and add a new file beside it for every version.\\ntype: changelog\\ndate: 2026-01-01\\n---\\n\\nThe first release. Edit \\`${dir}/changelog/v1-0-0.mdx\\` or add new entries beside it.\\n`,\n path: join(dir, \"changelog\", \"v1-0-0.mdx\"),\n },\n ],\n },\n docs: {\n configExtra: \"\",\n configImports: [],\n files: (dir) => [\n {\n content: page(\n \"Introduction\",\n \"Welcome to your new documentation site. Edit this page or add Markdown files beside it, and Blume turns each file into a page.\",\n `Welcome to **Blume**, the open-source docs framework for humans and agents.\\n\\nEdit \\`${dir}/index.mdx\\` and save: this page reloads with your changes.`\n ),\n path: join(dir, \"index.mdx\"),\n },\n ],\n },\n sdk: {\n configExtra: \"\",\n configImports: [],\n files: (dir) => [\n {\n content: page(\n \"Introduction\",\n \"Get started with the SDK. Install the package, configure a client, and make your first call in a few lines of code in your own app.\",\n \"Install the SDK and make your first call. See [Installation](/installation).\"\n ),\n path: join(dir, \"index.mdx\"),\n },\n {\n content: page(\n \"Installation\",\n \"Install the SDK with the package manager your project already uses, then import it into your code to start making requests to the API.\",\n \"```package-install\\nyour-sdk\\n```\"\n ),\n path: join(dir, \"installation.mdx\"),\n },\n ],\n },\n} satisfies Record<Template, Starter>;\n\n/**\n * Add, install, and dev commands to print for the chosen package manager, plus the\n * prefix that runs a locally installed bin (`exec`, e.g. `npx blume eject`) —\n * dependency bins aren't on PATH, so a bare `blume …` hint would not run.\n */\nexport const commandsFor = (pm: PackageManager) => ({\n // Adds a dependency: npm spells the verb `install`, the others `add`.\n add: pm === \"npm\" ? \"npm install\" : `${pm} add`,\n // `bun build` invokes Bun's bundler, not the package.json `build` script —\n // unlike `bun dev`, the script name is shadowed by a builtin subcommand.\n build: pm === \"npm\" || pm === \"bun\" ? `${pm} run build` : `${pm} build`,\n dev: pm === \"npm\" ? \"npm run dev\" : `${pm} dev`,\n exec: { bun: \"bunx\", npm: \"npx\", pnpm: \"pnpm exec\", yarn: \"yarn\" }[pm],\n install: `${pm} install`,\n});\n\nconst isPackageManager = (value: string): value is PackageManager =>\n PACKAGE_MANAGERS.some((pm) => pm === value);\n\n/**\n * Derive the package manager from an npm user-agent string (the first\n * `name/version` token of `npm_config_user_agent`), falling back to npm.\n * Right for `init`, where the project doesn't exist yet and the invoking\n * runner is the only signal.\n */\nexport const detectPackageManager = (userAgent?: string): PackageManager => {\n const name = userAgent?.split(\"/\")[0];\n return name !== undefined && isPackageManager(name) ? name : \"npm\";\n};\n\n/**\n * The nearest directory at or above `root` holding `.git` (a directory, or\n * the file a worktree or submodule carries), or null outside a repository.\n * Checked by presence rather than by asking git, so no path spelling is ever\n * compared: git prints its toplevel with symlinks and Windows 8.3 short\n * names resolved, which nothing in Node canonicalizes to.\n */\nconst repositoryRootOf = (root: string): string | null => {\n let dir = root;\n while (!existsSync(join(dir, \".git\"))) {\n const parent = dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n return dir;\n};\n\n/**\n * Detect an existing project's package manager from its lockfile /\n * `packageManager` field (package-manager-detector), falling back to the\n * user agent. Right for `eject`: the CLI is often run directly (`npx blume\n * eject`, a bare `blume eject`), where `npm_config_user_agent` is absent or\n * names the runner rather than the project's manager, and the old\n * user-agent-only detection silently printed npm hints for a pnpm project.\n */\nexport const detectProjectPackageManager = async (\n root: string\n): Promise<PackageManager> => {\n // A workspace package keeps its lockfile and `packageManager` field at the\n // repository root, so the walk climbs that far — but no further, or a\n // `package.json` in an unrelated ancestor (a user's home directory, say)\n // decides the project's commands. Outside a repository the project root is\n // the only directory that can be trusted.\n const detected = await detect({\n cwd: root,\n stopDir: repositoryRootOf(root) ?? root,\n });\n const name = detected?.name;\n return name !== undefined && isPackageManager(name)\n ? name\n : detectPackageManager(process.env.npm_config_user_agent);\n};\n\n/**\n * The content dir is joined into every scaffolded file path, so an absolute or\n * `../`-escaping value would write outside the project. Returns an error\n * message, or `undefined` when the dir is safe.\n */\nexport const validateContentDir = (\n root: string,\n dir: string\n): string | undefined =>\n isAbsolute(dir) || relative(root, join(root, dir)).startsWith(\"..\")\n ? \"Must be a relative path inside the project.\"\n : undefined;\n\n/** Turn a directory name into a display title: `my-docs` → `My Docs`. */\nexport const titleize = (raw: string): string => {\n const words = raw\n .replaceAll(/[-_.]+/gu, \" \")\n .split(/\\s+/u)\n .filter(Boolean);\n return words.length === 0\n ? \"My Docs\"\n : words\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n};\n\n/**\n * True when any selected source needs an explicit `content.sources` array —\n * everything except `filesystem`, which is what the implicit default already\n * desugars to.\n */\nconst needsExplicitSources = (sources: SourceKind[]): boolean =>\n sources.some((source) => source !== \"filesystem\");\n\n/** The `blume/sources` factory each source kind is written with. */\nconst SOURCE_FACTORIES = {\n contentful: \"contentful\",\n filesystem: \"filesystem\",\n \"github-releases\": \"githubReleases\",\n \"mdx-remote\": \"mdxRemote\",\n notion: \"notion\",\n obsidian: \"obsidian\",\n payload: \"payload\",\n sanity: \"sanity\",\n strapi: \"strapi\",\n} satisfies Record<SourceKind, string>;\n\n/**\n * The descriptor each remote source kind scaffolds — the same placeholder\n * options the emitted snippet shows — so the SDK deps and env vars `init`\n * sets up are read off the adapter rather than kept in a parallel table.\n */\nconst SOURCE_DESCRIPTORS = {\n contentful: contentful({\n contentType: \"doc\",\n prefix: \"contentful\",\n space: \"your-space-id\",\n }),\n \"github-releases\": githubReleases({\n owner: \"your-org\",\n prefix: \"changelog\",\n repo: \"your-repo\",\n }),\n \"mdx-remote\": mdxRemote({\n github: { owner: \"your-org\", path: \"docs\", repo: \"your-repo\" },\n prefix: \"remote\",\n }),\n notion: notion({ database: \"your-database-id\", prefix: \"notion\" }),\n obsidian: obsidian({ prefix: \"notes\", vault: \"vault\" }),\n payload: payload({\n collection: \"docs\",\n prefix: \"payload\",\n url: \"https://cms.example.com\",\n }),\n sanity: sanity({\n dataset: \"production\",\n prefix: \"sanity\",\n projectId: \"your-project-id\",\n query: '*[_type == \"doc\"]',\n }),\n strapi: strapi({\n contentType: \"docs\",\n prefix: \"strapi\",\n url: \"https://cms.example.com\",\n }),\n} satisfies Record<Exclude<SourceKind, \"filesystem\">, AnySourceAdapter>;\n\n/**\n * Config snippets for each remote source kind, with placeholder values to\n * replace and comments naming the env var each source authenticates with.\n */\nconst SOURCE_SNIPPETS = {\n contentful: ` // Entries of a Contentful content type. Reads CONTENTFUL_ACCESS_TOKEN\n // from the environment.\n contentful({\n space: \"your-space-id\",\n contentType: \"doc\",\n prefix: \"contentful\",\n }),`,\n \"github-releases\": ` // Changelog entries from GitHub Releases. Private repos read\n // GITHUB_TOKEN from the environment.\n githubReleases({\n owner: \"your-org\",\n repo: \"your-repo\",\n prefix: \"changelog\",\n }),`,\n \"mdx-remote\": ` // MDX fetched from a GitHub repo. Private repos read GITHUB_TOKEN\n // from the environment.\n mdxRemote({\n github: { owner: \"your-org\", repo: \"your-repo\", path: \"docs\" },\n prefix: \"remote\",\n }),`,\n notion: ` // Pages from a Notion database. Reads NOTION_TOKEN from the environment.\n notion({\n database: \"your-database-id\",\n prefix: \"notion\",\n }),`,\n obsidian: ` // An Obsidian vault, read in place. No export step, and no\n // generated notes in your repo. Point \\`vault\\` at your vault directory,\n // relative to this config file.\n obsidian({\n vault: \"vault\",\n prefix: \"notes\",\n }),`,\n payload: ` // Documents from a Payload collection. Reads PAYLOAD_API_KEY from\n // the environment.\n payload({\n url: \"https://cms.example.com\",\n collection: \"docs\",\n prefix: \"payload\",\n }),`,\n sanity: ` // Documents from a Sanity dataset. Private datasets read SANITY_TOKEN\n // from the environment.\n sanity({\n projectId: \"your-project-id\",\n dataset: \"production\",\n query: \\`*[_type == \"doc\"]\\`,\n prefix: \"sanity\",\n }),`,\n strapi: ` // Entries of a Strapi content type. Reads STRAPI_API_TOKEN from\n // the environment.\n strapi({\n url: \"https://cms.example.com\",\n contentType: \"docs\",\n prefix: \"strapi\",\n }),`,\n} satisfies Record<Exclude<SourceKind, \"filesystem\">, string>;\n\n/** The selected kinds in canonical order (the multiselect returns pick order). */\nconst orderedSources = (sources: SourceKind[]): SourceKind[] =>\n SOURCE_KINDS.filter((kind) => sources.includes(kind));\n\n/** The `blume/sources` import line for the selected kinds, in canonical order. */\nconst sourcesImportFor = (sources: SourceKind[]): string =>\n `import { ${orderedSources(sources)\n .map((kind) => SOURCE_FACTORIES[kind])\n .join(\", \")} } from \"blume/sources\";\\n`;\n\n/** The chosen source kinds; no selection means the implicit local source. */\nconst selectedSources = (answers: InitAnswers): SourceKind[] =>\n answers.sources.length === 0 ? [\"filesystem\"] : answers.sources;\n\n/**\n * The `content` block for the generated config, or an empty string when the\n * defaults (filesystem source, `docs` root) apply — keeping the default\n * scaffold byte-identical to a config with no `content` key at all.\n */\nconst contentBlockFor = (answers: InitAnswers): string => {\n const sources = selectedSources(answers);\n if (!needsExplicitSources(sources)) {\n return answers.contentDir === \"docs\"\n ? \"\"\n : `\n content: {\n root: ${JSON.stringify(answers.contentDir)},\n },`;\n }\n // Explicit sources replace the implicit filesystem desugar, so the local\n // content dir must be listed alongside the other sources to stay included.\n const entries = orderedSources(sources).map((kind) =>\n kind === \"filesystem\"\n ? ` filesystem({ root: ${JSON.stringify(answers.contentDir)} }),`\n : SOURCE_SNIPPETS[kind]\n );\n return `\n content: {\n sources: [\n${entries.join(\"\\n\")}\n ],\n },`;\n};\n\n/** The full `blume.config.ts` text for the chosen answers. */\nexport const buildConfig = (answers: InitAnswers): string => {\n const starter = STARTERS[answers.template];\n const sources = selectedSources(answers);\n // Only an explicit `sources` array calls factories; the shorthand `root`\n // (or no content block at all) needs no import.\n const sourcesImport = needsExplicitSources(sources)\n ? sourcesImportFor(sources)\n : \"\";\n const imports = [\n 'import { defineConfig } from \"blume\";',\n ...starter.configImports,\n ].join(\"\\n\");\n return `${imports}\n${sourcesImport}\nexport default defineConfig({\n title: ${JSON.stringify(answers.title)},\n description: \"Documentation powered by Blume.\",${starter.configExtra}${contentBlockFor(answers)}\n});\n`;\n};\n\n/** The version range `init` pins for each SDK an adapter declares. */\nconst SDK_VERSIONS = new Map([\n [\"@notionhq/client\", \"^5.26.0\"],\n [\"@sanity/client\", \"^8.6.1\"],\n]);\n\n/** The scaffolded descriptors for the selected remote source kinds. */\nconst descriptorsFor = (sources: SourceKind[]): AnySourceAdapter[] =>\n orderedSources(sources).flatMap((kind) =>\n kind === \"filesystem\" ? [] : [SOURCE_DESCRIPTORS[kind]]\n );\n\n/** SDK dependencies the selected sources declare, read off their descriptors. */\nconst extraDepsFor = (sources: SourceKind[]) => {\n const deps: Record<string, string> = {};\n for (const descriptor of descriptorsFor(sources)) {\n for (const dep of descriptor.runtimeDeps) {\n deps[dep] = SDK_VERSIONS.get(dep) ?? \"latest\";\n }\n }\n return deps;\n};\n\n/**\n * `pnpm-workspace.yaml` for a new pnpm project. pnpm runs a dependency's\n * build script only once it's approved, and fails the install over any it\n * wasn't told about. esbuild's postinstall checks its platform binary;\n * `@scarf/scarf` is a telemetry postinstall a transitive dependency pulls in,\n * and Blume doesn't need it to run.\n */\nconst PNPM_WORKSPACE = `allowBuilds:\n esbuild: true\n \"@scarf/scarf\": false\n`;\n\n/**\n * `.yarnrc.yml` for a new Yarn Berry project. Berry installs with Plug'n'Play\n * by default, which writes no `node_modules`; Blume's generated Astro project\n * resolves its packages from one. Yarn Classic never reads this file.\n */\nconst YARNRC = `# Blume's generated Astro project resolves packages from node_modules, which\n# Yarn's default Plug'n'Play install doesn't create.\nnodeLinker: node-modules\n`;\n\n/**\n * The nearest directory at or above `root` where `found` holds, searching up\n * to the repository root — or to the filesystem root outside a repository,\n * where a workspace can still enclose the project.\n */\nconst nearestAncestor = (\n root: string,\n found: (dir: string) => boolean\n): string | null => {\n const stop = repositoryRootOf(root);\n let dir = root;\n while (!found(dir)) {\n const parent = dirname(dir);\n if (dir === stop || parent === dir) {\n return null;\n }\n dir = parent;\n }\n return dir;\n};\n\n/** Read a file, or `\"\"` when it can't be read. */\nconst readText = (path: string): string => {\n try {\n return readFileSync(path, \"utf-8\");\n } catch {\n return \"\";\n }\n};\n\n/** The pnpm workspace enclosing `root`: the directory of its `pnpm-workspace.yaml`. */\nconst pnpmWorkspaceRoot = (root: string): string | null =>\n nearestAncestor(root, (dir) => existsSync(join(dir, \"pnpm-workspace.yaml\")));\n\n/**\n * The Yarn project enclosing `root`: a directory holding a lockfile, a\n * `.yarnrc.yml`, or a `package.json` that declares workspaces.\n */\nconst yarnProjectRoot = (root: string): string | null =>\n nearestAncestor(\n root,\n (dir) =>\n existsSync(join(dir, \"yarn.lock\")) ||\n existsSync(join(dir, \".yarnrc.yml\")) ||\n /\"workspaces\"\\s*:/u.test(readText(join(dir, \"package.json\")))\n );\n\n/**\n * The major version of the Yarn that ran `init`, read off the npm user agent\n * (`yarn/4.5.1 npm/? node/v22…`), or undefined when something else ran it.\n */\nexport const yarnMajor = (userAgent?: string): number | undefined => {\n const match = /^yarn\\/(?<major>\\d+)\\./u.exec(userAgent ?? \"\");\n return match?.groups?.major === undefined\n ? undefined\n : Number(match.groups.major);\n};\n\n/** Environment `buildPlan` and `workspaceNote` read, injectable for tests. */\nexport interface PlanEnvironment {\n /** `npm_config_user_agent` of the process that ran `init`. */\n userAgent?: string;\n}\n\n/**\n * The package-manager config file a project `init` creates from scratch\n * needs: pnpm's build approvals, or Yarn Berry's `node_modules` linker. An\n * existing package.json, or a workspace the project joins, already owns that\n * decision (see {@link workspaceNote}); Yarn Classic ignores `.yarnrc.yml`, so\n * a user agent naming Yarn 1 skips it.\n */\nconst packageManagerConfigFor = (\n root: string,\n answers: InitAnswers,\n env: PlanEnvironment\n): ScaffoldFile[] => {\n if (existsSync(join(root, \"package.json\"))) {\n return [];\n }\n if (answers.packageManager === \"pnpm\" && pnpmWorkspaceRoot(root) === null) {\n return [\n { content: PNPM_WORKSPACE, path: join(root, \"pnpm-workspace.yaml\") },\n ];\n }\n if (\n answers.packageManager === \"yarn\" &&\n yarnMajor(env.userAgent) !== 1 &&\n yarnProjectRoot(root) === null\n ) {\n return [{ content: YARNRC, path: join(root, \".yarnrc.yml\") }];\n }\n return [];\n};\n\n/**\n * What the project still needs from a workspace it joins, when `init` left\n * that workspace's config alone: pnpm's approval for esbuild's build script\n * (pnpm 10 and later fail the install without it), or Yarn Berry's\n * `node_modules` linker. Undefined when the workspace already has it, or the\n * project doesn't sit in one.\n */\nexport const workspaceNote = (\n root: string,\n answers: InitAnswers,\n env: PlanEnvironment = {}\n): string | undefined => {\n if (answers.packageManager === \"pnpm\") {\n const workspace = pnpmWorkspaceRoot(root);\n const file = workspace && join(workspace, \"pnpm-workspace.yaml\");\n if (!file || readText(file).includes(\"esbuild\")) {\n return;\n }\n return `This project joins the pnpm workspace at ${file}. Approve esbuild's build script there before installing, or pnpm 10 and later stop the install:\\n\\n allowBuilds:\\n esbuild: true`;\n }\n if (answers.packageManager !== \"yarn\" || yarnMajor(env.userAgent) === 1) {\n return;\n }\n const project = yarnProjectRoot(root);\n const rc = project && join(project, \".yarnrc.yml\");\n if (!rc || /^nodeLinker:\\s*[\"']?(?:node-modules|pnpm)/mu.test(readText(rc))) {\n return;\n }\n return `This project joins the Yarn project at ${project}. With Yarn 2 or later, set its linker in ${rc} so installs write the node_modules Blume's generated Astro project resolves packages from:\\n\\n nodeLinker: node-modules`;\n};\n\n/** Every file `init` should write for the given answers, package.json first. */\nexport const buildPlan = (\n root: string,\n answers: InitAnswers,\n env: PlanEnvironment = {}\n): ScaffoldFile[] => {\n const files: ScaffoldFile[] = [\n {\n content: blumePackageJson(\n toPackageName(basename(root)),\n extraDepsFor(answers.sources)\n ),\n path: join(root, \"package.json\"),\n },\n ...packageManagerConfigFor(root, answers, env),\n { content: buildConfig(answers), path: join(root, \"blume.config.ts\") },\n ];\n // Seed pages only make sense when a local filesystem source will read them.\n if (answers.sources.length === 0 || answers.sources.includes(\"filesystem\")) {\n files.push(\n ...STARTERS[answers.template]\n .files(answers.contentDir)\n .map((file) => ({ ...file, path: join(root, file.path) }))\n );\n }\n // The obsidian snippet points at `vault/`; seed the directory with a first\n // note so the scaffolded project passes the source's `validate()` and boots\n // before the user has opened Obsidian at all.\n if (answers.sources.includes(\"obsidian\")) {\n files.push({\n content:\n \"# Welcome\\n\\nThis folder is read by Blume's `obsidian` source. Open it as a vault in Obsidian and write notes — `[[Wikilinks]]` become site links.\\n\",\n path: join(root, \"vault\", \"Welcome.md\"),\n });\n }\n return files;\n};\n\nconst writeFileSafe = async (\n file: ScaffoldFile,\n log: ScaffoldLog\n): Promise<boolean> => {\n if (existsSync(file.path)) {\n log.info(`Skipped existing ${file.path}`);\n return false;\n }\n await mkdir(dirname(file.path), { recursive: true });\n await writeFile(file.path, file.content, \"utf-8\");\n log.success(`Created ${file.path}`);\n return true;\n};\n\n/**\n * Write the plan's files, skipping any that already exist. Reports whether a\n * `package.json` was newly created (it decides whether `init` installs).\n */\nexport const applyPlan = async (\n files: ScaffoldFile[],\n log: ScaffoldLog\n): Promise<{ createdPackage: boolean }> => {\n const created = await Promise.all(\n files.map((file) => writeFileSafe(file, log))\n );\n const createdPackage = files.some(\n (file, index) => created[index] && basename(file.path) === \"package.json\"\n );\n return { createdPackage };\n};\n\n/** Env vars the selected sources declare, deduplicated in a stable order. */\nconst envVarsFor = (sources: SourceKind[]): string[] => [\n ...new Set(\n descriptorsFor(sources).flatMap((descriptor) => descriptor.requiredSecrets)\n ),\n];\n\n/** What an existing package.json — one `init` left alone — already wires up. */\nexport interface ExistingPackage {\n /**\n * Whether `blume` is installed where the project resolves it: its own\n * `node_modules`, or an ancestor's in a hoisted workspace. Listing it isn't\n * enough — a rerun of `init --no-install` lists it without installing it.\n */\n blumeInstalled: boolean;\n /** Every package it lists in `dependencies` or `devDependencies`. */\n dependencies: string[];\n /** Whether its `dev` script runs Blume. */\n devRunsBlume: boolean;\n}\n\n/** Whether a `node_modules/blume` sits in `root` or any directory above it. */\nconst blumeResolves = (root: string): boolean => {\n let dir = root;\n while (!existsSync(join(dir, \"node_modules\", \"blume\", \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir) {\n return false;\n }\n dir = parent;\n }\n return true;\n};\n\n/**\n * Read the package.json `init` didn't write. An unreadable or malformed one\n * reads as wiring nothing up, so the next steps list everything to add.\n */\nexport const readExistingPackage = async (\n root: string\n): Promise<ExistingPackage> => {\n try {\n // SAFETY: only the two dependency maps and the `dev` script are read, all\n // optional; `String()` absorbs a script that isn't a string.\n const pkg = JSON.parse(\n await readFile(join(root, \"package.json\"), \"utf-8\")\n ) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n };\n return {\n blumeInstalled: blumeResolves(root),\n dependencies: Object.keys({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n }),\n devRunsBlume: String(pkg.scripts?.dev ?? \"\").includes(\"blume\"),\n };\n } catch {\n return {\n blumeInstalled: blumeResolves(root),\n dependencies: [],\n devRunsBlume: false,\n };\n }\n};\n\n/**\n * The next-steps message: `cd` hint, the install command when `init` did not\n * run it itself, the dev command, and token setup. With an `existing`\n * package.json — which `init` never edits — it first adds whatever of `blume`\n * and the sources' SDKs isn't listed yet (or installs, when everything is\n * listed but `blume` was never installed), then starts the dev server through\n * the package runner unless its `dev` script already runs Blume. A `note` —\n * what a workspace the project joins still needs — closes the message.\n */\nexport const nextSteps = (\n answers: InitAnswers,\n needsInstall: boolean,\n existing?: ExistingPackage,\n note?: string\n): string => {\n const commands = commandsFor(answers.packageManager);\n const lines: string[] = [];\n if (answers.directory !== \".\") {\n lines.push(`cd ${answers.directory}`);\n }\n if (needsInstall) {\n lines.push(commands.install);\n }\n if (existing) {\n const missing = [\n \"blume\",\n ...Object.keys(extraDepsFor(answers.sources)),\n ].filter((dep) => !existing.dependencies.includes(dep));\n if (missing.length > 0) {\n lines.push(`${commands.add} ${missing.join(\" \")}`);\n } else if (!(needsInstall || existing.blumeInstalled)) {\n lines.push(commands.install);\n }\n }\n lines.push(\n existing && !existing.devRunsBlume\n ? `${commands.exec} blume dev`\n : commands.dev\n );\n const envVars = envVarsFor(answers.sources);\n const auth =\n envVars.length > 0\n ? `\\nSet ${envVars.join(\" and \")} in .env.local so your sources can authenticate.\\n`\n : \"\";\n const workspace = note ? `\\n${note}\\n` : \"\";\n return `Next steps:\\n\\n ${lines.join(\"\\n \")}\\n${auth}${workspace}`;\n};\n",
|
|
125
|
+
"import { getBlumeVersion } from \"./version.ts\";\n\n/**\n * Derive a valid npm package name from a directory name, falling back to\n * `docs` when nothing usable remains.\n */\nexport const toPackageName = (raw: string): string =>\n raw\n .toLowerCase()\n .replaceAll(/[^a-z0-9._-]+/gu, \"-\")\n .replaceAll(/^[-_.]+|[-_.]+$/gu, \"\") || \"docs\";\n\n/**\n * A minimal, runnable `package.json` body for a Blume project: the `blume`\n * dependency pinned to the installed version plus `dev`/`build`/`doctor`\n * scripts, so `npm install && npm run dev` works immediately. Shared by\n * `blume init` and the migrators, which scaffold one when a project has none.\n * `extraDeps` adds source SDKs (e.g. `@notionhq/client`) beside `blume`.\n */\nexport const blumePackageJson = (\n name: string,\n extraDeps: Record<string, string> = {}\n): string => {\n const dependencies = Object.entries({\n blume: `^${getBlumeVersion()}`,\n ...extraDeps,\n })\n .toSorted(([a], [b]) => (a < b ? -1 : 1))\n .map(\n ([dep, range]) => ` ${JSON.stringify(dep)}: ${JSON.stringify(range)}`\n )\n .join(\",\\n\");\n return `{\n \"name\": ${JSON.stringify(name)},\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"blume dev\",\n \"build\": \"blume build\",\n \"doctor\": \"blume doctor\"\n },\n \"dependencies\": {\n${dependencies}\n }\n}\n`;\n};\n",
|
|
126
|
+
"import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport { basename, dirname, join, relative, resolve } from \"pathe\";\n\nimport { pageJsonPath } from \"../../ai/api/paths.ts\";\nimport { buildHomeLinkHeader } from \"../../ai/link-headers.ts\";\nimport {\n agentMarkdown,\n buildRawMarkdown,\n markdownRoutePaths,\n markdownTokenCount,\n} from \"../../ai/markdown.ts\";\nimport type { BlumeProject } from \"../../core/project-graph.ts\";\nimport type { ProjectContext } from \"../../core/types.ts\";\nimport { CLOUDFLARE_ADAPTER_PACKAGE } from \"../adapters/cloudflare.ts\";\nimport {\n injectWorkerNegotiation,\n NEGOTIATION_WORKER_FILE,\n} from \"../cloudflare-negotiation.ts\";\nimport { platformRedirects } from \"../redirects.ts\";\nimport { REDIRECTS_FILE } from \"./netlify.ts\";\nimport { clientDir, distDir, toSiteUrl } from \"./paths.ts\";\nimport type { BuildLog, DeployPlatform } from \"./types.ts\";\n\nconst WRANGLER_CONFIG_FILES = [\n \"wrangler.jsonc\",\n \"wrangler.json\",\n \"wrangler.toml\",\n];\n\n/**\n * The adapter's constructor options. Every Blume HTML route prerenders (the\n * only server routes are API endpoints), so images are optimized at build\n * time with sharp: the adapter's default (`cloudflare-binding`) would instead\n * declare a runtime `IMAGES` binding in the generated wrangler config that\n * nothing uses. A wrangler config at the project root is pointed at\n * explicitly, because the adapter would otherwise look beside the Astro\n * root — the hidden runtime — and the dev workerd runtime would miss\n * `nodejs_compat`.\n */\nconst adapterOptions = (context: ProjectContext) => {\n const options = { imageService: \"compile\", prerenderEnvironment: \"node\" };\n const wranglerPath = WRANGLER_CONFIG_FILES.map((file) =>\n join(context.root, file)\n ).find((file) => existsSync(file));\n if (!wranglerPath) {\n return options;\n }\n let configPath = relative(context.outDir, wranglerPath);\n // The wrangler config always lives at the project root, above the `.blume`\n // runtime, so `relative` yields a `../…` path; normalize the theoretical\n // sibling case to an explicit `./` so it reads as relative.\n if (!configPath.startsWith(\".\") && !configPath.startsWith(\"/\")) {\n configPath = `./${configPath}`;\n }\n return { ...options, configPath };\n};\n\nconst warnNegotiationSkipped = (log: BuildLog): void =>\n log.warn(\n \"Could not wire Accept: text/markdown negotiation into dist/server/wrangler.json — raw Markdown stays available at the .md URLs.\"\n );\n\n/**\n * Wire `Accept: text/markdown` negotiation into a server build. The ASSETS\n * binding serves the prerendered content pages before the Worker runs — and\n * even a request that reaches the Worker is answered by the adapter's handler\n * from that binding, ahead of the only place middleware runs — so the\n * negotiation lives in a generated wrapper Worker, routed to by\n * `assets.run_worker_first` (see `deploy/cloudflare-negotiation.ts`). Both\n * pieces are spliced into the adapter's emitted `dist/server` bundle.\n */\nexport const emitCloudflareNegotiation = async (\n project: BlumeProject,\n log: BuildLog\n): Promise<void> => {\n const { config, context } = project;\n const serverDir = join(distDir(context), \"server\");\n const wranglerPath = join(serverDir, \"wrangler.json\");\n if (!existsSync(wranglerPath)) {\n warnNegotiationSkipped(log);\n return;\n }\n const routePaths = markdownRoutePaths(project);\n // The homepage mirror is served from the static layer, so its\n // `x-markdown-tokens` estimate rides the wrapper Worker, mirroring the\n // Vercel routing config.\n const rawMarkdown = await buildRawMarkdown(project);\n const home = rawMarkdown[\"/\"];\n // The 404 twins the wrapper may substitute for the HTML shell; only wired\n // when the build actually emitted them (a project that owns `/404` gets\n // neither), like the Vercel routing config.\n const staticDir = clientDir(context);\n const injected = injectWorkerNegotiation(\n await readFile(wranglerPath, \"utf-8\"),\n {\n base: config.deployment.options.base,\n // The manifest routes guard the wrapper's redirect table; `routePaths`\n // also carries the synthesized homepage mirror, which must not block a\n // configured root redirect.\n contentRoutePaths: project.manifest.routes.map((route) => route.path),\n homeLinkHeader: buildHomeLinkHeader(config, routePaths),\n homeTokens: home ? markdownTokenCount(agentMarkdown(home)) : undefined,\n notFound: {\n json: existsSync(join(staticDir, \"404.json\")),\n markdown: existsSync(join(staticDir, \"404.md\")),\n },\n // Exactly the per-page JSON documents the API emits (see `pageParams`):\n // the non-hidden routes with agent Markdown, when the API is on.\n pageJsonPaths: config.agents.api\n ? project.manifest.routes\n .filter(\n (route) => !route.hidden && rawMarkdown[route.path] !== undefined\n )\n .map((route) => pageJsonPath(route.path))\n : [],\n // The wrapper Worker matches full served URLs, so the redirects are\n // based the same way the platform files are — it answers any the\n // worker-first rules claim, where `_redirects` is never consulted and\n // Astro would default their status.\n redirects: platformRedirects(config),\n routePaths,\n }\n );\n if (injected === null) {\n warnNegotiationSkipped(log);\n return;\n }\n await writeFile(\n join(serverDir, NEGOTIATION_WORKER_FILE),\n injected.worker,\n \"utf-8\"\n );\n await writeFile(wranglerPath, injected.wrangler, \"utf-8\");\n log.success(\n \"Wired Accept: text/markdown negotiation into the Cloudflare Worker\"\n );\n};\n\n/**\n * Where Cloudflare's deploy tooling looks for the redirect to the built\n * config, relative to the directory `wrangler deploy` runs in (or any parent).\n */\nconst DEPLOY_CONFIG = join(\".wrangler\", \"deploy\", \"config.json\");\n\n/** The redirect file the Cloudflare Vite plugin writes. */\ninterface DeployConfig {\n auxiliaryWorkers?: { configPath: string }[];\n configPath: string;\n prerenderWorkerConfigPath?: string;\n}\n\n/**\n * Point `wrangler deploy` run from the project root at the built Worker.\n * The adapter's Vite plugin writes its redirect beside the Astro root — the\n * hidden `.blume` runtime, where nobody runs wrangler — and wrangler only\n * looks in the working directory and its parents, so from the project root it\n * finds no config and fails with \"Could not detect a directory containing\n * static files\". This writes the same redirect at the project root, its paths\n * rebased there. A user wrangler config at the project root stays compatible:\n * wrangler accepts a redirect in the same directory's `.wrangler/deploy/`.\n */\nexport const emitCloudflareDeployConfig = async (\n context: ProjectContext\n): Promise<void> => {\n const builtConfig = join(distDir(context), \"server\", \"wrangler.json\");\n if (!existsSync(builtConfig)) {\n return;\n }\n const source = join(context.outDir, DEPLOY_CONFIG);\n const target = join(context.root, DEPLOY_CONFIG);\n const rebase = (path: string): string =>\n relative(dirname(target), resolve(dirname(source), path));\n const deployConfig: DeployConfig = existsSync(source)\n ? JSON.parse(await readFile(source, \"utf-8\"))\n : { configPath: relative(dirname(source), builtConfig) };\n const rebased: DeployConfig = {\n auxiliaryWorkers: (deployConfig.auxiliaryWorkers ?? []).map((worker) => ({\n configPath: rebase(worker.configPath),\n })),\n configPath: rebase(deployConfig.configPath),\n };\n if (deployConfig.prerenderWorkerConfigPath) {\n rebased.prerenderWorkerConfigPath = rebase(\n deployConfig.prerenderWorkerConfigPath\n );\n }\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, `${JSON.stringify(rebased)}\\n`, \"utf-8\");\n};\n\n/**\n * The name the Worker gets when the build names it: the generated runtime's\n * package name, which every Blume site shares. Left as is, two sites deployed\n * to one account would overwrite each other's Worker.\n */\nconst RUNTIME_WORKER_NAME = \"blume-runtime\";\n\n/**\n * A Worker name from free text: lowercase letters, digits, and dashes, no\n * leading or trailing dash, at most 63 characters (a Worker name is also a\n * `workers.dev` hostname label).\n */\nconst toWorkerName = (text: string): string =>\n text\n .toLowerCase()\n .replaceAll(/[^\\da-z]+/gu, \"-\")\n .slice(0, 63)\n .replaceAll(/^-+|-+$/gu, \"\");\n\n/**\n * The Worker name for a project that doesn't name its own: the project's\n * `package.json` name (a scope folded in, `@acme/docs` → `acme-docs`), else the\n * site's hostname, else the project folder's name.\n */\nconst projectWorkerName = async (\n project: BlumeProject\n): Promise<string | undefined> => {\n const { config, context } = project;\n const packageFile = join(context.root, \"package.json\");\n const manifest: { name?: string } = existsSync(packageFile)\n ? JSON.parse(await readFile(packageFile, \"utf-8\"))\n : {};\n const { site } = config.deployment.options;\n return [\n String(manifest.name ?? \"\"),\n site ? new URL(site).hostname : \"\",\n basename(context.root),\n ]\n .map(toWorkerName)\n .find((name) => name.length > 0);\n};\n\n/**\n * Name the built Worker after the project when it still carries the shared\n * runtime name. A name set in the project's own wrangler config reaches the\n * built config instead, and is left alone.\n */\nexport const nameCloudflareWorker = async (\n project: BlumeProject,\n log: BuildLog\n): Promise<void> => {\n const wranglerPath = join(\n distDir(project.context),\n \"server\",\n \"wrangler.json\"\n );\n if (!existsSync(wranglerPath)) {\n return;\n }\n // Only the two name fields are read; every other key rides through as parsed.\n const wrangler: { name?: string; topLevelName?: string } = JSON.parse(\n await readFile(wranglerPath, \"utf-8\")\n );\n const name = await projectWorkerName(project);\n if (wrangler.name !== RUNTIME_WORKER_NAME || name === undefined) {\n return;\n }\n wrangler.name = name;\n if (wrangler.topLevelName === RUNTIME_WORKER_NAME) {\n wrangler.topLevelName = name;\n }\n await writeFile(wranglerPath, JSON.stringify(wrangler), \"utf-8\");\n log.info(\n `Named the Cloudflare Worker \"${name}\"; set \"name\" in a wrangler.jsonc at the project root to choose another.`\n );\n};\n\n/**\n * Cloudflare Workers and Pages. A server build emits the Worker into\n * `dist/server` and serves `dist/client` through the ASSETS binding, which\n * honors `_headers` from that directory exactly as Pages does — so the file\n * applies to both output modes here. Without a configured driver the adapter\n * force-enables KV-backed sessions and declares a `SESSION` binding that\n * `wrangler deploy` then demands a namespace for, even though Blume never\n * reads `Astro.session`; `session: false` opts the project out.\n */\nexport const cloudflarePlatform: DeployPlatform = {\n astro: {\n config: { session: false },\n options: adapterOptions,\n package: CLOUDFLARE_ADAPTER_PACKAGE,\n },\n env: {\n detect: (env) => Boolean(env.CF_PAGES),\n site: (env) => toSiteUrl(env.CF_PAGES_URL),\n },\n finalizeBuild: async ({ isolated, log, project }) => {\n // The Worker's name, the wrapper Worker, and the deploy redirect are\n // deploy artifacts; an isolated verify skips them.\n if (!isolated) {\n await nameCloudflareWorker(project, log);\n await emitCloudflareNegotiation(project, log);\n await emitCloudflareDeployConfig(project.context);\n }\n return true;\n },\n hiddenRuntime: {\n // The redirected deploy config `wrangler deploy` reads from the project\n // root lands in `.wrangler/`, a build artifact like Vercel's `.vercel/`.\n ignoreDir: \".wrangler/\",\n showProjectRoot: false,\n surfacePath: null,\n },\n kind: \"cloudflare\",\n negotiatesMarkdown: true,\n readsHeaderFiles: { server: true, static: true },\n redirectFiles: [REDIRECTS_FILE],\n serverOutputDir: distDir,\n serverStaticDir: clientDir,\n};\n",
|
|
127
|
+
"/**\n * Where the JSON docs API and its OpenAPI description are served. Base-less\n * (like every route Blume emits); callers layer `deployment.base` on top.\n * Under `/api/` alongside the Ask AI endpoint (`/api/ask`) so the namespace a\n * Blume site reserves for live endpoints stays one prefix, and under its own\n * `docs` segment so a search provider's proxy at `/api/search` never collides.\n */\n\nexport const OPENAPI_PATH = \"/openapi.json\";\nexport const API_BASE = \"/api/docs\";\nexport const API_PAGES_PATH = `${API_BASE}/pages.json`;\nexport const API_PAGE_PATH = `${API_BASE}/pages/{route}.json`;\nexport const API_NAVIGATION_PATH = `${API_BASE}/navigation.json`;\nexport const API_SEARCH_PATH = `${API_BASE}/search`;\n\n/** The `pages/{route}.json` path segment for a route (`index` for home). */\nexport const pageParam = (route: string): string =>\n route === \"/\" ? \"index\" : route.slice(1);\n\n/** The base-less served path of a route's per-page JSON document. */\nexport const pageJsonPath = (route: string): string =>\n `${API_BASE}/pages/${pageParam(route)}.json`;\n",
|
|
128
|
+
"/**\n * Whether a name already reads as an API's name: it contains `API` or `APIs`\n * as a whole word, anywhere. Word-bounded on both sides, so \"OpenAPI\" and\n * \"AsyncAPI\" are product names rather than API names and still take the\n * suffix; unanchored at the end, so \"Petstore API v2\" is left alone too.\n */\nconst NAMES_AN_API = /\\bAPIs?\\b/iu;\n\n/**\n * `name` as the phrase \"the ___\" in generated prose — the spec title or\n * reference label, followed by ` API` unless it already says so. Keeps\n * \"Petstore\" reading as \"Petstore API\" without turning \"Petstore API\" into\n * \"Petstore API API\".\n */\nexport const apiNamePhrase = (name: string): string => {\n const trimmed = name.trim();\n return NAMES_AN_API.test(trimmed) ? trimmed : `${trimmed} API`;\n};\n",
|
|
129
|
+
"import { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\nimport { resolveReferences } from \"../openapi/references.ts\";\nimport { API_BASE, OPENAPI_PATH } from \"./api/paths.ts\";\n\n/**\n * RFC 9727 API catalog: a linkset (RFC 9264) at `/.well-known/api-catalog`\n * enumerating the APIs a publisher offers, so agents can discover them from\n * the domain alone. Blume already knows the site's APIs — the configured\n * OpenAPI/AsyncAPI references and the hosted MCP server — so the catalog is\n * generated, never hand-written: one entry per API, anchored at its docs\n * route (the RFC's own examples anchor on developer-portal pages), with\n * `service-doc` pointing at the rendered reference and `service-desc` at the\n * spec when it lives at a fetchable URL. The site's own JSON docs API is an\n * entry too, described by its generated `/openapi.json`.\n */\n\nexport const API_CATALOG_PATH = \"/.well-known/api-catalog\";\nexport const API_CATALOG_TYPE = \"application/linkset+json\";\n\n/** An RFC 9264 linkset entry, restricted to the relations Blume emits. */\ninterface LinksetEntry {\n anchor: string;\n \"service-desc\"?: { href: string; type?: string }[];\n \"service-doc\"?: { href: string; type: string }[];\n}\n\nconst HTTP_URL = /^https?:\\/\\//u;\n\n/** The catalog's linkset entries; empty when the site publishes no APIs. */\nconst linksetEntries = (config: ResolvedConfig): LinksetEntry[] => {\n const site = config.deployment.options.site ?? null;\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const abs = (path: string): string => {\n const based = withBasePath(deployBase, path);\n return site ? absoluteUrl(site, based) : based;\n };\n\n const entries: LinksetEntry[] = [];\n for (const reference of resolveReferences(config)) {\n // Blume-rendered pages mount under `basePath`; Scalar pages stay at the\n // raw route (see `referenceRoutes`).\n const docRoute =\n reference.kind === \"scalar\"\n ? reference.route\n : withBasePath(reference.basePath, reference.route);\n const entry: LinksetEntry = {\n anchor: abs(docRoute),\n \"service-doc\": [{ href: abs(docRoute), type: \"text/html\" }],\n };\n // A local spec file is parsed into pages, not served, so only a remote\n // spec has a fetchable `service-desc` URL.\n if (HTTP_URL.test(reference.spec)) {\n entry[\"service-desc\"] = [{ href: reference.spec }];\n }\n entries.push(entry);\n }\n\n if (config.agents.api) {\n entries.push({\n anchor: abs(API_BASE),\n \"service-desc\": [{ href: abs(OPENAPI_PATH), type: \"application/json\" }],\n \"service-doc\": [{ href: abs(\"/\"), type: \"text/html\" }],\n });\n }\n\n if (config.agents.mcp.enabled) {\n entries.push({\n anchor: abs(config.agents.mcp.route),\n \"service-desc\": [\n { href: abs(\"/.well-known/mcp.json\"), type: \"application/json\" },\n ],\n \"service-doc\": [{ href: abs(\"/\"), type: \"text/html\" }],\n });\n }\n return entries;\n};\n\n/** Whether the site has anything to catalog — gates every emission surface. */\nexport const hasApiCatalog = (config: ResolvedConfig): boolean =>\n linksetEntries(config).length > 0;\n\n/** The `application/linkset+json` document, or null when there are no APIs. */\nexport const buildApiCatalog = (config: ResolvedConfig): string | null => {\n const linkset = linksetEntries(config);\n if (linkset.length === 0) {\n return null;\n }\n return `${JSON.stringify({ linkset }, null, 2)}\\n`;\n};\n",
|
|
130
|
+
"import { withBasePath } from \"../../core/base-path.ts\";\nimport { absoluteUrl, siteRoot } from \"../../core/site-url.ts\";\nimport { trimChar } from \"../../core/trim.ts\";\nimport { MCP_TOOLS } from \"./tools.ts\";\nimport type { McpToolMeta } from \"./tools.ts\";\n\n/** Inputs needed to describe the MCP server in discovery documents. */\nexport interface McpDiscoveryInput {\n /** Normalized `deployment.base` (`\"\"` or `/seg`); the route is base-less. */\n base: string;\n name: string;\n route: string;\n site: string | null;\n version: string;\n}\n\n/** The MCP server's address — absolute when a site is configured. */\nconst serverUrl = (input: McpDiscoveryInput): string => {\n // The endpoint is a generated Astro page, so it's served under\n // `deployment.base` like every other route (the sitemap/llms.txt convention).\n const path = withBasePath(input.base, input.route);\n // Concatenate rather than `new URL(path, site)` — a root-absolute path\n // would drop the base path of a subpath deployment (`acme.com/docs`).\n return input.site ? absoluteUrl(input.site, path) : path;\n};\n\n/**\n * The `/.well-known/mcp.json` discovery document: the minimal pointer agents use\n * to find the server and its transport.\n */\nexport const buildMcpDiscovery = (input: McpDiscoveryInput) => ({\n servers: [\n {\n name: input.name,\n transport: \"streamable-http\",\n url: serverUrl(input),\n },\n ],\n});\n\n/** The published `/v1/` Server Card schema (SEP-2127 extension). */\nconst SERVER_CARD_SCHEMA =\n \"https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json\";\n\n/** The schema caps `description` (and `title`) at 100 characters. */\nconst CARD_TEXT_MAX = 100;\n\nconst truncate = (text: string): string =>\n text.length > CARD_TEXT_MAX ? `${text.slice(0, CARD_TEXT_MAX - 1)}…` : text;\n\n// The server-card schema constrains `name` to `namespace/server` in ASCII\n// (`^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$`), so the display name cannot reuse the\n// route slugifier, which keeps Unicode letters. Decompose (NFKD) and drop\n// combining marks first so an accented name transliterates (`Café` → `cafe`)\n// instead of losing the letter.\nconst NON_ASCII_SLUG = /[^a-z0-9]+/gu;\nconst COMBINING_MARKS = /\\p{M}+/gu;\n\nexport const asciiSlugify = (text: string): string =>\n trimChar(\n text\n .normalize(\"NFKD\")\n .replace(COMBINING_MARKS, \"\")\n .toLowerCase()\n .replace(NON_ASCII_SLUG, \"-\"),\n \"-\"\n );\n\n/**\n * The card's identity in the schema's reverse-DNS `namespace/server` form:\n * the site hostname reversed (`useblume.dev` → `dev.useblume`), or\n * `localhost` when no site is configured, plus the slugged display name (an\n * entirely non-ASCII name falls back to `docs`).\n */\nconst reverseDnsName = (input: McpDiscoveryInput): string => {\n let namespace = \"localhost\";\n if (input.site) {\n try {\n namespace = new URL(input.site).hostname\n .split(\".\")\n .toReversed()\n .join(\".\");\n } catch {\n // Not a parsable URL; the local namespace is honest enough.\n }\n }\n return `${namespace}/${asciiSlugify(input.name) || \"docs\"}`;\n};\n\nconst HTTP_URL = /^https?:\\/\\//u;\n\n/**\n * The `/.well-known/mcp/server-card.json` document. The core follows the\n * SEP-2127 Server Card extension schema (`$schema`, reverse-DNS `name`,\n * `remotes` — which the schema requires to be absolute, so it appears only\n * when a `site` is configured). Alongside it ride initialize-shaped compat\n * fields (`serverInfo`, `capabilities`, `transports`) for scanners built\n * against the SEP's earlier revision, plus Blume's advertised tool set —\n * schema-legal extras (`additionalProperties` is open), and the tool list is\n * genuinely static for a docs server, unlike the dynamic servers the spec\n * excludes primitives for. Full input schemas are served live via\n * `tools/list`.\n */\nexport interface McpServerCard {\n $schema: string;\n capabilities: {\n resources: { listChanged: boolean; subscribe: boolean };\n tools: { listChanged: boolean };\n };\n description: string;\n name: string;\n /** Absolute endpoints only — present when a `site` is configured. */\n remotes?: { type: string; url: string }[];\n serverInfo: { name: string; version: string };\n title: string;\n tools: McpToolMeta[];\n transport: string;\n transports: { endpoint: string; type: string }[];\n url: string;\n version: string;\n websiteUrl?: string;\n}\n\nexport const buildMcpServerCard = (input: McpDiscoveryInput): McpServerCard => {\n const url = serverUrl(input);\n const card: McpServerCard = {\n $schema: SERVER_CARD_SCHEMA,\n // Resources mirror the page list (one `text/markdown` resource per page);\n // a rebuilt site replaces the server wholesale, so nothing changes live.\n capabilities: {\n resources: { listChanged: false, subscribe: false },\n tools: { listChanged: false },\n },\n description: truncate(\n `Model Context Protocol server for the ${input.name} documentation.`\n ),\n name: reverseDnsName(input),\n serverInfo: { name: input.name, version: input.version },\n title: truncate(input.name),\n tools: MCP_TOOLS.map((tool) => ({\n annotations: tool.annotations,\n description: tool.description,\n name: tool.name,\n title: tool.title,\n })),\n transport: \"streamable-http\",\n transports: [{ endpoint: url, type: \"streamable-http\" }],\n url,\n version: input.version,\n };\n if (HTTP_URL.test(url)) {\n card.remotes = [{ type: \"streamable-http\", url }];\n }\n if (input.site) {\n card.websiteUrl = siteRoot(input.site);\n }\n return card;\n};\n",
|
|
131
|
+
"import { createHash } from \"node:crypto\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\n\nimport { join } from \"pathe\";\n\nimport { normalizeBasePath } from \"../core/base-path.ts\";\nimport matter from \"../core/frontmatter.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { buildTarGz } from \"./tar.ts\";\nimport type { TarEntry } from \"./tar.ts\";\n\n/**\n * Agent Skills discovery (Cloudflare's Agent Skills Discovery RFC v0.2.0):\n * the skills a site publishes are enumerated in an index at\n * `/.well-known/agent-skills/index.json`, each entry pointing at its artifact\n * with a SHA-256 digest. A skill that is only a `SKILL.md` publishes the file\n * verbatim (`type: \"skill-md\"`); a skill with supporting resources (scripts,\n * references, assets) is bundled into a deterministic `.tar.gz`\n * (`type: \"archive\"`) so its relative references resolve after unpacking.\n */\n\nexport const AGENT_SKILLS_DIR = \"/.well-known/agent-skills\";\nexport const AGENT_SKILLS_INDEX_PATH = \"/.well-known/agent-skills/index.json\";\n\nconst AGENT_SKILLS_SCHEMA =\n \"https://schemas.agentskills.io/discovery/0.2.0/schema.json\";\n\n/** Skill naming rule from the Agent Skills spec (1-64 chars enforced apart). */\nconst SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;\nconst SKILL_NAME_MAX = 64;\n/** The Agent Skills spec caps `description` at 1024 characters. */\nconst DESCRIPTION_MAX = 1024;\n\n/** One publishable skill artifact plus its index entry. */\nexport interface SkillArtifact {\n /** Raw bytes to publish (the digest is computed over exactly these). */\n content: Uint8Array;\n description: string;\n /** `sha256:{hex}` digest of `content`. */\n digest: string;\n name: string;\n /** Path under the agent-skills dir: `{name}/SKILL.md` or `{name}.tar.gz`. */\n path: string;\n type: \"archive\" | \"skill-md\";\n}\n\nexport interface CollectedSkills {\n skills: SkillArtifact[];\n /** Human-readable reasons for anything skipped. */\n warnings: string[];\n}\n\nconst sha256 = (content: Uint8Array): string =>\n `sha256:${createHash(\"sha256\").update(content).digest(\"hex\")}`;\n\n/**\n * Every regular file under a skill directory, as archive entries with\n * `/`-separated relative paths, dotfiles (`.DS_Store`, `.git`) excluded,\n * sorted for deterministic archives. The owner-execute bit is preserved so a\n * skill's scripts stay runnable after unpacking.\n */\nconst collectEntries = async (\n dir: string,\n prefix = \"\"\n): Promise<TarEntry[]> => {\n const entries: TarEntry[] = [];\n const items = await readdir(dir, { withFileTypes: true });\n for (const item of items.toSorted((a, b) => (a.name < b.name ? -1 : 1))) {\n if (item.name.startsWith(\".\")) {\n continue;\n }\n const path = join(dir, item.name);\n const relative = prefix ? `${prefix}/${item.name}` : item.name;\n if (item.isDirectory()) {\n // Sequential recursion keeps ordering deterministic.\n // oxlint-disable-next-line no-await-in-loop\n entries.push(...(await collectEntries(path, relative)));\n } else if (item.isFile()) {\n // oxlint-disable-next-line no-await-in-loop\n const [content, info] = await Promise.all([readFile(path), stat(path)]);\n entries.push({\n content: new Uint8Array(content),\n // oxlint-disable-next-line no-bitwise -- testing the owner-execute mode bit\n executable: (info.mode & 0o100) !== 0,\n path: relative,\n });\n }\n }\n return entries;\n};\n\n/** The two SKILL.md frontmatter fields the discovery index publishes. */\ninterface SkillMeta {\n description: string;\n name: string;\n}\n\ninterface SkillMetaResult {\n meta: SkillMeta | null;\n warning?: string;\n}\n\n/**\n * What js-yaml can put in a SKILL.md frontmatter field. Rich scalars (Dates)\n * ride along as the object arm; only strings are accepted below anyway.\n */\ntype FrontmatterField =\n | string\n | number\n | boolean\n | null\n | undefined\n | FrontmatterField[]\n | { [key: string]: FrontmatterField };\n\nconst isString = (value: FrontmatterField): value is string =>\n typeof value === \"string\";\n\n/** Frontmatter of a SKILL.md, or null with a warning when unusable. */\nconst skillMeta = (raw: string, dirName: string): SkillMetaResult => {\n let data: { description?: FrontmatterField; name?: FrontmatterField };\n try {\n ({ data } = matter(raw));\n } catch {\n return {\n meta: null,\n warning: `Skill \"${dirName}\" has unparsable SKILL.md frontmatter; skipped.`,\n };\n }\n const name = isString(data.name) ? data.name : \"\";\n const description = isString(data.description) ? data.description : \"\";\n if (!(name && description)) {\n return {\n meta: null,\n warning: `Skill \"${dirName}\" is missing the required \"name\"/\"description\" frontmatter; skipped.`,\n };\n }\n if (!SKILL_NAME.test(name) || name.length > SKILL_NAME_MAX) {\n return {\n meta: null,\n warning: `Skill \"${dirName}\" has an invalid name \"${name}\" (lowercase alphanumerics and single hyphens, max 64 chars); skipped.`,\n };\n }\n return {\n meta: { description: description.slice(0, DESCRIPTION_MAX), name },\n };\n};\n\n/**\n * Collect the publishable skills from a directory whose subdirectories each\n * hold a `SKILL.md` (the layout `npx skills add` consumes). Subdirectories\n * without one are ignored silently — the directory may hold other assets —\n * while a present-but-invalid skill earns a warning so it isn't dropped\n * behind the publisher's back.\n */\nexport const collectSkills = async (dir: string): Promise<CollectedSkills> => {\n const skills: SkillArtifact[] = [];\n const warnings: string[] = [];\n const items = await readdir(dir, { withFileTypes: true });\n for (const item of items.toSorted((a, b) => (a.name < b.name ? -1 : 1))) {\n if (!item.isDirectory() || item.name.startsWith(\".\")) {\n continue;\n }\n // oxlint-disable-next-line no-await-in-loop\n const entries = await collectEntries(join(dir, item.name));\n const skillMd = entries.find((entry) => entry.path === \"SKILL.md\");\n if (!skillMd) {\n continue;\n }\n const { meta, warning } = skillMeta(\n new TextDecoder().decode(skillMd.content),\n item.name\n );\n if (!meta) {\n if (warning) {\n warnings.push(warning);\n }\n continue;\n }\n // A lone SKILL.md ships verbatim; supporting resources ship as an\n // archive so the skill's relative references resolve after unpacking.\n const single = entries.length === 1;\n const content = single ? skillMd.content : buildTarGz(entries);\n skills.push({\n content,\n description: meta.description,\n digest: sha256(content),\n name: meta.name,\n path: single ? `${meta.name}/SKILL.md` : `${meta.name}.tar.gz`,\n type: single ? \"skill-md\" : \"archive\",\n });\n }\n return { skills, warnings };\n};\n\n/**\n * The discovery index (v0.2.0 schema). Artifact URLs are path-absolute under\n * `deployment.base` — the RFC resolves them against the index origin.\n */\nexport const buildSkillsIndex = (\n skills: readonly SkillArtifact[],\n config: ResolvedConfig\n): string => {\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const index = {\n $schema: AGENT_SKILLS_SCHEMA,\n skills: skills.map((skill) => ({\n description: skill.description,\n digest: skill.digest,\n name: skill.name,\n type: skill.type,\n url: `${deployBase}${AGENT_SKILLS_DIR}/${skill.path}`,\n })),\n };\n return `${JSON.stringify(index, null, 2)}\\n`;\n};\n",
|
|
132
|
+
"import { gzipSync } from \"node:zlib\";\n\nimport { createTar } from \"nanotar\";\n\n/**\n * `.tar.gz` writer for agent-skill archives, on nanotar's ustar writer.\n * Deterministic by construction — fixed mtime/uid/gid/owner attrs,\n * caller-ordered entries, and Node's gzip header carries no timestamp — so a\n * skill's archive digest only changes when its content does. That holds per\n * machine: the tar bytes are portable, but zlib's compressed stream differs\n * across architectures, so gzip-layer digests are not comparable across\n * platforms.\n */\n\n/** One regular file to archive. Paths are `/`-separated, relative, no `..`. */\nexport interface TarEntry {\n /** Raw file bytes. */\n content: Uint8Array;\n /** Preserve the owner-execute bit (e.g. a skill's scripts). */\n executable?: boolean;\n /** Archive-relative path, e.g. `SKILL.md` or `references/FORMS.md`. */\n path: string;\n}\n\n/** ustar `name` field capacity; skill layouts are shallow, so no `prefix`. */\nconst NAME_MAX = 100;\n\nconst encoder = new TextEncoder();\n\n/**\n * Build a gzipped ustar archive of the given files, in the given order. Paths\n * longer than the ustar `name` field or escaping the archive root throw to\n * surface a programming error — nanotar would silently truncate an oversized\n * name into a corrupt archive, so the validation stays here.\n */\nexport const buildTarGz = (entries: readonly TarEntry[]): Uint8Array => {\n for (const entry of entries) {\n if (encoder.encode(entry.path).byteLength > NAME_MAX) {\n throw new Error(`tar path exceeds ${NAME_MAX} bytes: ${entry.path}`);\n }\n if (entry.path.startsWith(\"/\") || entry.path.split(\"/\").includes(\"..\")) {\n throw new Error(`tar path must be archive-relative: ${entry.path}`);\n }\n }\n const tar = createTar(\n entries.map((entry) => ({\n // Root-owned, epoch-mtime, empty owner names: every field a rebuild\n // could vary is pinned so the archive bytes are a function of content.\n attrs: {\n gid: 0,\n group: \"\",\n mode: entry.executable ? \"755\" : \"644\",\n mtime: 0,\n uid: 0,\n user: \"\",\n },\n data: entry.content,\n name: entry.path,\n }))\n );\n // Sync gzip with a pinned level; Node writes no timestamp into the header.\n return new Uint8Array(gzipSync(tar, { level: 9 }));\n};\n",
|
|
133
|
+
"import { apiNamePhrase } from \"../core/api-name.ts\";\nimport { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\nimport { resolveReferences } from \"../openapi/references.ts\";\nimport { API_CATALOG_PATH, hasApiCatalog } from \"./api-catalog.ts\";\nimport { OPENAPI_PATH } from \"./api/paths.ts\";\nimport { asciiSlugify } from \"./mcp/discovery.ts\";\nimport { AGENT_SKILLS_DIR } from \"./skills.ts\";\nimport type { SkillArtifact } from \"./skills.ts\";\n\n/**\n * The AI Catalog (Agent-Card/ai-catalog data model, `specVersion` 1.0) at\n * `/.well-known/ai-catalog.json`, which is also the Agentic Resource\n * Discovery (ARD) manifest: one entry per agent-facing resource the site\n * publishes, each an `urn:air:<host>:<namespace>:<name>` identifier, a\n * display name, the artifact's media type, a URL, and the\n * `representativeQueries` registries embed for semantic search. Like the\n * RFC 9727 catalog next to it, everything is derived from `blume.config.ts`\n * and the build's published skills — nothing is hand-written.\n *\n * ARD v0.91 moved its manifest to `/.well-known/ard.json` and calls\n * `ai-catalog.json` the predecessor path that consumers only *may* consult,\n * while the ai-catalog spec and today's agent-readiness scanners key on\n * `ai-catalog.json`. The ARD manifest is just an `entries` array (other\n * members are ignored), so the one document is written to both paths.\n *\n * Served as plain `application/json`: the `.json` extension gets it from\n * every static host with no header rule, and the scanners that gate on the\n * file ask for exactly that type. The registered `application/ai-catalog+json`\n * is what the `Link`/`<link>` advertisements declare the document to be.\n */\n\nexport const AI_CATALOG_PATH = \"/.well-known/ai-catalog.json\";\nexport const ARD_MANIFEST_PATH = \"/.well-known/ard.json\";\nexport const AI_CATALOG_TYPE = \"application/ai-catalog+json\";\nconst SPEC_VERSION = \"1.0\";\n\n/** One catalog entry, restricted to the terms Blume emits. */\ninterface CatalogEntry {\n identifier: string;\n displayName: string;\n type: string;\n url: string;\n description?: string;\n capabilities?: string[];\n representativeQueries: string[];\n}\n\n/** An entry before its identifier and queries are resolved against the host. */\ninterface EntrySeed {\n /** `<namespace>:<name>` — the identifier's tail and the `queries` key. */\n key: string;\n displayName: string;\n type: string;\n url: string;\n description?: string;\n capabilities?: string[];\n /** Generated queries, replaced wholesale by a configured `queries[key]`. */\n queries: string[];\n}\n\nconst REFERENCE_KIND_LABEL = {\n asyncapi: \"AsyncAPI\",\n graphql: \"GraphQL\",\n openapi: \"OpenAPI\",\n scalar: \"API\",\n} as const;\n\n/** The `urn:air` publisher: the configured site's hostname. */\nconst publisherHost = (site: string): string => new URL(site).hostname;\n\n/**\n * Whether the site publishes a catalog: the feature is on, a `deployment.site`\n * anchors the identifiers, and at least one entry exists. Every entry source\n * is a config flag, so the answer needs no build output — the same gate the\n * header rules, the `Link` header, and the head links read.\n */\nexport const hasAiCatalog = (config: ResolvedConfig): boolean =>\n config.agents.catalog.enabled &&\n Boolean(config.deployment.options.site) &&\n (config.agents.mcp.enabled ||\n config.agents.api ||\n config.agents.llmsTxt.enabled ||\n Boolean(config.agents.skills) ||\n resolveReferences(config).length > 0);\n\n/**\n * The `.well-known` documents agent registries fetch cross-origin (browser\n * agents, hosted registries reading through a page). Each needs\n * `Access-Control-Allow-Origin: *` on the static surface; the MCP endpoint\n * itself already sets it at runtime.\n */\nexport const crossOriginDiscoveryPaths = (config: ResolvedConfig): string[] => {\n const paths: string[] = [];\n if (hasAiCatalog(config)) {\n paths.push(AI_CATALOG_PATH, ARD_MANIFEST_PATH);\n }\n if (hasApiCatalog(config)) {\n paths.push(API_CATALOG_PATH);\n }\n if (config.agents.mcp.enabled) {\n paths.push(\"/.well-known/mcp.json\", \"/.well-known/mcp/server-card.json\");\n }\n return paths;\n};\n\n/** A site title that already names its docs: \"Acme Docs\", \"Acme Documentation\". */\nconst NAMES_DOCS = /\\b(?:docs|documentation)$/iu;\n\n/**\n * The docs as \"the ___\" in generated prose: the title followed by `noun`,\n * unless the title already ends in \"Docs\" or \"Documentation\" — so \"Acme\"\n * reads \"the Acme documentation\" and \"Acme Docs\" reads \"the Acme Docs\", not\n * \"the Acme Docs docs\".\n */\nconst docsPhrase = (title: string, noun: \"docs\" | \"documentation\"): string =>\n NAMES_DOCS.test(title.trim()) ? `the ${title}` : `the ${title} ${noun}`;\n\nconst entrySeeds = (\n config: ResolvedConfig,\n skills: readonly SkillArtifact[],\n abs: (path: string) => string\n): EntrySeed[] => {\n const { title } = config;\n const documentation = docsPhrase(title, \"documentation\");\n const docs = docsPhrase(title, \"docs\");\n const seeds: EntrySeed[] = [];\n\n if (config.agents.mcp.enabled) {\n const name = config.agents.mcp.name ?? title;\n seeds.push({\n capabilities: [\"search_docs\", \"get_page\", \"list_pages\", \"get_navigation\"],\n description:\n config.agents.mcp.instructions ??\n `Model Context Protocol server over ${documentation}: full-text search, page Markdown, the page index, and the navigation tree.`,\n displayName: name,\n key: `mcp:${asciiSlugify(name) || \"docs\"}`,\n queries: [\n `search ${documentation}`,\n `get a page of ${docs} as Markdown`,\n `list every page in ${docs}`,\n ],\n type: \"application/mcp-server-card+json\",\n url: abs(\"/.well-known/mcp/server-card.json\"),\n });\n }\n\n for (const skill of skills) {\n seeds.push({\n description: skill.description,\n displayName: skill.name,\n key: `skill:${skill.name}`,\n queries: [\n `load the ${skill.name} agent skill`,\n `how do I use ${skill.name}`,\n ],\n type:\n skill.type === \"archive\"\n ? \"application/agent-skills+gzip\"\n : \"application/agent-skills+md\",\n url: abs(`${AGENT_SKILLS_DIR}/${skill.path}`),\n });\n }\n\n if (config.agents.api) {\n seeds.push({\n description: `REST API over ${documentation}: the page index, each page as JSON or Markdown, and the navigation tree, described by this OpenAPI document.`,\n displayName: NAMES_DOCS.test(title.trim())\n ? `${title} API`\n : `${title} docs API`,\n key: \"api:docs\",\n queries: [\n `fetch a page of ${docs} as JSON`,\n `list the pages in ${docs}`,\n `get the navigation tree of ${docs}`,\n ],\n type: \"application/vnd.oai.openapi+json\",\n url: abs(OPENAPI_PATH),\n });\n }\n\n for (const reference of resolveReferences(config)) {\n // Blume-rendered pages mount under `basePath`; Scalar pages stay at the\n // raw route (see `referenceRoutes`). The rendered reference is the\n // resource this publisher owns — the spec itself is catalogued by URL in\n // the RFC 9727 linkset.\n const docRoute =\n reference.kind === \"scalar\"\n ? reference.route\n : withBasePath(reference.basePath, reference.route);\n seeds.push({\n description: `${reference.label}: rendered ${REFERENCE_KIND_LABEL[reference.kind]} reference in ${documentation}.`,\n displayName: reference.label,\n key: `reference:${reference.slug}`,\n queries: [\n `what operations does the ${apiNamePhrase(reference.label)} expose`,\n `how do I call the ${apiNamePhrase(reference.label)}`,\n ],\n type: \"text/html\",\n url: abs(docRoute),\n });\n }\n\n if (config.agents.llmsTxt.enabled) {\n seeds.push({\n description: `llms.txt index of ${documentation}: every page with a one-line summary, plus the agent-facing resources on this site.`,\n displayName: `${title} llms.txt`,\n key: \"docs:llms-txt\",\n queries: [`what is ${title}`, `overview of ${documentation}`],\n type: \"text/plain\",\n url: abs(\"/llms.txt\"),\n });\n }\n\n return seeds;\n};\n\n/** The catalog document, or null when the site publishes none. */\nexport const buildAiCatalog = (\n config: ResolvedConfig,\n skills: readonly SkillArtifact[]\n): string | null => {\n const site = config.deployment.options.site ?? null;\n if (!(site && hasAiCatalog(config))) {\n return null;\n }\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const abs = (path: string): string =>\n absoluteUrl(site, withBasePath(deployBase, path));\n const host = publisherHost(site);\n const entries = entrySeeds(config, skills, abs).map((seed): CatalogEntry => {\n const entry: CatalogEntry = {\n displayName: seed.displayName,\n identifier: `urn:air:${host}:${seed.key}`,\n representativeQueries:\n config.agents.catalog.queries[seed.key] ?? seed.queries,\n type: seed.type,\n url: seed.url,\n };\n if (seed.description) {\n entry.description = seed.description;\n }\n if (seed.capabilities) {\n entry.capabilities = seed.capabilities;\n }\n return entry;\n });\n const catalog = {\n entries,\n host: {\n displayName: config.title,\n documentationUrl: abs(\"/\"),\n identifier: `did:web:${host}`,\n },\n specVersion: SPEC_VERSION,\n };\n return `${JSON.stringify(catalog, null, 2)}\\n`;\n};\n",
|
|
134
|
+
"import { normalizeBasePath } from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport {\n AI_CATALOG_PATH,\n AI_CATALOG_TYPE,\n hasAiCatalog,\n} from \"./ai-catalog.ts\";\nimport { API_CATALOG_PATH, hasApiCatalog } from \"./api-catalog.ts\";\nimport { OPENAPI_PATH } from \"./api/paths.ts\";\n\n/**\n * The homepage `Link` response header (RFC 8288) — agent discovery for the\n * machine-readable surface Blume already publishes. Agents probing a site read\n * this header off `GET /` to find the resources without scraping HTML:\n * `agent-readability.json` and `llms.txt` as `rel=\"describedby\"`, the OpenAPI\n * description of the JSON docs API as `rel=\"service-desc\"`, and the\n * homepage's raw-Markdown mirror as `rel=\"alternate\"` (only when the home\n * route is a content page — a user landing page has no mirror). Every rel\n * value is IANA-registered, which agent-readiness checkers require.\n *\n * The header is homepage-only by design: the root response is what agents\n * probe, and `agent-readability.json` indexes the rest of the surface (the\n * per-route Markdown pattern, MCP, feeds) far better than per-page headers\n * could. An agent that enters on a deep page (a search result, a shared link)\n * never sees this header at all — that path is covered in the HTML instead:\n * every page's `<head>` carries the same `describedby` links plus its own\n * Markdown mirror as an `alternate` (the `DiscoveryLinks.astro` partial every\n * layout renders), which also reaches hosts where Blume can't set response\n * headers. Targets are\n * root-relative under `deployment.base` — RFC 8288 resolves them against the\n * request URL. Returns null when nothing is advertisable.\n */\nexport const buildHomeLinkHeader = (\n config: ResolvedConfig,\n routePaths: readonly string[]\n): string | null => {\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const links: string[] = [];\n // RFC 9727 §3: the api-catalog relation is how a homepage advertises the\n // well-known catalog.\n if (hasApiCatalog(config)) {\n links.push(\n `<${deployBase}${API_CATALOG_PATH}>; rel=\"api-catalog\"; type=\"application/linkset+json\"`\n );\n }\n // The ai-catalog spec's own relation for its well-known document, the\n // header form of the `<link rel=\"ai-catalog\">` every page carries.\n if (hasAiCatalog(config)) {\n links.push(\n `<${deployBase}${AI_CATALOG_PATH}>; rel=\"ai-catalog\"; type=\"${AI_CATALOG_TYPE}\"`\n );\n }\n // RFC 8631: `service-desc` is the relation for a machine-readable\n // description of the service — the JSON docs API's OpenAPI document.\n if (config.agents.api) {\n links.push(\n `<${deployBase}${OPENAPI_PATH}>; rel=\"service-desc\"; type=\"application/json\"`\n );\n }\n if (config.agents.agentReadability) {\n links.push(\n `<${deployBase}/agent-readability.json>; rel=\"describedby\"; type=\"application/json\"`\n );\n }\n if (config.agents.llmsTxt.enabled) {\n links.push(\n `<${deployBase}/llms.txt>; rel=\"describedby\"; type=\"text/plain\"`\n );\n }\n // Same route list as the negotiation surfaces (`markdownRoutePaths`): \"/\"\n // always has a mirror — the page's own source when the home route is a\n // content page, the synthesized llms.txt fallback otherwise — so callers\n // passing that list always advertise `/index.md` here.\n if (routePaths.includes(\"/\")) {\n links.push(\n `<${deployBase}/index.md>; rel=\"alternate\"; type=\"text/markdown\"`\n );\n }\n return links.length > 0 ? links.join(\", \") : null;\n};\n",
|
|
135
|
+
"import { readFile } from \"node:fs/promises\";\n\nimport { hasGeneratedChangelog } from \"../astro/pages.ts\";\nimport { CHANGELOG_INDEX_ROUTE } from \"../core/changelog-index.ts\";\nimport { rewriteRelativeImages } from \"../core/content-assets.ts\";\nimport { discoverPages, discoverPagesSync } from \"../core/custom-pages.ts\";\nimport matter from \"../core/frontmatter.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { readExpandedEntryText } from \"../core/sources/read.ts\";\nimport type { RouteManifestEntry } from \"../core/types.ts\";\nimport { buildChangelogIndexMarkdown } from \"./changelog-markdown.ts\";\nimport { downlevelComponents } from \"./component-markdown.ts\";\nimport { buildLlmsIndex } from \"./llms.ts\";\nimport { relativeLinkRewriter } from \"./relative-links.ts\";\nimport { projectComponentSerializers } from \"./serializers.ts\";\nimport { applyAgentVisibility } from \"./visibility.ts\";\n\n/** One route's raw-Markdown variants. */\nexport interface RawMarkdownEntry {\n /**\n * The agent-facing Markdown served at `/<route>.md`: supported components\n * downleveled to plain Markdown (`<TypeTable>` → table, `<Callout>` →\n * blockquote, …). Present only when downleveling changed something, so\n * component-free pages aren't stored twice.\n */\n md?: string;\n /** The original source, served verbatim at `/<route>.mdx`. */\n mdx: string;\n}\n\n/** The Markdown an agent should read for a route. */\nexport const agentMarkdown = (entry: RawMarkdownEntry): string =>\n entry.md ?? entry.mdx;\n\n/**\n * Estimated token count of a Markdown document, for the `x-markdown-tokens`\n * response header (the convention Cloudflare's Markdown for Agents ships; the\n * tokenizer is unspecified there too, so this is the common ~4-characters-\n * per-token estimate). Kept in sync with the inline computation in\n * `rawMarkdownEndpointTemplate`, which can't import build-time code.\n */\nexport const markdownTokenCount = (text: string): number =>\n Math.ceil(text.length / 4);\n\n/**\n * Map every route to its raw source Markdown. Powers the `<route>.md` and\n * `<route>.mdx` endpoints: `.mdx` serves the original source so tools can see\n * exactly what the author wrote, while `.md` downlevels supported components\n * to plain Markdown for consumers that can't interpret JSX. `<Visibility>`\n * audiences are resolved for agents in both variants: web-only content is\n * removed, agents-only unwrapped. Relative image references are rewritten to\n * their served `/blume-assets/content/…` URLs in both variants too — an agent\n * fetches these endpoints by URL, where a colocated `./diagram.png` resolves\n * to nothing — and relative page links to the routes they mean, as the\n * rendered page's are (see `relative-links.ts`).\n */\nexport const buildRawMarkdown = async (\n project: BlumeProject\n): Promise<Record<string, RawMarkdownEntry>> => {\n const pageById = new Map(project.graph.pages.map((page) => [page.id, page]));\n\n const components = projectComponentSerializers(project);\n const rewriteLinks = relativeLinkRewriter(project);\n\n const readRoute = async (route: RouteManifestEntry): Promise<string> => {\n const page = pageById.get(route.id);\n if (page) {\n return await readExpandedEntryText(project, page);\n }\n return route.sourcePath ? await readFile(route.sourcePath, \"utf-8\") : \"\";\n };\n\n const entries = await Promise.all(\n project.manifest.routes.map(async (route) => {\n let text = await readRoute(route);\n if (route.sourcePath) {\n text = rewriteRelativeImages({\n deployBase: project.config.deployment.options.base,\n projectRoot: project.context.root,\n source: text,\n sourcePath: route.sourcePath,\n });\n // `./install` means the page's sibling, not whatever the `.md` URL\n // an agent fetched resolves it to.\n text = rewriteLinks(text, {\n route: route.path,\n sourcePath: route.sourcePath,\n });\n }\n const source = applyAgentVisibility(text);\n // The `.md` variant keeps the front-matter block in the output, but its\n // data must also be in scope for `prop={frontmatter.*}` expressions.\n const md = downlevelComponents(source, components, matter(source).data);\n const entry: RawMarkdownEntry =\n md === source ? { mdx: source } : { md, mdx: source };\n return [route.path, entry] as const;\n })\n );\n const map = Object.fromEntries(entries);\n // A landing-page homepage (user `.astro` page, or no home route at all) has\n // no Markdown source, but agents negotiating `Accept: text/markdown` on `/`\n // still expect a Markdown answer. The llms.txt index — the machine-readable\n // representation of the site a landing page fronts — becomes its mirror, so\n // `/index.md` always exists (see `markdownRoutePaths`).\n if (!map[\"/\"]) {\n map[\"/\"] = { mdx: buildLlmsIndex(project) };\n }\n // The generated changelog index has no source either; its release list is\n // its mirror, so `/changelog.md` and `get_page` answer as the page does.\n const userPages = project.context.pagesRoot\n ? await discoverPages(project.context.pagesRoot)\n : [];\n if (hasGeneratedChangelog(project, userPages)) {\n map[CHANGELOG_INDEX_ROUTE] = { mdx: buildChangelogIndexMarkdown(project) };\n }\n return map;\n};\n\n/**\n * Every route path with a raw-Markdown mirror: the manifest routes, plus the\n * homepage when its mirror is the synthesized llms.txt fallback and the\n * generated changelog index (see `buildRawMarkdown`). This is the route list the negotiation surfaces (dev\n * middleware, Vercel routing config) and the homepage `Link` header build\n * from, so `Accept: text/markdown` on `/` resolves even when the homepage is\n * a landing page.\n */\nexport const markdownRoutePaths = (project: BlumeProject): string[] => {\n const paths = project.manifest.routes.map((route) => route.path);\n if (!paths.includes(\"/\")) {\n paths.push(\"/\");\n }\n const userPages = project.context.pagesRoot\n ? discoverPagesSync(project.context.pagesRoot)\n : [];\n if (hasGeneratedChangelog(project, userPages)) {\n paths.push(CHANGELOG_INDEX_ROUTE);\n }\n return paths;\n};\n",
|
|
136
|
+
"import { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport { EN_UI, resolveUIStrings } from \"../core/i18n-ui.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\nimport type { PageRecord } from \"../core/types.ts\";\n\n/**\n * The generated `/changelog` index as Markdown, for its `/changelog.md`\n * mirror and MCP `get_page`: the timeline an agent would otherwise have to\n * scrape out of the rendered page. Lists what the index page lists — every\n * visible changelog entry of the current docs in the default locale, newest\n * first, grouped by year — one line each, with its date and category and a\n * link to the entry's own page.\n */\n\ninterface IndexRow {\n date: Date | null;\n page: PageRecord;\n}\n\nconst parseDate = (value: string | undefined): Date | null => {\n if (value === undefined) {\n return null;\n }\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\n/** A row's link: absolute under a configured site, like llms.txt. */\nconst entryUrl = (project: BlumeProject, route: string): string => {\n const { base, site } = project.config.deployment.options;\n const path = withBasePath(normalizeBasePath(base), route);\n return encodeURI(site ? absoluteUrl(site, path) : path);\n};\n\nconst rowLine = (project: BlumeProject, { date, page }: IndexRow): string => {\n const details = [\n date ? date.toISOString().slice(0, 10) : \"\",\n page.meta.changelog?.category ?? \"\",\n ].filter(Boolean);\n const title = page.title.replaceAll(/[[\\]]/gu, String.raw`\\$&`);\n const tail = details.length > 0 ? ` — ${details.join(\", \")}` : \"\";\n return `- [${title}](${entryUrl(project, page.route)})${tail}`;\n};\n\nexport const buildChangelogIndexMarkdown = (project: BlumeProject): string => {\n const { i18n } = project.config;\n const ui = i18n\n ? resolveUIStrings(i18n.defaultLocale, {\n defaultLocale: i18n.defaultLocale,\n overrides: i18n.ui,\n })\n : EN_UI;\n const rows: IndexRow[] = project.graph.pages\n .filter(\n (page) =>\n page.contentType === \"changelog\" &&\n !page.meta.draft &&\n !page.meta.sidebar.hidden &&\n !page.fallback &&\n page.version === \"\" &&\n (!i18n || page.locale === i18n.defaultLocale)\n )\n .map((page) => ({\n date: parseDate(page.meta.date ?? page.meta.changelog?.date),\n page,\n }))\n .toSorted((a, b) => (b.date?.getTime() ?? 0) - (a.date?.getTime() ?? 0));\n\n const blocks = [`# ${ui.changelog.title}`, ui.changelog.description];\n let year: number | null | undefined;\n let lines: string[] = [];\n const flush = (): void => {\n if (lines.length > 0) {\n blocks.push(lines.join(\"\\n\"));\n lines = [];\n }\n };\n for (const row of rows) {\n const rowYear = row.date ? row.date.getUTCFullYear() : null;\n if (rowYear !== year) {\n flush();\n year = rowYear;\n // Undated entries sort last, under a heading of their own.\n blocks.push(rowYear === null ? \"## Undated\" : `## ${rowYear}`);\n }\n lines.push(rowLine(project, row));\n }\n flush();\n return `${blocks.join(\"\\n\\n\")}\\n`;\n};\n",
|
|
137
|
+
"import { markdownTable } from \"markdown-table\";\nimport { mdxToMdast } from \"satteri\";\n\nimport { parseYouTubeId } from \"../components/content/youtube.ts\";\nimport type { ExampleLookup } from \"../core/types.ts\";\nimport { MDX_FEATURES } from \"../markdown/features.ts\";\n\n/**\n * Downlevel Blume's MDX components to plain Markdown for agent-facing output\n * (the `/<route>.md` mirror, llms-full.txt, MCP `get_page`). Each supported\n * component has a serializer — its \"toString\" — that renders the same\n * information as the Astro component, but as portable Markdown: `<TypeTable>`\n * becomes a GFM table, `<Callout>` a blockquote, `<Steps>` an ordered list,\n * `<Tabs>` labeled sections, `<YouTube>` a link.\n *\n * The transform is a position splice, not a re-stringify: the MDX source is\n * parsed to MDAST (via Satteri, which stamps byte offsets on every node) and\n * only the matched component ranges are replaced, so all surrounding Markdown\n * stays byte-identical to what the author wrote. Anything the serializers\n * can't faithfully convert — an unknown component, a prop bound to an import —\n * is left as JSX, and fenced code that merely *shows* component markup is\n * naturally untouched because it parses as a `code` node.\n */\n\n/** Minimal structural MDAST types — we model only what this module reads. */\ninterface Offset {\n offset: number;\n}\n\n/** The structural slice of an mdast node the downlevel walk reads. */\nexport interface MdastNode {\n attributes?: MdxAttribute[];\n children?: MdastNode[];\n name?: string;\n position?: { end: Offset; start: Offset };\n type: string;\n}\n\ninterface MdxAttribute {\n name?: string;\n type: string;\n value?: string | { type: string; value: string } | null;\n}\n\n/** A single source replacement: `[start, end)` byte range → `text`. */\ninterface Splice {\n end: number;\n start: number;\n text: string;\n}\n\n/**\n * A statically-recovered data value. Parsed front matter and evaluated\n * attribute literals are both plain data — scalars, dates, arrays, and\n * nested maps — never functions or class instances.\n */\nexport type EvaluatedValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | Date\n | EvaluatedValue[]\n | { [key: string]: EvaluatedValue };\n\nexport const isString = <Value>(value: Value): value is Value & string =>\n typeof value === \"string\";\n\nconst isNumber = <Value>(value: Value): value is Value & number =>\n typeof value === \"number\";\n\n/** A nested map of evaluated values — an object literal prop, not a date or a list. */\nconst isValueMap = (\n value: EvaluatedValue\n): value is { [key: string]: EvaluatedValue } =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value instanceof Date);\n\n/** Evaluated props plus whether any attribute resisted static evaluation. */\ninterface EvaluatedProps {\n lossy: boolean;\n props: Record<string, EvaluatedValue>;\n}\n\n/** A child component extracted by name (e.g. each `<Step>` under `<Steps>`). */\nexport interface ComponentMarkdownChild extends EvaluatedProps {\n /** The child's body, downleveled and dedented. */\n children: string;\n}\n\n/** One direct child of a component — a child component or prose — as Markdown. */\nexport interface ComponentMarkdownBlock {\n /**\n * The child downleveled: a serializable component's rendering (through the\n * registry, so a user override of that component applies), or — for prose,\n * a component with no serializer, or one that declined — its source with\n * any serializable descendants downleveled in place.\n */\n markdown: string;\n /** The JSX name of a child component; `undefined` for prose. */\n name?: string;\n}\n\n/** What a serializer receives for one component usage. */\nexport interface ComponentMarkdownContext extends EvaluatedProps {\n /**\n * Every direct child of the element in document order, components and\n * prose alike, each as a block of Markdown. For a container that is nothing\n * but its contents — `<CardGroup>` — joining these with blank lines is the\n * whole serializer.\n */\n childBlocks: () => ComponentMarkdownBlock[];\n /** Direct child components of `name`, each with evaluated props and body. */\n childComponents: (name: string) => ComponentMarkdownChild[];\n /** The element's body, downleveled and dedented (empty if self-closing). */\n children: string;\n /**\n * The page's parsed front-matter (empty when the caller has none). Lets a\n * serializer read page metadata directly, even when a prop expression is\n * not statically evaluable.\n */\n frontmatter: Record<string, EvaluatedValue>;\n}\n\n/**\n * A component's Markdown serializer. Return the replacement Markdown, or\n * `null` to leave the component's JSX in the output verbatim (the safe\n * fallback when the props can't be recovered statically).\n */\nexport type ComponentMarkdown = (\n context: ComponentMarkdownContext\n) => string | null;\n\n/**\n * Statically evaluate an MDX attribute expression (`prop={...}`). Component\n * data props are object/array/number literals in practice; evaluation runs at\n * build time over the author's own content — the same trust level as the MDX\n * itself, which Astro compiles and executes. The page's `frontmatter` is in\n * scope, mirroring what Astro provides an MDX body at render time, so\n * `prop={frontmatter.status}` resolves; expressions that reference imports or\n * other scope throw and report as not evaluable.\n */\nconst evaluateExpression = (\n raw: string,\n frontmatter: Record<string, EvaluatedValue> | undefined\n) => {\n try {\n // Build-time eval of the author's own attribute literals; a throw falls\n // back to leaving the JSX verbatim.\n // oxlint-disable-next-line no-new-func\n const value: EvaluatedValue = new Function(\n \"frontmatter\",\n `\"use strict\"; return (${raw});`\n )(frontmatter);\n return { ok: true, value };\n } catch {\n return { ok: false, value: undefined };\n }\n};\n\n/** Evaluate an element's attributes into a plain props object. */\nconst readProps = (\n node: MdastNode,\n frontmatter: Record<string, EvaluatedValue> | undefined\n): EvaluatedProps => {\n const props: Record<string, EvaluatedValue> = {};\n let lossy = false;\n for (const attribute of node.attributes ?? []) {\n // A spread ({...props}) can't be recovered statically.\n if (attribute.type !== \"mdxJsxAttribute\" || !attribute.name) {\n lossy = true;\n continue;\n }\n if (attribute.value === null || attribute.value === undefined) {\n // Boolean shorthand: `<Steps compact>`.\n props[attribute.name] = true;\n } else if (isString(attribute.value)) {\n props[attribute.name] = attribute.value;\n } else {\n const result = evaluateExpression(attribute.value.value, frontmatter);\n if (result.ok) {\n props[attribute.name] = result.value;\n } else {\n lossy = true;\n }\n }\n }\n return { lossy, props };\n};\n\n/** A node Satteri stamped with byte offsets. */\ntype Positioned = MdastNode & { position: { end: Offset; start: Offset } };\n\nconst hasOffsets = (node: MdastNode): node is Positioned =>\n typeof node.position?.start?.offset === \"number\" &&\n typeof node.position?.end?.offset === \"number\";\n\n/** Apply non-overlapping splices to `text` (offsets relative to `text`). */\nconst applySplices = (text: string, splices: Splice[]): string => {\n let result = text;\n for (const splice of [...splices].toSorted((a, b) => b.start - a.start)) {\n // An element indented under a parent starts mid-line after whitespace;\n // repeat that indent on the replacement's continuation lines so the block\n // stays uniformly indented (and dedents cleanly with its siblings).\n const lineStart = result.lastIndexOf(\"\\n\", splice.start - 1) + 1;\n const prefix = result.slice(lineStart, splice.start);\n const indent = /^[\\t ]+$/u.test(prefix) ? prefix : \"\";\n const replacement = indent\n ? splice.text\n .split(\"\\n\")\n .map((line, index) =>\n index === 0 || line === \"\" ? line : `${indent}${line}`\n )\n .join(\"\\n\")\n : splice.text;\n result =\n result.slice(0, splice.start) + replacement + result.slice(splice.end);\n }\n return result;\n};\n\n/**\n * Strip the common indentation JSX children carry in source (`<Step>` bodies\n * are typically indented two spaces under their tag). The first line starts\n * mid-line at the slice boundary, already past its own indent, so that indent\n * is passed in as `firstIndent` when it is known — the whitespace before the\n * slice — and counts toward the common prefix. Without it a nested list\n * (`- a` then ` - b`) would lose its nesting: the deeper following lines\n * alone would set the prefix. When the slice starts after other text on its\n * line (`<Step>Body…`), only the following lines are measured.\n */\nconst dedent = (text: string, firstIndent?: number): string => {\n const lines = text.split(\"\\n\");\n const rest = lines.slice(1).filter((line) => line.trim() !== \"\");\n if (rest.length === 0) {\n return text;\n }\n const indent = Math.min(\n ...rest.map((line) => line.length - line.trimStart().length),\n ...(firstIndent === undefined ? [] : [firstIndent])\n );\n if (indent === 0) {\n return text;\n }\n return [\n lines[0],\n ...lines\n .slice(1)\n .map((line) => (line.trim() === \"\" ? \"\" : line.slice(indent))),\n ].join(\"\\n\");\n};\n\n/**\n * The indent of the line `offset` sits on, when everything before `offset` on\n * that line is whitespace; `undefined` when the offset follows other text.\n */\nconst indentAt = (source: string, offset: number): number | undefined => {\n const lineStart = source.lastIndexOf(\"\\n\", offset - 1) + 1;\n const prefix = source.slice(lineStart, offset);\n return /^[\\t ]*$/u.test(prefix) ? prefix.length : undefined;\n};\n\nconst isJsxElement = (node: MdastNode): boolean =>\n node.type === \"mdxJsxFlowElement\" || node.type === \"mdxJsxTextElement\";\n\n/** Flatten a value to a single Markdown table cell (pipes escaped). */\nconst cellText = (value: EvaluatedValue): string =>\n String(value ?? \"\")\n .replaceAll(/\\s*\\n\\s*/gu, \" \")\n .replaceAll(\"|\", \"\\\\|\")\n .trim();\n\n/** A cell rendered as inline code, unless the value itself uses backticks. */\nconst cellCode = (value: EvaluatedValue): string => {\n const text = cellText(value);\n return text && !text.includes(\"`\") ? `\\`${text}\\`` : text;\n};\n\n/**\n * One `<TypeTable type={{...}}>` entry, matching the component's props. The\n * index signature keeps the interface interchangeable with the evaluated\n * data-value maps it is narrowed from.\n */\ninterface TypeEntry {\n [field: string]: EvaluatedValue;\n default?: EvaluatedValue;\n description?: EvaluatedValue;\n required?: EvaluatedValue;\n type?: EvaluatedValue;\n typeDescription?: EvaluatedValue;\n typeDescriptionLink?: EvaluatedValue;\n}\n\n/**\n * The `type` data prop's entry map. Structural only: each entry's fields are\n * rendered through cellText/cellCode, which stringify any value.\n */\nconst isTypeEntryMap = (\n value: EvaluatedValue\n): value is Record<string, TypeEntry> =>\n typeof value === \"object\" && value !== null;\n\nconst typeTable: ComponentMarkdown = ({ children, props }) => {\n const { type } = props;\n if (!isTypeEntryMap(type)) {\n // The data prop is missing or wasn't statically evaluable.\n return null;\n }\n const entries = Object.entries(type);\n const rows = entries.map(([name, info]) => {\n const prop = cellCode(`${name}${info.required ? \"\" : \"?\"}`);\n const typeCell = info.typeDescriptionLink\n ? `[${cellCode(info.type)}](${cellText(info.typeDescriptionLink)})`\n : cellCode(info.type);\n const defaultCell =\n info.default === undefined ? \"-\" : cellCode(info.default);\n const description = cellText(\n [info.description, info.typeDescription]\n .filter((part) => isString(part) && part !== \"\")\n .join(\" \")\n );\n return [prop, typeCell, defaultCell, description];\n });\n const table =\n rows.length > 0\n ? markdownTable([[\"Prop\", \"Type\", \"Default\", \"Description\"], ...rows], {\n // Unpadded columns: cells hold prose and the output is for model\n // consumption, so aligned delimiter rows are wasted tokens.\n alignDelimiters: false,\n })\n : \"\";\n // The component renders its slot after the table.\n return [table, children].filter(Boolean).join(\"\\n\\n\");\n};\n\nconst callout: ComponentMarkdown = ({ children, props }) => {\n const type = isString(props.type) ? props.type : \"info\";\n const label =\n isString(props.title) && props.title !== \"\"\n ? props.title\n : type.charAt(0).toUpperCase() + type.slice(1);\n if (!children) {\n return `> **${label}**`;\n }\n const body = children\n .split(\"\\n\")\n .map((line) => (line.trim() === \"\" ? \">\" : `> ${line}`))\n .join(\"\\n\");\n return `> **${label}**\\n>\\n${body}`;\n};\n\n/** Format `content` as one ordered-list item, continuation lines indented. */\nconst listItem = (index: number, content: string): string => {\n const marker = `${index}. `;\n return content\n .split(\"\\n\")\n .map((line, lineIndex) => {\n if (lineIndex === 0) {\n return `${marker}${line}`;\n }\n return line === \"\" ? \"\" : ` ${line}`;\n })\n .join(\"\\n\");\n};\n\nconst steps: ComponentMarkdown = ({ childComponents, children }) => {\n const items = childComponents(\"Step\");\n if (items.length === 0) {\n return children;\n }\n return items\n .map((step, index) => {\n const title =\n isString(step.props.title) && step.props.title !== \"\"\n ? `**${step.props.title}**`\n : \"\";\n const content = [title, step.children].filter(Boolean).join(\"\\n\\n\");\n return listItem(index + 1, content);\n })\n .join(\"\\n\\n\");\n};\n\nconst tabs: ComponentMarkdown = ({ childComponents, children }) => {\n const items = childComponents(\"Tab\");\n if (items.length === 0) {\n return children;\n }\n return items\n .map((tab, index) => {\n const title =\n isString(tab.props.title) && tab.props.title !== \"\"\n ? tab.props.title\n : `Tab ${index + 1}`;\n return tab.children ? `**${title}**\\n\\n${tab.children}` : `**${title}**`;\n })\n .join(\"\\n\\n\");\n};\n\n/** Escape the brackets that would end a link's text early. */\nconst linkText = (value: string): string =>\n value.replaceAll(/[[\\]]/gu, String.raw`\\$&`);\n\n/**\n * A link destination. Whitespace ends one, and a `)` ends one unless it is\n * part of a balanced pair — so an href carrying either goes in the angle\n * bracket form, where only `<` and `>` are special.\n */\nexport const linkDestination = (href: string): string =>\n /[\\s()<>]/u.test(href)\n ? `<${href.replaceAll(/[<>]/gu, String.raw`\\$&`)}>`\n : href;\n\n/** A text prop: a string, or a number stringified — `title={2024}` is a title. */\nconst textProp = (value: EvaluatedValue): string => {\n if (isString(value)) {\n return value.trim();\n }\n return isNumber(value) ? String(value) : \"\";\n};\n\n/**\n * A card is a link with a blurb, so that is what it becomes: the title as the\n * link text, the body under it, and the call to action last — the order the\n * card renders in. Shaped like {@link tabs}, a bold label over the body,\n * rather than a heading: a card sits inside a page whose outline its author\n * wrote, and a heading would add a level to it.\n *\n * The icon and image are presentation and drop out. A card with no title\n * falls back to its `href`, and one with neither is just its body. `lossy`\n * declines: a title or href recovered from an expression that would not\n * evaluate is a link pointing somewhere wrong, which is worse than the\n * visible JSX.\n */\nconst card: ComponentMarkdown = ({ children, lossy, props }) => {\n if (lossy) {\n return null;\n }\n const title = textProp(props.title);\n const href = isString(props.href) ? props.href.trim() : \"\";\n const body = children.trim();\n const cta = textProp(props.cta);\n const label = title || href;\n if (label === \"\") {\n // Nothing to head the card with, so it is whatever text it carries.\n const rest = [body, cta].filter(Boolean).join(\"\\n\\n\");\n // Nothing but presentation left — keep the JSX rather than delete a card.\n return rest === \"\" ? null : rest;\n }\n const head =\n href === \"\"\n ? `**${label}**`\n : `**[${linkText(label)}](${linkDestination(href)})**`;\n return [head, body, cta].filter(Boolean).join(\"\\n\\n\");\n};\n\n/**\n * `CardGroup` is the grid its cards sit in and carries no meaning of its own,\n * so it becomes its contents: every direct child in order, each a block, a\n * blank line between them. Built on `childBlocks` rather than extracting the\n * cards so nothing the group holds is lost — a `Card` renders through the\n * registry (a user override of `Card` applies in here too), a nested group\n * recurses, prose between the cards stays, and a card that declines keeps its\n * JSX as a block of its own instead of vanishing beside a rendered sibling.\n * Passing the body slice through instead would leave each card's source\n * indentation in the output and run one card's title straight on from the\n * previous card's body as the same paragraph. The other containers that are\n * only layout — `Accordion`, `Columns`, `CodeGroup`, the `Color` palette —\n * serialize the same way; a child that renders to nothing (an unlabeled\n * `Icon`) leaves no gap.\n */\nconst cardGroup: ComponentMarkdown = ({ childBlocks }) =>\n childBlocks()\n .map((block) => block.markdown)\n .filter(Boolean)\n .join(\"\\n\\n\");\n\nconst youtube: ComponentMarkdown = ({ props }) => {\n let input = \"\";\n if (isString(props.id)) {\n input = props.id;\n } else if (isString(props.url)) {\n input = props.url;\n }\n const videoId = parseYouTubeId(input);\n if (!videoId) {\n return null;\n }\n const start =\n isNumber(props.start) && props.start > 0\n ? `&t=${Math.floor(props.start)}s`\n : \"\";\n const title =\n isString(props.title) && props.title !== \"\"\n ? props.title\n : \"Watch on YouTube\";\n return `[${title}](https://www.youtube.com/watch?v=${videoId}${start})`;\n};\n\n/**\n * `text` as an inline code span whose delimiter outlengths any backtick run\n * inside it, padded with a space when the content starts or ends with a\n * backtick (CommonMark strips one such pair) — so a spec path or address\n * carrying a backtick cannot close the span early.\n */\nexport const inlineCode = (text: string): string => {\n const runs = text.match(/`+/gu);\n const longest = runs ? Math.max(...runs.map((run) => run.length)) : 0;\n const delimiter = \"`\".repeat(longest + 1);\n const padded =\n text.startsWith(\"`\") || text.endsWith(\"`\") ? ` ${text} ` : text;\n return `${delimiter}${padded}${delimiter}`;\n};\n\n/** Fence `code` so its opening/closing run outlengths any backticks inside. */\nconst fencedBlock = (lang: string, code: string): string => {\n const trimmed = code.replace(/(?<!\\n)\\n+$/u, \"\");\n const runs = trimmed.match(/`+/gu);\n const longest = runs ? Math.max(...runs.map((run) => run.length)) : 0;\n const fence = \"`\".repeat(Math.max(3, longest + 1));\n return `${fence}${lang}\\n${trimmed}\\n${fence}`;\n};\n\n/**\n * Build the `<Component>` serializer for a project's discovered examples. The\n * live preview can't survive the trip to Markdown, so the agent-facing output\n * carries the example's source — the same code the \"Code\" tab shows — as a\n * fenced block. An unknown `path` (or a missing `path` prop) declines, leaving\n * the JSX verbatim, mirroring the \"no example found\" note the component renders\n * on the page.\n */\nexport const exampleComponentSerializers = (examples: ExampleLookup) =>\n ({\n Component: ({ props }) => {\n const path = isString(props.path) ? props.path : undefined;\n const example = path === undefined ? undefined : examples[path];\n return example ? fencedBlock(example.lang, example.source) : null;\n },\n }) satisfies Record<string, ComponentMarkdown>;\n\n/** A bold label over a body — the shape {@link tabs} and {@link card} use. */\nconst labeled = (label: string, ...parts: string[]): string =>\n [label === \"\" ? \"\" : `**${label}**`, ...parts]\n .map((part) => part.trim())\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n/**\n * A disclosure — `AccordionItem`, and `Expandable` with its \"Show more\"\n * default — is its title over its body, open: an agent reads what a reader\n * would have to click for. A title that wouldn't evaluate declines.\n */\nconst disclosure = (\n { children, lossy, props }: ComponentMarkdownContext,\n fallbackTitle: string\n): string | null =>\n lossy\n ? null\n : labeled(\n textProp(props.title) || fallbackTitle,\n textProp(props.description),\n children\n );\n\nconst accordionItem: ComponentMarkdown = (context) => disclosure(context, \"\");\n\nconst expandable: ComponentMarkdown = (context) =>\n disclosure(context, \"Show more\");\n\n/** `Frame` is its slot, with the hint above and the caption below as text. */\nconst frame: ComponentMarkdown = ({ children, props }) =>\n [textProp(props.hint), children, textProp(props.caption)]\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n/** A layout wrapper whose body is the whole of its meaning. */\nconst body: ComponentMarkdown = ({ children }) => children;\n\n/** `Panel` is a titled aside: its title over its body. */\nconst panel: ComponentMarkdown = ({ children, props }) =>\n labeled(textProp(props.title), children);\n\n/**\n * `Tile` is a card with a preview, so it takes {@link card}'s shape: the\n * title as the link, then the description and the slot.\n */\nconst tile: ComponentMarkdown = ({ children, lossy, props }) => {\n if (lossy) {\n return null;\n }\n const title = textProp(props.title);\n const href = isString(props.href) ? props.href.trim() : \"\";\n const label = title || href;\n const head =\n href === \"\"\n ? labeled(label)\n : `**[${linkText(label)}](${linkDestination(href)})**`;\n const text = [head, textProp(props.description), children]\n .filter(Boolean)\n .join(\"\\n\\n\");\n return text === \"\" ? null : text;\n};\n\n/**\n * `Update` is one changelog entry: its label (or title) as the head, linked\n * when it has its own page, then the description, tags, and notes.\n */\nconst update: ComponentMarkdown = ({ children, lossy, props }) => {\n if (lossy) {\n return null;\n }\n const label = textProp(props.label) || textProp(props.title) || \"Update\";\n const href = isString(props.href) ? props.href.trim() : \"\";\n const head =\n href === \"\"\n ? `**${label}**`\n : `**[${linkText(label)}](${linkDestination(href)})**`;\n const tags = (Array.isArray(props.tags) ? props.tags : [props.tags])\n .map(textProp)\n .filter(Boolean);\n return [\n head,\n textProp(props.description),\n tags.length > 0 ? `Tags: ${tags.join(\", \")}` : \"\",\n children,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n};\n\n/**\n * `Prompt` is a prompt to copy: its description as the label, and the prompt\n * itself quoted, the way a {@link callout} quotes its body.\n */\nconst prompt: ComponentMarkdown = ({ children, props }) => {\n const quoted = children\n .split(\"\\n\")\n .map((line) => (line.trim() === \"\" ? \">\" : `> ${line}`))\n .join(\"\\n\");\n return labeled(\n textProp(props.description) || \"Prompt\",\n children ? quoted : \"\"\n );\n};\n\n/**\n * `GithubInfo` is a card for one repository, so it becomes a link to it. The\n * site-wide repo the component falls back to isn't in reach here, so a card\n * without `owner` and `repo` declines.\n */\nconst githubInfo: ComponentMarkdown = ({ lossy, props }) => {\n const owner = textProp(props.owner);\n const repo = textProp(props.repo);\n if (lossy || owner === \"\" || repo === \"\") {\n return null;\n }\n const host = (textProp(props.host) || \"https://github.com\").replace(\n /\\/+$/u,\n \"\"\n );\n return `[${linkText(`${owner}/${repo}`)}](${linkDestination(`${host}/${owner}/${repo}`)})`;\n};\n\n/** `CodeBlock` is a fenced block, its title kept in the fence's meta. */\nconst codeBlock: ComponentMarkdown = ({ lossy, props }) => {\n if (lossy || !isString(props.code)) {\n return null;\n }\n const lang = textProp(props.lang) || \"txt\";\n const title = textProp(props.title);\n return fencedBlock(\n title === \"\" ? lang : `${lang} title=${JSON.stringify(title)}`,\n props.code\n );\n};\n\n/**\n * `Diff` from an inline patch is that patch, fenced as `diff`; from `old` and\n * `new` strings, both sides fenced in turn. A diff read from files (`src`,\n * `before`/`after`) needs the file system, so it declines.\n */\nconst diff: ComponentMarkdown = ({ lossy, props }) => {\n if (lossy) {\n return null;\n }\n if (isString(props.patch)) {\n return fencedBlock(\"diff\", props.patch);\n }\n if (isString(props.old) && isString(props.new)) {\n const lang = textProp(props.lang);\n return [\n labeled(\"Before\", fencedBlock(lang, props.old)),\n labeled(\"After\", fencedBlock(lang, props.new)),\n ].join(\"\\n\\n\");\n }\n return null;\n};\n\n/** `Math` is its TeX source, as a display block or inline span. */\nconst math: ComponentMarkdown = ({ lossy, props }) => {\n if (lossy || !isString(props.code)) {\n return null;\n }\n return props.display === true ? `$$\\n${props.code}\\n$$` : `$${props.code}$`;\n};\n\n/** An `Icon` is decoration; one with an accessible label keeps the label. */\nconst icon: ComponentMarkdown = ({ props }) => textProp(props.label);\n\n/** A `Badge` is its text. */\nconst badge: ComponentMarkdown = ({ children }) => children;\n\n/**\n * A `Tooltip` is its trigger text followed by the tip, which is otherwise\n * only on hover: `term (tip)`, with the headline leading the tip.\n */\nconst tooltip: ComponentMarkdown = ({ children, lossy, props }) => {\n const tip = [textProp(props.headline), textProp(props.tip)]\n .filter(Boolean)\n .join(\": \");\n if (lossy || tip === \"\") {\n return null;\n }\n return children ? `${children} (${tip})` : tip;\n};\n\n/** Indent a list block's lines under its parent item. */\nconst nested = (block: string): string =>\n block\n .split(\"\\n\")\n .map((line) => (line === \"\" ? line : ` ${line}`))\n .join(\"\\n\");\n\n/**\n * `Tree` is the nested list it draws: each folder an item with a trailing\n * slash and its entries indented under it, each file an item.\n */\nconst treeList: ComponentMarkdown = ({ childBlocks }) =>\n childBlocks()\n .map((block) => block.markdown)\n .join(\"\\n\");\n\nconst treeFolder: ComponentMarkdown = ({ childBlocks, lossy, props }) => {\n const name = textProp(props.name);\n if (lossy || name === \"\") {\n return null;\n }\n const entries = childBlocks()\n .map((block) => nested(block.markdown))\n .join(\"\\n\");\n return entries === \"\" ? `- ${name}/` : `- ${name}/\\n${entries}`;\n};\n\nconst treeFile: ComponentMarkdown = ({ lossy, props }) => {\n const name = textProp(props.name);\n return lossy || name === \"\" ? null : `- ${name}`;\n};\n\n/**\n * A `Color.Item` is its name and value — both values when the light and dark\n * themes differ — and a `Color.Row` its title over its items.\n */\nconst colorItem: ComponentMarkdown = ({ lossy, props }) => {\n const name = textProp(props.name);\n const { value } = props;\n if (lossy || name === \"\") {\n return null;\n }\n if (isString(value)) {\n return `- **${name}**: ${inlineCode(value)}`;\n }\n if (!isValueMap(value)) {\n return null;\n }\n const light = textProp(value.light);\n const dark = textProp(value.dark);\n if (light === \"\" && dark === \"\") {\n return null;\n }\n const shown =\n light && dark && light !== dark\n ? `${inlineCode(light)} (light), ${inlineCode(dark)} (dark)`\n : inlineCode(light || dark);\n return `- **${name}**: ${shown}`;\n};\n\nconst colorRow: ComponentMarkdown = ({ childBlocks, props }) =>\n labeled(\n textProp(props.title),\n childBlocks()\n .map((block) => block.markdown)\n .join(\"\\n\")\n );\n\n/**\n * The built-in serializer registry, keyed by JSX name. `Step` and `Tab` are\n * intentionally absent: they only carry meaning inside their containers,\n * which extract them via `childComponents`; a stray one stays verbatim.\n * `AutoTypeTable` is absent too: its table comes from type-checking a source\n * file, which a serializer can't do synchronously, so it stays as JSX.\n */\nconst SERIALIZERS = {\n Accordion: cardGroup,\n AccordionItem: accordionItem,\n Badge: badge,\n Callout: callout,\n Card: card,\n CardGroup: cardGroup,\n CodeBlock: codeBlock,\n CodeGroup: cardGroup,\n Color: cardGroup,\n \"Color.Item\": colorItem,\n \"Color.Row\": colorRow,\n Column: body,\n Columns: cardGroup,\n Diff: diff,\n Expandable: expandable,\n FileTree: body,\n Frame: frame,\n GithubInfo: githubInfo,\n Icon: icon,\n Math: math,\n Panel: panel,\n Prompt: prompt,\n Steps: steps,\n Tabs: tabs,\n Tile: tile,\n Tooltip: tooltip,\n Tree: treeList,\n \"Tree.File\": treeFile,\n \"Tree.Folder\": treeFolder,\n TypeTable: typeTable,\n Update: update,\n YouTube: youtube,\n} satisfies Record<string, ComponentMarkdown>;\n\n/**\n * The built-ins that sit inside a line of prose, and so are downleveled as\n * text elements too: each renders to a single line.\n */\nconst INLINE_COMPONENTS = new Set([\"Badge\", \"Icon\", \"Math\", \"Tooltip\"]);\n\nconst escapeRegExp = (value: string): string =>\n value.replaceAll(/[$()*+.?[\\\\\\]^{|}]/gu, String.raw`\\$&`);\n\n// Skip the MDX parse when no serializable component name appears at all —\n// the common case for prose pages, and it keeps plain-Markdown sources (where\n// `<`/`{` may be literal text MDX would reject) out of the parser entirely.\nconst componentHint = (registry: Record<string, ComponentMarkdown>): RegExp =>\n new RegExp(\n `<(?:${Object.keys(registry).map(escapeRegExp).join(\"|\")})[\\\\s/>]`,\n \"u\"\n );\n\nconst BUILT_IN_HINT = componentHint(SERIALIZERS);\n\n/** One downlevel pass's inputs: the source, registry, and page metadata. */\n/** What a downlevel walk needs: the serializers, the page's front matter, and the source its nodes were parsed from. */\nexport interface DownlevelWalk {\n frontmatter: Record<string, EvaluatedValue> | undefined;\n registry: Record<string, ComponentMarkdown>;\n source: string;\n}\ntype Walk = DownlevelWalk;\n\n/** The serializer registry for a site: built-ins under a user's `agents.markdownComponents`. */\nexport const componentRegistry = (\n components?: Record<string, ComponentMarkdown>\n): Record<string, ComponentMarkdown> =>\n components && Object.keys(components).length > 0\n ? { ...SERIALIZERS, ...components }\n : SERIALIZERS;\n\n/**\n * A source slice as Markdown: the verbatim `[start, end)` range with any\n * serializable component under `nodes` downleveled in place, dedented and\n * trimmed. Mutually recursive with {@link collectSplices} (the nodes may hold\n * further serializable components), hence the forward reference.\n */\nconst renderSlice = (\n walk: Walk,\n start: number,\n end: number,\n nodes: MdastNode[]\n): string => {\n const splices: Splice[] = [];\n // oxlint-disable-next-line no-use-before-define\n collectSplices(walk, nodes, splices);\n const spliced = applySplices(\n walk.source.slice(start, end),\n splices.map((splice) => ({\n ...splice,\n end: splice.end - start,\n start: splice.start - start,\n }))\n );\n return dedent(spliced, indentAt(walk.source, start)).trim();\n};\n\n/** The element's body as Markdown: the slice covering all of its children. */\nconst renderChildren = (walk: Walk, node: MdastNode): string => {\n const children = (node.children ?? []).filter(hasOffsets);\n const [first] = children;\n if (!first) {\n return \"\";\n }\n const start = first.position.start.offset;\n return renderSlice(\n walk,\n start,\n children.at(-1)?.position.end.offset ?? start,\n children\n );\n};\n\n/**\n * One direct child as a block of Markdown: a registered component's own\n * rendering, else — prose, an unknown component, or one that declined — its\n * source slice, the same choice {@link collectSplices} makes at the top level.\n */\nconst renderBlock = (walk: Walk, node: Positioned): string => {\n const serializer =\n isJsxElement(node) && node.name ? walk.registry[node.name] : undefined;\n const text = serializer\n ? // oxlint-disable-next-line no-use-before-define\n serializeElement(serializer, walk, node)\n : null;\n return (\n text ??\n renderSlice(\n walk,\n node.position.start.offset,\n node.position.end.offset,\n node.children ?? []\n )\n );\n};\n\n/** Serialize one component usage, or `null` to keep its JSX verbatim. */\nconst serializeElement = (\n serializer: ComponentMarkdown,\n walk: Walk,\n node: MdastNode\n): string | null =>\n serializer({\n ...readProps(node, walk.frontmatter),\n childBlocks: () =>\n (node.children ?? []).filter(hasOffsets).map((child) => ({\n markdown: renderBlock(walk, child),\n name: isJsxElement(child) ? child.name : undefined,\n })),\n childComponents: (name) =>\n (node.children ?? [])\n .filter((child) => isJsxElement(child) && child.name === name)\n .map((child) => ({\n ...readProps(child, walk.frontmatter),\n children: renderChildren(walk, child),\n })),\n children: renderChildren(walk, node),\n frontmatter: walk.frontmatter ?? {},\n });\n\n/**\n * Walk the tree collecting replacements. A replaced element's subtree is\n * owned by its serializer (which downlevels its own children), so the walk\n * doesn't descend into it; when a serializer declines, the walk continues\n * inside so nested serializable components still convert.\n */\n/**\n * Downlevel one parsed component to the Markdown its serializer emits, or\n * `null` when the node isn't a component, has no serializer, or its\n * serializer declines. `walk.source` must be the text `node` was parsed from.\n */\nexport const downlevelComponentNode = (\n node: MdastNode,\n walk: DownlevelWalk\n): string | null => {\n const block =\n node.type === \"mdxJsxFlowElement\" ||\n (node.type === \"mdxJsxTextElement\" &&\n INLINE_COMPONENTS.has(node.name ?? \"\"));\n const serializer = block && node.name ? walk.registry[node.name] : undefined;\n return serializer && hasOffsets(node)\n ? serializeElement(serializer, walk, node)\n : null;\n};\n\nconst collectSplices = (\n walk: Walk,\n nodes: MdastNode[],\n out: Splice[]\n): void => {\n for (const node of nodes) {\n const text = hasOffsets(node) ? downlevelComponentNode(node, walk) : null;\n if (text !== null && hasOffsets(node)) {\n out.push({\n end: node.position.end.offset,\n start: node.position.start.offset,\n text,\n });\n continue;\n }\n collectSplices(walk, node.children ?? [], out);\n }\n};\n\n/**\n * Downlevel supported components in an MDX source to plain Markdown. Sources\n * with no supported components — and sources Satteri can't parse as MDX, e.g.\n * plain `.md` with literal `<`/`{` — are returned byte-identical.\n *\n * `components` adds user serializers from `agents.markdownComponents`, layered\n * over the built-ins: a same-name entry replaces the built-in serializer, and\n * one that always returns `null` effectively opts that component out.\n *\n * `frontmatter` is the page's parsed front-matter data. It is put in scope\n * when evaluating attribute expressions — so `prop={frontmatter.status}`\n * resolves the way it does when Astro renders the page — and handed to\n * serializers on their context.\n */\nexport const downlevelComponents = (\n source: string,\n components?: Record<string, ComponentMarkdown>,\n frontmatter?: Record<string, EvaluatedValue>\n): string => {\n const registry = componentRegistry(components);\n const hint =\n registry === SERIALIZERS ? BUILT_IN_HINT : componentHint(registry);\n if (!hint.test(source)) {\n return source;\n }\n let tree: MdastNode;\n try {\n // SAFETY: MdastNode is a structural subset of Satteri's mdast output —\n // every node carries `type`, and the walk reads only optional fields.\n tree = mdxToMdast(source, { features: MDX_FEATURES }) as MdastNode;\n } catch {\n return source;\n }\n const splices: Splice[] = [];\n collectSplices(\n { frontmatter, registry, source },\n tree.children ?? [],\n splices\n );\n return splices.length > 0 ? applySplices(source, splices) : source;\n};\n",
|
|
138
|
+
"/**\n * Helpers for the `<YouTube>` content component. Kept in a sibling `.ts` (like\n * `diff.ts`/`github-info.ts`) so the id parsing and embed-URL building are pure,\n * unit-testable functions — the `.astro` file stays a thin presentational shell.\n */\n\n// A YouTube video id is 11 characters of [A-Za-z0-9_-].\nconst BARE_ID = /^[\\w-]{11}$/u;\n\n// Pull the id out of any common YouTube URL: youtu.be/<id>, watch?v=<id>,\n// /embed/<id>, /shorts/<id>, /live/<id>.\nconst URL_ID =\n /(?:youtu\\.be\\/|\\/embed\\/|\\/shorts\\/|\\/live\\/|[?&]v=)(?<id>[\\w-]{11})/u;\n\n/**\n * Resolve a YouTube video id from either a bare id or a full URL. Returns `null`\n * when nothing that looks like an id can be found, so the component can render\n * nothing rather than a broken embed.\n */\nexport const parseYouTubeId = (input: string): string | null => {\n const value = input.trim();\n if (!value) {\n return null;\n }\n if (BARE_ID.test(value)) {\n return value;\n }\n return URL_ID.exec(value)?.groups?.id ?? null;\n};\n\n/**\n * Build a privacy-enhanced (`youtube-nocookie.com`) embed URL, optionally\n * starting at `start` seconds.\n */\nexport const youtubeEmbedUrl = (\n id: string,\n options: { start?: number } = {}\n): string => {\n const base = `https://www.youtube-nocookie.com/embed/${id}`;\n const { start } = options;\n if (start && start > 0) {\n const params = new URLSearchParams({ start: String(Math.floor(start)) });\n return `${base}?${params.toString()}`;\n }\n return base;\n};\n",
|
|
139
|
+
"import type { Features } from \"satteri\";\n\n/**\n * Sätteri's feature set for plain `.md` pages. Shared by the renderer and the\n * search extractor so the index reads the same grammar the page renders.\n */\nexport const MARKDOWN_FEATURES = {\n subscript: true,\n superscript: true,\n} satisfies Features;\n\n/**\n * The `.mdx` feature set: Markdown's plus `:::` directives (→ `<Callout>`) and\n * block-only math — `singleDollarTextMath: false` keeps a bare `$` (currency,\n * shell, code) as literal text and only parses `$$…$$`.\n */\nexport const MDX_FEATURES = {\n ...MARKDOWN_FEATURES,\n directive: true,\n math: { singleDollarTextMath: false },\n} satisfies Features;\n",
|
|
140
|
+
"// html-escaper's five-entity table is XML-safe: `'` becomes the numeric\n// `'` reference rather than `'`, which XML accepts equally.\nimport { escape as escapeXml } from \"html-escaper\";\n\nimport { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { siteRoot } from \"../core/site-url.ts\";\nimport type { PageRecord } from \"../core/types.ts\";\n\n/** A single feed entry derived from a content page. */\nexport interface RssItem {\n title: string;\n /** Absolute item URL. */\n link: string;\n description?: string;\n /** Publish date, when the page declares one. */\n date?: Date;\n}\n\n/** A resolved RSS feed for one content type. */\nexport interface RssFeed {\n /** Content type the feed covers, e.g. `blog`. */\n type: string;\n /** Feed URL path, e.g. `/blog/rss.xml`. */\n path: string;\n /** Channel title, e.g. `Blume — Blog`. */\n title: string;\n /** Absolute site link. */\n link: string;\n description?: string;\n items: RssItem[];\n}\n\nconst capitalize = (value: string): string =>\n value.charAt(0).toUpperCase() + value.slice(1);\n\n/** Publish date for a page: top-level `date`, else `changelog.date`. */\nconst pageDate = (page: PageRecord): Date | undefined => {\n const raw = page.meta.date ?? page.meta.changelog?.date;\n if (!raw) {\n return;\n }\n const date = new Date(raw);\n return Number.isNaN(date.getTime()) ? undefined : date;\n};\n\n/**\n * Build an RSS feed per configured content type that has publishable pages.\n * Returns an empty list when RSS is disabled or no `deployment.site` is set —\n * absolute URLs are required for a valid feed, mirroring `buildSitemap`.\n */\nexport const buildRssFeeds = (project: BlumeProject): RssFeed[] => {\n const { config } = project;\n const { rss } = config.seo;\n const { site } = config.deployment.options;\n if (!(rss.enabled && site)) {\n return [];\n }\n const base = siteRoot(site);\n // Routes carry `basePath`; a `deployment.base` subdirectory is layered on top.\n // The feed's own `link`/self URL points at the docs root under that base, while\n // `path` stays base-less (it's also the on-disk output location).\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const rootLink = `${base}${deployBase}`;\n\n const feeds: RssFeed[] = [];\n for (const type of rss.types) {\n const pages = project.graph.pages.filter(\n (page) =>\n page.contentType === type &&\n !(page.meta.draft || page.meta.sidebar.hidden)\n );\n if (pages.length === 0) {\n continue;\n }\n\n const items: RssItem[] = pages\n .map((page) => ({\n date: pageDate(page),\n description: page.description,\n // Encode like the sitemap does: a route with spaces or non-ASCII\n // must still yield a valid <link>/<guid> URL after XML decoding.\n link: encodeURI(`${base}${withBasePath(deployBase, page.route)}`),\n title: page.title,\n }))\n .toSorted((a, b) => (b.date?.getTime() ?? 0) - (a.date?.getTime() ?? 0))\n .slice(0, rss.limit);\n\n feeds.push({\n description: config.description,\n items,\n link: rootLink,\n path: `/${type}/rss.xml`,\n title: `${config.title} — ${capitalize(type)}`,\n type,\n });\n }\n return feeds;\n};\n\nconst renderItem = (item: RssItem): string => {\n const parts = [\n ` <title>${escapeXml(item.title)}</title>`,\n ` <link>${escapeXml(item.link)}</link>`,\n ` <guid isPermaLink=\"true\">${escapeXml(item.link)}</guid>`,\n ];\n if (item.description) {\n parts.push(` <description>${escapeXml(item.description)}</description>`);\n }\n if (item.date) {\n parts.push(` <pubDate>${item.date.toUTCString()}</pubDate>`);\n }\n return ` <item>\\n${parts.join(\"\\n\")}\\n </item>`;\n};\n\n/** Serialize a resolved feed into an RSS 2.0 XML document. */\nexport const renderRssFeed = (feed: RssFeed): string => {\n const feedSelfHref = `${feed.link}${feed.path}`;\n const channel = [\n ` <title>${escapeXml(feed.title)}</title>`,\n ` <link>${escapeXml(feed.link)}</link>`,\n ` <description>${escapeXml(feed.description ?? feed.title)}</description>`,\n ` <atom:link href=\"${escapeXml(feedSelfHref)}\" rel=\"self\" type=\"application/rss+xml\" />`,\n ];\n const items = feed.items.map(renderItem).join(\"\\n\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n<channel>\n${channel.join(\"\\n\")}\n${items}\n</channel>\n</rss>\n`;\n};\n",
|
|
141
|
+
"import { basename } from \"pathe\";\n\nimport { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport { nextFenceState } from \"../core/code-fences.ts\";\nimport type { FenceState } from \"../core/code-fences.ts\";\nimport {\n buildFileRouteIndex,\n isIndexFileName,\n resolveRelativeHref,\n routeOfLinkedFile,\n} from \"../core/links.ts\";\nimport type { RelativeLinkBase } from \"../core/links.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { extractLinks } from \"../core/sources/normalize.ts\";\n\n/**\n * Relative page links on the agent surfaces — the `.md`/`.mdx` mirrors,\n * llms-full.txt, MCP `get_page` and `resources/read`. An agent resolves\n * `[Install](./install)` against the URL it fetched (`/guides.md`), so the\n * link lands on `/install`; the rendered page rewrites it to the route it\n * means (`markdown/relative-links.ts`), and the Markdown an agent reads gets\n * the same rewrite from the same resolver (`resolveRelativeHref`), so both\n * point at one page. Inline links and reference definitions are rewritten;\n * fenced and inline code, images, and anything not a relative page link are\n * left as written.\n */\n\n/** The page a Markdown text was written for. */\nexport interface LinkedPage {\n route: string;\n sourcePath?: string;\n}\n\n/** Rewrite a page's relative page links to the routes they mean. */\nexport type RelativeLinkRewriter = (text: string, page: LinkedPage) => string;\n\n/** A reference definition's target: `[label]: ./install` or `<./install>`. */\nconst DEFINITION =\n /^(?<lead> {0,3}\\[(?:[^\\]\\\\]|\\\\.)+\\]:[\\t ]*)(?:<(?<angled>[^>]*)>|(?<bare>\\S+))/u;\n\n/**\n * Whether a text could hold a relative page link at all: an inline link, a\n * reference definition, or a component `href` whose target isn't a URL with\n * a scheme, a root path, or a fragment. Most pages hold none, and those skip\n * the link parse and the line-by-line fence scan entirely.\n */\nconst MAYBE_RELATIVE =\n /\\]\\([\\t ]*<?(?![a-z][\\d+.a-z-]*:|\\/|#)|^ {0,3}\\[[^\\]\\n]+\\]:[\\t ]*<?(?![a-z][\\d+.a-z-]*:|\\/|#)|\\shref=[\"'](?![a-z][\\d+.a-z-]*:|\\/|#)/imu;\n\ninterface Splice {\n column: number;\n length: number;\n text: string;\n}\n\n/** Apply same-line splices, right to left so earlier columns stay valid. */\nconst spliceLine = (line: string, splices: readonly Splice[]): string => {\n let out = line;\n for (const splice of splices.toSorted((a, b) => b.column - a.column)) {\n out =\n out.slice(0, splice.column) +\n splice.text +\n out.slice(splice.column + splice.length);\n }\n return out;\n};\n\n/** One line's reference-definition splice, when it defines a routed target. */\nconst definitionSplice = (\n line: string,\n routed: (target: string) => string | undefined\n): Splice | undefined => {\n const groups = DEFINITION.exec(line)?.groups;\n const lead = groups?.lead;\n const target = groups?.angled ?? groups?.bare;\n const route = target === undefined ? undefined : routed(target);\n if (lead === undefined || target === undefined || route === undefined) {\n return undefined;\n }\n // An angle-bracketed target starts one past its `<`.\n const angled = groups?.angled === undefined ? 0 : 1;\n return { column: lead.length + angled, length: target.length, text: route };\n};\n\n/** Every routed splice in `text`, by 0-based line: links, then definitions. */\nconst collectSplices = (\n text: string,\n lines: readonly string[],\n routed: (target: string) => string | undefined\n): Map<number, Splice[]> => {\n const splices = new Map<number, Splice[]>();\n const add = (index: number, splice: Splice): void => {\n splices.set(index, [...(splices.get(index) ?? []), splice]);\n };\n for (const link of extractLinks(text)) {\n const route = link.image ? undefined : routed(link.target);\n if (route !== undefined) {\n add(link.line - 1, {\n column: link.column - 1,\n length: link.target.length,\n text: route,\n });\n }\n }\n let fence: FenceState = null;\n for (const [index, line] of lines.entries()) {\n const next = nextFenceState(line, fence);\n const inFence = fence !== null || next !== null;\n fence = next;\n const splice = inFence ? undefined : definitionSplice(line, routed);\n if (splice !== undefined) {\n add(index, splice);\n }\n }\n return splices;\n};\n\n/**\n * Build the rewriter for a project: the file → route lookup a `.md`/`.mdx`\n * link resolves through is built once. A file shared by every locale\n * publishes once per locale, and the default locale's route stands for it;\n * fallback copies render another locale's file, so they never stand for one.\n */\nexport const relativeLinkRewriter = (\n project: BlumeProject\n): RelativeLinkRewriter => {\n const { deployment, i18n } = project.config;\n const deployBase = normalizeBasePath(deployment.options.base);\n const localeTokens = i18n\n ? [\"$\", ...i18n.locales.map((locale) => locale.code)]\n : [];\n const fileRoutes = buildFileRouteIndex(project.graph.pages, i18n ?? null);\n const navPathBySource = new Map(\n project.graph.pages.map((graphPage) => [\n graphPage.sourcePath,\n graphPage.navPath,\n ])\n );\n const routes = new Set(project.manifest.routes.map((route) => route.path));\n\n return (text, page) => {\n const { sourcePath } = page;\n if (!sourcePath || !MAYBE_RELATIVE.test(text)) {\n return text;\n }\n const from: RelativeLinkBase = {\n isIndex: isIndexFileName(basename(sourcePath), localeTokens),\n route: page.route,\n };\n const navPath = navPathBySource.get(sourcePath) ?? basename(sourcePath);\n const resolveFile = (path: string): string | undefined =>\n routeOfLinkedFile(fileRoutes, { navPath, sourcePath }, path);\n const routed = (target: string): string | undefined => {\n const route = resolveRelativeHref(target, from, resolveFile, (path) =>\n routes.has(path)\n );\n return route === undefined ? undefined : withBasePath(deployBase, route);\n };\n\n const lines = text.split(\"\\n\");\n const splices = collectSplices(text, lines, routed);\n\n return lines\n .map((line, index) => {\n const lineSplices = splices.get(index);\n return lineSplices ? spliceLine(line, lineSplices) : line;\n })\n .join(\"\\n\");\n };\n};\n",
|
|
142
|
+
"import type { Document, OperationObject } from \"@scalar/openapi-types/3.1\";\n\nimport type { AsyncApiAction, AsyncApiDocument } from \"./asyncapi.ts\";\n// Type-only, so the import can't cycle at runtime (graphql.ts imports the\n// collector from here).\nimport type { GraphqlDocument, GraphqlMember } from \"./graphql.ts\";\nimport type { ReferenceKind } from \"./references.ts\";\nimport { slugify } from \"./references.ts\";\n\n// The slug rules live with the reference resolver so operation routes and\n// reference-source tokens can never drift apart; re-exported for existing\n// importers.\nexport { slugify } from \"./references.ts\";\n\n/**\n * Blume's own API reference model, shared by both spec kinds. OpenAPI specs\n * are parsed and upgraded to 3.1, AsyncAPI specs normalized to 3.x (see\n * `parse.ts`), with internal `$ref`s left intact — the document stays\n * JSON-serializable (a fully dereferenced graph can be circular), and the schema\n * components resolve refs against `document.components.schemas` at render time.\n * Each operation is flattened into an {@link ApiOperationRef} with a real,\n * per-operation route so it becomes a first-class Blume page.\n */\n\n/** A normalized OpenAPI 3.1 document, internal `$ref`s intact. */\nexport type ApiDocument = Document;\n\n/** The HTTP methods an OpenAPI path item may declare, in spec order. */\nexport const HTTP_METHODS = [\n \"get\",\n \"put\",\n \"post\",\n \"delete\",\n \"options\",\n \"head\",\n \"patch\",\n \"trace\",\n] as const;\n\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n\n/** Group used for operations that declare no tag. */\nconst UNTAGGED = \"Operations\";\n\n/** A lower-case letter or digit followed by a capital: `addPet`, `v2List`. */\nconst CASE_BOUNDARY = /(?<before>[\\p{Ll}\\p{N}])(?<capital>\\p{Lu})/gu;\n/** The last capital of an acronym before a capitalized word: `HTTPResponse`. */\nconst ACRONYM_BOUNDARY = /(?<acronym>\\p{Lu})(?<word>\\p{Lu}\\p{Ll})/gu;\n\n/**\n * Hyphenate an identifier's word boundaries before slugifying, so a camelCase\n * `operationId` keeps its words in the URL (`getHTTPResponse` ->\n * `get-http-response`) instead of collapsing once `slugify` lowercases it.\n * OpenAPI generators reuse operation ids as SDK method names, so camelCase is\n * the norm there; GraphQL field and type names and AsyncAPI operation ids go\n * through the same rule so every spec kind derives routes alike. An id that\n * is already kebab-case has no boundaries to split and passes through as is.\n */\nconst splitIdentifier = (identifier: string): string =>\n identifier\n .replace(CASE_BOUNDARY, \"$<before>-$<capital>\")\n .replace(ACRONYM_BOUNDARY, \"$<acronym>-$<word>\");\n\n/** A stable, URL-safe key for an operation: its `operationId`, else method+path. */\nexport const operationKey = (\n method: string,\n path: string,\n operationId?: string\n): string => {\n const fromId = operationId ? slugify(splitIdentifier(operationId)) : \"\";\n return fromId || slugify(`${method}-${path}`);\n};\n\n/** One operation, flattened out of its document and mapped to a route. */\nexport interface ApiOperationRef {\n /** Stable key, unique within a spec; matches the MDX `<Operation id>`. */\n key: string;\n /**\n * HTTP method (OpenAPI), `send`/`receive` action (AsyncAPI), or the member\n * kind — a root-field operation kind or a named-type kind (GraphQL).\n */\n method: HttpMethod | AsyncApiAction | GraphqlMember;\n /**\n * Templated path, e.g. `/pets/{id}` — the channel address (AsyncAPI), or\n * the root field / type name (GraphQL).\n */\n path: string;\n /** Full site route for this operation's page, e.g. `/reference/pet/add-pet`. */\n route: string;\n /** Display tag name (first tag; `Operations` or the channel address when untagged). */\n tag: string;\n tagSlug: string;\n summary: string;\n description: string;\n /** The `operationId` (OpenAPI) or the `operations` map key (AsyncAPI). */\n operationId?: string;\n deprecated: boolean;\n /** The channel the operation acts on (AsyncAPI only). */\n channelId?: string;\n}\n\n/** A tag/section, in first-seen order. */\nexport interface ApiTagRef {\n slug: string;\n name: string;\n description: string;\n}\n\n/** Everything the runtime needs for one spec, serialized into `blume:openapi`. */\nexport interface ApiSpecData {\n /** Which front-end parsed the spec (and which components render it). */\n kind: ReferenceKind;\n /** Unique token used as the `<Operation source>` and the data-module key. */\n slug: string;\n /** Base route the spec's operations hang off, e.g. `/reference`. */\n route: string;\n label: string;\n title: string;\n version: string;\n description: string;\n document: ApiDocument | AsyncApiDocument | GraphqlDocument;\n /**\n * URL of the live GraphQL endpoint the playground and code samples target\n * (GraphQL only; OpenAPI documents carry their servers in the document).\n */\n endpoint?: string;\n /** Operations keyed by {@link ApiOperationRef.key}. */\n operations: Record<string, ApiOperationRef>;\n tags: ApiTagRef[];\n /** Code-sample languages to render per operation. */\n codeSamples: string[];\n /** Whether nested schema rows start expanded. */\n expandSchemas: boolean;\n /**\n * The \"Try it\" playground: whether operation pages render it, and the\n * resolved proxy the Send button targets — `false` for direct requests, a\n * URL string otherwise (the built-in `/_api-proxy` route already carries\n * the site `basePath`).\n */\n playground: { enabled: boolean; proxy: string | false };\n}\n\n/** The generated `blume:openapi` module: specs keyed by {@link ApiSpecData.slug}. */\nexport type OpenApiData = Record<string, ApiSpecData>;\n\n/**\n * The spec a `<Operation source>` / `<ApiOverview source>` names, or nothing.\n * `blume:openapi` crosses a JSON boundary as a plain object, so a lookup must\n * be an own-property one: `source=\"toString\"` would otherwise resolve to the\n * inherited function, which is truthy and carries no `operations`, and every\n * consumer would throw where it means to decline. Shared by the components\n * and the agent-surface serializers so they miss the same way.\n */\nexport const specOf = (\n specs: OpenApiData,\n source: string\n): ApiSpecData | undefined =>\n Object.hasOwn(specs, source) ? specs[source] : undefined;\n\n/** The operation an `<Operation id>` names within its spec, or nothing. */\nexport const operationOf = (\n spec: ApiSpecData,\n id: string\n): ApiOperationRef | undefined =>\n Object.hasOwn(spec.operations, id) ? spec.operations[id] : undefined;\n\n/** The addresses an API overview lists, and what to call them. */\nexport interface SpecAddresses {\n /** `Base URL` (OpenAPI), `Servers` (AsyncAPI) or `Endpoint` (GraphQL). */\n label: string;\n addresses: string[];\n}\n\n/**\n * Where the API lives, flattened into one list for the overview page. OpenAPI\n * declares `servers` as an array of URLs; AsyncAPI as a named map of\n * host/protocol/pathname; a GraphQL schema names no server, so its configured\n * live endpoint stands in.\n */\nexport const specAddresses = (spec: ApiSpecData): SpecAddresses => {\n const addresses: string[] = [];\n if (spec.kind === \"graphql\") {\n if (spec.endpoint) {\n addresses.push(spec.endpoint);\n }\n return { addresses, label: \"Endpoint\" };\n }\n if (spec.kind === \"asyncapi\") {\n // SAFETY: an `asyncapi` spec's document is the AsyncAPI shape (`parse.ts`\n // routes each kind to its own parser).\n const servers = (spec.document as AsyncApiDocument).servers ?? {};\n for (const server of Object.values(servers)) {\n if (server?.host) {\n addresses.push(\n `${server.protocol ? `${server.protocol}://` : \"\"}${server.host}${server.pathname ?? \"\"}`\n );\n }\n }\n return { addresses, label: \"Servers\" };\n }\n // Hand-written specs sometimes declare `servers` as a bare object; degrade\n // to no addresses instead of throwing mid-build.\n // SAFETY: the remaining kind is OpenAPI, whose document declares `servers`\n // as an array of server objects; the array check below guards a spec that\n // wrote something else there.\n const declared = (spec.document as { servers?: { url?: string }[] }).servers;\n for (const server of Array.isArray(declared) ? declared : []) {\n if (server.url) {\n addresses.push(server.url);\n }\n }\n return { addresses, label: \"Base URL\" };\n};\n\n// The runtime object check stands guard because the document was parsed from\n// arbitrary YAML/JSON: a spec can put a scalar where the type promises an\n// operation object.\nconst isOperation = (\n value: OperationObject | undefined\n): value is OperationObject => typeof value === \"object\" && value !== null;\n\n/** A declared tag whose `name` really is a string at runtime, type aside. */\nconst hasTagName = (tag: SpecTag): tag is SpecTag =>\n typeof tag.name === \"string\";\n\n/**\n * Assign each distinct tag name a unique slug. `slugify` can collapse\n * different names onto one value — any two punctuation-only tags (`!!!`,\n * `???`) both fall through to the `operations` fallback — and a shared slug\n * silently merges the tags' routes, sidebar groups, and overview sections.\n * Collisions gain `-2`, `-3`, … in first-seen order. Shared with the AsyncAPI\n * extractor (`asyncapi.ts`), whose untagged fallback groups are channel\n * addresses.\n */\nexport const tagSlugger = (): ((name: string) => string) => {\n const assigned = new Map<string, string>();\n const taken = new Set<string>();\n return (name) => {\n const existing = assigned.get(name);\n if (existing) {\n return existing;\n }\n const base = slugify(name) || \"operations\";\n let slug = base;\n for (let suffix = 2; taken.has(slug); suffix += 1) {\n slug = `${base}-${suffix}`;\n }\n taken.add(slug);\n assigned.set(name, slug);\n return slug;\n };\n};\n\n/** An operation before the collector assigns its unique key and route. */\ntype CollectedOperation = Omit<ApiOperationRef, \"route\" | \"tagSlug\">;\n\n/** A document's declared tag entry (`tags[n]`). */\ntype SpecTag = NonNullable<ApiDocument[\"tags\"]>[number];\n\n/** The flattened output both extractors produce. */\nexport interface CollectedOperations {\n operations: ApiOperationRef[];\n tags: ApiTagRef[];\n}\n\n/** The collector handle: feed operations in, read the flattened output out. */\nexport interface OperationCollector {\n add: (entry: CollectedOperation) => void;\n finish: () => CollectedOperations;\n}\n\n/** {@link CollectedOperations} plus anything the extractor had to skip. */\nexport interface ExtractedOperations extends CollectedOperations {\n warnings: string[];\n}\n\n/**\n * The collector behind both extractors (OpenAPI here, AsyncAPI in\n * `asyncapi.ts`): first-seen tag ordering, key de-duplication (a repeated key\n * gains its method/action as a suffix), and the shared route template — so\n * URL shape and slug rules can never drift between the two spec kinds.\n */\nexport const operationCollector = (\n baseRoute: string,\n tagMeta: ReadonlyMap<string, string>\n): OperationCollector => {\n const operations: ApiOperationRef[] = [];\n const tagOrder: string[] = [];\n const tagsSeen = new Set<string>();\n const seen = new Set<string>();\n const slugForTag = tagSlugger();\n\n const add = (entry: CollectedOperation): void => {\n const tagSlug = slugForTag(entry.tag);\n if (!tagsSeen.has(entry.tag)) {\n tagsSeen.add(entry.tag);\n tagOrder.push(entry.tag);\n }\n let { key } = entry;\n while (seen.has(key)) {\n key = `${key}-${entry.method}`;\n }\n seen.add(key);\n operations.push({\n ...entry,\n key,\n // A root-mounted reference (`route: \"/\"`) must not emit `//tag/key`.\n route: `${baseRoute === \"/\" ? \"\" : baseRoute}/${tagSlug}/${key}`,\n tagSlug,\n });\n };\n\n const finish = (): CollectedOperations => ({\n operations,\n tags: tagOrder.map((name) => ({\n description: tagMeta.get(name) ?? \"\",\n name,\n // The same slugger instance, so every tag resolves to the slug its\n // operations were routed under.\n slug: slugForTag(name),\n })),\n });\n\n return { add, finish };\n};\n\n/**\n * Flatten a 3.1 document into a route-mapped operation list and its ordered\n * tags. Operations inherit the first tag they declare; keys are de-duplicated so\n * a repeated `operationId` still yields distinct routes. `warnings` reports\n * anything skipped (a `$ref` path item), so missing operations aren't silent.\n */\nexport const extractOperations = (\n document: ApiDocument,\n baseRoute: string\n): ExtractedOperations => {\n const warnings: string[] = [];\n const tagMeta = new Map(\n (document.tags ?? [])\n .filter(hasTagName)\n .map((tag) => [tag.name, tag.description ?? \"\"])\n );\n const collector = operationCollector(baseRoute, tagMeta);\n\n for (const [path, item] of Object.entries(document.paths ?? {})) {\n // A parsed spec can carry a null path item despite the type; skip it.\n if (!item) {\n continue;\n }\n if (\"$ref\" in item) {\n warnings.push(\n `Path \"${path}\" is a $ref to a shared path item; referenced path items are not resolved, so its operations are missing from the reference. Inline the path item under \"paths\" to render it.`\n );\n continue;\n }\n for (const method of HTTP_METHODS) {\n const operation = item[method];\n if (!isOperation(operation)) {\n continue;\n }\n collector.add({\n deprecated: operation.deprecated ?? false,\n description: operation.description ?? \"\",\n key: operationKey(method, path, operation.operationId),\n method,\n operationId: operation.operationId,\n path,\n summary: operation.summary ?? \"\",\n tag: operation.tags?.[0] ?? UNTAGGED,\n });\n }\n }\n\n return { ...collector.finish(), warnings };\n};\n\n/** Resolve the operation object for a ref out of its (OpenAPI) document. */\nexport const operationObject = (\n spec: ApiSpecData,\n ref: ApiOperationRef\n): OperationObject | undefined => {\n // Only OpenAPI refs carry HTTP methods; the AsyncAPI counterpart is\n // `asyncApiOperationObject` in `asyncapi.ts`.\n const method = HTTP_METHODS.find((candidate) => candidate === ref.method);\n // SAFETY: only OpenAPI specs route their refs through this resolver\n // (AsyncAPI documents go to `asyncApiOperationObject`), so the spec's\n // document is the OpenAPI shape.\n const document = spec.document as ApiDocument;\n const item = document.paths?.[ref.path];\n const operation = method === undefined ? undefined : item?.[method];\n return isOperation(operation) ? operation : undefined;\n};\n",
|
|
143
|
+
"import type { ApiOperationRef, ApiTagRef } from \"./model.ts\";\nimport { operationCollector, operationKey } from \"./model.ts\";\n\n/**\n * Blume's own AsyncAPI model — the second front-end of the API reference\n * pipeline. Specs are normalized to AsyncAPI 3.x at parse time (see\n * `parseAsyncApiSpec` in `parse.ts`), so this module only handles one shape:\n * top-level `operations` with `action: send | receive` pointing at `channels`.\n * Internal `$ref`s are deliberately left in place, mirroring `model.ts` — the\n * components resolve them lazily, which keeps circular schemas serializable\n * and lets type labels keep their `#/components/schemas/<name>` names.\n * Browser-safe: no Node imports (the components import from here).\n */\n\n/** The two AsyncAPI 3.x operation actions, from the application's perspective. */\nexport const ASYNCAPI_ACTIONS = [\"send\", \"receive\"] as const;\n\nexport type AsyncApiAction = (typeof ASYNCAPI_ACTIONS)[number];\n\n/**\n * A value carried by a parsed spec document: JSON-compatible data whose exact\n * position in the document is not modeled (extension fields, bindings,\n * protocol-specific extras). `undefined` covers absent optional members.\n */\nexport type AsyncApiSpecValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | AsyncApiSpecValue[]\n | { [key: string]: AsyncApiSpecValue };\n\n/** A permissive view of an AsyncAPI reference object. */\nexport interface AsyncApiRefLike {\n $ref?: string;\n [key: string]: AsyncApiSpecValue;\n}\n\n/** A permissive view of an AsyncAPI 3.x channel — only the fields we render. */\nexport interface AsyncApiChannelObject {\n address?: string | null;\n title?: string;\n summary?: string;\n description?: string;\n messages?: Record<string, AsyncApiRefLike>;\n parameters?: Record<string, AsyncApiRefLike>;\n servers?: AsyncApiRefLike[];\n bindings?: Record<string, Record<string, AsyncApiSpecValue>>;\n [key: string]: AsyncApiSpecValue;\n}\n\n/** A permissive view of an AsyncAPI 3.x operation — only the fields we render. */\nexport interface AsyncApiOperationObject {\n action?: string;\n channel?: AsyncApiRefLike;\n title?: string;\n summary?: string;\n description?: string;\n deprecated?: boolean;\n tags?: { name?: string; description?: string }[];\n security?: AsyncApiRefLike[];\n messages?: AsyncApiRefLike[];\n bindings?: Record<string, Record<string, AsyncApiSpecValue>>;\n [key: string]: AsyncApiSpecValue;\n}\n\n/** A permissive view of an AsyncAPI 3.x server object. */\nexport interface AsyncApiServerObject {\n host?: string;\n protocol?: string;\n pathname?: string;\n description?: string;\n security?: AsyncApiRefLike[];\n [key: string]: AsyncApiSpecValue;\n}\n\n/** A normalized AsyncAPI 3.x document, internal `$ref`s intact. */\nexport interface AsyncApiDocument {\n asyncapi?: string;\n info?: {\n title?: string;\n version?: string;\n description?: string;\n tags?: { name?: string; description?: string }[];\n [key: string]: AsyncApiSpecValue;\n };\n defaultContentType?: string;\n servers?: Record<string, AsyncApiServerObject>;\n channels?: Record<string, AsyncApiChannelObject>;\n operations?: Record<string, AsyncApiOperationObject>;\n components?: Record<string, Record<string, AsyncApiSpecValue>>;\n [key: string]: AsyncApiSpecValue;\n}\n\n/** Decode a JSON-pointer token: `user~1signedup` -> `user/signedup`. */\nconst unescapePointer = (token: string): string =>\n token.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\");\n\nconst CHANNEL_REF = /^#\\/channels\\/(?<id>.+)$/u;\n\nconst isString = (value: AsyncApiSpecValue): value is string =>\n typeof value === \"string\";\n\n/** The channel id an operation's `channel.$ref` points at, if resolvable. */\nexport const channelIdOf = (channel?: AsyncApiRefLike): string | undefined => {\n const id = CHANNEL_REF.exec(channel?.$ref ?? \"\")?.groups?.id;\n return id === undefined ? undefined : unescapePointer(id);\n};\n\n/**\n * A channel's display address. AsyncAPI 3.x allows `address: null` (unknown at\n * design time) — fall back to the channel id so the operation still shows\n * where it lives.\n */\nexport const channelAddress = (\n channelId: string,\n channel?: AsyncApiChannelObject\n): string => {\n const address = channel?.address;\n return isString(address) && address !== \"\" ? address : channelId;\n};\n\nconst isObject = (\n value: AsyncApiSpecValue\n): value is Record<string, AsyncApiSpecValue> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst COMPONENT_SECTION_REF =\n /^#\\/components\\/(?<section>channels|operations)\\/(?<name>[^/]+)$/u;\n\n/**\n * Inline top-level `channels`/`operations` entries declared as Reference\n * Objects (`{ $ref: \"#/components/channels/…\" }` — the spec's reuse pattern)\n * by replacing them with their components target. Runs before trait merging\n * so an inlined operation's traits merge exactly like an inline one's.\n * Unresolvable refs stay in place; the extractor reports them.\n */\nconst inlineComponentRefs = (document: AsyncApiDocument): void => {\n const maps: [Record<string, AsyncApiSpecValue> | undefined, string][] = [\n [document.channels, \"channels\"],\n [document.operations, \"operations\"],\n ];\n for (const [map, section] of maps) {\n if (!isObject(map)) {\n continue;\n }\n const table = document.components?.[section];\n for (const [id, entry] of Object.entries(map)) {\n if (!isObject(entry) || !isString(entry.$ref)) {\n continue;\n }\n const groups = COMPONENT_SECTION_REF.exec(entry.$ref)?.groups;\n if (groups?.section !== section) {\n continue;\n }\n const resolved = isObject(table)\n ? table[unescapePointer(groups.name ?? \"\")]\n : undefined;\n // A shallow copy per alias: trait merging mutates its node in place\n // (fields written, `traits` deleted), and two entries pointing at the\n // same component — or the component table itself — must not share it.\n if (isObject(resolved) && !isString(resolved.$ref)) {\n map[id] = { ...resolved };\n }\n }\n }\n};\n\nconst TRAIT_REF =\n /^#\\/components\\/(?<section>operationTraits|messageTraits)\\/(?<name>[^/]+)$/u;\n\n/**\n * Merge `traits` into their operation/message objects, in declaration order,\n * with the object's own properties taking precedence (the spec's merge rule;\n * applied shallowly, which covers the fields traits carry in practice —\n * bindings, security, tags, headers). Runs once at parse time so the\n * serialized document and every downstream consumer are trait-free; the\n * `traits` key itself is dropped. Unresolvable trait `$ref`s are skipped.\n */\nexport const applyAsyncApiTraits = (\n document: AsyncApiDocument\n): AsyncApiDocument => {\n const resolveTrait = (\n trait: AsyncApiSpecValue\n ): Record<string, AsyncApiSpecValue> | undefined => {\n if (!isObject(trait)) {\n return undefined;\n }\n if (!isString(trait.$ref)) {\n return trait;\n }\n const groups = TRAIT_REF.exec(trait.$ref)?.groups;\n const section = groups?.section\n ? document.components?.[groups.section]\n : undefined;\n const resolved = section?.[groups?.name ?? \"\"];\n return isObject(resolved) ? resolved : undefined;\n };\n\n const mergeTraits = (node: Record<string, AsyncApiSpecValue>): void => {\n const { traits } = node;\n if (!Array.isArray(traits)) {\n return;\n }\n delete node.traits;\n const merged: Record<string, AsyncApiSpecValue> = {};\n for (const trait of traits) {\n Object.assign(merged, resolveTrait(trait));\n }\n for (const [key, value] of Object.entries(merged)) {\n if (!(key in node)) {\n node[key] = value;\n }\n }\n };\n\n for (const operation of Object.values(document.operations ?? {})) {\n if (isObject(operation)) {\n mergeTraits(operation);\n }\n }\n const channelMaps = [\n ...Object.values(document.channels ?? {}),\n // Reusable channels under components carry messages too; their traits\n // must merge the same way so a resolved component channel renders alike.\n ...Object.values(document.components?.channels ?? {}),\n ];\n const messageMaps = [\n ...channelMaps.map((channel) =>\n isObject(channel) ? channel.messages : undefined\n ),\n document.components?.messages,\n ];\n for (const messages of messageMaps) {\n if (!isObject(messages)) {\n continue;\n }\n for (const message of Object.values(messages)) {\n // A channel message that is itself a `$ref` resolves to a components\n // message, which this loop also visits — don't merge through the ref.\n if (isObject(message) && !isString(message.$ref)) {\n mergeTraits(message);\n }\n }\n }\n return document;\n};\n\n/**\n * The parse-time normalization pass: component channel/operation refs inlined,\n * then traits merged. The serialized document and every downstream consumer\n * see plain channel/operation objects, trait-free.\n */\nexport const normalizeAsyncApiDocument = (\n document: AsyncApiDocument\n): AsyncApiDocument => {\n inlineComponentRefs(document);\n return applyAsyncApiTraits(document);\n};\n\n/**\n * Resolve where one operation renders from: its action and its declared\n * channel. A string return is the warning explaining why the operation can't\n * appear in the reference.\n */\nconst operationSite = (\n id: string,\n operation: AsyncApiOperationObject,\n channels: Record<string, AsyncApiChannelObject>\n): { action: AsyncApiAction; channelId: string; address: string } | string => {\n const action = ASYNCAPI_ACTIONS.find((a) => a === operation.action);\n if (!action) {\n return `Operation \"${id}\" declares no send/receive action; it is missing from the reference.`;\n }\n const channelId = channelIdOf(operation.channel);\n const channel = channelId === undefined ? undefined : channels[channelId];\n // A channel entry that is still a bare `$ref` survived normalization — its\n // components target doesn't exist — so it renders nothing useful either.\n if (channelId === undefined || !isObject(channel) || isString(channel.$ref)) {\n return `Operation \"${id}\" references a channel that isn't declared under \"channels\"; it is missing from the reference.`;\n }\n return { action, address: channelAddress(channelId, channel), channelId };\n};\n\n/** The route-mapped operations, ordered tags, and skip warnings of one document. */\nexport interface AsyncApiOperationCatalog {\n operations: ApiOperationRef[];\n tags: ApiTagRef[];\n warnings: string[];\n}\n\n/**\n * Flatten a normalized AsyncAPI 3.x document into a route-mapped operation\n * list and its ordered tags — the AsyncAPI counterpart of `extractOperations`\n * in `model.ts`, built on the same `operationCollector`. Operations group by\n * their first tag; untagged operations fall back to their channel address, so\n * a spec with no tags still gets one sidebar group per channel. Keys come from\n * the operation id (the `operations` map key), which the official 2.x\n * converter synthesizes deterministically (`<channel>.publish` /\n * `<channel>.subscribe`) — so a 2.x spec and its converter-upgraded 3.x form\n * yield identical URLs. An id that slugifies to nothing falls back to\n * action + address, the same scheme `operationKey` uses for method + path.\n */\nexport const extractAsyncApiOperations = (\n document: AsyncApiDocument,\n baseRoute: string\n): AsyncApiOperationCatalog => {\n const warnings: string[] = [];\n const tagMeta = new Map(\n (document.info?.tags ?? [])\n .filter(\n (tag): tag is { name: string; description?: string } =>\n typeof tag?.name === \"string\"\n )\n .map((tag): [string, string] => [tag.name, tag.description ?? \"\"])\n );\n const collector = operationCollector(baseRoute, tagMeta);\n const channels = document.channels ?? {};\n\n for (const [id, operation] of Object.entries(document.operations ?? {})) {\n if (!isObject(operation)) {\n continue;\n }\n // An operation entry still carrying a `$ref` is one normalization could\n // not inline; name the real problem instead of the missing-action one.\n if (isString(operation.$ref)) {\n warnings.push(\n `Operation \"${id}\" is a reference that doesn't resolve to a components operation; it is missing from the reference.`\n );\n continue;\n }\n const site = operationSite(id, operation, channels);\n if (isString(site)) {\n warnings.push(site);\n continue;\n }\n const { action, address, channelId } = site;\n const tag = operation.tags?.find(\n (candidate): candidate is { name: string; description?: string } =>\n typeof candidate?.name === \"string\"\n )?.name;\n collector.add({\n channelId,\n deprecated: operation.deprecated === true,\n description: operation.description ?? \"\",\n key: operationKey(action, address, id),\n method: action,\n operationId: id,\n path: address,\n summary: operation.title ?? operation.summary ?? \"\",\n tag: tag ?? address,\n });\n }\n\n return { ...collector.finish(), warnings };\n};\n\n/** Resolve the operation object for a ref out of its (AsyncAPI) document. */\nexport const asyncApiOperationObject = (\n document: AsyncApiDocument,\n ref: ApiOperationRef\n): AsyncApiOperationObject | undefined => {\n const operation =\n ref.operationId === undefined\n ? undefined\n : document.operations?.[ref.operationId];\n return isObject(operation) ? operation : undefined;\n};\n",
|
|
144
|
+
"import type { ApiOperationRef, ExtractedOperations } from \"./model.ts\";\nimport { operationCollector, operationKey } from \"./model.ts\";\n\n/**\n * Blume's own GraphQL model — the third front-end of the API reference\n * pipeline. Schemas are lowered to this JSON-serializable document at parse\n * time (see `buildGraphqlDocument` in `graphql-build.ts`, kept separate so\n * `graphql`-js stays out of this module's import graph), so the components\n * render entirely from plain data, mirroring how `model.ts` keeps OpenAPI\n * documents serializable. Browser-safe: no Node imports (the components\n * import from here).\n */\n\n/** The three GraphQL operation kinds, each a sidebar group of root fields. */\nexport const GRAPHQL_OPERATION_KINDS = [\n \"query\",\n \"mutation\",\n \"subscription\",\n] as const;\n\nexport type GraphqlOperationKind = (typeof GRAPHQL_OPERATION_KINDS)[number];\n\n/** The named-type kinds that get reference pages, in sidebar-group order. */\nexport const GRAPHQL_TYPE_KINDS = [\n \"object\",\n \"input\",\n \"enum\",\n \"interface\",\n \"union\",\n \"scalar\",\n] as const;\n\nexport type GraphqlTypeKind = (typeof GRAPHQL_TYPE_KINDS)[number];\n\n/** Everything a GraphQL operation ref's `method` can carry. */\nexport type GraphqlMember = GraphqlOperationKind | GraphqlTypeKind;\n\n/** Sidebar/overview group label for each member kind. */\nexport const GRAPHQL_GROUP_LABELS = {\n enum: \"Enums\",\n input: \"Input Objects\",\n interface: \"Interfaces\",\n mutation: \"Mutations\",\n object: \"Objects\",\n query: \"Queries\",\n scalar: \"Scalars\",\n subscription: \"Subscriptions\",\n union: \"Unions\",\n} satisfies Record<GraphqlMember, string>;\n\n/**\n * A type expression as it appears in the schema: the rendered display form\n * (`[String!]!`) plus the named type at its core (`String`), so components can\n * print the exact wrapper shape and still link to the named type's page.\n */\nexport interface GraphqlTypeRef {\n display: string;\n name: string;\n}\n\n/** An argument or input-object field. */\nexport interface GraphqlInputValue {\n name: string;\n description: string;\n type: GraphqlTypeRef;\n /** Default value printed as a GraphQL literal (`10`, `\"asc\"`, `[1, 2]`). */\n default?: string;\n deprecationReason?: string;\n}\n\n/** An output field of an object or interface type (root fields included). */\nexport interface GraphqlField {\n name: string;\n description: string;\n type: GraphqlTypeRef;\n args: GraphqlInputValue[];\n deprecationReason?: string;\n}\n\n/** One member of an enum type. */\nexport interface GraphqlEnumValue {\n name: string;\n description: string;\n deprecationReason?: string;\n}\n\n/** One named type of the schema, flattened to the fields the reference renders. */\nexport interface GraphqlTypeDef {\n name: string;\n kind: GraphqlTypeKind;\n description: string;\n /** Output fields (object and interface types). */\n fields?: GraphqlField[];\n /** Input fields (input object types). */\n inputFields?: GraphqlInputValue[];\n /** Members (enum types). */\n enumValues?: GraphqlEnumValue[];\n /** Member type names (unions) or implementing object types (interfaces). */\n possibleTypes?: string[];\n /** Interfaces this object/interface type implements. */\n interfaces?: string[];\n /** `specifiedBy` URL (custom scalars). */\n specifiedByUrl?: string;\n /**\n * A spec-defined scalar (`String`, `Int`, …): kept for type refs to resolve\n * against, but never given a reference page of its own.\n */\n builtIn?: boolean;\n}\n\n/** A normalized GraphQL schema, lowered to serializable data at parse time. */\nexport interface GraphqlDocument {\n /** Mirrors the OpenAPI `info` block so `source.ts` reads one shape. */\n info?: { title?: string; version?: string; description?: string };\n /** Root operation type names (`Query`, `Mutation`, `Subscription`). */\n roots: Partial<Record<GraphqlOperationKind, string>>;\n /** Named types by name, spec-defined scalars included, introspection types excluded. */\n types: Record<string, GraphqlTypeDef>;\n}\n\n/** Whether an operation ref's method is a root-field kind (vs a type page). */\nexport const isGraphqlOperationKind = (\n method: string\n): method is GraphqlOperationKind =>\n GRAPHQL_OPERATION_KINDS.some((kind) => kind === method);\n\n/** The SDL keyword that declares each named-type kind: `type Pet`, `enum Status`. */\nconst GRAPHQL_TYPE_KEYWORDS = {\n enum: \"enum\",\n input: \"input\",\n interface: \"interface\",\n object: \"type\",\n scalar: \"scalar\",\n union: \"union\",\n} satisfies Record<GraphqlTypeKind, string>;\n\n/**\n * A GraphQL member in the schema's own notation — `query pets` for a root\n * field, `type Pet` / `input PetInput` / `enum Status` for a named type. The\n * rendered page shows the same pair as a kind badge beside the name; the\n * text form spells the kind the way SDL does, so a reader who knows GraphQL\n * and not Blume's badges reads it right.\n */\nexport const graphqlSignature = (\n operation: Pick<ApiOperationRef, \"method\" | \"path\">\n): string => {\n // SAFETY: the GraphQL extractor only ever assigns member kinds as the\n // method (see `extractGraphqlOperations`).\n const member = operation.method as GraphqlMember;\n const keyword = isGraphqlOperationKind(member)\n ? member\n : GRAPHQL_TYPE_KEYWORDS[member];\n return `${keyword} ${operation.path}`;\n};\n\n// Deterministic name order for type pages, independent of schema declaration\n// order and of the platform's collation (localeCompare varies across ICU\n// builds; codepoint order does not).\nconst byName = (a: GraphqlTypeDef, b: GraphqlTypeDef): number =>\n a.name < b.name ? -1 : 1;\n\n/**\n * Flatten a GraphQL document into a route-mapped page list and its ordered\n * groups — the GraphQL counterpart of `extractOperations` in `model.ts`, built\n * on the same `operationCollector`. Root fields become operation pages grouped\n * as Queries/Mutations/Subscriptions; every other named type becomes a type\n * page grouped by kind (Objects, Input Objects, …). Spec-defined scalars and\n * the root types themselves get no page — the roots' fields ARE the operation\n * pages, and `String`/`Int`/… document nothing.\n */\nexport const extractGraphqlOperations = (\n document: GraphqlDocument,\n baseRoute: string\n): ExtractedOperations => {\n const collector = operationCollector(baseRoute, new Map());\n const rootNames = new Set(Object.values(document.roots));\n\n for (const kind of GRAPHQL_OPERATION_KINDS) {\n const rootName = document.roots[kind];\n const root = rootName === undefined ? undefined : document.types[rootName];\n for (const field of root?.fields ?? []) {\n collector.add({\n deprecated: field.deprecationReason !== undefined,\n description: field.description,\n // `operationKey` slug rules keep GraphQL URLs consistent with the\n // other spec kinds; its fallback covers a name that slugifies empty.\n key: operationKey(kind, field.name, field.name),\n method: kind,\n operationId: field.name,\n path: field.name,\n summary: \"\",\n tag: GRAPHQL_GROUP_LABELS[kind],\n });\n }\n }\n\n for (const kind of GRAPHQL_TYPE_KINDS) {\n const members = Object.values(document.types)\n .filter(\n (type) =>\n type.kind === kind && !(type.builtIn || rootNames.has(type.name))\n )\n .toSorted(byName);\n for (const type of members) {\n collector.add({\n deprecated: false,\n description: type.description,\n key: operationKey(kind, type.name, type.name),\n method: kind,\n operationId: type.name,\n path: type.name,\n summary: \"\",\n tag: GRAPHQL_GROUP_LABELS[kind],\n });\n }\n }\n\n return { ...collector.finish(), warnings: [] };\n};\n\n/** Resolve the root field behind an operation-kind ref, if it still exists. */\nexport const graphqlRootField = (\n document: GraphqlDocument,\n ref: ApiOperationRef\n): GraphqlField | undefined => {\n if (!isGraphqlOperationKind(ref.method)) {\n return undefined;\n }\n const rootName = document.roots[ref.method];\n const root = rootName === undefined ? undefined : document.types[rootName];\n return root?.fields?.find((field) => field.name === ref.operationId);\n};\n\n/** Resolve the named type behind a type-page ref, if it still exists. */\nexport const graphqlTypeDef = (\n document: GraphqlDocument,\n ref: ApiOperationRef\n): GraphqlTypeDef | undefined => {\n const type = document.types[ref.operationId ?? \"\"];\n return type && type.kind === ref.method ? type : undefined;\n};\n",
|
|
145
|
+
"import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\n\nimport type * as ConverterModule from \"@asyncapi/converter\";\nimport { normalize, upgrade } from \"@scalar/openapi-parser\";\nimport pRetry, { AbortError } from \"p-retry\";\nimport { isAbsolute, join } from \"pathe\";\nimport type * as UndiciModule from \"undici\";\n\nimport {\n commandsFor,\n detectProjectPackageManager,\n} from \"../cli/init/scaffold.ts\";\nimport { nodeRequire } from \"../core/node-require.ts\";\nimport { hashText } from \"../core/sources/cache.ts\";\nimport type { AsyncApiDocument } from \"./asyncapi.ts\";\nimport { normalizeAsyncApiDocument } from \"./asyncapi.ts\";\nimport { buildGraphqlDocument } from \"./graphql-build.ts\";\nimport type { GraphqlDocument } from \"./graphql.ts\";\nimport type { ApiDocument } from \"./model.ts\";\nimport { SpecDependencyError } from \"./spec-dependency-error.ts\";\n\n/**\n * Spec loading and normalization. Blume reuses Scalar's parser\n * (`@scalar/openapi-parser`) to read a spec (YAML or JSON), then upgrade Swagger\n * 2.0 / OpenAPI 3.0 documents to 3.1 so the renderer only handles one shape.\n * Internal `$ref`s are deliberately left in place (see `model.ts`).\n *\n * Remote (`http(s)`) specs are fetched defensively — bounded per attempt, retried\n * on transient failures, proxy-aware, and cached on disk — mirroring the\n * resilience the external link checker (`core/links.ts`) and the Notion source\n * (`core/sources/notion.ts`) already have. A bare `fetch` is the classic \"curl\n * works but the build doesn't\" gap: it ignores `*_PROXY`, has no timeout, and\n * dies on a single cold-start blip.\n */\n\nconst URL_SPEC = /^https?:\\/\\//u;\n\nconst FETCH_TIMEOUT_MS = 15_000;\nconst MAX_ATTEMPTS = 3;\nconst BASE_BACKOFF_MS = 500;\n// Honor Retry-After only up to a sane ceiling: a server answering with\n// `Retry-After: 3600` must not stall a build for an hour per attempt.\nconst MAX_RETRY_WAIT_MS = 10_000;\nconst SECOND_MS = 1000;\n// Worth another try: request timeout, too-early, rate-limited, and the 5xx range.\nconst RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]);\nconst USER_AGENT = \"blume (+https://github.com/haydenbleasel/blume)\";\nconst PROXY_ENV_VARS = [\n \"HTTP_PROXY\",\n \"http_proxy\",\n \"HTTPS_PROXY\",\n \"https_proxy\",\n \"ALL_PROXY\",\n \"all_proxy\",\n];\n\nexport interface ParsedSpec {\n document: ApiDocument;\n warnings: string[];\n}\n\n/**\n * The spec was read successfully but its contents aren't an OpenAPI document\n * (an empty file, or YAML that parses to a scalar or list — say, a README\n * pointed at by mistake). Kept distinct from read/fetch failures so callers\n * can suggest fixing the file instead of checking reachability.\n */\nexport class InvalidSpecError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidSpecError\";\n }\n}\n\n/** Where and whether to cache a remote spec's text between runs. */\nexport interface SpecFetchOptions {\n /** Dir for a last-good on-disk copy of a remote spec (offline fallback). */\n cacheDir?: string;\n /**\n * Re-fetch even when a cached copy exists. Builds/sync refresh; dev is\n * cache-first for fast, offline-tolerant restarts (see `SourceContext`).\n */\n refresh?: boolean;\n}\n\n/**\n * Route Node's global `fetch` through an HTTP(S) proxy the first time a remote\n * spec is fetched with one configured. Node's built-in `fetch` ignores `*_PROXY`\n * on its own; undici's env proxy agent, installed on the shared global-dispatcher\n * symbol, wires it in without replacing `fetch` (so tests can still stub it).\n * Best-effort and lazy: no proxy env means undici never loads, and an\n * unavailable undici just leaves the direct connection in place.\n */\nlet proxyInstalled = false;\nconst ensureProxyDispatcher = (): void => {\n // Only memoize a successful install: with no proxy configured we cheaply\n // re-check each time, so a proxy set later in the process still takes effect.\n if (proxyInstalled || !PROXY_ENV_VARS.some((name) => process.env[name])) {\n return;\n }\n try {\n // `require`, not `import()`: an ejected app scans in `astro:build:done`\n // (see `core/node-require.ts`).\n const { EnvHttpProxyAgent, setGlobalDispatcher }: typeof UndiciModule =\n nodeRequire(\"undici\");\n setGlobalDispatcher(new EnvHttpProxyAgent());\n proxyInstalled = true;\n } catch {\n // No proxy support available; fall back to a direct connection.\n }\n};\n\n/**\n * `Retry-After` in ms when the server sent a sane one, else undefined. RFC\n * 9110 allows both forms: delta-seconds (`120`) and an HTTP-date (`Wed, 21\n * Oct 2015 07:28:00 GMT`); the date form arrives from CDN rate limiters and\n * was previously ignored.\n */\nconst retryAfterMs = (response: Response): number | undefined => {\n const header = response.headers.get(\"retry-after\");\n if (!header) {\n return undefined;\n }\n const seconds = Number(header);\n if (Number.isFinite(seconds)) {\n return seconds > 0 ? seconds * SECOND_MS : undefined;\n }\n const delta = Date.parse(header) - Date.now();\n return Number.isFinite(delta) && delta > 0 ? delta : undefined;\n};\n\n/** One fetch attempt, normalized: the body text, or a (maybe-retryable) error. */\ntype Attempt =\n | { text: string }\n | { error: Error; retryable: boolean; retryAfter?: number };\n\nconst attemptFetch = async (spec: string): Promise<Attempt> => {\n try {\n const response = await fetch(spec, {\n headers: {\n accept: \"application/json, application/yaml, text/yaml, */*\",\n \"user-agent\": USER_AGENT,\n },\n redirect: \"follow\",\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (response.ok) {\n return { text: await response.text() };\n }\n return {\n error: new Error(`${spec} -> ${response.status} ${response.statusText}`),\n retryAfter: retryAfterMs(response),\n retryable: RETRYABLE_STATUS.has(response.status),\n };\n } catch (error) {\n // Network error, DNS/TLS failure, or an aborted (timed-out) request — all\n // transient by nature, so worth a retry.\n return {\n error: error instanceof Error ? error : new Error(String(error)),\n retryable: true,\n };\n }\n};\n\n/**\n * A retryable failure, wrapped in a plain Error p-retry never special-cases:\n * it refuses to retry a non-network `TypeError`, and the underlying error's\n * type is the server's choice, not ours. The message is the underlying\n * error's, so the exhaustion throw still reads `spec -> 503 Service\n * Unavailable`.\n */\ntype RetryableFetchError = Error & { retryAfter?: number };\n\nconst retryableFetchError = (\n error: Error,\n retryAfter?: number\n): RetryableFetchError => {\n const wrapper: RetryableFetchError = new Error(error.message, {\n cause: error,\n });\n wrapper.name = \"RetryableFetchError\";\n wrapper.retryAfter = retryAfter;\n return wrapper;\n};\n\n/** Fetch a remote spec's text, retrying transient failures with backoff. */\nconst fetchSpecText = async (spec: string): Promise<string> => {\n ensureProxyDispatcher();\n return await pRetry(\n async () => {\n const attempt = await attemptFetch(spec);\n if (\"text\" in attempt) {\n return attempt.text;\n }\n if (!attempt.retryable) {\n // AbortError stops retrying and rethrows the original untouched.\n throw new AbortError(attempt.error);\n }\n throw retryableFetchError(attempt.error, attempt.retryAfter);\n },\n {\n factor: 2,\n maxTimeout: MAX_RETRY_WAIT_MS,\n minTimeout: BASE_BACKOFF_MS,\n // A sane `Retry-After` replaces the exponential backoff rather than\n // stacking on it: p-retry's own (capped) delay still runs after this\n // hook, so only the difference is slept here.\n onFailedAttempt: async (context) => {\n // SAFETY: every retryable throw above is a RetryableFetchError; any\n // other error reaching this hook reads an absent retryAfter.\n const { retryAfter } = context.error as RetryableFetchError;\n if (retryAfter !== undefined && context.retriesLeft > 0) {\n await sleep(\n Math.max(\n 0,\n Math.min(retryAfter, MAX_RETRY_WAIT_MS) - context.retryDelay\n )\n );\n }\n },\n retries: MAX_ATTEMPTS - 1,\n }\n );\n};\n\nconst cacheFileFor = (cacheDir: string, spec: string): string =>\n join(cacheDir, `spec-${hashText(spec)}.cache`);\n\nconst readCache = async (file: string): Promise<string | undefined> => {\n try {\n return await readFile(file, \"utf-8\");\n } catch {\n return undefined;\n }\n};\n\nconst writeCache = async (\n dir: string,\n file: string,\n text: string\n): Promise<void> => {\n try {\n await mkdir(dir, { recursive: true });\n await writeFile(file, text, \"utf-8\");\n } catch {\n // Best-effort cache; a write failure must not fail the load.\n }\n};\n\n/** Read a spec's raw text from an `http(s)` URL or a local (project-relative) path. */\nconst readSpecText = async (\n spec: string,\n root: string,\n options: SpecFetchOptions\n): Promise<{ text: string; warnings: string[] }> => {\n if (!URL_SPEC.test(spec)) {\n const absolute = isAbsolute(spec) ? spec : join(root, spec);\n return { text: await readFile(absolute, \"utf-8\"), warnings: [] };\n }\n\n const cacheFile = options.cacheDir\n ? cacheFileFor(options.cacheDir, spec)\n : undefined;\n\n // Cache-first in dev: serve the last-good snapshot without touching the network.\n if (cacheFile && options.refresh === false) {\n const cached = await readCache(cacheFile);\n if (cached !== undefined) {\n return { text: cached, warnings: [] };\n }\n }\n\n try {\n const text = await fetchSpecText(spec);\n if (options.cacheDir && cacheFile) {\n await writeCache(options.cacheDir, cacheFile, text);\n }\n return { text, warnings: [] };\n } catch (error) {\n // A transient outage falls back to the last good fetch, with a warning.\n if (cacheFile) {\n const cached = await readCache(cacheFile);\n if (cached !== undefined) {\n // SAFETY: fetchSpecText throws only Error instances — attemptFetch\n // wraps every non-Error throw in an Error.\n return {\n text: cached,\n warnings: [\n `Could not fetch ${spec} (${(error as Error).message}); using the last cached copy.`,\n ],\n };\n }\n }\n throw error;\n }\n};\n\n/**\n * Read, normalize, and upgrade a spec to an OpenAPI 3.1 document. Throws when the\n * spec can't be read and no cache is available; callers turn that into a source\n * diagnostic (an error in build, a warning in dev) rather than a hard failure so\n * a broken spec doesn't take down the whole build.\n */\n/**\n * A parsed mapping is the only shape the renderer can treat as a document:\n * `normalize` yields undefined for anything that isn't a YAML/JSON mapping\n * (empty file, scalar, list) and `upgrade(undefined)` a null specification.\n */\nconst isApiDocument = <Value>(value: Value): value is Value & ApiDocument =>\n typeof value === \"object\" && value !== null;\n\nexport const parseSpec = async (\n spec: string,\n root: string,\n options: SpecFetchOptions = {}\n): Promise<ParsedSpec> => {\n const { text, warnings } = await readSpecText(spec, root, options);\n const normalized = normalize(text);\n const { specification } = upgrade(normalized);\n // Reject a non-mapping here so the renderer never sees a non-document.\n if (!isApiDocument(specification)) {\n throw new InvalidSpecError(\n `${spec} is not a valid OpenAPI document (expected a YAML or JSON object).`\n );\n }\n return { document: specification, warnings };\n};\n\nexport interface ParsedAsyncApiSpec {\n document: AsyncApiDocument;\n warnings: string[];\n}\n\n/**\n * An object carrying a non-empty `asyncapi` version string — the only input\n * the converter and extractor can key on. `normalize` yields undefined for\n * non-mapping input, which fails the object check here.\n */\nconst isAsyncApiDocument = <Value>(\n value: Value\n): value is Value & AsyncApiDocument & { asyncapi: string } =>\n typeof value === \"object\" &&\n value !== null &&\n \"asyncapi\" in value &&\n typeof value.asyncapi === \"string\" &&\n value.asyncapi !== \"\";\n\nconst CONVERTER = \"@asyncapi/converter\";\n\n/**\n * Load `@asyncapi/converter`, an optional peer. Only a 1.x/2.x spec needs it,\n * and it depends on `@asyncapi/parser` — which it never loads — and so on\n * Spectral and Scarf's telemetry postinstall, an unapproved build script that\n * pnpm 12 refuses to install past. Leaving it out of a default install keeps\n * `pnpm dlx blume` working; a spec that needs it gets the install command\n * instead, through {@link SpecDependencyError}.\n */\nconst loadConverter = async (\n spec: string,\n version: string,\n root: string\n): Promise<typeof ConverterModule> => {\n try {\n // `require`, not `import()`: see `core/node-require.ts`.\n const converter: typeof ConverterModule = nodeRequire(CONVERTER);\n return converter;\n } catch (error) {\n // SAFETY: a failed `require` throws a Node error; `code` and `message`\n // are the only fields read.\n const { code, message } = error as NodeJS.ErrnoException;\n // Only the converter itself missing is the project's to fix; anything\n // else (a broken install of one of its own dependencies) surfaces as is.\n if (code !== \"MODULE_NOT_FOUND\" || !message.includes(`'${CONVERTER}'`)) {\n throw error;\n }\n const { add } = commandsFor(await detectProjectPackageManager(root));\n throw new SpecDependencyError(\n `${spec} is AsyncAPI ${version}, and converting it to AsyncAPI 3.0 needs \"${CONVERTER}\", which isn't installed`,\n `Install it with \\`${add} ${CONVERTER}\\`, or convert the spec to AsyncAPI 3.0.`\n );\n }\n};\n\n/**\n * Read and normalize a spec to an AsyncAPI 3.x document — the AsyncAPI mirror\n * of {@link parseSpec}. 1.x/2.x documents are lifted to 3.0 with the official\n * `@asyncapi/converter` (channels + operations with `send`/`receive` actions),\n * so the extractor and components only ever handle one shape; `$ref`s stay\n * intact, matching the OpenAPI path. Error semantics match `parseSpec`: an\n * unreadable spec throws, a readable non-AsyncAPI document throws\n * {@link InvalidSpecError}, a pre-3.0 document without the converter installed\n * throws {@link SpecDependencyError}, and callers lower all three into source\n * diagnostics.\n */\nexport const parseAsyncApiSpec = async (\n spec: string,\n root: string,\n options: SpecFetchOptions = {}\n): Promise<ParsedAsyncApiSpec> => {\n const { text, warnings } = await readSpecText(spec, root, options);\n const normalized = normalize(text);\n if (!isAsyncApiDocument(normalized)) {\n throw new InvalidSpecError(\n `${spec} is not a valid AsyncAPI document (expected a YAML or JSON object with an \\`asyncapi\\` version field).`\n );\n }\n const version = normalized.asyncapi;\n let document: AsyncApiDocument = normalized;\n if (!version.startsWith(\"3.\")) {\n const { convert } = await loadConverter(spec, version, root);\n // The converter reports lossy conversions (e.g. a 2.x parameter schema\n // that 3.0 can't express) through console.warn — capture those as spec\n // warnings instead of letting them leak into CLI output.\n const captured: string[] = [];\n const originalWarn = console.warn;\n console.warn = (...args: unknown[]) => {\n captured.push(args.map(String).join(\" \"));\n };\n try {\n // SAFETY: the converter accepts any pre-3.0 AsyncAPI object and returns\n // the 3.0 shape the extractor consumes; the two packages just declare\n // the document type differently.\n document = convert(\n document as Parameters<typeof convert>[0],\n \"3.0.0\"\n ) as AsyncApiDocument;\n } catch (error) {\n // An unconvertible document (say, an unknown `asyncapi` version) is a\n // content problem, not a network one — same class as a non-document.\n // SAFETY: @asyncapi/converter throws Error instances for bad input.\n throw new InvalidSpecError(\n `${spec} could not be converted to AsyncAPI 3.0 (${(error as Error).message}).`\n );\n } finally {\n console.warn = originalWarn;\n }\n warnings.push(\n ...captured.map(\n (message) => `Converting ${spec} to AsyncAPI 3.0: ${message}`\n )\n );\n }\n return { document: normalizeAsyncApiDocument(document), warnings };\n};\n\nexport interface ParsedGraphqlSpec {\n document: GraphqlDocument;\n warnings: string[];\n}\n\n/**\n * Read and lower a GraphQL schema — SDL text or an introspection JSON result —\n * to the serializable document the reference renders from; the GraphQL mirror\n * of {@link parseSpec}. Error semantics match the other kinds: an unreadable\n * spec throws the read/fetch error, while readable-but-invalid schema text\n * (SDL syntax errors, validation failures, JSON that isn't an introspection\n * result) throws {@link InvalidSpecError} so callers suggest fixing the file\n * rather than checking reachability.\n */\nexport const parseGraphqlSpec = async (\n spec: string,\n root: string,\n options: SpecFetchOptions = {}\n): Promise<ParsedGraphqlSpec> => {\n const { text, warnings } = await readSpecText(spec, root, options);\n try {\n return { document: buildGraphqlDocument(text), warnings };\n } catch (error) {\n // SAFETY: `graphql`-js throws GraphQLError (an Error) for syntax and\n // validation failures, and `buildGraphqlDocument` throws plain Errors for\n // non-introspection JSON; only the message is surfaced.\n throw new InvalidSpecError(\n `${spec} is not a valid GraphQL schema (${(error as Error).message.trim()})`\n );\n }\n};\n",
|
|
146
|
+
"import { createRequire } from \"node:module\";\n\n/**\n * Node's own `require`, for the SDKs and heavy modules Blume loads only when a\n * feature needs them. Resolution starts from this file, inside the installed\n * package, exactly like the `import()` it stands in for, and Node 22.12+ loads\n * ES modules through it too.\n *\n * Never `import()` in their place. When Node can't import the generated Astro\n * config itself — it refuses to strip types from TypeScript under\n * `node_modules`, which is where an installed Blume's runtime source lives —\n * Astro evaluates the config, and every Blume module it reaches, in a Vite\n * module runner that it closes as soon as the config has loaded. A dynamic\n * `import()` in one of those modules resolves through that runner, so a call\n * made any later (an `astro:build:done` hook, a Markdown plugin) throws \"Vite\n * module runner has been closed\". `require` is Node's, so it works however the\n * calling module was evaluated. The repo itself never sees the failure: its\n * workspace link puts Blume outside `node_modules`, so Node imports the config\n * natively.\n */\nexport const nodeRequire = createRequire(import.meta.url);\n",
|
|
147
|
+
"import type {\n GraphQLArgument,\n GraphQLEnumType,\n GraphQLField,\n GraphQLInputField,\n GraphQLInputObjectType,\n GraphQLInterfaceType,\n GraphQLNamedType,\n GraphQLObjectType,\n GraphQLScalarType,\n GraphQLSchema,\n GraphQLUnionType,\n} from \"graphql\";\nimport {\n buildClientSchema,\n buildSchema,\n getNamedType,\n isEnumType,\n isInputObjectType,\n isInterfaceType,\n isObjectType,\n isSpecifiedScalarType,\n isUnionType,\n print,\n} from \"graphql\";\n\nimport type {\n GraphqlDocument,\n GraphqlEnumValue,\n GraphqlField as ModelField,\n GraphqlInputValue,\n GraphqlTypeDef,\n GraphqlTypeRef,\n} from \"./graphql.ts\";\n\n/**\n * Lower schema text — SDL or an introspection result — into the serializable\n * {@link GraphqlDocument} the reference renders from. This is the only module\n * that imports `graphql`-js, and it runs Node-side at parse time only (see\n * `parseGraphqlSpec` in `parse.ts`), so the parser never reaches the generated\n * runtime or the browser. Throws plain Errors for unreadable schemas; the\n * caller wraps them as content problems.\n */\n\n/** A type expression flattened to its display form and core named type. */\nconst typeRef = (\n type: GraphQLField<unknown, unknown>[\"type\"] | GraphQLInputField[\"type\"]\n): GraphqlTypeRef => ({\n display: String(type),\n name: getNamedType(type).name,\n});\n\n/**\n * An argument's or input field's default, printed as a GraphQL literal. Both\n * SDL- and introspection-built schemas carry the default as a const AST node\n * (`default.literal`); a schema constructed programmatically with a coerced\n * `value` instead never reaches this module (it only builds from text).\n */\nconst defaultLiteral = (\n input: GraphQLArgument | GraphQLInputField\n): string | undefined => {\n const literal = input.default?.literal;\n return literal ? print(literal) : undefined;\n};\n\nconst inputValue = (\n input: GraphQLArgument | GraphQLInputField\n): GraphqlInputValue => {\n const value: GraphqlInputValue = {\n description: input.description ?? \"\",\n name: input.name,\n type: typeRef(input.type),\n };\n const printed = defaultLiteral(input);\n if (printed !== undefined) {\n value.default = printed;\n }\n // `deprecationReason` is null on non-deprecated members in some builds;\n // absent means \"not deprecated\" downstream, so both collapse to absent.\n if (\n input.deprecationReason !== null &&\n input.deprecationReason !== undefined\n ) {\n value.deprecationReason = input.deprecationReason;\n }\n return value;\n};\n\nconst outputField = (field: GraphQLField<unknown, unknown>): ModelField => {\n const value: ModelField = {\n args: field.args.map(inputValue),\n description: field.description ?? \"\",\n name: field.name,\n type: typeRef(field.type),\n };\n if (\n field.deprecationReason !== null &&\n field.deprecationReason !== undefined\n ) {\n value.deprecationReason = field.deprecationReason;\n }\n return value;\n};\n\nconst enumValues = (type: GraphQLEnumType): GraphqlEnumValue[] =>\n type.getValues().map((value) => {\n const member: GraphqlEnumValue = {\n description: value.description ?? \"\",\n name: value.name,\n };\n if (\n value.deprecationReason !== null &&\n value.deprecationReason !== undefined\n ) {\n member.deprecationReason = value.deprecationReason;\n }\n return member;\n });\n\nconst objectDef = (\n type: GraphQLObjectType | GraphQLInterfaceType,\n kind: \"object\" | \"interface\"\n): GraphqlTypeDef => {\n const interfaces = type.getInterfaces().map((iface) => iface.name);\n const def: GraphqlTypeDef = {\n description: type.description ?? \"\",\n fields: Object.values(type.getFields()).map(outputField),\n kind,\n name: type.name,\n };\n if (interfaces.length > 0) {\n def.interfaces = interfaces;\n }\n return def;\n};\n\nconst inputDef = (type: GraphQLInputObjectType): GraphqlTypeDef => ({\n description: type.description ?? \"\",\n inputFields: Object.values(type.getFields()).map(inputValue),\n kind: \"input\",\n name: type.name,\n});\n\nconst unionDef = (type: GraphQLUnionType): GraphqlTypeDef => ({\n description: type.description ?? \"\",\n kind: \"union\",\n name: type.name,\n possibleTypes: type.getTypes().map((member) => member.name),\n});\n\nconst scalarDef = (type: GraphQLScalarType): GraphqlTypeDef => {\n const def: GraphqlTypeDef = {\n description: type.description ?? \"\",\n kind: \"scalar\",\n name: type.name,\n };\n if (type.specifiedByURL !== null && type.specifiedByURL !== undefined) {\n def.specifiedByUrl = type.specifiedByURL;\n }\n if (isSpecifiedScalarType(type)) {\n def.builtIn = true;\n }\n return def;\n};\n\nconst typeDef = (\n type: GraphQLNamedType,\n schema: GraphQLSchema\n): GraphqlTypeDef => {\n if (isObjectType(type)) {\n return objectDef(type, \"object\");\n }\n if (isInterfaceType(type)) {\n const def = objectDef(type, \"interface\");\n // Implementations are indexed on the schema, not the type — captured here\n // so the type page can list \"implemented by\" without a schema in hand.\n const implementers = schema\n .getImplementations(type)\n .objects.map((object) => object.name);\n if (implementers.length > 0) {\n def.possibleTypes = implementers;\n }\n return def;\n }\n if (isInputObjectType(type)) {\n return inputDef(type);\n }\n if (isEnumType(type)) {\n return {\n description: type.description ?? \"\",\n enumValues: enumValues(type),\n kind: \"enum\",\n name: type.name,\n };\n }\n if (isUnionType(type)) {\n return unionDef(type);\n }\n // SAFETY: the named-type union is exhaustive — after the object, interface,\n // input, enum, and union guards, only scalars remain.\n return scalarDef(type as GraphQLScalarType);\n};\n\n/** Lower a built schema to the serializable document. */\nconst documentOf = (schema: GraphQLSchema): GraphqlDocument => {\n const types: Record<string, GraphqlTypeDef> = {};\n for (const [name, type] of Object.entries(schema.getTypeMap())) {\n // Introspection meta-types (`__Schema`, `__Type`, …) are machinery, not API.\n if (name.startsWith(\"__\")) {\n continue;\n }\n types[name] = typeDef(type, schema);\n }\n const roots: GraphqlDocument[\"roots\"] = {};\n const query = schema.getQueryType();\n const mutation = schema.getMutationType();\n const subscription = schema.getSubscriptionType();\n if (query) {\n roots.query = query.name;\n }\n if (mutation) {\n roots.mutation = mutation.name;\n }\n if (subscription) {\n roots.subscription = subscription.name;\n }\n return {\n info: { description: schema.description ?? \"\" },\n roots,\n types,\n };\n};\n\n/**\n * A parsed JSON value carrying an introspection result's `__schema` key —\n * possibly under the standard `{ data: … }` GraphQL response envelope. The\n * generic-guard shape mirrors the document checks in `parse.ts`; the real\n * validation is `buildClientSchema`'s, which throws a descriptive error on\n * anything malformed inside `__schema`.\n */\nconst hasSchemaKey = <Value>(\n value: Value\n): value is Value & { __schema: object } =>\n typeof value === \"object\" && value !== null && \"__schema\" in value;\n\n/** A parsed JSON value shaped like a GraphQL response envelope. */\nconst hasDataEnvelope = <Value>(\n value: Value\n): value is Value & { data: unknown } =>\n typeof value === \"object\" && value !== null && \"data\" in value;\n\n/** The introspection result inside a parsed JSON value, if it carries one. */\nconst introspectionOf = <Value>(parsed: Value): object | undefined => {\n if (hasSchemaKey(parsed)) {\n return parsed;\n }\n return hasDataEnvelope(parsed) && hasSchemaKey(parsed.data)\n ? parsed.data\n : undefined;\n};\n\n/**\n * Build the document from schema text: an introspection JSON result (the raw\n * `{ __schema }` shape or a `{ data: { __schema } }` response envelope) or\n * SDL. Anything else throws — JSON that isn't an introspection result names\n * that problem directly instead of earning SDL syntax errors for a `{`.\n */\nexport const buildGraphqlDocument = (text: string): GraphqlDocument => {\n let parsed: unknown;\n let isJson = true;\n try {\n parsed = JSON.parse(text);\n } catch {\n isJson = false;\n }\n if (isJson) {\n const introspection = introspectionOf(parsed);\n if (!introspection) {\n throw new Error(\n \"the JSON document is not a GraphQL introspection result (no `__schema` key).\"\n );\n }\n // SAFETY: the guard above only establishes the `__schema` key;\n // `buildClientSchema` validates the full introspection shape itself and\n // throws a descriptive error on anything malformed.\n return documentOf(\n buildClientSchema(\n introspection as Parameters<typeof buildClientSchema>[0]\n )\n );\n }\n return documentOf(buildSchema(text));\n};\n",
|
|
148
|
+
"/**\n * Reading a spec needs an optional package the project hasn't installed (the\n * AsyncAPI converter, for a pre-3.0 document). Carries its own suggestion —\n * the install command — because neither of the other spec failures fits: the\n * file is fine and so is the network.\n */\nexport class SpecDependencyError extends Error {\n readonly suggestion: string;\n\n constructor(message: string, suggestion: string) {\n super(message);\n this.name = \"SpecDependencyError\";\n this.suggestion = suggestion;\n }\n}\n",
|
|
149
|
+
"import type { Nodes, Root } from \"mdast\";\nimport { fromMarkdown } from \"mdast-util-from-markdown\";\nimport { toString as mdastToString } from \"mdast-util-to-string\";\nimport stringWidth from \"string-width\";\n\nimport { apiNamePhrase } from \"../core/api-name.ts\";\nimport { unsafeLinkSpans } from \"../core/safe-links.ts\";\nimport { columnsPrefix } from \"../core/text-width.ts\";\nimport type { GraphqlMember } from \"./graphql.ts\";\nimport { isGraphqlOperationKind } from \"./graphql.ts\";\nimport type { ApiOperationRef, ApiSpecData } from \"./model.ts\";\nimport type { ReferenceSource } from \"./references.ts\";\nimport { asSentence } from \"./sentence.ts\";\nimport { operationSignature } from \"./signature.ts\";\n\n/**\n * Lower a parsed spec into MDX for the staged content source. Each operation and\n * the spec overview become a thin MDX page: the frontmatter carries the\n * searchable `title` (so operations flow into Blume's search, OG, and llms.txt),\n * the operation/overview **description is emitted as markdown in the body** so it\n * renders parsed (links, formatting) and is indexed, and the structured UI is\n * deferred to a Blume-owned component (`<Operation>` / `<ApiOverview>`). The\n * catch-all renders the frontmatter title as the page `<h1>`, so the components\n * omit their own top heading.\n */\n\n// Neutralize the few characters MDX treats specially (`{` expressions, `<`\n// JSX) so an arbitrary spec description can be embedded in the body verbatim\n// without breaking compilation. They render as their literal selves. `>` is\n// deliberately not escaped: it isn't MDX-special on its own, and escaping it\n// turns a `> Note:` blockquote into literal \"> Note:\" text.\nconst MDX_UNSAFE = /[<{}]/gu;\nconst ENTITIES = new Map([\n [\"<\", \"<\"],\n [\"{\", \"{\"],\n [\"}\", \"}\"],\n]);\n// MDX also parses lines starting with `import`/`export` as ESM (\"import the\n// SDK…\" is common spec prose). Entity-escape the keyword's first letter so the\n// construct can't match; it still renders as the literal word.\nconst MDX_ESM_KEYWORD = /^(?<keyword>import|export)\\b/gmu;\nconst escapeProse = (text: string): string =>\n text\n .replace(MDX_UNSAFE, (char) => ENTITIES.get(char) ?? char)\n .replace(\n MDX_ESM_KEYWORD,\n (keyword) => `&#${keyword.codePointAt(0)};${keyword.slice(1)}`\n );\n\n/**\n * The source offset ranges of code constructs — inline spans and fences —\n * that MDX treats as literal (entities are NOT decoded inside them, so\n * escaping there would render `/pets/{petId}` verbatim). The ranges\n * come from a CommonMark parse rather than fence-emulating regexes: the\n * parser is the authority on equal-length backtick pairing, longer tilde\n * closers, unclosed fences running to EOF, and fences nested in blockquotes —\n * each of which the replaced regexes had to re-derive (two with a recorded\n * bug history in this file).\n *\n * One CommonMark construct is deliberately *not* masked: indented code. MDX\n * disables indented code blocks, so a 4-space-indented sample is a paragraph\n * whose braces genuinely need escaping; fence-or-backtick is told apart from\n * indentation by the construct's first character.\n */\nconst codeSpans = (text: string, tree: Root): [number, number][] => {\n const spans: [number, number][] = [];\n const collect = (node: Nodes): void => {\n if (node.type === \"inlineCode\" || node.type === \"code\") {\n // fromMarkdown always stamps positions; -1 is an unreachable guard.\n const start = node.position?.start.offset ?? -1;\n const end = node.position?.end.offset ?? -1;\n const head = text.slice(Math.max(start, 0), Math.max(end, 0)).trimStart();\n if (\n start >= 0 &&\n (node.type === \"inlineCode\" ||\n head.startsWith(\"`\") ||\n head.startsWith(\"~\"))\n ) {\n spans.push([start, end]);\n }\n return;\n }\n if (\"children\" in node) {\n for (const child of node.children) {\n collect(child);\n }\n }\n };\n collect(tree);\n return spans;\n};\n\n/**\n * Escape MDX-special syntax in prose while leaving code verbatim. A spec is\n * someone else's content, so a link whose destination isn't a web, mail, or\n * relative address (`javascript:`, `data:`) is reduced to its label rather\n * than rendered clickable on the docs site (see `core/safe-links.ts`).\n */\nconst mdxSafe = (text: string): string => {\n const tree = fromMarkdown(text);\n const unsafe = unsafeLinkSpans(tree);\n const insideUnsafe = (offset: number): boolean =>\n unsafe.some((span) => offset >= span.start && offset < span.end);\n const segments = [\n ...codeSpans(text, tree)\n .filter(([start]) => !insideUnsafe(start))\n .map(([start, end]) => ({ end, start, text: text.slice(start, end) })),\n ...unsafe,\n ].toSorted((a, b) => a.start - b.start);\n let out = \"\";\n let cursor = 0;\n for (const segment of segments) {\n out += escapeProse(text.slice(cursor, segment.start));\n out += segment.text;\n cursor = segment.end;\n }\n return out + escapeProse(text.slice(cursor));\n};\n\n/**\n * Frontmatter emitted for one operation or overview page. Boolean flags are\n * assigned only when set, so absent keys stay absent in the staged MDX.\n */\nexport interface RenderedPageData {\n ai?: { exclude: boolean };\n deprecated?: boolean;\n search?: { exclude?: boolean; tags?: string[] };\n seo: { description: string; noindex?: boolean };\n sidebar: { badge?: string; label: string };\n title: string;\n type?: string;\n}\n\n/** Frontmatter + body for one operation or overview page. */\nexport interface RenderedPage {\n data: RenderedPageData;\n body: string;\n}\n\n// Meta descriptions. A page that sets none falls back to the site-wide default,\n// so a spec's pages would otherwise all ship one identical description — what\n// search engines treat as duplicate content. These go in `seo.description`, not\n// `description`: the prose already renders in the body, and a `description`\n// frontmatter field would print it a second time as the page subtitle.\nconst META_DESCRIPTION_MAX = 160;\nconst WHITESPACE = /\\s+/gu;\nconst TRAILING_WORD = /\\s+\\S*$/u;\n\n/**\n * Flatten markdown prose to its first paragraph as single-line plain text,\n * via a real parse (`mdast-util-to-string`). The regex strip this replaces\n * was lossy on literal prose — `snake_case` → `snakecase`, `C#` → `C` — and\n * these strings ship as `seo.description` meta tags. A description with no\n * paragraph (say, only a heading or list) falls back to its first block.\n */\nconst plainProse = (markdown: string): string => {\n const tree = fromMarkdown(markdown);\n const first =\n tree.children.find((node) => node.type === \"paragraph\") ?? tree.children[0];\n return first ? mdastToString(first).replace(WHITESPACE, \" \").trim() : \"\";\n};\n\n/** Cap `text` at `max` display columns, cutting on a word boundary. */\nconst clip = (text: string, max: number): string => {\n if (max <= 0) {\n return \"\";\n }\n if (stringWidth(text) <= max) {\n return text;\n }\n const head = columnsPrefix(text, max - 1);\n const onWordBoundary = head.replace(TRAILING_WORD, \"\");\n // One very long token — an endpoint path has no spaces — would be dropped\n // whole, leaving a stub. Hard-cut it instead of losing it.\n return `${stringWidth(onWordBoundary) >= max / 2 ? onWordBoundary : head}…`;\n};\n\nconst apiName = (spec: ApiSpecData): string => spec.title || spec.label;\n/** The spec's name as \"the ___\" in generated prose (see `apiNamePhrase`). */\nconst apiPhrase = (spec: ApiSpecData): string => apiNamePhrase(apiName(spec));\n\n/** Human phrase for each GraphQL page kind, for meta descriptions. */\nconst GRAPHQL_MEMBER_PHRASES = {\n enum: \"enum type\",\n input: \"input object type\",\n interface: \"interface type\",\n mutation: \"mutation\",\n object: \"object type\",\n query: \"query\",\n scalar: \"scalar type\",\n subscription: \"subscription\",\n union: \"union type\",\n} satisfies Record<GraphqlMember, string>;\n\n/**\n * The spec's own prose for the operation, followed by the endpoint it documents\n * — so every operation page carries a distinct, self-describing meta\n * description even when the spec's summaries are terse. With the suffix\n * switched off (`seoDescriptionSuffix: false`, for sites whose prose isn't\n * English) the description is the prose alone, or the page `title` — a\n * language-neutral `GET /pets`, channel, or field name — when the operation\n * has no prose at all, so no page ships an empty description.\n */\nconst operationDescription = (\n spec: ApiSpecData,\n operation: ApiOperationRef,\n options: { suffix: boolean; title: string }\n): string => {\n if (!options.suffix) {\n return clip(\n plainProse(operation.description || operation.summary) || options.title,\n META_DESCRIPTION_MAX\n );\n }\n // AsyncAPI operations act on a channel, not an HTTP endpoint; GraphQL pages\n // document a root field or a named type.\n let subject: string;\n if (spec.kind === \"asyncapi\") {\n subject = `${operation.method} operation on ${operation.path}`;\n } else if (spec.kind === \"graphql\") {\n // SAFETY: the GraphQL extractor only ever assigns member kinds as the\n // method (see `extractGraphqlOperations`).\n subject = `${operation.path} ${GRAPHQL_MEMBER_PHRASES[operation.method as GraphqlMember]}`;\n } else {\n subject = `${operation.method.toUpperCase()} ${operation.path} endpoint`;\n }\n const suffix = `Reference for the ${subject} in the ${apiPhrase(spec)}.`;\n // Room for the joining space and the period `asSentence` may add, so a\n // title-like summary (\"Get a flag\") ends before the suffix begins.\n const prose = clip(\n plainProse(operation.description || operation.summary),\n META_DESCRIPTION_MAX - stringWidth(suffix) - 2\n );\n return clip(\n [asSentence(prose), suffix].filter(Boolean).join(\" \"),\n META_DESCRIPTION_MAX\n );\n};\n\n/** Prepend a markdown description (if any) above a component invocation. */\nconst withDescription = (description: string, component: string): string =>\n description.trim()\n ? `${mdxSafe(description.trim())}\\n\\n${component}`\n : component;\n\nexport const operationMdx = (\n spec: ApiSpecData,\n operation: ApiOperationRef,\n reference?: Pick<\n ReferenceSource,\n \"includeInLlms\" | \"includeInSearch\" | \"noindex\" | \"seoDescriptionSuffix\"\n >\n): RenderedPage => {\n const method = operation.method.toUpperCase();\n const graphql = spec.kind === \"graphql\";\n // A GraphQL page IS its field/type — `query pets` would double the badge the\n // page already renders; the other kinds title an endpoint or channel action.\n const fallbackTitle = graphql\n ? operation.path\n : operationSignature(spec, operation);\n const title = operation.summary || fallbackTitle;\n // Skip the body description when it only repeats the summary (the `<h1>`) —\n // common in specs that set summary and description to the same string.\n const description =\n operation.description.trim() === operation.summary.trim()\n ? \"\"\n : operation.description;\n const flags: Pick<RenderedPageData, \"ai\" | \"deprecated\"> = {};\n if (reference?.includeInLlms === false) {\n flags.ai = { exclude: true };\n }\n if (operation.deprecated) {\n flags.deprecated = true;\n }\n const searchFlags: Pick<\n NonNullable<RenderedPageData[\"search\"]>,\n \"exclude\"\n > = {};\n if (reference?.includeInSearch === false) {\n searchFlags.exclude = true;\n }\n const seo: RenderedPageData[\"seo\"] = {\n description: operationDescription(spec, operation, {\n suffix: reference?.seoDescriptionSuffix !== false,\n title,\n }),\n };\n if (reference?.noindex) {\n seo.noindex = true;\n }\n const sidebar: RenderedPageData[\"sidebar\"] = {\n label: operation.summary || operation.path,\n };\n // GraphQL operation kinds badge like HTTP methods, but a type page's kind\n // already heads its sidebar group (\"Objects\", \"Enums\", …) — an `OBJECT`\n // badge on every row would only repeat it, so type pages get none. The\n // uppercased method is likewise an internal token on GraphQL pages, so\n // their search tags carry only the group name.\n if (!graphql || isGraphqlOperationKind(operation.method)) {\n sidebar.badge = method;\n }\n const tags = graphql ? [operation.tag] : [operation.tag, method];\n return {\n body: withDescription(\n description,\n `<Operation source=\"${spec.slug}\" id=\"${operation.key}\" />`\n ),\n data: {\n ...flags,\n search: { ...searchFlags, tags },\n seo,\n sidebar,\n title,\n // Signals the two-column API layout (request panel instead of the TOC).\n type: \"openapi-operation\",\n },\n };\n};\n\nexport const overviewMdx = (\n spec: ApiSpecData,\n reference?: Pick<\n ReferenceSource,\n \"includeInLlms\" | \"includeInSearch\" | \"noindex\"\n >\n): RenderedPage => {\n // Tag sections: declared tags in spec order, then any tag an operation\n // references that isn't declared under `tags`. The section headings are\n // emitted as real markdown `##` (not markup inside a component) so the\n // markdown pipeline gives them ids, permalink anchors, and table-of-contents\n // entries; only the operation-link list defers to a component.\n const operations = Object.values(spec.operations);\n // Dedupe by slug: two declared tags that slugify identically (`Store` and\n // `store`) must render one section, not the same operation list twice.\n const sections: typeof spec.tags = [];\n const known = new Set<string>();\n for (const tag of spec.tags) {\n if (!known.has(tag.slug)) {\n known.add(tag.slug);\n sections.push(tag);\n }\n }\n for (const operation of operations) {\n if (!known.has(operation.tagSlug)) {\n known.add(operation.tagSlug);\n sections.push({\n description: \"\",\n name: operation.tag,\n slug: operation.tagSlug,\n });\n }\n }\n const tagSections: string[] = [];\n for (const tag of sections) {\n if (!operations.some((operation) => operation.tagSlug === tag.slug)) {\n continue;\n }\n const description = tag.description.trim()\n ? [mdxSafe(tag.description.trim())]\n : [];\n tagSections.push(\n [\n `## ${mdxSafe(tag.name)}`,\n ...description,\n `<ApiTagOperations source=\"${spec.slug}\" tag=\"${tag.slug}\" />`,\n ].join(\"\\n\\n\")\n );\n }\n const flags: Pick<RenderedPageData, \"ai\" | \"search\"> = {};\n if (reference?.includeInLlms === false) {\n flags.ai = { exclude: true };\n }\n if (reference?.includeInSearch === false) {\n flags.search = { exclude: true };\n }\n const seo: RenderedPageData[\"seo\"] = {\n description:\n clip(plainProse(spec.description), META_DESCRIPTION_MAX) ||\n `${apiPhrase(spec)} reference.`,\n };\n if (reference?.noindex) {\n seo.noindex = true;\n }\n return {\n body: [\n withDescription(\n spec.description,\n `<ApiOverview source=\"${spec.slug}\" />`\n ),\n ...tagSections,\n ].join(\"\\n\\n\"),\n data: {\n ...flags,\n seo,\n sidebar: { label: \"Overview\" },\n title: apiName(spec),\n },\n };\n};\n",
|
|
150
|
+
"import type { Nodes, Root } from \"mdast\";\nimport { fromMarkdown } from \"mdast-util-from-markdown\";\nimport { toString } from \"mdast-util-to-string\";\n\nimport { isSafeHref } from \"./safe-href.ts\";\nimport { escapeMarkdownText } from \"./sources/lower.ts\";\n\n/** A link (or link definition) whose destination isn't safe. */\nexport interface UnsafeLinkSpan {\n /** End offset in the source, exclusive. */\n end: number;\n /** Start offset in the source. */\n start: number;\n /**\n * What replaces it: the link's label, escaped so it can't form a link\n * again; empty for a definition.\n */\n text: string;\n}\n\n/**\n * The unsafe links in a parsed Markdown tree, in source order: inline and\n * reference links (autolinks included) and link definitions whose parsed\n * destination fails {@link isSafeHref}. The parsed `url` is what a browser\n * would get, character references and all, so `javascript:` is caught.\n */\nexport const unsafeLinkSpans = (tree: Root): UnsafeLinkSpan[] => {\n const spans: UnsafeLinkSpan[] = [];\n const visit = (node: Nodes): void => {\n if (\n (node.type === \"link\" || node.type === \"definition\") &&\n !isSafeHref(node.url)\n ) {\n // fromMarkdown stamps every node's position.\n const start = node.position?.start.offset ?? 0;\n const end = node.position?.end.offset ?? 0;\n spans.push({\n end,\n start,\n text: node.type === \"link\" ? escapeMarkdownText(toString(node)) : \"\",\n });\n return;\n }\n if (\"children\" in node) {\n for (const child of node.children) {\n visit(child);\n }\n }\n };\n visit(tree);\n return spans;\n};\n\n/**\n * Markdown with every unsafe link reduced to its label text and every unsafe\n * link definition removed. Everything else — safe links, raw HTML, code —\n * passes through as written.\n */\nexport const neutralizeUnsafeLinks = (markdown: string): string => {\n const spans = unsafeLinkSpans(fromMarkdown(markdown));\n let out = \"\";\n let cursor = 0;\n for (const span of spans) {\n out += markdown.slice(cursor, span.start) + span.text;\n cursor = span.end;\n }\n return out + markdown.slice(cursor);\n};\n",
|
|
151
|
+
"/**\n * Link destinations in content Blume imports from someone else — an API spec's\n * descriptions, a repository's release notes, CMS rich text — that are safe to\n * render as a clickable link. Author-written pages are trusted and never pass\n * through here; imported content can carry a `javascript:` (or `data:`,\n * `vbscript:`) link that would run as the docs site when a reader clicks it.\n * A destination with no scheme (a relative path, a fragment) stays a link, as\n * does one whose scheme is on this list.\n */\nconst SAFE_SCHEMES = new Set([\"http\", \"https\", \"mailto\", \"tel\"]);\n\nconst SCHEME = /^(?<scheme>[a-z][\\d+.a-z-]*):/iu;\n\n// The URL parser removes ASCII tabs and newlines anywhere, and strips leading\n// C0 controls and spaces, before it reads a scheme — so `java\\tscript:` is a\n// `javascript:` URL to a browser, and the check must see it the same way.\nconst URL_IGNORED = /[\\t\\n\\r]/gu;\n\n/** Whether a link destination from imported content is safe to keep. */\nexport const isSafeHref = (href: string): boolean => {\n const cleaned = href.replaceAll(URL_IGNORED, \"\");\n let start = 0;\n while (start < cleaned.length && (cleaned.codePointAt(start) ?? 0) <= 0x20) {\n start += 1;\n }\n const scheme = SCHEME.exec(cleaned.slice(start))?.groups?.scheme;\n return scheme === undefined || SAFE_SCHEMES.has(scheme.toLowerCase());\n};\n",
|
|
152
|
+
"/**\n * Shared primitives for lowering a CMS's rich-text tree to Markdown text.\n * Every rich-text lowerer (Portable Text, Contentful, Lexical, Strapi\n * blocks) renders inline runs, wraps them in block syntax, and joins blocks\n * with blank lines; these helpers keep that Markdown identical across them.\n */\n\nimport { isSafeHref } from \"../safe-href.ts\";\n\n// Markdown/raw-HTML structure characters. Rich-text leaves are *plain text* —\n// formatting arrives as marks, never as syntax in the text — so a literal\n// `*`, `_`, `[`, backtick, `~`, or `<` typed in the CMS must render as\n// itself. Unescaped, it opened emphasis or a code span mid-paragraph, and `<`\n// let CMS prose inject raw HTML into the rendered page. `{` and `}` open an\n// expression once an entry is written as MDX (see {@link writesMdx}). CommonMark\n// backslash-escapes every ASCII punctuation character, so `\\*` is always the\n// literal asterisk, in `.md` and `.mdx` alike.\nconst MARKDOWN_SPECIALS = /[\\\\`*_{}[\\]~<]/gu;\n\n// An entity or numeric character reference (`©`, `&`) is decoded\n// even in plain text, so one typed in the CMS would render as the character\n// it names rather than as written. A bare `&` is left alone.\nconst CHARACTER_REFERENCE = /&(?=#?[a-z0-9]+;)/giu;\n\n// Block syntax is only syntax at the start of a line: `# `, `- `, `+ ` and\n// `1. `/`1) ` need the space (or line end) to become a heading or list item,\n// while `>` opens a quote on its own, and a line of only `=` or `-` turns the\n// line above it into a heading (or, alone, into a rule). A CMS paragraph that\n// begins with one of these — a soft break inside it counts as a line start\n// too — must stay prose.\nconst BLOCK_START =\n /^(?<marker>[#+-]|\\d+[.)])(?=[ \\t]|$)|^(?<quote>>)|^(?<rule>=+|-{2,})(?=[ \\t]*$)/gmu;\n\n// MDX reads a top-level paragraph that opens with `import ` or `export ` as an\n// ESM statement, and prose like \"import the CSV first\" then fails the whole\n// page. The keyword's first letter as a character reference renders the same\n// in `.md` and `.mdx`, and MDX no longer sees the keyword. Only a paragraph's\n// first line counts; a blank line inside a run starts a new paragraph.\nconst ESM_START = /(?<=^|\\n[ \\t]*\\n)(?<keyword>import|export)(?= )/gu;\n\nconst escapeBlockStart = (text: string): string =>\n text.replaceAll(BLOCK_START, (marker: string) => {\n // A numbered marker escapes its punctuation (`1\\.`), the rest themselves.\n const index = marker.search(/[.)]/u);\n return index === -1\n ? `\\\\${marker}`\n : `${marker.slice(0, index)}\\\\${marker.slice(index)}`;\n });\n\nconst escapeEsmStart = (text: string): string =>\n text.replaceAll(\n ESM_START,\n (keyword: string) => `&#${keyword.codePointAt(0)};${keyword.slice(1)}`\n );\n\nexport const escapeMarkdownText = (text: string): string =>\n escapeEsmStart(\n escapeBlockStart(\n text\n .replaceAll(MARKDOWN_SPECIALS, String.raw`\\$&`)\n .replaceAll(CHARACTER_REFERENCE, String.raw`\\&`)\n )\n );\n\n/** The marks a lowerer can put on an inline run. */\nexport interface InlineMarks {\n bold?: boolean;\n code?: boolean;\n italic?: boolean;\n strike?: boolean;\n}\n\nconst BACKTICK_RUN = /`+/gu;\n\n/** The longest run of backticks in `text`, 0 when there is none. */\nconst longestBacktickRun = (text: string): number => {\n let longest = 0;\n for (const run of text.match(BACKTICK_RUN) ?? []) {\n longest = Math.max(longest, run.length);\n }\n return longest;\n};\n\n/**\n * A code span whose delimiter outruns any backtick run inside it, padded with\n * a space on each side when the code starts or ends with a backtick (the\n * CommonMark rule that keeps the padding out of the rendered code).\n */\nexport const codeSpan = (code: string): string => {\n const fence = \"`\".repeat(longestBacktickRun(code) + 1);\n const pad = code.startsWith(\"`\") || code.endsWith(\"`\") ? \" \" : \"\";\n return `${fence}${pad}${code}${pad}${fence}`;\n};\n\nconst EDGE_SPACE = /^(?<lead>\\s*)(?<body>[\\s\\S]*?)(?<trail>\\s*)$/u;\n\n/**\n * Wrap a text run in the Markdown for its marks. Code stays verbatim inside\n * the backticks (an escape would render as a backslash); everything else is\n * escaped first. Whitespace at either edge moves outside the delimiters,\n * since `** bold **` is not strong emphasis but `**bold**` is — editors\n * routinely bold a word together with the space after it.\n */\nexport const renderInline = (text: string, marks: InlineMarks): string => {\n const match = EDGE_SPACE.exec(text);\n const lead = match?.groups?.lead ?? \"\";\n const body = match?.groups?.body ?? \"\";\n const trail = match?.groups?.trail ?? \"\";\n if (body === \"\") {\n return text;\n }\n let out = marks.code ? codeSpan(body) : escapeMarkdownText(body);\n if (marks.bold) {\n out = `**${out}**`;\n }\n if (marks.italic) {\n out = `*${out}*`;\n }\n if (marks.strike) {\n out = `~~${out}~~`;\n }\n return `${lead}${out}${trail}`;\n};\n\n// A destination with whitespace or parentheses ends early in `[label](…)`;\n// CommonMark's pointy-bracket form carries it intact.\nconst UNSAFE_DESTINATION = /[\\s()]/u;\n\n/** A link or image destination as Markdown can carry it verbatim. */\nexport const destination = (url: string): string =>\n UNSAFE_DESTINATION.test(url) ? `<${url}>` : url;\n\n/**\n * A Markdown link, or the label alone when the target is missing — or unsafe:\n * CMS content is the editor's, not the site author's, so a destination that\n * isn't a web, mail, or relative address (`javascript:`, `data:`) never\n * becomes a clickable link on the docs site (see `safe-links.ts`).\n */\nexport const renderLink = (label: string, href?: string): string =>\n href && isSafeHref(href) ? `[${label}](${destination(href)})` : label;\n\n/** The ATX prefix for a heading level, clamped to Markdown's six. */\nexport const headingPrefix = (level: number): string =>\n `${\"#\".repeat(Math.min(Math.max(Math.trunc(level), 1), 6))} `;\n\n/** Quote every line of a block. */\nexport const blockquote = (text: string): string =>\n text\n .split(\"\\n\")\n .map((line) => (line === \"\" ? \">\" : `> ${line}`))\n .join(\"\\n\");\n\n/**\n * A list item: the marker on the first line, and every continuation line\n * indented to the marker's width so nested blocks stay inside the item.\n */\nexport const listItem = (marker: string, body: string): string => {\n const [first = \"\", ...rest] = body.split(\"\\n\");\n const pad = \" \".repeat(marker.length + 1);\n return [\n `${marker} ${first}`,\n ...rest.map((line) => (line === \"\" ? \"\" : `${pad}${line}`)),\n ].join(\"\\n\");\n};\n\n/** Indent every non-empty line, for a nested list hanging off an item. */\nexport const indent = (text: string, width: number): string => {\n const pad = \" \".repeat(width);\n return text\n .split(\"\\n\")\n .map((line) => (line === \"\" ? \"\" : `${pad}${line}`))\n .join(\"\\n\");\n};\n\n/** A fenced code block whose fence outruns any backtick run in the code. */\nexport const codeFence = (code: string, language = \"\"): string => {\n const fence = \"`\".repeat(Math.max(3, longestBacktickRun(code) + 1));\n return `${fence}${language}\\n${code}\\n${fence}`;\n};\n\n/** A Markdown image; the alt is escaped so a `]` in a caption can't close it. */\nexport const image = (alt: string, url: string): string =>\n `})`;\n\n/**\n * Whether a lowerer's output is written as MDX. Serializers are how a CMS\n * block becomes a Blume component, and components (like directives) only\n * render in MDX, so configuring any serializer switches the source's\n * rich-text bodies to `.mdx`. The escaping above keeps the rest of the\n * lowered text valid there.\n */\nexport const writesMdx = <Node>(\n serializers?: Record<string, (node: Node) => string>\n): boolean => serializers !== undefined && Object.keys(serializers).length > 0;\n\n/**\n * A comment marking a node the lowerer has no Markdown for — an MDX comment\n * when the output is MDX, which rejects `<!-- -->`.\n */\nexport const unsupported = (what: string, mdx = false): string =>\n mdx ? `{/* unsupported ${what} */}` : `<!-- unsupported ${what} -->`;\n\n/** Blocks separated by blank lines; empty blocks are dropped. */\nexport const joinBlocks = (blocks: string[]): string =>\n blocks.filter((block) => block !== \"\").join(\"\\n\\n\");\n\n/** A whole document: its blocks plus the trailing newline a file ends with. */\nexport const markdownDocument = (blocks: string[]): string =>\n `${joinBlocks(blocks)}\\n`;\n\nconst ABSOLUTE = /^[a-z][a-z0-9+.-]*:/iu;\n\n/**\n * A media URL as a static site can reference it. A protocol-relative\n * Contentful asset (`//images.ctfassets.net/…`) gets `https:`; a path a\n * self-hosted CMS serves (`/uploads/x.png`) resolves against the CMS origin.\n */\nexport const absoluteUrl = (url: string, base?: string): string => {\n if (url.startsWith(\"//\")) {\n return `https:${url}`;\n }\n if (ABSOLUTE.test(url) || base === undefined) {\n return url;\n }\n return new URL(url, base).href;\n};\n",
|
|
153
|
+
"import stringWidth from \"string-width\";\n\n/**\n * The longest prefix of `text` that renders within `max` display columns\n * without cutting inside a grapheme cluster. Columns are `string-width`'s: a\n * fullwidth or wide character counts 2, a combining mark 0, everything else 1\n * — the same measure `blume audit` grades titles and meta descriptions with,\n * so text cut here stays inside the audit's thresholds for every script, not\n * just Latin. Grapheme segmentation is rule-based (UAX #29), so unlike word\n * segmentation it does not drift across ICU builds, and it can never split a\n * surrogate pair or halve an emoji sequence.\n */\nexport const columnsPrefix = (text: string, max: number): string => {\n let end = 0;\n let used = 0;\n const graphemes = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n for (const { index, segment } of graphemes.segment(text)) {\n const width = stringWidth(segment);\n if (used + width > max) {\n break;\n }\n used += width;\n end = index + segment.length;\n }\n return text.slice(0, end);\n};\n",
|
|
154
|
+
"/**\n * A sentence's closing punctuation, allowing trailing closing quotes or\n * brackets (`…done.\")`) and the CJK full-width marks.\n */\nconst TERMINAL_PUNCTUATION = /[.!?…。!?][\"'”’)\\]]*$/u;\n\n/**\n * Close a fragment of spec prose as a sentence. OpenAPI `summary` values are\n * usually title-like (\"Get a flag\", no period), so prose that runs straight\n * into the next generated sentence (\"Get a flag Reference for …\") needs one.\n * Empty text stays empty.\n */\nexport const asSentence = (text: string): string =>\n text === \"\" || TERMINAL_PUNCTUATION.test(text) ? text : `${text}.`;\n",
|
|
155
|
+
"import { graphqlSignature } from \"./graphql.ts\";\nimport type { ApiOperationRef, ApiSpecData } from \"./model.ts\";\n\n/**\n * The one-line name of what an operation page documents, in the notation of\n * its spec kind: `GET /pets/{id}` for an HTTP endpoint, `SEND user/signup`\n * for an AsyncAPI channel action, `query pets` or `type Pet` for a GraphQL\n * member. The page titles an untitled operation with it and the agent\n * surfaces (`<route>.md`, llms-full.txt, MCP `get_page`) downlevel\n * `<Operation>` to it, so the two can never disagree about the endpoint.\n */\nexport const operationSignature = (\n spec: Pick<ApiSpecData, \"kind\">,\n operation: Pick<ApiOperationRef, \"method\" | \"path\">\n): string =>\n spec.kind === \"graphql\"\n ? graphqlSignature(operation)\n : `${operation.method.toUpperCase()} ${operation.path}`;\n",
|
|
156
|
+
"import { withBasePath } from \"../core/base-path.ts\";\nimport matter from \"../core/frontmatter.ts\";\nimport type { FolderMeta } from \"../core/schema.ts\";\nimport { hashText } from \"../core/sources/cache.ts\";\nimport type {\n ContentSource,\n SourceContext,\n SourceEntry,\n SourceLoadResult,\n} from \"../core/sources/types.ts\";\nimport type { Diagnostic } from \"../core/types.ts\";\nimport { extractAsyncApiOperations } from \"./asyncapi.ts\";\nimport type { AsyncApiDocument } from \"./asyncapi.ts\";\nimport { extractGraphqlOperations } from \"./graphql.ts\";\nimport type { GraphqlDocument } from \"./graphql.ts\";\nimport { extractOperations } from \"./model.ts\";\nimport type {\n ApiDocument,\n ApiOperationRef,\n ApiSpecData,\n ApiTagRef,\n OpenApiData,\n} from \"./model.ts\";\nimport {\n InvalidSpecError,\n parseAsyncApiSpec,\n parseGraphqlSpec,\n parseSpec,\n} from \"./parse.ts\";\nimport type { BlumeReferenceSource } from \"./references.ts\";\nimport { operationMdx, overviewMdx } from \"./render-mdx.ts\";\nimport type { RenderedPage } from \"./render-mdx.ts\";\nimport { SpecDependencyError } from \"./spec-dependency-error.ts\";\n\n/**\n * The staged content source behind Blume's own API reference renderer (OpenAPI\n * and AsyncAPI alike). Each configured spec is parsed once here, then lowered\n * into one MDX page per operation plus an overview page — so operations become\n * first-class Blume pages (real routes, sidebar, search, i18n, OG) and the\n * parsed documents are handed to the generated `blume:openapi` module for the\n * UI components to render. The source keeps its historical `openapi` name for\n * both kinds — downstream consumers (`agents.llmsTxt.openapi`, the llms noindex\n * exemption) key on it as \"the generated API reference source\".\n */\n\n/** A content source that also exposes the specs it parsed during `load()`. */\nexport interface OpenApiContentSource extends ContentSource {\n readonly kind: \"openapi-source\";\n /** Parsed spec data, populated by `load()`; `{}` before the first load. */\n openApiData: () => OpenApiData;\n}\n\n/** Narrow a content source to the OpenAPI source (to read its parsed specs). */\nexport const isOpenApiSource = (\n source: ContentSource\n): source is OpenApiContentSource =>\n \"kind\" in source && source.kind === \"openapi-source\";\n\n/** Route (`/reference/pet/add-pet`) to a staged content ref, without extension. */\nconst routeToRef = (route: string): string => route.replace(/^\\/+/u, \"\");\n\n/** Human label per spec kind, so one kind's failure never reads as another's. */\nconst KIND_LABELS = {\n asyncapi: \"AsyncAPI\",\n graphql: \"GraphQL\",\n openapi: \"OpenAPI\",\n} satisfies Record<BlumeReferenceSource[\"kind\"], string>;\n\n/** Diagnostic-code prefix per spec kind. */\nconst CODE_PREFIXES = {\n asyncapi: \"BLUME_ASYNCAPI\",\n graphql: \"BLUME_GRAPHQL\",\n openapi: \"BLUME_OPENAPI\",\n} satisfies Record<BlumeReferenceSource[\"kind\"], string>;\n\n/**\n * Parse-level warning code per kind: an offline cache fallback for any kind,\n * plus lossy 2.x→3.0 conversion notes for AsyncAPI — hence the broader codes\n * there and for GraphQL (OpenAPI keeps its historical one).\n */\nconst SPEC_WARNING_CODES = {\n asyncapi: \"BLUME_ASYNCAPI_SPEC_WARNING\",\n graphql: \"BLUME_GRAPHQL_SPEC_WARNING\",\n openapi: \"BLUME_OPENAPI_STALE\",\n} satisfies Record<BlumeReferenceSource[\"kind\"], string>;\n\n/**\n * Extract-level skip code per kind. OpenAPI keeps its historical code (the\n * only extract warning it emits is the unresolved $ref path item); the\n * GraphQL extractor currently skips nothing, so its code is reserved.\n */\nconst SKIPPED_CODES = {\n asyncapi: \"BLUME_ASYNCAPI_SKIPPED_OPERATION\",\n graphql: \"BLUME_GRAPHQL_SKIPPED\",\n openapi: \"BLUME_OPENAPI_REF_PATH_ITEM\",\n} satisfies Record<BlumeReferenceSource[\"kind\"], string>;\n\n/** `_EMPTY` diagnostic suggestion per kind. */\nconst EMPTY_SUGGESTIONS = {\n asyncapi:\n \"Check the spec points at an AsyncAPI document with `channels` and `operations`.\",\n graphql:\n \"Check the spec points at a GraphQL schema (SDL or introspection JSON) whose root types declare fields.\",\n openapi:\n \"Check the spec points at an OpenAPI document with operations under `paths`.\",\n} satisfies Record<BlumeReferenceSource[\"kind\"], string>;\n\n/** `_UNAVAILABLE` suggestion for a readable-but-invalid spec, per kind. */\nconst INVALID_SUGGESTIONS = {\n asyncapi:\n \"Point the spec at an AsyncAPI document (a YAML or JSON file with an object at the top level).\",\n graphql:\n \"Point the spec at a GraphQL schema — SDL text or an introspection JSON result.\",\n openapi:\n \"Point the spec at an OpenAPI document (a YAML or JSON file with an object at the top level).\",\n} satisfies Record<BlumeReferenceSource[\"kind\"], string>;\n\n/**\n * What to suggest for a spec that failed to load: the install command when\n * reading it needs a package the project lacks, a fix to the file when it\n * isn't a spec of its kind, and reachability for everything else (a fetch or\n * read failure).\n */\nconst failureSuggestion = (\n error: Error,\n kind: BlumeReferenceSource[\"kind\"]\n): string => {\n if (error instanceof SpecDependencyError) {\n return error.suggestion;\n }\n if (error instanceof InvalidSpecError) {\n return INVALID_SUGGESTIONS[kind];\n }\n return \"Check the spec URL/path is reachable from the build environment; behind a proxy, set HTTP(S)_PROXY.\";\n};\n\nconst toEntry = (rendered: RenderedPage, ref: string): SourceEntry => {\n const raw = matter.stringify(`${rendered.body}\\n`, rendered.data);\n return {\n body: { format: \"mdx\", text: rendered.body },\n // Spread so the named frontmatter shape satisfies the open metadata\n // dictionary every source entry carries.\n data: { ...rendered.data },\n hash: hashText(raw),\n raw,\n ref,\n };\n};\n\n/** All staged entries for one spec: operations first, overview last. */\nconst specEntries = (\n spec: ApiSpecData,\n operations: ApiOperationRef[],\n reference: BlumeReferenceSource\n): SourceEntry[] => {\n const entries = operations.map((operation) =>\n toEntry(\n operationMdx(spec, operation, reference),\n `${routeToRef(operation.route)}.mdx`\n )\n );\n // Overview last so an operation sets the section's routePath before the index\n // page is inserted (the group's routePath is derived from its first child).\n // A root-mounted reference refs `index.mdx`, not `/index.mdx`.\n const base = routeToRef(spec.route);\n entries.push(\n toEntry(\n overviewMdx(spec, reference),\n base ? `${base}/index.mdx` : \"index.mdx\"\n )\n );\n return entries;\n};\n\n/**\n * Label each tag's sidebar group with the spec's own tag name. The group label\n * is otherwise re-humanized from the tag's route slug (split on hyphens,\n * title-cased), which mangles authored casing and symbols — `OAuth2` →\n * \"Oauth2\", `Größe` → \"Größe\" only by luck of the slug. Keys are the tag\n * directories under the reference route, the same group paths `meta.ts` files\n * use, so user-authored meta still overrides these.\n */\nconst tagFolderMeta = (\n spec: ApiSpecData,\n tags: { slug: string; name: string }[]\n): Record<string, FolderMeta> => {\n const base = routeToRef(spec.route);\n return Object.fromEntries(\n tags.map((tag) => [\n base ? `${base}/${tag.slug}` : tag.slug,\n { title: tag.name },\n ])\n );\n};\n\ninterface LoadedSpec {\n slug: string;\n spec: ApiSpecData;\n entries: SourceEntry[];\n /** Sidebar-group labels for the spec's tag directories. */\n folderMeta: Record<string, FolderMeta>;\n /** Non-fatal notes from the load (e.g. an offline cache fallback). */\n diagnostics: Diagnostic[];\n}\n\n/** One parsed spec, whichever front-end read it — the kind dispatch seam. */\ninterface ParsedReference {\n document: ApiDocument | AsyncApiDocument | GraphqlDocument;\n warnings: string[];\n operations: ApiOperationRef[];\n tags: ApiTagRef[];\n extractWarnings: string[];\n}\n\nconst parseReference = async (\n reference: BlumeReferenceSource,\n ctx: SourceContext\n): Promise<ParsedReference> => {\n const options = { cacheDir: ctx.cacheDir, refresh: ctx.refresh };\n if (reference.kind === \"asyncapi\") {\n const { document, warnings } = await parseAsyncApiSpec(\n reference.spec,\n ctx.projectRoot,\n options\n );\n const extracted = extractAsyncApiOperations(document, reference.route);\n return {\n document,\n extractWarnings: extracted.warnings,\n operations: extracted.operations,\n tags: extracted.tags,\n warnings,\n };\n }\n if (reference.kind === \"graphql\") {\n const { document, warnings } = await parseGraphqlSpec(\n reference.spec,\n ctx.projectRoot,\n options\n );\n const extracted = extractGraphqlOperations(document, reference.route);\n return {\n document,\n extractWarnings: extracted.warnings,\n operations: extracted.operations,\n tags: extracted.tags,\n warnings,\n };\n }\n const { document, warnings } = await parseSpec(\n reference.spec,\n ctx.projectRoot,\n options\n );\n const extracted = extractOperations(document, reference.route);\n return {\n document,\n extractWarnings: extracted.warnings,\n operations: extracted.operations,\n tags: extracted.tags,\n warnings,\n };\n};\n\nexport const openApiSource = (\n references: BlumeReferenceSource[],\n ctx: SourceContext\n): OpenApiContentSource => {\n let parsed: OpenApiData = {};\n\n const loadReference = async (\n reference: BlumeReferenceSource\n ): Promise<LoadedSpec | Diagnostic> => {\n // Human label and diagnostic-code prefix for the spec's kind, so an\n // AsyncAPI failure never reads as an OpenAPI one.\n const kindLabel = KIND_LABELS[reference.kind];\n const codePrefix = CODE_PREFIXES[reference.kind];\n try {\n const { document, warnings, operations, tags, extractWarnings } =\n await parseReference(reference, ctx);\n const info = document.info ?? { title: reference.label, version: \"\" };\n // The playground proxy resolves here, not client-side: `true` selects\n // the built-in `/_api-proxy` route (mounted under the site `basePath`,\n // like every served URL this module emits), a non-empty string is an\n // external proxy used verbatim, and anything else (`false`, `\"\"`)\n // means the Send button fetches the API directly.\n const { proxy: configuredProxy } = reference.display.playground;\n let proxy: string | false = false;\n if (configuredProxy === true) {\n proxy = withBasePath(reference.basePath, \"/_api-proxy\");\n } else if (configuredProxy !== false && configuredProxy !== \"\") {\n proxy = configuredProxy;\n }\n const spec: ApiSpecData = {\n codeSamples: reference.display.codeSamples,\n description: info.description ?? \"\",\n document,\n expandSchemas: reference.display.expandSchemas,\n kind: reference.kind,\n label: reference.label,\n // Operation pages flow through the content pipeline, which mounts them\n // under the site-wide `basePath` (staged entry refs below stay\n // base-less); serialize the served route so components link to the\n // pages' real URLs.\n operations: Object.fromEntries(\n operations.map((operation) => [\n operation.key,\n {\n ...operation,\n route: withBasePath(reference.basePath, operation.route),\n },\n ])\n ),\n playground: { enabled: reference.display.playground.enabled, proxy },\n route: reference.route,\n slug: reference.slug,\n tags,\n title: info.title ?? reference.label,\n version: info.version ?? \"\",\n };\n // Only GraphQL references carry a live endpoint (a schema names no\n // server); assigned separately so the key stays absent otherwise.\n if (reference.endpoint !== undefined) {\n spec.endpoint = reference.endpoint;\n }\n return {\n diagnostics: [\n ...warnings.map((message) => ({\n code: SPEC_WARNING_CODES[reference.kind],\n message,\n severity: \"warning\" as const,\n })),\n ...extractWarnings.map((message) => ({\n code: SKIPPED_CODES[reference.kind],\n message: `In ${kindLabel} spec \"${reference.spec}\": ${message}`,\n severity: \"warning\" as const,\n })),\n // A document with no operations (say, a config file that happens to\n // parse as YAML) would otherwise build a nav tab onto an empty\n // reference with no hint why.\n ...(operations.length === 0\n ? [\n {\n code: `${codePrefix}_EMPTY`,\n message: `${kindLabel} spec \"${reference.spec}\" for ${reference.route} declares no operations; its API reference is empty.`,\n severity: \"warning\" as const,\n suggestion: EMPTY_SUGGESTIONS[reference.kind],\n },\n ]\n : []),\n ],\n entries: specEntries(spec, operations, reference),\n folderMeta: tagFolderMeta(spec, tags),\n slug: reference.slug,\n spec,\n };\n } catch (error) {\n // SAFETY: spec loading fails with Error instances (fetch, read, parse,\n // and missing-package errors alike).\n const failure = error as Error;\n return {\n code: `${codePrefix}_UNAVAILABLE`,\n message: `Could not load ${kindLabel} spec \"${reference.spec}\" for ${reference.route} (${failure.message}); its reference pages were skipped.`,\n // A configured-but-unloadable spec ships a dead nav tab (a 404 route),\n // so fail loudly in build (blocks under --strict) while staying a warning\n // in dev so offline work still runs.\n severity: ctx.mode === \"build\" ? \"error\" : \"warning\",\n suggestion: failureSuggestion(failure, reference.kind),\n };\n }\n };\n\n const load = async (): Promise<SourceLoadResult> => {\n const results = await Promise.all(references.map(loadReference));\n const entries: SourceEntry[] = [];\n // Route collisions recorded while deduping (see `blumeReferences`): a\n // dropped source loses a whole spec's pages, so warn even when the kept\n // spec loads cleanly.\n const diagnostics: Diagnostic[] = references.flatMap((reference) =>\n (reference.collisions ?? []).map((message) => ({\n code: \"BLUME_OPENAPI_ROUTE_COLLISION\",\n message,\n severity: \"warning\" as const,\n }))\n );\n const data: OpenApiData = {};\n const folderMeta: Record<string, FolderMeta> = {};\n for (const result of results) {\n if (\"severity\" in result) {\n diagnostics.push(result);\n continue;\n }\n data[result.slug] = result.spec;\n entries.push(...result.entries);\n Object.assign(folderMeta, result.folderMeta);\n diagnostics.push(...result.diagnostics);\n }\n parsed = data;\n return { diagnostics, entries, folderMeta };\n };\n\n return {\n kind: \"openapi-source\",\n load,\n name: \"openapi\",\n openApiData: () => parsed,\n staged: true,\n };\n};\n",
|
|
157
|
+
"import type { ApiOperationRef, OpenApiData } from \"../openapi/model.ts\";\nimport { operationOf, specAddresses, specOf } from \"../openapi/model.ts\";\nimport { asSentence } from \"../openapi/sentence.ts\";\nimport { operationSignature } from \"../openapi/signature.ts\";\nimport type {\n ComponentMarkdown,\n EvaluatedValue,\n} from \"./component-markdown.ts\";\nimport { inlineCode, isString, linkDestination } from \"./component-markdown.ts\";\n\n/**\n * Spec-authored prose as one line of inline Markdown. Unlike the props the\n * other serializers pass through, a summary is written by whoever wrote the\n * spec, not by the docs author, so the characters CommonMark would read as\n * markup — `<user>` as inline HTML, `*only*` as emphasis — are escaped.\n */\nconst inlineText = (text: string): string =>\n text\n .trim()\n .replaceAll(/\\s+/gu, \" \")\n .replaceAll(/[\\\\`*_[\\]<>~]/gu, String.raw`\\$&`);\n\n/** One operation as a link, for the tag listings. */\nconst listItem = (\n signature: string,\n operation: Pick<ApiOperationRef, \"deprecated\" | \"route\" | \"summary\">\n): string => {\n const tail = [\n // Title-like summaries (\"Get a flag\") need their own period before the\n // \"Deprecated.\" that may follow.\n inlineText(asSentence(operation.summary.trim())),\n operation.deprecated ? \"Deprecated.\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n return `- [${inlineCode(signature)}](${linkDestination(operation.route)})${tail ? ` — ${tail}` : \"\"}`;\n};\n\n/**\n * Agent-facing Markdown for the components a generated reference page is made\n * of: `<Operation>`, `<ApiTagOperations>` and `<ApiOverview>`.\n *\n * `render-mdx.ts` builds each reference page as the operation's description in\n * the body plus one of these components, deliberately: the structured UI is the\n * component's job, and the prose stays Markdown so it indexes. That split is\n * right for the rendered page and lossy everywhere else — `<route>.md`,\n * llms-full.txt, MCP `get_page` and the Ask AI corpus all downlevel components\n * to Markdown, and these three had no serializer, so an operation page reached\n * an agent as its description followed by a bare tag. On a site whose reference\n * is most of the corpus, that is most of the corpus: measured on one 449-page\n * site, 266 pages and 266 raw `<Operation>` in llms-full.txt, so \"which\n * endpoint do I call?\" had no answer anywhere in the agent surface.\n *\n * Each serializer emits what its component renders and no more: the endpoint\n * in the spec kind's own notation ({@link operationSignature}), the version and\n * addresses the overview shows ({@link specAddresses}), the linked list a tag\n * section shows. Parameters, schemas and responses are deliberately left out:\n * those are `operation-model.ts` plus each component's own preparation, and a\n * second implementation here would be free to disagree with the page. The\n * endpoint and what it does is the part that was missing altogether.\n *\n * `specs` is the parsed `blume:openapi` data — empty when the project has no\n * API reference, in which case every serializer declines.\n */\nexport const openapiComponentSerializers = (specs: OpenApiData) => {\n const spec = (source: EvaluatedValue) =>\n isString(source) ? specOf(specs, source) : undefined;\n\n return {\n /**\n * The spec-level block at the top of the overview page: its version and\n * where the API lives. The tag sections that follow are real Markdown\n * headings over `<ApiTagOperations>`, so they downlevel on their own.\n */\n ApiOverview: ({ props }) => {\n const data = spec(props.source);\n if (!data) {\n return null;\n }\n const { addresses, label } = specAddresses(data);\n const lines = [\n data.version ? `Version ${inlineText(data.version)}` : \"\",\n addresses.length > 0\n ? `${label}: ${addresses.map(inlineCode).join(\", \")}`\n : \"\",\n ].filter(Boolean);\n return lines.length > 0 ? lines.join(\"\\n\\n\") : null;\n },\n\n /** One tag's operations, mirroring the list the rendered page shows. */\n ApiTagOperations: ({ props }) => {\n const { tag } = props;\n const data = spec(props.source);\n if (!(data && isString(tag))) {\n return null;\n }\n const items = Object.values(data.operations)\n .filter((operation) => operation.tagSlug === tag)\n .map((operation) =>\n listItem(operationSignature(data, operation), operation)\n );\n return items.length > 0 ? items.join(\"\\n\") : null;\n },\n\n /**\n * One operation. Declines when the spec carries no such key — Blume's own\n * fallback, which leaves the JSX visible rather than publishing a page that\n * silently lost its endpoint.\n */\n Operation: ({ props }) => {\n const { id } = props;\n const data = spec(props.source);\n if (!(data && isString(id))) {\n return null;\n }\n const operation = operationOf(data, id);\n if (!operation) {\n return null;\n }\n const signature = inlineCode(operationSignature(data, operation));\n return operation.deprecated\n ? `${signature}\\n\\n**Deprecated.**`\n : signature;\n },\n } satisfies Record<string, ComponentMarkdown>;\n};\n",
|
|
158
|
+
"import type { BlumeProject } from \"../core/project-graph.ts\";\nimport { isOpenApiSource } from \"../openapi/source.ts\";\nimport type { ComponentMarkdown } from \"./component-markdown.ts\";\nimport { exampleComponentSerializers } from \"./component-markdown.ts\";\nimport { openapiComponentSerializers } from \"./openapi-components.ts\";\n\n/**\n * Every serializer a project brings to a downlevel pass, layered once for all\n * the agent surfaces (`<route>.md`, llms-full.txt, the search and Ask AI\n * corpora): the built-in families that read project data — examples, then the\n * API reference — under the user's `agents.markdownComponents`, which is spread\n * last so an entry of the same name still wins. One layering, so a new family\n * or a new surface cannot leave one consumer printing raw JSX.\n */\nexport const projectComponentSerializers = (\n project: Pick<BlumeProject, \"config\" | \"examples\" | \"sources\">\n) =>\n ({\n ...exampleComponentSerializers(project.examples ?? {}),\n ...openapiComponentSerializers(\n project.sources.find(isOpenApiSource)?.openApiData() ?? {}\n ),\n ...project.config.agents.markdownComponents,\n }) satisfies Record<string, ComponentMarkdown>;\n",
|
|
159
|
+
"// Mirrors the fence masking in `core/sources/assets.ts`: a fenced code sample\n// that *shows* `<Visibility>` markup must keep showing what the author wrote.\nconst CODE_FENCE_BLOCK =\n /^(?<fence>`{3,}|~{3,})[^\\n]*\\n[\\s\\S]*?^\\k<fence>[^\\n]*(?=\\n|$)/gmu;\n// NUL delimiters cannot appear in authored markdown, so tokens never collide.\n// oxlint-disable-next-line no-control-regex -- the NUL is the collision guard.\nconst FENCE_TOKEN = /\\u0000blume-fence-(?<index>\\d+)\\u0000/gu;\n\n/** The audience an output surface serves — the component's two `for` values. */\nexport type VisibilityAudience = \"agents\" | \"web\";\n\n// `<Visibility for=\"…\">…</Visibility>` in either quote style, tolerant of\n// whitespace around the attribute and inside the tags. Non-greedy bodies stop\n// at the first close tag, so nesting is not supported: a nested block closes\n// the outer match early and any remainder passes through verbatim.\nconst visibilityBlock = (audience: VisibilityAudience): RegExp =>\n new RegExp(\n `<Visibility\\\\s+for\\\\s*=\\\\s*(?:\"${audience}\"|'${audience}')\\\\s*>(?<inner>[\\\\s\\\\S]*?)</Visibility\\\\s*>`,\n \"gu\"\n );\n\nconst BLOCKS = {\n agents: visibilityBlock(\"agents\"),\n web: visibilityBlock(\"web\"),\n} satisfies Record<VisibilityAudience, RegExp>;\n\n/**\n * Resolve `<Visibility>` blocks for one audience: blocks addressed to the\n * other audience are removed entirely and blocks addressed to `audience` are\n * unwrapped (tags dropped, body kept), matching what the Astro component\n * renders on the web. Other `for` values (the component's default) are left\n * untouched, and markdown with no matching blocks is returned byte-identical,\n * so raw sources stay raw.\n */\nexport const applyAudienceVisibility = (\n markdown: string,\n audience: VisibilityAudience\n): string => {\n // Mask fenced code blocks so documentation *about* Visibility survives.\n const fences: string[] = [];\n const masked = markdown.replace(CODE_FENCE_BLOCK, (block) => {\n fences.push(block);\n return `\\u0000blume-fence-${fences.length - 1}\\u0000`;\n });\n\n let touched = false;\n const filtered = masked\n .replaceAll(BLOCKS[audience === \"agents\" ? \"web\" : \"agents\"], () => {\n touched = true;\n return \"\";\n })\n .replaceAll(BLOCKS[audience], (_match, inner: string) => {\n touched = true;\n return inner;\n });\n\n // Removing/unwrapping block-level tags leaves runs of blank lines behind;\n // collapse them only when something matched so untouched files round-trip\n // exactly. Fences are masked as single-line tokens, so they are unaffected.\n const tidied = touched ? filtered.replaceAll(/\\n{3,}/gu, \"\\n\\n\") : filtered;\n\n return tidied.replaceAll(\n FENCE_TOKEN,\n (token, index) => fences[Number(index)] ?? token\n );\n};\n\n/**\n * Resolve `<Visibility>` blocks for agent-facing Markdown (llms-full.txt, the\n * `.md`/`.mdx` mirrors, MCP tools, Ask AI grounding): `for=\"web\"` content is\n * removed and `for=\"agents\"` content is unwrapped.\n */\nexport const applyAgentVisibility = (markdown: string): string =>\n applyAudienceVisibility(markdown, \"agents\");\n",
|
|
160
|
+
"import { normalizeBasePath, withBasePath } from \"../core/base-path.ts\";\nimport { rewriteRelativeImages } from \"../core/content-assets.ts\";\nimport matter from \"../core/frontmatter.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\nimport { readExpandedEntryText } from \"../core/sources/read.ts\";\nimport type { NavNode, Navigation, PageRecord } from \"../core/types.ts\";\nimport { buildRssFeeds } from \"../deploy/rss.ts\";\nimport { AI_CATALOG_PATH, hasAiCatalog } from \"./ai-catalog.ts\";\nimport { API_CATALOG_PATH, hasApiCatalog } from \"./api-catalog.ts\";\nimport { API_PAGES_PATH, OPENAPI_PATH } from \"./api/paths.ts\";\nimport { downlevelComponents } from \"./component-markdown.ts\";\nimport { relativeLinkRewriter } from \"./relative-links.ts\";\nimport { projectComponentSerializers } from \"./serializers.ts\";\nimport { AGENT_SKILLS_DIR, AGENT_SKILLS_INDEX_PATH } from \"./skills.ts\";\nimport type { SkillArtifact } from \"./skills.ts\";\nimport { applyAgentVisibility } from \"./visibility.ts\";\n\n// Routes carry `basePath`; a `deployment.base` subdirectory is layered on top —\n// with or without a `site` (the mcp.json convention) — so the emitted URL\n// matches where the page is served. Encoded like the sitemap: a route with\n// spaces or non-ASCII must still yield a valid Markdown link.\nconst pageUrl = (route: string, site?: string, base = \"\"): string => {\n const path = withBasePath(base, route);\n return encodeURI(site ? absoluteUrl(site, path) : path);\n};\n\n/** Inputs only the build has: the published skills, collected once per build. */\nexport interface LlmsIndexOptions {\n /**\n * The Agent Skills the build publishes under `/.well-known/agent-skills/`,\n * listed in their own section with each skill's description — which is\n * where a skill says when to use it. Absent (empty) for the homepage\n * Markdown mirror, which is synthesized before the skills are collected.\n */\n skills?: readonly SkillArtifact[];\n}\n\n/** A skill description on one line — SKILL.md frontmatter may wrap it. */\nconst oneLine = (text: string): string => text.replaceAll(/\\s+/gu, \" \").trim();\n\n/**\n * The \"Agent resources\" section: every machine-readable artifact the site\n * publishes, so an agent that only reads llms.txt still finds the full\n * Markdown dump, the per-page Markdown mirrors, the JSON docs API, the MCP\n * server, the skills index, the API catalog, the readability manifest, and\n * the sitemap. The\n * same artifact set `agent-readability.json` indexes, in prose an agent can\n * act on without a second fetch.\n */\nconst agentResourceLines = (project: BlumeProject): string[] => {\n const { config } = project;\n const { site } = config.deployment.options;\n const url = (path: string): string =>\n pageUrl(path, site, normalizeBasePath(config.deployment.options.base));\n const lines = [\n `- [llms-full.txt](${url(\"/llms-full.txt\")}): The full Markdown of every page in one file.`,\n `- [Page Markdown](${url(\"/index.md\")}): Append \\`.md\\` to any page URL to fetch that page as raw Markdown.`,\n ];\n if (config.agents.api) {\n lines.push(\n `- [JSON API](${url(API_PAGES_PATH)}): Page index of the JSON docs API; each entry links the page's JSON and Markdown forms. Described by the OpenAPI document at ${url(OPENAPI_PATH)}.`\n );\n }\n if (config.agents.mcp.enabled) {\n lines.push(\n `- [MCP server](${url(config.agents.mcp.route)}): Streamable HTTP Model Context Protocol server with search_docs, get_page, list_pages, and get_navigation tools, plus every page as a resource. Discovery document: ${url(\"/.well-known/mcp.json\")}`\n );\n }\n if (config.agents.skills) {\n lines.push(\n `- [Agent skills](${url(AGENT_SKILLS_INDEX_PATH)}): Agent Skills discovery index of the skills this site publishes.`\n );\n }\n if (hasApiCatalog(config)) {\n lines.push(\n `- [API catalog](${url(API_CATALOG_PATH)}): RFC 9727 linkset of the APIs documented here.`\n );\n }\n if (hasAiCatalog(config)) {\n lines.push(\n `- [AI catalog](${url(AI_CATALOG_PATH)}): ARD manifest of the agent-facing resources on this site (MCP server, skills, APIs).`\n );\n }\n if (config.agents.agentReadability) {\n lines.push(\n `- [agent-readability.json](${url(\"/agent-readability.json\")}): Manifest of every agent-facing artifact on this site.`\n );\n }\n if (site && config.seo.sitemap) {\n lines.push(\n `- [Sitemap](${url(\"/sitemap.xml\")}): Every indexable page URL with its last-modified date.`\n );\n }\n return lines;\n};\n\n// Drafts, hidden, and ordinary `noindex` pages are excluded. Generated API\n// references keep crawler visibility (`noindex`) separate from LLM visibility\n// (`ai.exclude`), and are excluded wholesale when `agents.llmsTxt.openapi` is off.\n// `versions: \"current\"` additionally drops archived-snapshot pages — the flat\n// llms-full.txt dump serves agents the live docs, not every frozen copy.\nconst eligiblePages = (\n project: BlumeProject,\n options: { versions?: \"all\" | \"current\" } = {}\n): PageRecord[] =>\n project.graph.pages.filter(\n (page) =>\n !(\n page.meta.ai.exclude ||\n page.meta.draft ||\n page.meta.sidebar.hidden ||\n (page.meta.seo.noindex && page.source.name !== \"openapi\") ||\n (options.versions === \"current\" && page.version !== \"\")\n ) &&\n (project.config.agents.llmsTxt.openapi || page.source.name !== \"openapi\")\n );\n\n/**\n * The navigation trees the index mirrors: the site tree, or one per locale\n * under i18n (each labeled with the locale except the default, so sections\n * don't repeat ambiguously). On a versioned site each archived snapshot's\n * trees follow the current ones, labeled with the version (and locale) so an\n * agent reading the index knows which docs are frozen.\n */\nconst indexedNavigations = (\n project: BlumeProject\n): { label?: string; nav: Navigation }[] => {\n const { i18n, versions } = project.config;\n const current: { label?: string; nav: Navigation }[] = i18n\n ? i18n.locales.flatMap(({ code, label }) => {\n const nav = project.graph.navigationByLocale[code];\n if (!nav) {\n return [];\n }\n return [\n { label: code === i18n.defaultLocale ? undefined : label, nav },\n ];\n })\n : [{ nav: project.graph.navigation }];\n\n const archived = (versions?.archived ?? []).flatMap((version) => {\n const byLocale = project.graph.navigationByVersion[version.id] ?? {};\n const versionLabel = `${version.label ?? version.id} (archived)`;\n return Object.entries(byLocale).flatMap(([code, nav]) => {\n const locale = i18n?.locales.find((entry) => entry.code === code);\n const label =\n locale && code !== i18n?.defaultLocale\n ? `${locale.label} — ${versionLabel}`\n : versionLabel;\n return [{ label, nav }];\n });\n });\n\n return [...current, ...archived];\n};\n\n/**\n * Build the compact `llms.txt` index: title and summary, then the sidebar tree\n * rendered as sections — group labels become headings, pages become link lists —\n * so the file mirrors how the docs are organized rather than one flat blob.\n * Also serves as the homepage's synthesized Markdown mirror when the home\n * route is a landing page (see `buildRawMarkdown`).\n */\nexport const buildLlmsIndex = (\n project: BlumeProject,\n options: LlmsIndexOptions = {}\n): string => {\n const { config } = project;\n const { site } = config.deployment.options;\n const base = normalizeBasePath(config.deployment.options.base);\n const eligible = eligiblePages(project);\n const byRoute = new Map(eligible.map((page) => [page.route, page]));\n const seen = new Set<string>();\n\n const line = (page: PageRecord): string => {\n seen.add(page.route);\n const summary = page.description ? `: ${page.description}` : \"\";\n return `- [${page.title}](${pageUrl(page.route, site, base)})${summary}`;\n };\n\n // One nav level -> Markdown blocks: the level's loose pages as a link list,\n // then each group as a heading (depth-capped at h6) followed by its own\n // blocks. Nav entries whose route has no eligible page — external links,\n // padded i18n fallbacks, `noindex` pages, excluded API references — are\n // skipped, and a group left with nothing emits no heading at all.\n const renderLevel = (nodes: NavNode[], depth: number): string[] => {\n const list: string[] = [];\n const groupBlocks: string[] = [];\n for (const node of nodes) {\n if (node.kind === \"page\") {\n const page = byRoute.get(node.route);\n if (page && !seen.has(page.route)) {\n list.push(line(page));\n }\n continue;\n }\n // An explicit-config group may link its index page on the group itself\n // (`root`) rather than as a child; keep it at the top of the section.\n const rootPage = node.route ? byRoute.get(node.route) : undefined;\n const blocks = renderLevel(node.children, depth + 1);\n if (rootPage && !seen.has(rootPage.route)) {\n blocks.unshift(line(rootPage));\n }\n if (blocks.length > 0) {\n groupBlocks.push(\n `${\"#\".repeat(Math.min(depth, 6))} ${node.label}`,\n ...blocks\n );\n }\n }\n return list.length > 0 ? [list.join(\"\\n\"), ...groupBlocks] : groupBlocks;\n };\n\n // Loose pages at a tree's root get a \"Docs\" section of their own, so every\n // link sits under an h2 as llms.txt consumers expect.\n const renderNav = (nav: Navigation, depth: number): string[] => {\n const loose = nav.sidebar.filter((node) => node.kind === \"page\");\n const groups = nav.sidebar.filter((node) => node.kind === \"group\");\n const looseBlocks = renderLevel(loose, depth + 1);\n return [\n ...(looseBlocks.length > 0\n ? [`${\"#\".repeat(depth)} Docs`, ...looseBlocks]\n : []),\n ...renderLevel(groups, depth),\n ];\n };\n\n const blocks: string[] = [];\n for (const { label, nav } of indexedNavigations(project)) {\n if (label) {\n const localized = renderNav(nav, 3);\n if (localized.length > 0) {\n blocks.push(`## ${label}`, ...localized);\n }\n continue;\n }\n blocks.push(...renderNav(nav, 2));\n }\n\n // Pages the navigation doesn't reach (an explicit sidebar that omits them,\n // or a hand-rolled tree) still belong in the index.\n const leftover = eligible\n .filter((page) => !seen.has(page.route))\n .toSorted((a, b) => a.route.localeCompare(b.route));\n if (leftover.length > 0) {\n blocks.push(\n blocks.length > 0 ? \"## Other\" : \"## Docs\",\n leftover.map(line).join(\"\\n\")\n );\n }\n\n // Surface the RSS feeds so agents can find fresh content (new blog posts,\n // changelog entries) without re-crawling the index. `buildRssFeeds` is empty\n // unless RSS is enabled and an absolute `site` is set — the same condition\n // under which agent-readability.json lists `artifacts.feeds`.\n const feeds = buildRssFeeds(project);\n if (feeds.length > 0) {\n blocks.push(\n \"## RSS Feeds\",\n feeds\n .map((feed) => `- [${feed.title}](${pageUrl(feed.path, site, base)})`)\n .join(\"\\n\")\n );\n }\n\n // The published skills, each with its description — the one place a skill\n // states when an agent should reach for it.\n const skills = options.skills ?? [];\n if (skills.length > 0) {\n blocks.push(\n \"## Agent skills\",\n skills\n .map(\n (skill) =>\n `- [${skill.name}](${pageUrl(`${AGENT_SKILLS_DIR}/${skill.path}`, site, base)}): ${oneLine(skill.description)}`\n )\n .join(\"\\n\")\n );\n }\n\n blocks.push(\"## Agent resources\", agentResourceLines(project).join(\"\\n\"));\n\n const header = config.description\n ? `# ${config.title}\\n\\n> ${config.description}`\n : `# ${config.title}`;\n // `details` is the llms.txt spec's free-form block between the summary and\n // the file sections — \"when to use this\" guidance in the site's own words.\n const { details } = config.agents.llmsTxt;\n const lead = details ? `${header}\\n\\n${details}` : header;\n return `${[lead, ...blocks].join(\"\\n\\n\")}\\n`;\n};\n\n/** Build `llms-full.txt`: the full Markdown body of every current-docs page. */\nconst buildFull = async (project: BlumeProject): Promise<string> => {\n const { config } = project;\n const pages = eligiblePages(project, { versions: \"current\" }).toSorted(\n (a, b) => a.route.localeCompare(b.route)\n );\n const components = projectComponentSerializers(project);\n const rewriteLinks = relativeLinkRewriter(project);\n\n const sections = await Promise.all(\n pages.map(async (page) => {\n let raw = await readExpandedEntryText(project, page);\n // Colocated `./image.png` references resolve to nothing for a reader of\n // llms-full.txt; point them at the served originals instead.\n if (page.sourcePath) {\n raw = rewriteRelativeImages({\n deployBase: config.deployment.options.base,\n projectRoot: project.context.root,\n source: raw,\n sourcePath: page.sourcePath,\n });\n // Relative page links too: a reader of one flat file has no page URL\n // to resolve `./install` against.\n raw = rewriteLinks(raw, page);\n }\n // Resolve `<Visibility>` audiences (web-only content omitted from the\n // agent-facing output, agents-only unwrapped), then downlevel supported\n // components to plain Markdown.\n const parsed = matter(raw);\n const body = downlevelComponents(\n applyAgentVisibility(parsed.content),\n components,\n parsed.data\n ).trim();\n const url = pageUrl(\n page.route,\n config.deployment.options.site,\n normalizeBasePath(config.deployment.options.base)\n );\n return [`# ${page.title}`, `Source: ${url}`, \"\", body].join(\"\\n\");\n })\n );\n\n const header = config.description\n ? `# ${config.title}\\n\\n> ${config.description}\\n`\n : `# ${config.title}\\n`;\n\n return `${header}\\n${sections.join(\"\\n\\n---\\n\\n\")}\\n`;\n};\n\n/** Build both LLM text artifacts for a project. */\nexport const buildLlmsFiles = async (\n project: BlumeProject,\n options: LlmsIndexOptions = {}\n): Promise<{ index: string; full: string }> => ({\n full: await buildFull(project),\n index: buildLlmsIndex(project, options),\n});\n",
|
|
161
|
+
"/**\n * `Accept: text/markdown` content negotiation for Cloudflare server builds.\n *\n * Blume prerenders every content page — even in a server build (`deployment:\n * cloudflare()`) — and on Cloudflare the ASSETS binding serves those files before\n * the Worker script runs, so no server-side code (Astro middleware included)\n * ever sees a content-page request. Worse, even a content-page request that\n * does reach the Worker is answered by `@astrojs/cloudflare`'s handler\n * straight from the ASSETS binding, ahead of `app.render` — the only place\n * middleware runs — because `app.match` resolves a prerendered route to\n * nothing and the handler then falls back to the binding.\n *\n * Negotiation therefore needs two coordinated pieces, both applied to the\n * adapter's emitted deploy bundle after `astro build`:\n *\n * 1. `assets.run_worker_first` in `dist/server/wrangler.json`, claiming every\n * path except the static files that never negotiate, so the platform\n * routes page requests — and requests for pages that do not exist — to\n * the Worker instead of serving the static HTML directly (see\n * `buildRunWorkerFirstRules`).\n * 2. A generated entry Worker that fronts the adapter's: when the client\n * prefers `text/markdown` it serves the page's prerendered `.md` mirror\n * from the ASSETS binding, and it delegates everything else to the Astro\n * Worker untouched.\n *\n * The prerendered per-page JSON documents (`/api/docs/pages/{route}.json`)\n * are the one prerendered surface the adapter's fallback does *not* cover.\n * They come from a prerendered *dynamic* route, and for those Astro's\n * `matchRequest` returns the first non-prerendered route matching the same\n * path — on a server build that is the `/api/[...path]` catch-all, which\n * answers with a 404 problem document; `fallbackToAssets` never runs. The\n * static-pathname endpoints (`pages.json`, `navigation.json`) are unaffected:\n * they sit in the manifest's asset set, which the handler serves from the\n * binding first. So whenever a worker-first rule claims a page JSON URL, the\n * wrapper answers it from the binding itself, keyed by the exact set of\n * documents the build emitted. The generated rule set claims them (a miss\n * must reach the API's `PAGE_NOT_FOUND` answer, see `STATIC_EXEMPTIONS`), and\n * so do user-configured rules or a bare `true`.\n *\n * Cloudflare does not apply `_headers` to worker-first routes, so the wrapper\n * also re-stamps what the static layer would otherwise add on the routes it\n * takes over: the homepage agent-discovery `Link` header and the Markdown\n * `charset=utf-8` (see `deploy/headers.ts`). The raw `.md`/`.mdx` URLs are\n * exempted from worker-first routing with negative rules, keeping their\n * `_headers` treatment and their zero-Worker serving path.\n *\n * Configured redirects are baked into the wrapper as well, and answered there\n * with their exact configured status. On a server build Blume routes\n * `redirects` through Astro's own config, and `@astrojs/cloudflare` turns\n * those into `_redirects` entries carrying the exact status — but only\n * Cloudflare's static layer reads that file, and a worker-first route never\n * reaches it. Astro's SSR redirect handler would answer instead, and it honors\n * the configured status only when the destination resolves to a discrete\n * route: Blume serves every page from `[...slug]`, so it never does, and\n * `computeRedirectStatus` defaults a GET to **301** — a permanent redirect\n * that browsers cache indefinitely. The wrapper checking its own redirect\n * table before delegating closes that hole at zero rule cost: unlike negative\n * `run_worker_first` exemptions, a baked-in table spends nothing against\n * Wrangler's 100-rule / 100-character limits, cannot collide with\n * user-configured rules (or a bare `true`), and needs no basing gymnastics —\n * its keys are full served URLs, which is exactly what the Worker sees.\n * Redirects outside every worker-first rule still never invoke the Worker;\n * the static layer serves them from `_redirects` as before.\n *\n * Missing pages negotiate too. Under an explicit `run_worker_first` list the\n * platform answers every request outside the rules from the static layer —\n * an asset miss included, as the nearest `404.html` — which is why the rules\n * claim every path: a request for a URL no page backs then reaches the\n * Worker, and the Astro Worker answers it with the HTML 404 shell from the\n * binding (`not_found_handling: \"404-page\"`). When the client prefers\n * Markdown the wrapper swaps that shell for the prerendered `/404.md` twin,\n * and when it prefers JSON for the `/404.json` problem document, keeping the\n * 404 status either way — the counterpart of the miss-phase routes in\n * `deploy/vercel-negotiation.ts`. A raw `.md` or `.json` URL no file backs\n * asks for the same twin implicitly, but on this platform such a request only\n * reaches the Worker for `.json` (the generated set keeps `.md` on the static\n * layer for its `_headers`). Only an HTML 404 is swapped, so an API endpoint's\n * own problem document is never overwritten.\n */\n\nimport {\n API_NAVIGATION_PATH,\n API_PAGES_PATH,\n OPENAPI_PATH,\n} from \"../ai/api/paths.ts\";\nimport { normalizePath } from \"../core/base-path.ts\";\nimport type { NotFoundVariants } from \"./vercel-negotiation.ts\";\n\n/** Filename of the generated wrapper Worker, next to the adapter's entry. */\nexport const NEGOTIATION_WORKER_FILE = \"blume-worker.mjs\";\n\n/**\n * Wrangler's limits on `assets.run_worker_first`: at most 100 rules of at\n * most 100 characters each. A rule set over either limit fails\n * `wrangler deploy` outright, so the injection is skipped instead — only\n * user-configured rules can push the generated set over.\n */\nconst MAX_RULES = 100;\nconst MAX_RULE_LENGTH = 100;\n\n/**\n * The paths the generated rules leave on the static layer, relative to the\n * deployment base: the fingerprinted build assets, and the files whose\n * response headers come from `_headers` — which Cloudflare does not apply to\n * a response the Worker produced — and which never negotiate. Those are the\n * raw AI-ready endpoints (`charset=utf-8` on `.md`/`.mdx`/`.txt`) and the\n * `.well-known` discovery documents (the extensionless api-catalog's content\n * type, the CORS headers).\n *\n * The JSON Blume writes at fixed paths stays there too, but JSON as a whole\n * does not: a negative rule outranks every positive one, so a `*.json`\n * exemption would keep a request for a page JSON that doesn't exist\n * (`/api/docs/pages/nope.json`) off the Worker, and the platform would answer\n * it with an empty 404 instead of the API's `PAGE_NOT_FOUND` problem document.\n * The per-page documents themselves reach the wrapper, which serves them from\n * the binding (see the module comment); any other JSON goes through the Astro\n * Worker, which serves a static file from the binding as well.\n */\nconst STATIC_EXEMPTIONS = [\n \"/_astro/*\",\n \"/*.md\",\n \"/*.mdx\",\n \"/*.txt\",\n \"/.well-known/*\",\n \"/404.json\",\n \"/agent-readability.json\",\n \"/blume-search.json\",\n OPENAPI_PATH,\n API_PAGES_PATH,\n API_NAVIGATION_PATH,\n];\n\n/**\n * The deployment base as a rule/URL prefix: trailing slash stripped, empty\n * for a root deploy — the same normalization the dev middleware applies in\n * `astro/markdown-negotiation.ts`.\n */\nconst basePrefix = (base?: string): string =>\n base && base !== \"/\" ? base.replace(/\\/$/u, \"\") : \"\";\n\n/** A value as `JSON.parse` produces it (the wrangler config's value space). */\ntype JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\n/** Narrow a parsed JSON value to a plain (non-array) object. */\nconst isJsonObject = (\n value: JsonValue | undefined\n): value is { [key: string]: JsonValue } =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\n/** Narrow a parsed JSON value to a string. */\nconst isJsonString = (value: JsonValue | undefined): value is string =>\n typeof value === \"string\";\n\nconst isNegativeRule = (rule: string): boolean => rule.startsWith(\"!\");\n\nconst ruleBody = (rule: string): string =>\n isNegativeRule(rule) ? rule.slice(1) : rule;\n\n/**\n * The `run_worker_first` rules: every path under the deployment base goes\n * through the Worker except the {@link STATIC_EXEMPTIONS}. Claiming\n * everything — rather than only the content routes — is what lets a\n * *missing* page negotiate: under an explicit rule list the platform answers\n * any request outside every rule from the static layer, an asset miss\n * included (as the nearest `404.html`), so a rule set scoped to the content\n * routes would never let the Worker see a request for a URL that has no\n * page. The price is a Worker hop on every page request the site does serve.\n * On a subpath deploy the base is claimed in both request spellings.\n *\n * Configured redirects need no exemption from these rules: the wrapper Worker\n * answers any it claims from its baked-in redirect table with the configured\n * status (see the module comment).\n */\nexport const buildRunWorkerFirstRules = (base?: string): string[] => {\n const prefix = encodeURI(basePrefix(base));\n const exemptions = STATIC_EXEMPTIONS.map((path) => `!${prefix}${path}`);\n return prefix\n ? [prefix, `${prefix}/*`, ...exemptions]\n : [`/*`, ...exemptions];\n};\n\n/**\n * Whether `other` is a same-polarity glob that already covers `rule`.\n * Wrangler's deploy-time validator *rejects* a rule set containing a rule\n * another glob makes redundant, so covered rules must be dropped, not kept.\n */\nconst coveredBy = (rule: string, other: string): boolean =>\n other !== rule &&\n isNegativeRule(other) === isNegativeRule(rule) &&\n ruleBody(other).endsWith(\"*\") &&\n ruleBody(rule).startsWith(ruleBody(other).slice(0, -1));\n\n/**\n * Merge the generated rules into a user-configured `run_worker_first` (which\n * flows into the adapter's emitted config from the project's own wrangler\n * file). `true` already routes everything through the Worker, so it is kept\n * as-is; an array is unioned with the generated rules and then swept for\n * redundancy, since coverage by a glob is equivalent routing but a hard\n * validation error at deploy time.\n */\nexport const mergeRunWorkerFirstRules = (\n existing: JsonValue | undefined,\n added: readonly string[]\n): string[] | true => {\n if (existing === true) {\n return true;\n }\n const user = Array.isArray(existing)\n ? existing.filter((rule): rule is string => typeof rule === \"string\")\n : [];\n const merged = [...user, ...added.filter((rule) => !user.includes(rule))];\n return merged.filter(\n (rule) => !merged.some((other) => coveredBy(rule, other))\n );\n};\n\nconst withinWranglerLimits = (rules: string[] | true): boolean =>\n rules === true ||\n (rules.length <= MAX_RULES &&\n rules.every((rule) => rule.length <= MAX_RULE_LENGTH));\n\n/** A configured redirect the wrapper Worker serves itself. */\nexport interface WorkerRedirect {\n /**\n * Served path of the redirect, based the way the host platform matches it\n * (see `applyBaseToPlatformRedirects`) — the full URL path the Worker sees.\n */\n from: string;\n /** Configured HTTP status (301, 302, 307, or 308). */\n status: number;\n /** Destination, percent-encoded into the `Location` header. */\n to: string;\n}\n\nexport interface NegotiationWorkerOptions {\n /** Import specifier of the adapter's built entry, relative to the Worker. */\n mainSpecifier: string;\n /** Content routes with a raw-Markdown mirror (see `markdownRoutePaths`). */\n routePaths: readonly string[];\n /** Name of the assets binding the wrapper serves the `.md` mirrors from. */\n assetsBinding: string;\n /** `deployment.base` for subpath deploys. */\n base?: string;\n /** Homepage agent-discovery `Link` header (see `ai/link-headers.ts`). */\n homeLinkHeader?: string | null;\n /** Estimated token count of the homepage Markdown mirror. */\n homeTokens?: number;\n /** Configured redirects the wrapper answers with their exact status. */\n redirects?: readonly WorkerRedirect[];\n /**\n * Base-less served paths of the prerendered per-page JSON documents the\n * build emitted (see `pageJsonPath`), decoded. The wrapper answers exactly\n * these from the assets binding, since the Astro Worker would route them to\n * the `/api/` catch-all (see the module comment).\n */\n pageJsonPaths?: readonly string[];\n /**\n * Which prerendered 404 twins the build emitted (`404.md`, `404.json`), so\n * the wrapper only substitutes a twin that exists. A project that owns\n * `/404` emits neither and keeps the HTML answer.\n */\n notFound?: NotFoundVariants;\n}\n\n/**\n * The wrapper Worker module. The negotiation helpers are a JavaScript copy of\n * `astro/markdown-negotiation.ts` — the deploy bundle is uploaded with\n * `no_bundle`, so the module must be self-contained; behavioral parity with\n * the dev middleware is enforced by `test/cloudflare-negotiation.test.ts`.\n */\nexport const buildNegotiationWorker = (\n options: NegotiationWorkerOptions\n): string => {\n const routes = JSON.stringify(options.routePaths);\n const pageJson = JSON.stringify(options.pageJsonPaths ?? []);\n const binding = JSON.stringify(options.assetsBinding);\n const prefix = JSON.stringify(encodeURI(basePrefix(options.base)));\n const homeLinkHeader = JSON.stringify(options.homeLinkHeader ?? null);\n const homeTokens = JSON.stringify(\n options.homeTokens === undefined ? null : String(options.homeTokens)\n );\n const notFound = JSON.stringify({\n json: options.notFound?.json === true,\n markdown: options.notFound?.markdown === true,\n });\n // Keyed by the normalized served path; the runtime lookup decodes and\n // trims the request path the same way, so both spellings of a URL match.\n // The destination is percent-encoded here because it ships as a `Location`\n // header, which cannot carry non-ASCII.\n const redirects = JSON.stringify(\n Object.fromEntries(\n (options.redirects ?? []).map((redirect) => [\n normalizePath(redirect.from),\n [encodeURI(redirect.to), redirect.status],\n ])\n )\n );\n return `// Generated by Blume. Do not edit; this file is recreated on each build.\n//\n// Request-time \\`Accept: text/markdown\\` negotiation for a Cloudflare server\n// build. \\`assets.run_worker_first\\` routes content-page requests here instead\n// of the platform's static layer; a client that prefers Markdown gets the\n// page's prerendered \\`.md\\` mirror from the assets binding, a configured\n// redirect is answered with its exact configured status, and a prerendered\n// per-page JSON document is served from the binding (the Astro Worker would\n// route it to the \\`/api/\\` catch-all, because Astro resolves a prerendered\n// dynamic route to the first live route on the same path). Every other\n// request is delegated to the Astro Worker untouched — except a missing\n// page, whose HTML 404 shell is swapped for the prerendered Markdown or JSON\n// 404 twin when the client prefers one. \\`_headers\\` does not apply to\n// worker-first routes, so the homepage Link header and the Markdown charset\n// are re-stamped here.\nimport server from ${JSON.stringify(options.mainSpecifier)};\n\nconst ROUTES = new Set(${routes});\nconst PAGE_JSON = new Set(${pageJson});\nconst BASE_PREFIX = ${prefix};\nconst ASSETS_BINDING = ${binding};\nconst HOME_LINK_HEADER = ${homeLinkHeader};\nconst HOME_TOKENS = ${homeTokens};\nconst REDIRECTS = ${redirects};\nconst NOT_FOUND = ${notFound};\n\n// Configured redirects live in \\`_redirects\\`, which only the static layer\n// reads — a worker-first route never reaches it. Answering from this baked-in\n// copy keeps the exact configured status; delegating instead would let Astro's\n// SSR handler default a GET to a permanent 301.\nconst redirectFor = (pathname) => {\n const trimmed =\n pathname !== \"/\" && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n const path = safeDecode(trimmed);\n return Object.hasOwn(REDIRECTS, path) ? REDIRECTS[path] : null;\n};\n\n// The request path with the deployment base removed: the whole path on a\n// root deploy, \\`\"\"\\` for the bare base, \\`null\\` for a path outside the base.\nconst stripBase = (pathname) => {\n if (!BASE_PREFIX) {\n return pathname;\n }\n if (pathname === BASE_PREFIX) {\n return \"\";\n }\n return pathname.startsWith(BASE_PREFIX + \"/\")\n ? pathname.slice(BASE_PREFIX.length)\n : null;\n};\n\n// Decoded for the lookups, which are keyed by decoded paths; a malformed\n// escape keeps the raw path, which simply won't match anything.\nconst safeDecode = (path) => {\n try {\n return decodeURIComponent(path);\n } catch {\n return path;\n }\n};\n\n// \\`_redirects\\` semantics, which the static layer applies to these same\n// paths: the request's query string is forwarded unless the destination\n// carries its own, and a destination fragment stays after the query.\nconst redirectLocation = (destination, search) => {\n const hashIndex = destination.indexOf(\"#\");\n const bare = hashIndex === -1 ? destination : destination.slice(0, hashIndex);\n if (!search || bare.includes(\"?\")) {\n return destination;\n }\n return hashIndex === -1\n ? bare + search\n : bare + search + destination.slice(hashIndex);\n};\n\nconst parseAccept = (accept) =>\n accept.split(\",\").map((part) => {\n const segments = part.trim().split(\";\");\n const type = (segments[0] ?? \"\").trim().toLowerCase();\n const qSegment = segments\n .slice(1)\n .map((segment) => segment.trim())\n .find((segment) => segment.startsWith(\"q=\"));\n const q = qSegment ? Number(qSegment.slice(2)) : 1;\n return { q: Number.isNaN(q) ? 1 : q, type };\n });\n\n// Whether the client explicitly prefers one of \\`types\\` over HTML. Browsers\n// never send these, so an ordinary page request is false.\nconst prefers = (accept, types) => {\n if (!accept) {\n return false;\n }\n let wantedQ = -1;\n let htmlQ = 0;\n for (const { q, type } of parseAccept(accept)) {\n if (types.includes(type)) {\n wantedQ = Math.max(wantedQ, q);\n } else if (type === \"text/html\") {\n htmlQ = Math.max(htmlQ, q);\n }\n }\n return wantedQ > 0 && wantedQ >= htmlQ;\n};\n\nconst prefersMarkdown = (accept) =>\n prefers(accept, [\"text/markdown\", \"text/x-markdown\"]);\n\nconst prefersJson = (accept) =>\n prefers(accept, [\"application/json\", \"application/problem+json\"]);\n\n// The prerendered 404 twins, in the order a client asking for both is\n// answered: which twin, when a client prefers it, the raw URL extension that\n// asks for it implicitly, where it lives, and the content type to re-pin.\nconst NOT_FOUND_TWINS = [\n {\n contentType: \"text/markdown; charset=utf-8\",\n extension: /\\\\.mdx?$/u,\n key: \"markdown\",\n path: \"/404.md\",\n prefers: prefersMarkdown,\n },\n {\n contentType: \"application/problem+json; charset=utf-8\",\n extension: /\\\\.json$/u,\n key: \"json\",\n path: \"/404.json\",\n prefers: prefersJson,\n },\n];\n\n// A missing page comes back from the Astro Worker as the HTML 404 shell (the\n// binding's \\`not_found_handling\\`); a client that prefers Markdown or JSON —\n// or asked for a raw \\`.md\\`/\\`.json\\` URL no file backs — gets the prerendered\n// twin instead, with the same 404 status. Anything but an HTML 404 (an API\n// endpoint's own problem document, a missing image) is left alone. The twin\n// is fetched without the request's conditional headers, so a stray ETag match\n// cannot turn the 404 into a 304.\nconst notFoundTwin = async (request, url, response, assets) => {\n if (response.status !== 404 || assets === undefined) {\n return null;\n }\n const type = response.headers.get(\"content-type\") ?? \"\";\n if (!type.startsWith(\"text/html\")) {\n return null;\n }\n const accept = request.headers.get(\"accept\");\n for (const twin of NOT_FOUND_TWINS) {\n if (!NOT_FOUND[twin.key]) {\n continue;\n }\n const negotiated = twin.prefers(accept);\n if (!negotiated && !twin.extension.test(url.pathname)) {\n continue;\n }\n const asset = await assets.fetch(\n new Request(new URL(BASE_PREFIX + twin.path, url), {\n method: request.method,\n })\n );\n if (!asset.ok) {\n return null;\n }\n const patched = new Response(asset.body, {\n headers: asset.headers,\n status: 404,\n });\n patched.headers.set(\"content-type\", twin.contentType);\n if (negotiated) {\n patched.headers.append(\"vary\", \"Accept\");\n }\n return patched;\n }\n return null;\n};\n\nconst markdownVariantUrl = (rawUrl) => {\n const queryIndex = rawUrl.indexOf(\"?\");\n const query = queryIndex === -1 ? \"\" : rawUrl.slice(queryIndex);\n const rawPath = queryIndex === -1 ? rawUrl : rawUrl.slice(0, queryIndex);\n const rest = stripBase(rawPath);\n if (rest === null) {\n return null;\n }\n const path = rest || \"/\";\n const trimmed = path !== \"/\" && path.endsWith(\"/\") ? path.slice(0, -1) : path;\n const pathname = safeDecode(trimmed);\n if (!ROUTES.has(pathname)) {\n return null;\n }\n const target = pathname === \"/\" ? \"/index\" : pathname;\n return BASE_PREFIX + encodeURI(target) + \".md\" + query;\n};\n\n// Exactly the per-page JSON documents the build emitted, so a URL the site\n// never generated (a hidden page, a path outside the API) takes the normal\n// route to the Astro Worker and its problem document.\nconst isPageJson = (pathname) => {\n const rest = stripBase(pathname);\n return rest !== null && PAGE_JSON.has(safeDecode(rest));\n};\n\nconst isHomePath = (pathname) => {\n const rest = stripBase(pathname);\n return rest === \"\" || rest === \"/\";\n};\n\nconst withHeaders = (response, apply) => {\n const patched = new Response(response.body, response);\n apply(patched.headers);\n return patched;\n};\n\nexport default {\n async fetch(request, env, context) {\n const url = new URL(request.url);\n // Before the method guard: the static layer applies \\`_redirects\\` to every\n // method, so the wrapper does too.\n const redirect = redirectFor(url.pathname);\n if (redirect !== null) {\n return new Response(null, {\n headers: { location: redirectLocation(redirect[0], url.search) },\n status: redirect[1],\n });\n }\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n return server.fetch(request, env, context);\n }\n const assets = env[ASSETS_BINDING];\n // The request goes through untouched, so a conditional revalidation\n // reaches the binding and comes back as a 304 — anything but a miss is\n // the document's own answer. A miss falls through to the Astro Worker.\n if (assets !== undefined && isPageJson(url.pathname)) {\n const asset = await assets.fetch(request);\n if (asset.status !== 404) {\n return asset;\n }\n }\n const variant = markdownVariantUrl(url.pathname + url.search);\n const home = isHomePath(url.pathname);\n if (\n variant !== null &&\n assets !== undefined &&\n prefersMarkdown(request.headers.get(\"accept\"))\n ) {\n const asset = await assets.fetch(\n new Request(new URL(variant, url), request)\n );\n if (asset.ok) {\n return withHeaders(asset, (headers) => {\n headers.set(\"content-type\", \"text/markdown; charset=utf-8\");\n headers.append(\"vary\", \"Accept\");\n if (home) {\n if (HOME_LINK_HEADER !== null) {\n headers.set(\"link\", HOME_LINK_HEADER);\n }\n if (HOME_TOKENS !== null) {\n headers.set(\"x-markdown-tokens\", HOME_TOKENS);\n }\n }\n });\n }\n }\n const response = await server.fetch(request, env, context);\n const twin = await notFoundTwin(request, url, response, assets);\n if (twin !== null) {\n return twin;\n }\n if (variant === null && !(home && HOME_LINK_HEADER !== null)) {\n return response;\n }\n return withHeaders(response, (headers) => {\n if (variant !== null) {\n headers.append(\"vary\", \"Accept\");\n }\n if (home && HOME_LINK_HEADER !== null && !headers.has(\"link\")) {\n headers.set(\"link\", HOME_LINK_HEADER);\n }\n });\n },\n};\n`;\n};\n\nexport interface WorkerNegotiation {\n /** Updated `wrangler.json` text (worker-first rules + swapped `main`). */\n wrangler: string;\n /** The wrapper Worker module, to write as {@link NEGOTIATION_WORKER_FILE}. */\n worker: string;\n}\n\nexport interface WorkerNegotiationOptions extends Omit<\n NegotiationWorkerOptions,\n \"assetsBinding\" | \"mainSpecifier\"\n> {\n /**\n * The manifest content routes, based like `routePaths` — the guard that\n * keeps the wrapper's redirect table off real pages. Defaults to\n * `routePaths`, which also carries the synthesized homepage mirror (see\n * `markdownRoutePaths`); passing the manifest routes keeps that synthetic\n * `/` from blocking a configured root redirect.\n */\n contentRoutePaths?: readonly string[];\n}\n\n/**\n * Wire the negotiation into the adapter's emitted `dist/server/wrangler.json`:\n * point `main` at the wrapper Worker and scope `assets.run_worker_first` to\n * the content routes (merged with any user-configured rules). Returns the\n * updated config text plus the wrapper module, or `null` when there is\n * nothing to do or nowhere safe to do it: no routes, unparsable config, no\n * usable `main` or assets binding (the wrapper serves the `.md` mirrors from\n * it), an already-swapped `main` (the original entry is unrecoverable), or\n * user-configured rules that push the set over Wrangler's limits.\n *\n * The configured redirects are baked into the wrapper, which answers any the\n * worker-first rules claim with the exact configured status (see the module\n * comment) — whichever rules do the claiming: the generated `/*`, or the\n * user's own (including a bare `true`). A\n * redirect at a content route's own path is never baked: the page owns it,\n * and answering a redirect there would take a real page off the air. When\n * `null` is returned no rule set is written at all, so every request stays on\n * the static layer and `_redirects` serves the configured statuses as before.\n */\nexport const injectWorkerNegotiation = (\n wranglerText: string,\n options: WorkerNegotiationOptions\n): WorkerNegotiation | null => {\n if (options.routePaths.length === 0) {\n return null;\n }\n let config: JsonValue;\n try {\n config = JSON.parse(wranglerText);\n } catch {\n return null;\n }\n if (!isJsonObject(config)) {\n return null;\n }\n const { main } = config;\n if (\n !isJsonString(main) ||\n main.length === 0 ||\n main === NEGOTIATION_WORKER_FILE\n ) {\n return null;\n }\n const { assets } = config;\n if (!isJsonObject(assets) || !isJsonString(assets.binding)) {\n return null;\n }\n const {\n contentRoutePaths = options.routePaths,\n redirects = [],\n ...workerOptions\n } = options;\n // The content-route guard compares against redirect `from`s, which carry the\n // full `{deployment.base}{basePath}` stack; the routes carry only\n // `basePath`, so the deployment base is applied here.\n const deployPrefix = basePrefix(options.base);\n const guardRoutes = new Set(\n contentRoutePaths.map((route) =>\n normalizePath(\n deployPrefix && route !== \"/\"\n ? `${deployPrefix}${route}`\n : deployPrefix || route\n )\n )\n );\n const workerRedirects = redirects.filter(\n (redirect) =>\n redirect.from.startsWith(\"/\") &&\n !guardRoutes.has(normalizePath(redirect.from))\n );\n const rules = mergeRunWorkerFirstRules(\n assets.run_worker_first,\n buildRunWorkerFirstRules(options.base)\n );\n if (!withinWranglerLimits(rules)) {\n return null;\n }\n if (rules !== true) {\n assets.run_worker_first = rules;\n }\n config.main = NEGOTIATION_WORKER_FILE;\n const mainSpecifier =\n main.startsWith(\".\") || main.startsWith(\"/\") ? main : `./${main}`;\n const worker = buildNegotiationWorker({\n ...workerOptions,\n assetsBinding: assets.binding,\n mainSpecifier,\n redirects: workerRedirects,\n });\n // The adapter and Wrangler both write this file unformatted; match them.\n return { worker, wrangler: JSON.stringify(config) };\n};\n",
|
|
162
|
+
"import {\n normalizeBasePath,\n withBasePath,\n withComposedBasePath,\n} from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport type { VercelHeader } from \"./headers.ts\";\n\n/**\n * Platform redirect files for a static build. Astro already emits redirect HTML\n * (meta-refresh) pages for static output, but that's a soft client redirect.\n * These give the host a real HTTP 3xx: Netlify/Cloudflare read `_redirects`,\n * Vercel reads `vercel.json`, and `blume-redirects.json` is a structured\n * manifest for anything else (Apache/nginx rules, an edge worker).\n */\n\ntype Redirect = ResolvedConfig[\"redirects\"][number];\n\n/**\n * Base a redirect for Astro's `redirects` config, where the two sides are not\n * symmetric:\n *\n * - `from` gains only `basePath`. Astro builds the match pattern with\n * `deployment.base` already applied (`getPattern(segments, config.base)`), so\n * adding it here would serve the redirect at `{base}{base}/from`.\n * - `to` gains the full `{deployment.base}{basePath}` stack. Astro resolves a\n * destination that matches a known route by regenerating it from that route's\n * segments, which carry no base — and passes an unmatched destination through\n * verbatim. Neither path prepends `base`, so a root-relative `to` escapes the\n * base entirely (withastro/astro#7774, still the behavior in Astro 7).\n *\n * Both sides are authored as if mounted at root; external `to` URLs pass\n * through. Idempotent, so a hand-written base isn't doubled.\n */\nexport const applyBaseToAstroRedirects = (\n redirects: Redirect[],\n basePath: string,\n deployBase: string\n): Redirect[] => {\n // `deployment.base` arrives as the user wrote it (Astro accepts `/base/`,\n // even `base`); normalizing here keeps the composed paths well-formed.\n const base = normalizeBasePath(deployBase);\n return basePath || base\n ? redirects.map((redirect) => ({\n ...redirect,\n from: withBasePath(basePath, redirect.from),\n to: withComposedBasePath(base, basePath, redirect.to),\n }))\n : redirects;\n};\n\n/**\n * Base a redirect for the host platform files below. Unlike Astro's config,\n * these are matched against the real served URL, so both sides carry the full\n * `{deployment.base}{basePath}` stack.\n */\nexport const applyBaseToPlatformRedirects = (\n redirects: Redirect[],\n basePath: string,\n deployBase: string\n): Redirect[] => {\n const base = normalizeBasePath(deployBase);\n return basePath || base\n ? redirects.map((redirect) => ({\n ...redirect,\n from: withComposedBasePath(base, basePath, redirect.from),\n to: withComposedBasePath(base, basePath, redirect.to),\n }))\n : redirects;\n};\n\n/**\n * The configured redirects as the host platform matches them, via\n * {@link applyBaseToPlatformRedirects}. The one basing every consumer must\n * share: the emitted redirect files and the Cloudflare worker-first redirect\n * exemptions both compare these paths against real served URLs.\n */\nexport const platformRedirects = (config: ResolvedConfig): Redirect[] =>\n applyBaseToPlatformRedirects(\n config.redirects,\n config.basePath,\n config.deployment.options.base ?? \"\"\n );\n\n/** `_redirects` text (Netlify + Cloudflare Pages): `from to status` per line. */\nexport const buildNetlifyRedirects = (redirects: Redirect[]): string =>\n `${redirects\n .map((redirect) => `${redirect.from} ${redirect.to} ${redirect.status}`)\n .join(\"\\n\")}\\n`;\n\n/** The `vercel.json` Blume writes for a static deploy of `dist/`. */\ninterface VercelConfig {\n headers?: readonly VercelHeader[];\n redirects: { destination: string; source: string; statusCode: number }[];\n}\n\n/**\n * `vercel.json` contents with a `redirects` array, and a `headers` array when\n * header rules are given (see `buildVercelHeaders`). Uses `statusCode` (Vercel's\n * alternative to the boolean `permanent`) so the configured code ships exactly:\n * `permanent` would silently coerce a 301 to 308 and a 302 to 307, diverging\n * from the `_redirects` file, which preserves exact codes.\n */\nexport const buildVercelConfig = (\n redirects: Redirect[],\n headers: readonly VercelHeader[] = []\n): string => {\n const config: VercelConfig = {\n redirects: redirects.map((redirect) => ({\n destination: redirect.to,\n source: redirect.from,\n statusCode: redirect.status,\n })),\n };\n if (headers.length > 0) {\n config.headers = headers;\n }\n return `${JSON.stringify(config, null, 2)}\\n`;\n};\n\n/** Structured manifest for hosts that need manual wiring. */\nexport const buildRedirectManifest = (redirects: Redirect[]): string =>\n `${JSON.stringify(\n redirects.map((redirect) => ({\n from: redirect.from,\n status: redirect.status,\n to: redirect.to,\n })),\n null,\n 2\n )}\\n`;\n",
|
|
163
|
+
"import { dirname, join } from \"pathe\";\n\nimport type { ProjectContext } from \"../../core/types.ts\";\n\n/** Astro's build output dir: the runtime's own `distDir`, else `<root>/dist`. */\nexport const distDir = (context: ProjectContext): string =>\n context.distDir ?? join(context.root, \"dist\");\n\n/**\n * The `client/` half of a server build that keeps Astro's `dist/client` +\n * `dist/server` split and serves only the client half: the Node standalone\n * server's static handler reads only `build.client`, and `@astrojs/cloudflare`\n * declares `preserveBuildClientDir: true` and points the ASSETS binding in the\n * `dist/server/wrangler.json` it generates at `../client`.\n */\nexport const clientDir = (context: ProjectContext): string =>\n join(distDir(context), \"client\");\n\n/**\n * The root a deploy adapter is shown, in place of the `.blume` runtime Astro\n * actually roots at. Adapters assume `outDir` is `<root>/dist` and resolve\n * their own output (and Vercel's dependency trace) against `root`, so the\n * root implied by Blume's `outDir` is the one that keeps that assumption\n * true. See `withAdapterRoot`.\n *\n * For a normal build that is the project root (`<project>/dist` ->\n * `<project>`). For a relocated runtime (`blume build --isolated`) it is the\n * runtime dir itself (`<runtime>/dist` -> `<runtime>`), keeping a verify\n * build's adapter output self-contained instead of overwriting the real\n * `.vercel/output`.\n */\nexport const adapterRoot = (context: ProjectContext): string =>\n dirname(distDir(context));\n\n/** Prefix a bare host with `https://`; pass values that are already absolute. */\nexport const toSiteUrl = (value: string | undefined): string | null => {\n const trimmed = value?.trim();\n if (!trimmed) {\n return null;\n }\n return /^https?:\\/\\//u.test(trimmed) ? trimmed : `https://${trimmed}`;\n};\n",
|
|
164
|
+
"import { NETLIFY_ADAPTER_PACKAGE } from \"../adapters/netlify.ts\";\nimport { buildNetlifyRedirects } from \"../redirects.ts\";\nimport { distDir, toSiteUrl } from \"./paths.ts\";\nimport type { DeployPlatform, RedirectFile } from \"./types.ts\";\n\n/** `_redirects`, the format Netlify and Cloudflare Pages/Workers read. */\nexport const REDIRECTS_FILE: RedirectFile = {\n build: buildNetlifyRedirects,\n name: \"_redirects\",\n};\n\n/**\n * Netlify. A server build runs on Netlify Functions from the Frameworks API\n * tree the adapter writes to `.netlify/v1`, relative to the Astro root —\n * which for Blume is the hidden `.blume` runtime, so the tree is moved up to\n * the project root after the build (the `.netlify/build` sibling is only the\n * intermediate SSR bundle, already traced into `v1/functions`, and moving\n * `v1` alone keeps the `.netlify/state.json` from `netlify link` intact).\n * Static assets are served from `dist/` either way.\n */\nexport const netlifyPlatform: DeployPlatform = {\n astro: {\n config: {},\n options: () => ({}),\n package: NETLIFY_ADAPTER_PACKAGE,\n },\n env: {\n detect: (env) => Boolean(env.NETLIFY),\n // Fall through per *resolved* value, not per variable — a platform can\n // set a var to the empty string, which `??` on the raw values treats as\n // present, dead-ending the chain and silently losing the site URL.\n site: (env) =>\n toSiteUrl(env.URL) ??\n toSiteUrl(env.DEPLOY_PRIME_URL) ??\n toSiteUrl(env.DEPLOY_URL),\n },\n finalizeBuild: null,\n hiddenRuntime: {\n ignoreDir: \".netlify/\",\n showProjectRoot: false,\n surfacePath: \".netlify/v1\",\n },\n kind: \"netlify\",\n negotiatesMarkdown: false,\n // Netlify reads `_headers` from the publish directory of a static deploy.\n // A server build's static assets ride the Frameworks API tree instead,\n // where the file has never been applied.\n readsHeaderFiles: { server: false, static: true },\n redirectFiles: [REDIRECTS_FILE],\n serverOutputDir: distDir,\n serverStaticDir: distDir,\n};\n",
|
|
165
|
+
"import { existsSync } from \"node:fs\";\nimport { readFile, rename, writeFile } from \"node:fs/promises\";\n\nimport { join } from \"pathe\";\n\nimport { crossOriginDiscoveryPaths } from \"../ai/ai-catalog.ts\";\nimport {\n API_CATALOG_PATH,\n API_CATALOG_TYPE,\n hasApiCatalog,\n} from \"../ai/api-catalog.ts\";\nimport {\n SIGNATURES_DIRECTORY_PATH,\n SIGNATURES_DIRECTORY_TYPE,\n} from \"../ai/web-bot-auth.ts\";\nimport { normalizeBasePath } from \"../core/base-path.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { SVG_ASSET_POLICY } from \"./headers.ts\";\nimport { distDir } from \"./platforms/paths.ts\";\nimport type { BuildLog } from \"./platforms/types.ts\";\n\n/**\n * The response headers the Node standalone server can't set itself. Its static\n * handler (`send`) types a file by its extension alone and sends no CORS\n * header, so the extensionless well-known files go out as\n * `application/octet-stream` and a registry reading the discovery documents\n * from another origin is blocked — the half of the `_headers` rules\n * (`deploy/headers.ts`) that a Node server has no file to read from. The Markdown\n * and text charsets need no rule here: `send` already adds `charset=UTF-8` to\n * `text/*` types.\n */\n\n/** The headers one exact served path (deployment base included) gets. */\nexport interface NodeHeaderRule {\n headers: Record<string, string>;\n path: string;\n}\n\n/** The server entry `@astrojs/node` writes, which the wrapper takes over. */\nexport const NODE_ENTRY_FILE = \"entry.mjs\";\n/** Where Astro's own entry moves, beside the wrapper that imports it. */\nexport const NODE_ASTRO_ENTRY_FILE = \"astro-entry.mjs\";\n/** First line of the wrapper, so a second pass over the same build is a no-op. */\nconst WRAPPER_MARKER = \"// blume:node-headers\";\n\n/** The header rules for this config, merged per path. */\nexport const nodeHeaderRules = (config: ResolvedConfig): NodeHeaderRule[] => {\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const byPath = new Map<string, Record<string, string>>();\n const add = (path: string, name: string, value: string): void => {\n byPath.set(path, { ...byPath.get(path), [name]: value });\n };\n if (hasApiCatalog(config)) {\n add(API_CATALOG_PATH, \"Content-Type\", API_CATALOG_TYPE);\n }\n if (config.agents.webBotAuth.keys.length > 0) {\n add(SIGNATURES_DIRECTORY_PATH, \"Content-Type\", SIGNATURES_DIRECTORY_TYPE);\n }\n for (const path of crossOriginDiscoveryPaths(config)) {\n add(path, \"Access-Control-Allow-Origin\", \"*\");\n }\n return [...byPath].map(([path, headers]) => ({\n headers,\n path: `${deployBase}${path}`,\n }));\n};\n\n/** Exact-path rules, as `[path, headers]` pairs for the wrapper's lookup. */\nconst exactRules = (\n rules: readonly NodeHeaderRule[]\n): [string, Record<string, string>][] =>\n rules\n .filter((rule) => !rule.path.includes(\"*\"))\n .map((rule) => [rule.path, rule.headers]);\n\n/**\n * Glob rules (`/blume-assets/*.svg`), as `[prefix, suffix, headers]` — the\n * text before and after the one `*`, which spans path segments.\n */\nconst patternRules = (\n rules: readonly NodeHeaderRule[]\n): [string, string, Record<string, string>][] =>\n rules\n .filter((rule) => rule.path.includes(\"*\"))\n .map((rule) => {\n const star = rule.path.indexOf(\"*\");\n return [\n rule.path.slice(0, star),\n rule.path.slice(star + 1),\n rule.headers,\n ];\n });\n\n/**\n * The entry that replaces Astro's: it stamps the rules' headers on the\n * response, then hands the request to Astro's handler. `send` leaves a\n * Content-Type that is already set alone, so the registered media type wins.\n *\n * It keeps Astro's contract — the `handler`, `options`, and `startServer`\n * exports `astro preview` and a middleware-mode host import — and its\n * autostart: Astro's entry is imported with autostart off (the env var is read\n * when that module evaluates, so the import has to be dynamic), and the\n * wrapper starts the server itself with its listener in front of Astro's.\n */\nexport const nodeEntryWrapper = (rules: readonly NodeHeaderRule[]): string =>\n `${WRAPPER_MARKER}\n// Written by \\`blume build\\`: Astro's server entry is ./${NODE_ASTRO_ENTRY_FILE}.\n// This wrapper sets the media types and CORS headers of the .well-known\n// discovery files, which the standalone server's static handler can't, then\n// hands every request to Astro.\nconst RULES = new Map(${JSON.stringify(exactRules(rules))});\nconst PATTERNS = ${JSON.stringify(patternRules(rules))};\nconst applyHeaders = (req, res) => {\n const path = (req.url ?? \"\").split(\"?\")[0];\n const headers =\n RULES.get(path) ??\n PATTERNS.find(([prefix, suffix]) => path.startsWith(prefix) && path.endsWith(suffix))?.[2];\n if (headers) {\n for (const [name, value] of Object.entries(headers)) {\n res.setHeader(name, value);\n }\n }\n};\nconst previous = process.env.ASTRO_NODE_AUTOSTART;\nprocess.env.ASTRO_NODE_AUTOSTART = \"disabled\";\nconst astro = await import(\"./${NODE_ASTRO_ENTRY_FILE}\");\nif (previous === undefined) {\n delete process.env.ASTRO_NODE_AUTOSTART;\n} else {\n process.env.ASTRO_NODE_AUTOSTART = previous;\n}\nexport const { options } = astro;\nexport const handler = (req, res, ...rest) => {\n applyHeaders(req, res);\n return astro.handler(req, res, ...rest);\n};\nexport const startServer = () => {\n const started = astro.startServer();\n // Stamp the headers only where the adapter exposes its HTTP server as\n // expected; a different shape serves the files without them rather than\n // failing to start.\n const httpServer = started?.server?.server;\n if (typeof httpServer?.prependListener === \"function\") {\n httpServer.prependListener(\"request\", applyHeaders);\n }\n return started;\n};\nif (options.mode === \"standalone\" && previous !== \"disabled\") {\n startServer();\n}\n`;\n\n/**\n * Put the header wrapper in front of a Node server build's entry. A build\n * with no rule (no API catalog, AI catalog, MCP server, signatures directory,\n * or downloaded content assets) leaves Astro's entry alone.\n */\nexport const wrapNodeEntry = async (\n project: BlumeProject,\n log: BuildLog\n): Promise<void> => {\n // Content assets a CMS source downloaded ship as static files, which the\n // standalone server serves without the SVG sandbox static hosts get from\n // `_headers`; only a build that has them needs the rule.\n const assetsDir = join(distDir(project.context), \"client\", \"blume-assets\");\n const rules = [\n ...nodeHeaderRules(project.config),\n ...(existsSync(assetsDir)\n ? [\n {\n headers: { \"Content-Security-Policy\": SVG_ASSET_POLICY },\n path: `${normalizeBasePath(project.config.deployment.options.base)}/blume-assets/*.svg`,\n },\n ]\n : []),\n ];\n if (rules.length === 0) {\n return;\n }\n const serverDir = join(distDir(project.context), \"server\");\n const entry = join(serverDir, NODE_ENTRY_FILE);\n if (!existsSync(entry)) {\n log.warn(\n `Could not find the Node server entry at ${entry}, so the .well-known discovery files are served without their media types and CORS headers.`\n );\n return;\n }\n const source = await readFile(entry, \"utf-8\");\n if (source.startsWith(WRAPPER_MARKER)) {\n return;\n }\n await rename(entry, join(serverDir, NODE_ASTRO_ENTRY_FILE));\n await writeFile(entry, nodeEntryWrapper(rules), \"utf-8\");\n log.success(\n \"Wired the .well-known discovery headers into the Node server entry\"\n );\n};\n",
|
|
166
|
+
"import type { ResolvedConfig } from \"../core/schema.ts\";\n\n/**\n * Web Bot Auth (IETF `webbotauth` WG): an org that runs agents publishes the\n * agents' HTTP Message Signature public keys in a JWKS at a well-known path\n * on its domain; sites receiving the signed requests fetch it to verify them.\n * Blume publishes the directory from `agents.webBotAuth.keys` — the schema admits\n * public keys only, so the site can never leak signing credentials.\n */\n\n/** Well-known path (draft-meunier-http-message-signatures-directory). */\nexport const SIGNATURES_DIRECTORY_PATH =\n \"/.well-known/http-message-signatures-directory\";\n\n/** The directory's registered media type — extensionless, so static hosts\n * need an explicit Content-Type rule (see `deploy/headers.ts` and the Vercel\n * `overrides` injection) to serve anything better than octet-stream. */\nexport const SIGNATURES_DIRECTORY_TYPE =\n \"application/http-message-signatures-directory+json\";\n\n/** The JWKS document to publish, or null when no keys are configured. */\nexport const buildSignaturesDirectory = (\n config: ResolvedConfig\n): string | null => {\n const { keys } = config.agents.webBotAuth;\n if (keys.length === 0) {\n return null;\n }\n return `${JSON.stringify({ keys }, null, 2)}\\n`;\n};\n",
|
|
167
|
+
"import { crossOriginDiscoveryPaths } from \"../ai/ai-catalog.ts\";\nimport {\n API_CATALOG_PATH,\n API_CATALOG_TYPE,\n hasApiCatalog,\n} from \"../ai/api-catalog.ts\";\nimport {\n SIGNATURES_DIRECTORY_PATH,\n SIGNATURES_DIRECTORY_TYPE,\n} from \"../ai/web-bot-auth.ts\";\nimport { normalizeBasePath } from \"../core/base-path.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\n\n/**\n * The `_headers` file for a static build (Netlify + Cloudflare Pages/Workers\n * static assets). Blume's raw AI-ready endpoints — `/<route>.md`, `/<route>.mdx`,\n * and the `.txt` files (`llms.txt`, `llms-full.txt`) — are valid UTF-8, but a\n * static host serves them from the file extension alone, and common hosts send\n * `text/markdown` / `text/plain` with **no** `charset`. Browsers then fall back\n * to Windows-1252 for non-HTML text, so any non-ASCII docs (Japanese, accented\n * Latin, …) render as mojibake when the raw URL is opened directly. HTML pages\n * escape this because they carry `<meta charset>`; the raw endpoints have only\n * the HTTP header. Pinning `charset=utf-8` here matches the Content-Type these\n * same routes already send from the dev/server runtime (see\n * `astro/templates.ts`). Hosts that don't read `_headers` ignore the file\n * harmlessly; Vercel gets the same rules in `vercel.json` (see\n * {@link buildVercelHeaders}).\n */\n\n/**\n * One rule per served extension. `.mdx` uses `text/markdown` to match the\n * runtime endpoint, which serves both variants as `text/markdown`. The raw\n * Markdown mirrors live under the page routes (which carry `basePath`), while\n * the `.txt` files (`llms.txt`, `llms-full.txt`) are written to the dist root\n * and served at the deployment base — so only the `.md`/`.mdx` rules take the\n * `basePath` layer.\n */\nconst HEADER_RULES: readonly {\n contentType: string;\n ext: string;\n underBasePath: boolean;\n}[] = [\n {\n contentType: \"text/markdown; charset=utf-8\",\n ext: \"md\",\n underBasePath: true,\n },\n {\n contentType: \"text/markdown; charset=utf-8\",\n ext: \"mdx\",\n underBasePath: true,\n },\n {\n contentType: \"text/plain; charset=utf-8\",\n ext: \"txt\",\n underBasePath: false,\n },\n];\n\n/** Where the generated endpoint serves content-source images from. */\nconst CONTENT_ASSETS_ROOT = \"/blume-assets\";\n\n/**\n * The policy a content-source SVG is served with: an opaque origin with\n * scripts off, so an uploaded SVG that carries a `<script>` stays inert when\n * opened directly. The endpoint sends it from the server and dev runtimes;\n * {@link headerRules} carries it to static hosts.\n */\nexport const SVG_ASSET_POLICY = \"sandbox\";\n\n/**\n * One static-host header rule: a served path (a `*` glob spanning path\n * segments, or an exact path) and the header it sets there.\n */\nexport interface HeaderRule {\n name: string;\n path: string;\n value: string;\n}\n\n/**\n * The header rules every static host should apply, in `_headers` glob syntax.\n * The glob carries the served prefix (`{deployment.base}{basePath}` for the\n * Markdown mirrors, `{deployment.base}` for the root `.txt` files) so the rules\n * still match once the site is mounted under a subpath (`/docs/*.md`); the\n * wildcard spans path segments, so a nested route like `/docs/ja/intro.md`\n * matches too.\n *\n * When a homepage `Link` header is provided (see `ai/link-headers.ts`), an\n * exact-path rule for the root page advertises the agent-discovery resources —\n * the static-host counterpart of the Vercel routing-config injection.\n */\nexport const headerRules = (\n config: ResolvedConfig,\n homeLinkHeader?: string | null\n): HeaderRule[] => {\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const rules: HeaderRule[] = HEADER_RULES.map((rule) => {\n const prefix = rule.underBasePath\n ? `${deployBase}${config.basePath}`\n : deployBase;\n return {\n name: \"Content-Type\",\n path: `${prefix}/*.${rule.ext}`,\n value: rule.contentType,\n };\n });\n if (homeLinkHeader) {\n rules.push({ name: \"Link\", path: `${deployBase}/`, value: homeLinkHeader });\n }\n // The well-known discovery files are extensionless, so without an explicit\n // rule a static host serves their registered media types as octet-stream or\n // text/plain.\n if (hasApiCatalog(config)) {\n rules.push({\n name: \"Content-Type\",\n path: `${deployBase}${API_CATALOG_PATH}`,\n value: API_CATALOG_TYPE,\n });\n }\n if (config.agents.webBotAuth.keys.length > 0) {\n rules.push({\n name: \"Content-Type\",\n path: `${deployBase}${SIGNATURES_DIRECTORY_PATH}`,\n value: SIGNATURES_DIRECTORY_TYPE,\n });\n }\n // Agent registries fetch the discovery documents cross-origin; a static\n // host sends no CORS header unless told to.\n for (const path of crossOriginDiscoveryPaths(config)) {\n rules.push({\n name: \"Access-Control-Allow-Origin\",\n path: `${deployBase}${path}`,\n value: \"*\",\n });\n }\n // Published skills live at the deployment base, outside `basePath` — the\n // `.md` charset rule above misses them whenever a basePath is set, and the\n // RFC wants archives served as application/gzip explicitly.\n if (config.agents.skills) {\n rules.push(\n {\n name: \"Content-Type\",\n path: `${deployBase}/.well-known/agent-skills/*.md`,\n value: \"text/markdown; charset=utf-8\",\n },\n {\n name: \"Content-Type\",\n path: `${deployBase}/.well-known/agent-skills/*.tar.gz`,\n value: \"application/gzip\",\n }\n );\n }\n // Images a content source downloads (a CMS upload, a remote page's figure)\n // are served from the docs origin, and an SVG opened directly is a document\n // that can run script. A sandbox policy keeps it inert; an `<img>` that\n // embeds it is unaffected.\n rules.push({\n name: \"Content-Security-Policy\",\n path: `${deployBase}${CONTENT_ASSETS_ROOT}/*.svg`,\n value: SVG_ASSET_POLICY,\n });\n return rules;\n};\n\n/**\n * `_headers` contents: each {@link headerRules} entry as its path with an\n * indented header line, in the two-space format Netlify and Cloudflare read.\n */\nexport const buildNetlifyHeaders = (\n config: ResolvedConfig,\n homeLinkHeader?: string | null\n): string =>\n `${headerRules(config, homeLinkHeader)\n .map((rule) => `${rule.path}\\n ${rule.name}: ${rule.value}`)\n .join(\"\\n\")}\\n`;\n\n/** One entry of `vercel.json`'s `headers` array. */\nexport interface VercelHeader {\n headers: { key: string; value: string }[];\n source: string;\n}\n\n/** The characters `path-to-regexp` would read as syntax in a literal path. */\nconst SOURCE_SYNTAX = /[\\\\(){}?+:]/gu;\n\n/**\n * A `_headers` path as a `vercel.json` `source`, which `path-to-regexp` reads:\n * the literal parts are escaped, and a `*` glob becomes the `(.*)` group that\n * spans path segments as the glob does. An exact directory path (the homepage\n * rule's `/docs/`) drops its trailing slash, the URL Vercel serves it at.\n */\nconst vercelSource = (path: string): string => {\n const trimmed =\n path.length > 1 && path.endsWith(\"/\") ? path.slice(0, -1) : path;\n return trimmed\n .split(\"*\")\n .map((part) => part.replaceAll(SOURCE_SYNTAX, String.raw`\\$&`))\n .join(\"(.*)\");\n};\n\n/**\n * The {@link headerRules} as `vercel.json` `headers` entries. Vercel reads no\n * `_headers` file, so a static deploy of `dist/` carries the same rules here —\n * the charset on the raw Markdown and text files, the homepage `Link` header,\n * and the media types and CORS header of the discovery files.\n */\nexport const buildVercelHeaders = (\n config: ResolvedConfig,\n homeLinkHeader?: string | null\n): VercelHeader[] =>\n headerRules(config, homeLinkHeader).map((rule) => ({\n headers: [{ key: rule.name, value: rule.value }],\n source: vercelSource(rule.path),\n }));\n",
|
|
168
|
+
"import { NODE_ADAPTER_PACKAGE } from \"../adapters/node.ts\";\nimport { wrapNodeEntry } from \"../node-headers.ts\";\nimport { clientDir, distDir } from \"./paths.ts\";\nimport type { DeployPlatform } from \"./types.ts\";\n\n/**\n * A self-hosted Node server. The standalone server in `dist/server` serves\n * `dist/client` through its own static handler, which has no `_headers` or\n * `_redirects` support — redirects are answered at request time from the\n * Astro config, and a header file written there would be inert. The headers\n * the discovery files need come from a wrapper around the server entry\n * instead (`deploy/node-headers.ts`). No platform env to detect: the site URL\n * has to be configured.\n */\nexport const nodePlatform: DeployPlatform = {\n astro: {\n config: {},\n options: () => ({ mode: \"standalone\" }),\n package: NODE_ADAPTER_PACKAGE,\n },\n env: null,\n finalizeBuild: async ({ isolated, log, project }) => {\n // The wrapped entry is a deploy artifact; an isolated verify skips it.\n if (!isolated) {\n await wrapNodeEntry(project, log);\n }\n return true;\n },\n hiddenRuntime: {\n ignoreDir: null,\n showProjectRoot: false,\n surfacePath: null,\n },\n kind: \"node\",\n negotiatesMarkdown: false,\n readsHeaderFiles: { server: false, static: false },\n redirectFiles: [],\n serverOutputDir: distDir,\n serverStaticDir: clientDir,\n};\n",
|
|
169
|
+
"import { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\n\nimport { join } from \"pathe\";\n\nimport { crossOriginDiscoveryPaths } from \"../../ai/ai-catalog.ts\";\nimport {\n API_CATALOG_PATH,\n API_CATALOG_TYPE,\n hasApiCatalog,\n} from \"../../ai/api-catalog.ts\";\nimport { buildHomeLinkHeader } from \"../../ai/link-headers.ts\";\nimport {\n agentMarkdown,\n buildRawMarkdown,\n markdownRoutePaths,\n markdownTokenCount,\n} from \"../../ai/markdown.ts\";\nimport {\n SIGNATURES_DIRECTORY_PATH,\n SIGNATURES_DIRECTORY_TYPE,\n} from \"../../ai/web-bot-auth.ts\";\nimport type { BlumeProject } from \"../../core/project-graph.ts\";\nimport type { ProjectContext } from \"../../core/types.ts\";\nimport { VERCEL_ADAPTER_PACKAGE } from \"../adapters/vercel.ts\";\nimport {\n addDevDependencyCommand,\n auditVercelFunctions,\n blumeDependencyNames,\n functionBundleVerdict,\n} from \"../function-bundle.ts\";\nimport { buildVercelConfig } from \"../redirects.ts\";\nimport { injectNegotiationRoutes } from \"../vercel-negotiation.ts\";\nimport { adapterRoot, toSiteUrl } from \"./paths.ts\";\nimport type { BuildLog, DeployPlatform, RedirectFile } from \"./types.ts\";\n\n/** `vercel.json` with a `redirects` array, for a static deploy of `dist/`. */\nexport const VERCEL_JSON_FILE: RedirectFile = {\n build: buildVercelConfig,\n name: \"vercel.json\",\n};\n\n/**\n * The Build Output tree. The adapter is shown the project root (see\n * `hiddenRuntime.showProjectRoot`), so for a real build this is\n * `<project>/.vercel/output`; an isolated build keeps it under the relocated\n * runtime.\n */\nconst buildOutputDir = (context: ProjectContext): string =>\n join(adapterRoot(context), \".vercel\", \"output\");\n\n/**\n * Refuse to ship a function bundle that would crash at runtime: a bare import\n * the adapter's dependency trace silently dropped (see\n * `deploy/function-bundle.ts`). A missing package that is one of Blume's own\n * dependencies is fatal — the generated runtime imports it, so every request\n * would die; a project's own external import is reported as a warning and\n * left to the author. Resolves to whether the bundle may ship.\n */\nexport const checkVercelFunctionBundles = async (\n outputDir: string,\n root: string,\n log: BuildLog\n): Promise<boolean> => {\n const audits = await auditVercelFunctions(outputDir);\n const own = blumeDependencyNames();\n // The remedy names the project's own package manager (`pnpm add -D`, …).\n const addDevCommand = await addDevDependencyCommand(root);\n let fatal = false;\n for (const audit of audits) {\n const verdict = functionBundleVerdict(audit, root, own, addDevCommand);\n if (verdict.fatal) {\n fatal = true;\n log.error(verdict.message);\n } else {\n log.warn(verdict.message);\n }\n }\n return !fatal;\n};\n\n/**\n * Splice `Accept: text/markdown` negotiation routes into the adapter's Build\n * Output config, so a content-page request that prefers Markdown gets the\n * page's prerendered `.md` mirror (content pages are prerendered even in\n * server output, so Astro middleware never sees them — the routing layer is\n * the only request-time hook). The adapter writes the config straight to the\n * root it was shown.\n */\nexport const emitVercelNegotiation = async (\n project: BlumeProject,\n log: BuildLog\n): Promise<void> => {\n const { config, context } = project;\n const outputDir = buildOutputDir(context);\n const configPath = join(outputDir, \"config.json\");\n if (!existsSync(configPath)) {\n return;\n }\n const routePaths = markdownRoutePaths(project);\n const overrides: Record<string, string> = {};\n if (hasApiCatalog(config)) {\n overrides[API_CATALOG_PATH.slice(1)] = API_CATALOG_TYPE;\n }\n if (config.agents.webBotAuth.keys.length > 0) {\n overrides[SIGNATURES_DIRECTORY_PATH.slice(1)] = SIGNATURES_DIRECTORY_TYPE;\n }\n // The homepage rewrite serves `/index.md` from the static layer, so its\n // `x-markdown-tokens` estimate has to ride the routing config; the runtime\n // endpoint stamps it on dev/server-rendered responses itself.\n const rawMarkdown = await buildRawMarkdown(project);\n const home = rawMarkdown[\"/\"];\n // The Markdown and JSON 404 routes point at the prerendered twins; only\n // wire each when the build actually emitted it (a project that owns `/404`\n // gets none).\n const staticDir = join(outputDir, \"static\");\n const injected = injectNegotiationRoutes(\n await readFile(configPath, \"utf-8\"),\n routePaths,\n buildHomeLinkHeader(config, routePaths),\n overrides,\n home ? markdownTokenCount(agentMarkdown(home)) : undefined,\n {\n json: existsSync(join(staticDir, \"404.json\")),\n markdown: existsSync(join(staticDir, \"404.md\")),\n },\n crossOriginDiscoveryPaths(config)\n );\n if (injected === null) {\n log.warn(\n \"Could not wire Accept: text/markdown negotiation into .vercel/output/config.json — raw Markdown stays available at the .md URLs.\"\n );\n return;\n }\n await writeFile(configPath, injected, \"utf-8\");\n log.success(\n \"Wired Accept: text/markdown negotiation into the Vercel routing config\"\n );\n};\n\n/**\n * Vercel. A server build's Build Output tree lands at `.vercel/output` — at\n * the project root, because the adapter is handed that root up front: its\n * `@vercel/nft` dependency trace is rooted there too, and tracing from the\n * hidden runtime silently drops the function's chunks and `node_modules`.\n * Static assets are served from the tree's `static/` half, so the deploy\n * artifacts are written there; headers arrive through the routing config\n * rather than a `_headers` file, which Vercel never reads.\n */\nexport const vercelPlatform: DeployPlatform = {\n astro: {\n config: {},\n options: () => ({}),\n package: VERCEL_ADAPTER_PACKAGE,\n },\n env: {\n detect: (env) => Boolean(env.VERCEL),\n // The stable production domain wins over the per-deployment preview URL\n // so the inferred origin (sitemap, OG, RSS) stays put across deploys;\n // the chain falls through per resolved value, so an empty\n // VERCEL_PROJECT_PRODUCTION_URL doesn't dead-end it.\n site: (env) =>\n toSiteUrl(env.VERCEL_PROJECT_PRODUCTION_URL) ?? toSiteUrl(env.VERCEL_URL),\n },\n finalizeBuild: async ({ isolated, log, project }) => {\n const { context } = project;\n const ok = await checkVercelFunctionBundles(\n buildOutputDir(context),\n context.root,\n log\n );\n if (!ok) {\n return false;\n }\n // An isolated verify only proves the bundle would ship; the routing\n // config is a deploy artifact and stays untouched.\n if (!isolated) {\n await emitVercelNegotiation(project, log);\n }\n return true;\n },\n hiddenRuntime: {\n ignoreDir: \".vercel/\",\n showProjectRoot: true,\n surfacePath: null,\n },\n kind: \"vercel\",\n negotiatesMarkdown: true,\n readsHeaderFiles: { server: false, static: false },\n redirectFiles: [VERCEL_JSON_FILE],\n serverOutputDir: buildOutputDir,\n serverStaticDir: (context) => join(buildOutputDir(context), \"static\"),\n};\n",
|
|
170
|
+
"import { existsSync, readFileSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { builtinModules } from \"node:module\";\n\nimport { init, parse } from \"es-module-lexer\";\nimport { dirname, join, relative } from \"pathe\";\nimport { z } from \"zod\";\n\nimport {\n commandsFor,\n detectProjectPackageManager,\n} from \"../cli/init/scaffold.ts\";\nimport { packageRoot } from \"../core/package-root.ts\";\n\n/**\n * Post-build audit of a Vercel serverless function bundle.\n *\n * The Vercel adapter traces the server entry with `@vercel/nft` and copies\n * every file it reaches into `.vercel/output/functions/_render.func`. A bare\n * import the trace cannot resolve — a package that isn't reachable by walking\n * `node_modules` up from the chunk that imports it — is dropped *silently*,\n * and the deployed function dies on its first request with\n * `ERR_MODULE_NOT_FOUND` (Vercel reports it as `FUNCTION_INVOCATION_FAILED`).\n * Under an isolated linker (pnpm, Bun's `isolated` mode) that is exactly the\n * shape of Blume's own runtime dependencies: the SSR build leaves them\n * external, and they live under `blume`'s store directory, not the project\n * root. Nothing before deploy surfaces it — the build is green, a warm-cache\n * preview is green — so the bundle is re-checked here with Node's own\n * resolution rule: a package is present when some `node_modules/<name>` on\n * the walk from the importing chunk up to the function root exists.\n */\n\n/** A bare package import the function bundle cannot satisfy. */\nexport interface MissingPackage {\n /** Function-relative paths of the chunks that import the package. */\n importers: string[];\n name: string;\n}\n\n/** One function directory's audit result. */\nexport interface FunctionBundleAudit {\n /** Absolute path of the `*.func` directory. */\n dir: string;\n missing: MissingPackage[];\n}\n\nconst BUILTINS = new Set(builtinModules);\n\n/** Specifier prefixes that never name an installed package. */\nconst NON_PACKAGE_PREFIXES = [\"node:\", \"astro:\", \"virtual:\", \"data:\", \"\\0\"];\n\n/**\n * The package a bare specifier resolves through (`@scope/name` or `name`), or\n * null for relative/absolute paths, Node builtins, and virtual ids.\n */\nexport const packageName = (specifier: string): string | null => {\n if (\n specifier.startsWith(\".\") ||\n specifier.startsWith(\"/\") ||\n NON_PACKAGE_PREFIXES.some((prefix) => specifier.startsWith(prefix)) ||\n BUILTINS.has(specifier)\n ) {\n return null;\n }\n const segments = specifier.split(\"/\");\n if (specifier.startsWith(\"@\")) {\n return segments.length >= 2 ? `${segments[0]}/${segments[1]}` : null;\n }\n return segments[0] || null;\n};\n\n/**\n * Fallback static specifiers for a module the lexer rejects: a side-effect\n * `import \"x\"` or an `import`/`export … from \"x\"` clause. Only `import` takes\n * the bare-string form — `export \"x\"` is not syntax, so a runtime message\n * quoting `export 'ALL'` must not match.\n */\nconst STATIC_IMPORT =\n /(?:^|[;\\s}])(?:import\\s*[\"'](?<bare>[^\"'\\n]+)[\"']|(?:import|export)\\s*[\\w$*{},\\s]*?\\s*from\\s*[\"'](?<from>[^\"'\\n]+)[\"'])/gu;\n\n/** Fallback dynamic `import(\"…\")` specifiers. */\nconst DYNAMIC_IMPORT = /\\bimport\\(\\s*[\"'](?<dynamic>[^\"'\\n]+)[\"']\\s*\\)/gu;\n\n/**\n * Textual best effort for a module `es-module-lexer` cannot parse: every\n * quoted specifier in import position, string contents included.\n */\nconst scannedSpecifiers = (source: string): string[] => {\n const specifiers: string[] = [];\n for (const pattern of [STATIC_IMPORT, DYNAMIC_IMPORT]) {\n for (const match of source.matchAll(pattern)) {\n const groups = match.groups ?? {};\n specifiers.push(groups.bare ?? groups.from ?? groups.dynamic ?? \"\");\n }\n }\n return specifiers;\n};\n\n/**\n * Every specifier a module's syntax imports, read with `es-module-lexer` so\n * text inside string literals never counts. That matters for Blume's data\n * chunks: the MCP snapshot is `JSON.parse(\"…\")` over every page's Markdown,\n * and a code sample there reading `import { config } from 'dotenv'` is prose\n * to a bundle audit, not a module the function needs. `import.meta` carries no\n * specifier and a template-literal `import(\\`pkg/${x}\\`)` is a glob the\n * bundler already resolved, so neither names a package.\n */\nconst lexedSpecifiers = (source: string, name: string): string[] => {\n const [imports] = parse(source, name);\n const specifiers: string[] = [];\n for (const entry of imports) {\n if (entry.type === \"dynamic\" && entry.glob) {\n continue;\n }\n if (entry.specifier) {\n specifiers.push(entry.specifier);\n }\n }\n return specifiers;\n};\n\n/**\n * Every bare package name a module's source imports. A module the lexer\n * rejects (an unterminated string, an invalid escape in a specifier) falls\n * back to the textual scan rather than going unaudited.\n */\nexport const importedPackages = async (\n source: string,\n name = \"module\"\n): Promise<string[]> => {\n await init();\n let specifiers: string[];\n try {\n specifiers = lexedSpecifiers(source, name);\n } catch {\n specifiers = scannedSpecifiers(source);\n }\n const names = new Set<string>();\n for (const specifier of specifiers) {\n const packageId = packageName(specifier);\n if (packageId) {\n names.add(packageId);\n }\n }\n return [...names];\n};\n\n/** Whether `node_modules/<name>` exists on the walk from `from` up to `root`. */\nconst resolvable = (name: string, from: string, root: string): boolean => {\n let dir = from;\n for (;;) {\n if (existsSync(join(dir, \"node_modules\", name, \"package.json\"))) {\n return true;\n }\n if (dir === root) {\n return false;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n return false;\n }\n dir = parent;\n }\n};\n\nconst MODULE_FILE = /\\.(?:m?js|cjs)$/u;\n\n/** The one `.vc-config.json` field the audit reads; the rest passes through. */\nconst vcConfigSchema = z.looseObject({ handler: z.string().optional() });\n\n/** Every JavaScript module under `dir`, skipping any `node_modules`. */\nconst listModules = async (dir: string): Promise<string[]> => {\n const files: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const path = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (entry.name !== \"node_modules\") {\n // oxlint-disable-next-line no-await-in-loop -- sequential walk keeps ordering deterministic\n files.push(...(await listModules(path)));\n }\n } else if (entry.isFile() && MODULE_FILE.test(entry.name)) {\n files.push(path);\n }\n }\n return files;\n};\n\n/**\n * Audit one function directory: read its `.vc-config.json` handler, scan\n * every module beside the handler (the adapter's `dist/server` tree) for bare\n * imports, and report the packages no `node_modules` on the walk up to the\n * function root provides. A function without a handler has nothing to check.\n */\nexport const auditFunctionBundle = async (\n funcDir: string\n): Promise<MissingPackage[]> => {\n const configPath = join(funcDir, \".vc-config.json\");\n if (!existsSync(configPath)) {\n return [];\n }\n const config = vcConfigSchema.safeParse(\n JSON.parse(await readFile(configPath, \"utf-8\"))\n );\n if (!config.success || !config.data.handler) {\n return [];\n }\n const serverDir = dirname(join(funcDir, config.data.handler));\n if (!existsSync(serverDir)) {\n return [];\n }\n const missing = new Map<string, string[]>();\n for (const file of await listModules(serverDir)) {\n // oxlint-disable-next-line no-await-in-loop -- sequential read keeps the importer lists ordered\n const source = await readFile(file, \"utf-8\");\n // oxlint-disable-next-line no-await-in-loop -- the lexer runs per file, in the same order\n for (const name of await importedPackages(source, file)) {\n if (resolvable(name, dirname(file), funcDir)) {\n continue;\n }\n const importers = missing.get(name) ?? [];\n importers.push(relative(funcDir, file));\n missing.set(name, importers);\n }\n }\n return [...missing]\n .map(([name, importers]) => ({ importers, name }))\n .toSorted((a, b) => a.name.localeCompare(b.name));\n};\n\n/**\n * Audit every function in a Vercel Build Output tree (`.vercel/output`).\n * Functions with nothing missing are omitted; an output tree without a\n * `functions/` directory (a static build) yields nothing.\n */\nexport const auditVercelFunctions = async (\n outputDir: string\n): Promise<FunctionBundleAudit[]> => {\n const functionsDir = join(outputDir, \"functions\");\n if (!existsSync(functionsDir)) {\n return [];\n }\n const audits: FunctionBundleAudit[] = [];\n const entries = await readdir(functionsDir, { withFileTypes: true });\n for (const entry of entries.toSorted((a, b) => (a.name < b.name ? -1 : 1))) {\n if (!(entry.isDirectory() && entry.name.endsWith(\".func\"))) {\n continue;\n }\n const dir = join(functionsDir, entry.name);\n // oxlint-disable-next-line no-await-in-loop -- sequential audit keeps the report ordered\n const missing = await auditFunctionBundle(dir);\n if (missing.length > 0) {\n audits.push({ dir, missing });\n }\n }\n return audits;\n};\n\n/** Blume's own runtime dependency names, from its published `package.json`. */\nexport const blumeDependencyNames = (): Set<string> => {\n const manifest: { dependencies?: Record<string, string> } = JSON.parse(\n readFileSync(join(packageRoot(), \"package.json\"), \"utf-8\")\n );\n return new Set(Object.keys(manifest.dependencies ?? {}));\n};\n\n/** What a build should do about an audit: nothing, warn, or fail. */\nexport interface FunctionBundleVerdict {\n /**\n * A missing package is one of Blume's own dependencies — the runtime Blume\n * generated imports it, so the function is certain to crash. Anything else\n * (a project's own external import) is reported but left to the author.\n */\n fatal: boolean;\n message: string;\n}\n\n/**\n * The command that adds a dev dependency with the project's package manager\n * (`pnpm add -D`, `npm install -D`, …), for the fix a verdict prints. The\n * missing packages are an isolated-linker problem, so the project is often\n * not on npm at all.\n */\nexport const addDevDependencyCommand = async (root: string): Promise<string> =>\n `${commandsFor(await detectProjectPackageManager(root)).add} -D`;\n\n/**\n * Describe a function's missing packages and how to fix them. Vercel's trace\n * only reaches packages resolvable from the project root, so the remedy is a\n * root-level dependency entry for each — the same mirror rule Blume's native\n * dependencies (`sharp`, `takumi-js`) already follow — added with\n * `addDevCommand` (see {@link addDevDependencyCommand}).\n */\nexport const functionBundleVerdict = (\n audit: FunctionBundleAudit,\n root: string,\n ownDependencies: ReadonlySet<string>,\n addDevCommand = \"npm install -D\"\n): FunctionBundleVerdict => {\n const names = audit.missing.map((entry) => entry.name);\n const lines = audit.missing.map(\n (entry) => ` - ${entry.name} (imported by ${entry.importers.join(\", \")})`\n );\n const fatal = names.some((name) => ownDependencies.has(name));\n const message = [\n `The Vercel function bundle at ${relative(root, audit.dir) || audit.dir} is missing packages its server code imports, so the deployed function would fail on every request with ERR_MODULE_NOT_FOUND:`,\n ...lines,\n \"Vercel's dependency trace only includes packages resolvable from the project root; under an isolated linker (pnpm, Bun's isolated mode) Blume's own dependencies are not. Add them to the project's package.json so the trace can find them:\",\n ` ${addDevCommand} ${names.join(\" \")}`,\n ].join(\"\\n\");\n return { fatal, message };\n};\n",
|
|
171
|
+
"/**\n * `Accept: text/markdown` content negotiation for Vercel server builds.\n *\n * Blume prerenders every content page — even in a server build (`deployment:\n * vercel()`) — so a page request never reaches Astro middleware: Vercel serves\n * the prerendered HTML straight from its static layer. Request-time negotiation\n * therefore has to live in the platform's routing config. The Vercel adapter\n * emits a Build Output API `config.json`; these helpers splice extra routes\n * into it so a content-page request that prefers `text/markdown` is rewritten\n * (not redirected) to the page's prerendered `.md` mirror — the deployed\n * counterpart of the dev-server rewrite in `astro/markdown-negotiation.ts`.\n * The same routing config also answers a *missing* page: a request that\n * prefers Markdown (or asks for a `.md` URL no page backs) gets the\n * prerendered Markdown 404 body with the 404 status, instead of the HTML\n * shell, and one that prefers JSON (or asks for a `.json` URL) gets the\n * prerendered problem-details 404.\n */\n\n/**\n * Regex for the `accept` header condition. Written to hold under both matching\n * semantics a router may apply — full-string and substring — by anchoring the\n * end and letting `(.*,)?` absorb any earlier list entries: it requires a\n * `text/markdown` or `text/x-markdown` entry terminated by `;`, `,`, or the end\n * of the header. Kept lookaround-free so it stays valid in RE2, and lowercase\n * only — real agents send lowercase media types, and q-values are not compared\n * (a client sending `text/markdown` at `q=0` is pathological). Browsers never\n * send `text/markdown`, so ordinary page requests are unaffected.\n */\nexport const ACCEPT_MARKDOWN_HEADER_VALUE =\n \"(.*,)?\\\\s*text/(x-)?markdown(\\\\s*[;,].*)?$\";\n\n/**\n * The JSON counterpart, for the problem-details 404: `application/json` or\n * `application/problem+json`. Browsers never send either on a navigation\n * (the catch-all wildcard does not match), so ordinary page requests are\n * unaffected.\n */\nexport const ACCEPT_JSON_HEADER_VALUE =\n \"(.*,)?\\\\s*application/(problem\\\\+)?json(\\\\s*[;,].*)?$\";\n\n/**\n * A Build Output API route — the subset these helpers read and write. Parsed\n * routes keep whatever other fields they carry at runtime; only these are\n * typed.\n */\nexport interface VercelRoute {\n continue?: boolean;\n dest?: string;\n handle?: string;\n has?: { key?: string; type: string; value?: string }[];\n headers?: Record<string, string>;\n src?: string;\n status?: number;\n}\n\n/** Whether a parsed route field is a real string (the config is raw JSON). */\nconst isString = (value: string | undefined): value is string =>\n typeof value === \"string\";\n\nconst ACCEPT_MARKDOWN_CONDITION: VercelRoute[\"has\"] = [\n { key: \"accept\", type: \"header\", value: ACCEPT_MARKDOWN_HEADER_VALUE },\n];\n\nconst ACCEPT_JSON_CONDITION: VercelRoute[\"has\"] = [\n { key: \"accept\", type: \"header\", value: ACCEPT_JSON_HEADER_VALUE },\n];\n\nconst VARY_ACCEPT = { vary: \"Accept\" };\n\n/** Where the prerendered Markdown 404 (`pages/404.md.ts`) lands. */\nconst NOT_FOUND_MARKDOWN_DEST = \"/404.md\";\n\n/** Where the prerendered JSON 404 (`pages/404.json.ts`) lands. */\nconst NOT_FOUND_JSON_DEST = \"/404.json\";\n\n/** The adapter's own not-found fallback — the anchor the Markdown 404 precedes. */\nconst NOT_FOUND_HTML_DEST = \"/404.html\";\n\n/**\n * Miss-phase routes that answer a missing page with the Markdown 404 body: any\n * path when the client prefers Markdown, and any `.md`/`.mdx` URL (a request\n * for a raw-Markdown mirror that has no page wants Markdown back, not the HTML\n * shell). Both keep the 404 status. Spliced immediately before the adapter's\n * `/404.html` fallback, so they run after every server route (the MCP\n * endpoint, server islands, images) has had its turn and never hijack a\n * request one of those would have answered.\n */\nconst NOT_FOUND_MARKDOWN_ROUTES: readonly VercelRoute[] = [\n {\n dest: NOT_FOUND_MARKDOWN_DEST,\n has: ACCEPT_MARKDOWN_CONDITION,\n headers: VARY_ACCEPT,\n src: \"^/.*$\",\n status: 404,\n },\n { dest: NOT_FOUND_MARKDOWN_DEST, src: \"^/.*\\\\.mdx?$\", status: 404 },\n];\n\n/**\n * The JSON 404's miss-phase routes, the problem-details twin of the Markdown\n * ones: any path when the client prefers JSON, and any `.json` URL no file\n * backs. Spliced at the same anchor, after every server route — so the\n * `/api/` catch-all (which answers its own namespace with a problem document)\n * has already had its turn.\n */\nconst NOT_FOUND_JSON_ROUTES: readonly VercelRoute[] = [\n {\n dest: NOT_FOUND_JSON_DEST,\n has: ACCEPT_JSON_CONDITION,\n headers: VARY_ACCEPT,\n src: \"^/.*$\",\n status: 404,\n },\n { dest: NOT_FOUND_JSON_DEST, src: \"^/.*\\\\.json$\", status: 404 },\n];\n\n/** Which prerendered 404 twins the build emitted, so their routes get wired. */\nexport interface NotFoundVariants {\n json?: boolean;\n markdown?: boolean;\n}\n\n/**\n * Vercel rejects route `src` patterns longer than 4096 characters, so route\n * alternations are split across as many route entries as needed. The budget\n * leaves headroom for the `^(` … `)/?$` wrapper.\n */\nconst MAX_ALTERNATION_LENGTH = 3900;\n\nconst REGEX_SPECIALS = /[$()*+.?[\\]^{|}\\\\]/gu;\n\n/**\n * A route path as it appears on the wire (percent-encoded, matching the layout\n * of the prerendered files), escaped for literal use inside the alternation.\n * Escaping runs after encoding; the `%` an encode introduces is not a regex\n * metacharacter.\n */\nconst routePattern = (route: string): string =>\n encodeURI(route).replace(REGEX_SPECIALS, \"\\\\$&\");\n\n/** Group patterns so each group's alternation stays under the `src` limit. */\nconst chunkPatterns = (patterns: readonly string[]): string[][] => {\n const chunks: string[][] = [];\n let current: string[] = [];\n let length = 0;\n for (const pattern of patterns) {\n if (\n current.length > 0 &&\n length + pattern.length + 1 > MAX_ALTERNATION_LENGTH\n ) {\n chunks.push(current);\n current = [];\n length = 0;\n }\n current.push(pattern);\n length += pattern.length + 1;\n }\n if (current.length > 0) {\n chunks.push(current);\n }\n return chunks;\n};\n\nexport interface NegotiationRoutes {\n /**\n * `Vary: Accept` for the plain-HTML side of every negotiated URL, so shared\n * caches keep the two variants apart. Spliced *before* `handle:\n * \"filesystem\"` with `continue`: main-phase headers accumulate and ride on\n * whatever ultimately serves the request. Routes placed after the filesystem\n * marker are the miss phase — they run only when no static file matches, and\n * every Blume content page is a prerendered static file, so a header route\n * there never fires.\n */\n headerRoutes: VercelRoute[];\n /**\n * The negotiation itself: header-conditional rewrites to the `.md` mirror.\n * Spliced *before* `handle: \"filesystem\"` so they run ahead of static-file\n * matching; the rewritten path then resolves to the prerendered `.md` file.\n */\n rewriteRoutes: VercelRoute[];\n}\n\n/**\n * Build the routes for the given content-route paths (the routes that have a\n * raw-Markdown mirror, straight from the manifest). Paths are matched with an\n * optional trailing slash and rewritten `/{route}` → `/{route}.md`; the home\n * page's mirror lives at `/index.md`. When `homeTokens` is given, the home\n * rewrite also stamps `x-markdown-tokens` — the estimated token count of the\n * homepage mirror (Cloudflare's Markdown for Agents convention). Only the home\n * route can carry it: the other rewrites are chunked alternations spanning\n * many pages, and a count is per-page.\n */\nexport const buildNegotiationRoutes = (\n routePaths: readonly string[],\n homeTokens?: number\n): NegotiationRoutes => {\n const home = routePaths.includes(\"/\");\n const rest = routePaths\n .filter((path) => path !== \"/\")\n .map((path) => routePattern(path));\n const chunks = chunkPatterns(rest);\n\n const rewriteRoutes: VercelRoute[] = home\n ? [\n {\n dest: \"/index.md\",\n has: ACCEPT_MARKDOWN_CONDITION,\n headers:\n homeTokens === undefined\n ? VARY_ACCEPT\n : { ...VARY_ACCEPT, \"x-markdown-tokens\": String(homeTokens) },\n src: \"^/$\",\n },\n ]\n : [];\n for (const chunk of chunks) {\n rewriteRoutes.push({\n dest: \"$1.md\",\n has: ACCEPT_MARKDOWN_CONDITION,\n headers: VARY_ACCEPT,\n src: `^(${chunk.join(\"|\")})/?$`,\n });\n }\n\n const headerChunks = chunkPatterns(home ? [\"/\", ...rest] : rest);\n const headerRoutes: VercelRoute[] = headerChunks.map((chunk) => ({\n continue: true,\n headers: VARY_ACCEPT,\n src: `^(?:${chunk.join(\"|\")})/?$`,\n }));\n\n return { headerRoutes, rewriteRoutes };\n};\n\n/** The `src` of the injected homepage `Link` header route. */\nconst HOME_SRC = \"^/$\";\n\nconst ALLOW_ANY_ORIGIN = \"*\";\n\n/**\n * A main-phase `continue` route stamping `Access-Control-Allow-Origin: *` on\n * one static discovery document (see `crossOriginDiscoveryPaths`), so a\n * registry reading it from another origin isn't refused by the browser.\n */\nconst corsRoute = (path: string): VercelRoute => ({\n continue: true,\n headers: { \"access-control-allow-origin\": ALLOW_ANY_ORIGIN },\n src: `^${routePattern(path)}$`,\n});\n\n/** Whether a route is a `corsRoute` — the same three-field shape test as the others. */\nconst isCorsRoute = (route: VercelRoute): boolean =>\n route.continue === true &&\n route.headers?.[\"access-control-allow-origin\"] === ALLOW_ANY_ORIGIN &&\n isString(route.src) &&\n Object.keys(route).length === 3;\n\n/**\n * Whether a route is one this module previously injected, so re-injection\n * replaces rather than duplicates. Rewrites are identified by their `accept`\n * condition; the `Vary` routes by their exact three-field shape (a\n * user-authored route of that identical shape would be semantically equal to\n * the one re-added); the homepage `Link` route by its three-field\n * continue-with-link shape (the Build Output config is adapter-generated, so\n * no user-authored route competes in this file); the Markdown 404 routes by\n * their `/404.md` destination.\n */\nconst isNegotiationRoute = (route: VercelRoute): boolean =>\n route.has?.some(\n (condition) => condition.value === ACCEPT_MARKDOWN_HEADER_VALUE\n ) === true ||\n (route.dest === NOT_FOUND_MARKDOWN_DEST && route.status === 404) ||\n (route.dest === NOT_FOUND_JSON_DEST && route.status === 404) ||\n (route.continue === true &&\n route.headers?.vary === \"Accept\" &&\n isString(route.src) &&\n Object.keys(route).length === 3) ||\n (route.continue === true &&\n isString(route.headers?.link) &&\n route.src === HOME_SRC &&\n Object.keys(route).length === 3) ||\n isCorsRoute(route);\n\n/**\n * Splice the negotiation routes into a Build Output `config.json`, plus — when\n * given — a homepage `Link` header route for agent discovery (see\n * `ai/link-headers.ts`), applied the same way the `Vary` routes are: in the\n * main phase before `handle: \"filesystem\"` with `continue`, so the header\n * rides on the prerendered homepage response. `contentTypeOverrides` maps static-dir\n * relative paths to media types via the Build Output `overrides` field — the\n * platform's mechanism for extensionless static files (e.g. the Web Bot Auth\n * signature directory). The trailing-slash redirect that collapses `/docs/`\n * onto `/docs` is not spliced here: the generated config sets Astro's\n * `trailingSlash: \"never\"`, which the adapter turns into the platform's own\n * 308 route ahead of everything below (so a slashed Markdown request takes\n * that hop first, then negotiates). For each 404 twin the build emitted (`notFound.markdown` for\n * `404.md`, `notFound.json` for `404.json`), its routes go into the miss\n * phase right before the adapter's `/404.html` fallback — and nowhere when\n * that fallback is absent, since a `dest` with no file behind it would serve\n * nothing. Returns the updated JSON\n * text (tab-indented, like the adapter's own output), or `null` when there is\n * nowhere safe to splice: an unparsable config, no `routes` array, or no\n * `handle: \"filesystem\"` marker to anchor the splice.\n */\nexport const injectNegotiationRoutes = (\n configText: string,\n routePaths: readonly string[],\n homeLinkHeader?: string | null,\n contentTypeOverrides?: Record<string, string>,\n homeTokens?: number,\n notFound: NotFoundVariants = {},\n corsPaths: readonly string[] = []\n): string | null => {\n const overrideEntries = Object.entries(contentTypeOverrides ?? {});\n let config: {\n overrides?: Record<string, { contentType?: string; path?: string }>;\n routes?: VercelRoute[];\n };\n try {\n config = JSON.parse(configText);\n } catch {\n return null;\n }\n if (!Array.isArray(config.routes)) {\n return null;\n }\n for (const [path, contentType] of overrideEntries) {\n // Keyed assignment, so re-injection replaces rather than duplicates and a\n // user's own override of the same path is simply refreshed.\n config.overrides = { ...config.overrides, [path]: { contentType } };\n }\n const routes = config.routes.filter((route) => !isNegotiationRoute(route));\n const filesystemIndex = routes.findIndex(\n (route) => route.handle === \"filesystem\"\n );\n if (filesystemIndex === -1) {\n return null;\n }\n const { headerRoutes, rewriteRoutes } = buildNegotiationRoutes(\n routePaths,\n homeTokens\n );\n if (homeLinkHeader) {\n headerRoutes.push({\n continue: true,\n headers: { link: homeLinkHeader },\n src: HOME_SRC,\n });\n }\n headerRoutes.push(...corsPaths.map(corsRoute));\n // Headers first: `continue` routes accumulate, so a request the rewrite\n // route then terminates (Markdown negotiation on the homepage) still carries\n // the Link header.\n routes.splice(filesystemIndex, 0, ...headerRoutes, ...rewriteRoutes);\n const notFoundRoutes = [\n ...(notFound.markdown ? NOT_FOUND_MARKDOWN_ROUTES : []),\n ...(notFound.json ? NOT_FOUND_JSON_ROUTES : []),\n ];\n if (notFoundRoutes.length > 0) {\n const fallbackIndex = routes.findIndex(\n (route) => route.status === 404 && route.dest === NOT_FOUND_HTML_DEST\n );\n if (fallbackIndex !== -1) {\n routes.splice(fallbackIndex, 0, ...notFoundRoutes);\n }\n }\n config.routes = routes;\n return `${JSON.stringify(config, null, \"\\t\")}\\n`;\n};\n",
|
|
172
|
+
"import { REDIRECTS_FILE } from \"./netlify.ts\";\nimport { distDir } from \"./paths.ts\";\nimport type { DeployPlatform } from \"./types.ts\";\nimport { VERCEL_JSON_FILE } from \"./vercel.ts\";\n\n/**\n * A static build for an unnamed host — the default. Nothing is known about\n * where `dist/` ends up, so the build writes every platform's redirect file\n * (`_redirects` for Netlify and Cloudflare, `vercel.json` for Vercel, plus the\n * manifest for everything else) and the `_headers` file; a host that reads\n * none of them ignores them harmlessly. The site URL is still inferred from\n * whichever platform env the build runs in.\n */\nexport const staticPlatform: DeployPlatform = {\n astro: null,\n env: null,\n finalizeBuild: null,\n hiddenRuntime: {\n ignoreDir: null,\n showProjectRoot: false,\n surfacePath: null,\n },\n kind: \"static\",\n negotiatesMarkdown: false,\n readsHeaderFiles: { server: false, static: true },\n redirectFiles: [REDIRECTS_FILE, VERCEL_JSON_FILE],\n serverOutputDir: distDir,\n serverStaticDir: distDir,\n};\n",
|
|
173
|
+
"import type {\n DeployAdapterKind,\n ResolvedDeployment,\n} from \"../adapters/registry.ts\";\nimport { cloudflarePlatform } from \"./cloudflare.ts\";\nimport { netlifyPlatform } from \"./netlify.ts\";\nimport { nodePlatform } from \"./node.ts\";\nimport { staticPlatform } from \"./static.ts\";\nimport type { DeployPlatform } from \"./types.ts\";\nimport { vercelPlatform } from \"./vercel.ts\";\n\n/**\n * Every platform, in the order their env detection is tried when a build's\n * own adapter says nothing about where it runs (a static build on Vercel\n * still gets its site URL from `VERCEL_URL`).\n */\nexport const DEPLOY_PLATFORMS: readonly DeployPlatform[] = [\n vercelPlatform,\n netlifyPlatform,\n cloudflarePlatform,\n nodePlatform,\n staticPlatform,\n];\n\nconst byKind = new Map<DeployAdapterKind, DeployPlatform>(\n DEPLOY_PLATFORMS.map((platform) => [platform.kind, platform])\n);\n\n/** The behaviors behind a resolved deployment descriptor. */\nexport const deployPlatform = (\n deployment: Pick<ResolvedDeployment, \"kind\">\n): DeployPlatform => {\n const platform = byKind.get(deployment.kind);\n if (!platform) {\n throw new Error(`Unknown deployment adapter \"${deployment.kind}\".`);\n }\n return platform;\n};\n\n/**\n * The site URL the platform env implies, or null. The configured adapter's\n * own platform is asked first, then the rest in registration order, so a\n * static build (which names no host) still picks up the URL of whichever\n * platform it is building on.\n */\nexport const inferDeploymentSite = (\n deployment: Pick<ResolvedDeployment, \"kind\">,\n env: NodeJS.ProcessEnv\n): string | null => {\n const own = deployPlatform(deployment);\n const candidates = [own, ...DEPLOY_PLATFORMS.filter((p) => p !== own)];\n const detected = candidates.find(\n (platform) => platform.env?.detect(env) ?? false\n );\n // `find` only returns a platform whose `env` matched, so it is present.\n return detected?.env?.site(env) ?? null;\n};\n\nexport type {\n AstroAdapterSpec,\n BuildLog,\n DeployPlatform,\n FinalizeBuildOptions,\n HiddenRuntime,\n PlatformEnv,\n RedirectFile,\n} from \"./types.ts\";\n",
|
|
174
|
+
"import { existsSync } from \"node:fs\";\n\nimport { isAbsolute, join, resolve } from \"pathe\";\n\nimport type { ResolvedConfig } from \"./schema.ts\";\nimport { resolveDocsCollection } from \"./sources/collection.ts\";\nimport type { ProjectContext } from \"./types.ts\";\n\nconst CONFIG_FILENAMES = [\n \"blume.config.ts\",\n \"blume.config.mjs\",\n \"blume.config.js\",\n];\n\nconst THEME_FILENAMES = [\"theme.css\"];\nconst COMPONENTS_FILENAMES = [\"components.tsx\", \"components.ts\"];\n\nconst firstExisting = (root: string, names: string[]): string | null => {\n for (const name of names) {\n const candidate = join(root, name);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n return null;\n};\n\n/** Locate the Blume config file for a project root, if any. */\nexport const findConfigFile = (root: string): string | null =>\n firstExisting(root, CONFIG_FILENAMES);\n\n/** Locate the project's `components.ts`/`.tsx` override file, if any. */\nexport const findComponentsFile = (root: string): string | null =>\n firstExisting(root, COMPONENTS_FILENAMES);\n\n/**\n * Resolve the generated runtime directory for a project. Defaults to\n * `<root>/.blume`; an override (e.g. `.blume-verify` for an isolated build that\n * runs alongside a live `blume dev`) may be relative to the root or absolute.\n */\nexport const resolveRuntimeDir = (\n root: string,\n runtimeDir = \".blume\"\n): string =>\n isAbsolute(runtimeDir) ? runtimeDir : join(resolve(root), runtimeDir);\n\n/**\n * Resolve every path Blume needs from a project root and its resolved config.\n * Paths are absolute and normalized. `options.runtimeDir` relocates the whole\n * generated runtime (and its build output) so a verify build/check can run\n * without touching a live dev server's `.blume/` or the real `dist/`.\n */\nexport const resolveProjectContext = (\n root: string,\n config: ResolvedConfig,\n options?: { runtimeDir?: string }\n): ProjectContext => {\n const absoluteRoot = resolve(root);\n // The content root is where the `docs` collection roots: the first\n // filesystem source (the implicit one, for a zero-config project).\n const contentRoot = resolveDocsCollection(config, absoluteRoot).base;\n\n const pagesPath = join(absoluteRoot, config.content.pages);\n const pagesRoot = existsSync(pagesPath) ? pagesPath : null;\n\n const outDir = resolveRuntimeDir(absoluteRoot, options?.runtimeDir);\n // A relocated runtime keeps its build output self-contained under itself, so a\n // verify build never empties the user's real `<root>/dist`.\n const distDir = options?.runtimeDir\n ? join(outDir, \"dist\")\n : join(absoluteRoot, \"dist\");\n\n return {\n componentsFile: findComponentsFile(absoluteRoot),\n configFile: findConfigFile(absoluteRoot),\n contentRoot,\n distDir,\n outDir,\n pagesRoot,\n root: absoluteRoot,\n themeFile: firstExisting(absoluteRoot, THEME_FILENAMES),\n };\n};\n",
|
|
175
|
+
"import { existsSync, readFileSync } from \"node:fs\";\n\nimport { z } from \"zod\";\n\nimport type { BlumeConfig } from \"./config-input.ts\";\nimport { applyDeploymentEnv } from \"./deployment-env.ts\";\nimport {\n BlumeError,\n diagnosticsFromIssues,\n diagnosticsFromZod,\n} from \"./diagnostics.ts\";\nimport { createModuleLoader } from \"./load-module.ts\";\nimport { findConfigFile } from \"./project.ts\";\nimport { blumeConfigSchema } from \"./schema.ts\";\nimport type { ResolvedConfig } from \"./schema.ts\";\nimport type { Diagnostic } from \"./types.ts\";\n\n/**\n * Define a Blume site's configuration with full type-checking and editor\n * autocomplete. Place the call in `blume.config.ts` at your project root and\n * `export default` the result:\n *\n * ```ts\n * import { defineConfig } from \"blume\";\n *\n * export default defineConfig({\n * title: \"Acme Docs\",\n * description: \"Everything you need to build with Acme.\",\n * });\n * ```\n *\n * Every field is optional — an empty `defineConfig({})` produces a working\n * site from the Markdown/MDX in your `docs/` directory. Configure only what you\n * want to change; sensible defaults fill in the rest.\n *\n * This is an identity helper: it returns its input unchanged and exists purely\n * for type inference (and as a stable home for future plugin hooks). The object\n * is validated against the Blume schema when the CLI loads it.\n *\n * ## Top-level fields\n *\n * **Site identity**\n * - `title` — site title, shown in the header, `<title>`, and OG images.\n * Defaults to `\"Documentation\"`.\n * - `description` — default meta description, used where a page sets none.\n * - `logo` — brand mark. A string is an image path/URL; the object form splits\n * an `image` mark from wordmark `text` and can override the brand `href`.\n * - `banner` — site-wide announcement bar; a string, or `{ content, link,\n * dismissible }`.\n *\n * **Content & navigation**\n * - `content` — where content lives: adapters from `blume/sources` under\n * `sources` (`filesystem({ root })`, `mdxRemote({…})`, `githubReleases({…})`,\n * `sanity({…})`, `notion({…})`, `contentful({…})`, `payload({…})`,\n * `strapi({…})`, `obsidian({…})`, or `custom(source)`), or the\n * zero-config shorthand `root`/`include`/`exclude`, which desugars to one\n * `filesystem()` source and can't be combined with `sources`.\n * - `navigation` — sidebar, header `tabs`, `selectors` (version/language/product\n * switchers), pinned `featured` links, header `actions` and the one `cta`,\n * and the `repo` link (a toggle, or a URL). Omit `sidebar` to generate it\n * from the content tree.\n * - `redirects` — `{ from, to, status }` rules (301 by default).\n * - `github` — `{ owner, repo, branch, dir, host, api }`, powering \"Edit this\n * page\" links and the header repo link; `host` points them at a GitHub\n * Enterprise instance, `api` overrides the REST base derived from it.\n *\n * **Appearance**\n * - `theme` — `accent` color, `fonts` (curated slugs, any provider family, or\n * local font files), `radius`,\n * `mode` (`system`/`light`/`dark`), and `background`.\n * - `markdown` — `code` (language icons, inline highlighting, line wrap),\n * `headingAnchors`, `imageZoom`, and opt-in KaTeX `math`.\n * - `toc` — on-page table of contents; `true`/`false` or a heading-level range.\n * - `lastModified` — \"Last updated\" stamps from `git` history or frontmatter.\n * - `feedback` — the per-page \"Was this helpful?\" widget (on by default).\n * - `export` — reader-facing PDF/EPUB export actions (off by default).\n *\n * **Reference docs**\n * - `reference` — API references as a list of adapters from\n * `blume/reference`: `openapi({…})` and `asyncapi({…})` render native pages\n * (one real page per operation, woven into the sidebar and search; AsyncAPI\n * 2.x specs are normalized to 3.x), `graphql({…})` renders a schema, and\n * `scalar({…})` embeds the Scalar reference instead.\n *\n * **Search, AI & agents**\n * - `search` — a search adapter from `blume/search` (`orama()` by default;\n * `flexsearch()`, `pagefind()`, `algolia({…})`, `oramaCloud({…})`,\n * `typesense({…})`, `mixedbread({…})`, or `false`), or `{ provider,\n * popular, indexing }` to add curated links and indexing settings.\n * - `ai` — what faces a model at read time: `ask` (the Ask AI assistant, with\n * a provider adapter from `blume/ai` such as `gateway()` or `openrouter()`)\n * and `openInChat` (the \"Open in chat\" page action).\n * - `agents` — the machine-readable surface: `llmsTxt`, the JSON `api`, the\n * `mcp` server, published `skills`, `markdownComponents` (Markdown\n * serializers for custom components), the `catalog` manifests,\n * `agentReadability`, robots `contentSignals`, `webmcp`, and `webBotAuth`.\n *\n * **SEO, feeds & analytics**\n * - `seo` — `og` images, `sitemap`, `robots`, `rss` feeds, and\n * `structuredData` JSON-LD.\n * - `analytics` — a list of adapters from `blume/analytics`, one per provider\n * (`posthog()`, `googleAnalytics()`, `plausible()`, `fathom()`, `vercel()`,\n * `cloudflare()`, …), or `script()` for anything without one.\n *\n * **Astro**\n * - `integrations` — Astro integrations appended after Blume's built-ins, in\n * declaration order. Install and maintain each integration in the site.\n *\n * **Deployment & i18n**\n * - `deployment` — a host adapter from `blume/deploy` (`vercel()`, `node()`,\n * `netlify()`, `cloudflare()`) for a server build, each taking `site`,\n * `base`, and `output`; or `{ site, base }` for a static build anywhere.\n * `site` is auto-detected on Vercel/Netlify/Cloudflare from the platform env.\n * - `i18n` — opt-in multi-locale: `locales`, `defaultLocale`, `parser`\n * (`dir` vs filename `dot` suffix), and per-locale UI overrides.\n *\n * - `examples` — `<Component path>` previews: `source` (default `examples/`;\n * supports a glob for colocated registries) and `css`, a stylesheet injected\n * into the isolated preview frames (e.g. shadcn variables).\n *\n * @example Zero-config — just render the Markdown under `docs/`.\n * ```ts\n * export default defineConfig({});\n * ```\n *\n * @example A production docs site with theming, search, and deployment.\n * ```ts\n * import { vercel } from \"blume/deploy\";\n * import { orama } from \"blume/search\";\n *\n * export default defineConfig({\n * title: \"Acme Docs\",\n * description: \"Build faster with Acme.\",\n * logo: { image: \"/logo.svg\", text: \"Acme\" },\n * github: { owner: \"acme\", repo: \"acme\" },\n * theme: { accent: \"purple\", fonts: { body: \"inter\" }, radius: \"lg\" },\n * navigation: {\n * tabs: [\n * { label: \"Guides\", path: \"/guides\" },\n * { label: \"API\", path: \"/api\" },\n * ],\n * },\n * search: orama(),\n * // A server build on Vercel.\n * deployment: vercel({ site: \"https://docs.acme.com\" }),\n * });\n * ```\n *\n * @example An OpenAPI reference with the Ask AI assistant enabled.\n * ```ts\n * import { openapi } from \"blume/reference\";\n *\n * export default defineConfig({\n * title: \"Acme API\",\n * reference: [\n * openapi({\n * route: \"/reference\",\n * sources: [{ label: \"Core\", spec: \"./openapi.json\" }],\n * }),\n * ],\n * agents: { llmsTxt: true },\n * ai: { ask: { enabled: true } },\n * });\n * ```\n *\n * @param config - The site configuration. All fields are optional.\n * @returns The same config object, typed for inference.\n * @see https://useblume.dev/docs for the full configuration reference.\n */\nexport const defineConfig = (config: BlumeConfig): BlumeConfig => config;\n\n/**\n * A config that fails validation. `diagnostic` folds every issue into the one\n * message a command prints; `issues` keeps each on its own, with its own\n * line, for `blume upgrade`, which lists them one by one.\n */\nexport class ConfigValidationError extends BlumeError {\n readonly issues: Diagnostic[];\n\n constructor(diagnostic: Diagnostic, issues: Diagnostic[]) {\n super(diagnostic);\n this.name = \"ConfigValidationError\";\n this.issues = issues;\n }\n}\n\n/** Result of loading + validating a project config. */\nexport interface ConfigLoadResult {\n config: ResolvedConfig;\n /** Absolute path of the config file used, or null when defaults were used. */\n configFile: string | null;\n diagnostics: Diagnostic[];\n /**\n * Whether the config file set `theme.fonts` itself. The schema always fills\n * the roles with defaults, so the resolved config can't tell an intentional\n * font choice from the fallback — and only intentional choices should flow\n * into derived surfaces like OG card fonts.\n */\n themeFontsConfigured: boolean;\n}\n\nconst importConfigModule = createModuleLoader();\n\n/**\n * The slice of a user config module probed before schema defaults apply:\n * whether `theme.fonts` was actually set. `looseObject` keeps every other key\n * out of scope; a non-object at either level simply fails the probe. `fonts`\n * is optional here — Zod 4 treats a bare `z.unknown()` key as required, which\n * would fail the probe for every `theme` that doesn't set fonts.\n */\nconst themeFontsProbeSchema = z.looseObject({\n theme: z.looseObject({ fonts: z.unknown().optional() }).optional(),\n});\n\nconst isPathSegment = (segment: PropertyKey): segment is string | number =>\n typeof segment !== \"symbol\";\n\n/**\n * Where an issue is located in the config source: its own path, except that\n * an unknown key — which Zod reports on its parent's path — is located at the\n * key itself, so a removed field points at the line that sets it.\n */\nconst locationPath = (issue: z.core.$ZodIssue): (string | number)[] => [\n ...issue.path.filter(isPathSegment),\n ...(issue.code === \"unrecognized_keys\" ? issue.keys.slice(0, 1) : []),\n];\n\n/** Sort key for a config issue: the line that set the field, else last. */\nconst lineRank = (diagnostic: Diagnostic): number =>\n diagnostic.line ?? Number.MAX_SAFE_INTEGER;\n\n/**\n * One diagnostic per config issue, each anchored to the config file and, when\n * the source is on disk, to the line and column that set the field. Issues on\n * the config's own top level (a removed top-level block) lead, since they name\n * the biggest moves; the rest read top to bottom, in source order.\n */\nconst configIssues = (\n error: z.ZodError,\n options: { file?: string; source?: string }\n): Diagnostic[] => {\n const code = \"BLUME_CONFIG_INVALID\";\n const located = diagnosticsFromIssues(\n error.issues.map((issue) => ({\n message: issue.message,\n path: locationPath(issue),\n })),\n { code, source: options.source }\n );\n return diagnosticsFromZod(error, { code, ...options })\n .map((diagnostic, index) => ({\n ...diagnostic,\n column: located[index]?.column,\n line: located[index]?.line,\n }))\n .toSorted(\n (a, b) =>\n Number(Boolean(a.schemaPath)) - Number(Boolean(b.schemaPath)) ||\n lineRank(a) - lineRank(b)\n );\n};\n\n/**\n * Load and validate the project config. When no config file exists, schema\n * defaults produce a fully resolved config so the zero-boilerplate path works.\n */\nexport const loadConfig = async (\n root: string,\n /**\n * Supplied only by `blume dev`: the local dev server URL, used as the\n * `deployment.site` fallback when none is configured or detected. Builds\n * never pass it, so production output can't end up pointing at localhost.\n */\n options: { devServerUrl?: string } = {}\n): Promise<ConfigLoadResult> => {\n const configFile = findConfigFile(root);\n\n let raw: unknown;\n if (configFile) {\n try {\n raw = await importConfigModule(configFile);\n } catch (error) {\n // SAFETY: the module loader rejects with the thrown load/parse failure,\n // which Node surfaces as an Error; a non-Error rejection only degrades\n // the interpolated message.\n throw new BlumeError({\n code: \"BLUME_CONFIG_LOAD_FAILED\",\n file: configFile,\n message: `Failed to load config: ${(error as Error).message}`,\n severity: \"error\",\n });\n }\n }\n\n // Read before parsing: schema defaults erase the set-vs-defaulted distinction.\n const probe = themeFontsProbeSchema.safeParse(raw);\n const themeFontsConfigured =\n probe.success && probe.data.theme?.fonts !== undefined;\n\n const parsed = blumeConfigSchema.safeParse(raw ?? {});\n if (!parsed.success) {\n // Read the raw config text (when on disk) so errors carry a line/column.\n const source =\n configFile && existsSync(configFile)\n ? readFileSync(configFile, \"utf-8\")\n : undefined;\n const diagnostics = configIssues(parsed.error, {\n file: configFile ?? undefined,\n source,\n });\n const [first, ...rest] = diagnostics;\n const primary = first ?? {\n code: \"BLUME_CONFIG_INVALID\",\n file: configFile ?? undefined,\n message: \"Invalid Blume config.\",\n severity: \"error\" as const,\n };\n // Surface every issue in one failing run — reporting only the first turns\n // a three-mistake config into three fix-rerun-fail loops.\n const moreIssues = rest.map((d) => ` - ${d.message}`).join(\"\\n\");\n const detail =\n rest.length > 0\n ? {\n ...primary,\n message: `${primary.message}\\n${rest.length} more config issue(s):\\n${moreIssues}`,\n }\n : primary;\n throw new ConfigValidationError(detail, diagnostics);\n }\n\n // Resolve the canonical site URL, then SEO defaults that depend on it.\n // Precedence: explicit config > platform env (Vercel/Netlify/Cloudflare, via\n // applyDeploymentEnv) > the local dev server URL (dev only).\n const config = applyDeploymentEnv(parsed.data);\n const site = config.deployment.options.site ?? options.devServerUrl;\n\n // OG images need an absolute `og:image`, so they default on once a site URL\n // is known and off otherwise. An explicit `seo.og.enabled` always wins.\n const ogEnabled = config.seo.og.enabled ?? Boolean(site);\n\n return {\n config: {\n ...config,\n deployment: site\n ? {\n ...config.deployment,\n options: { ...config.deployment.options, site },\n }\n : config.deployment,\n seo: { ...config.seo, og: { ...config.seo.og, enabled: ogEnabled } },\n },\n configFile,\n diagnostics: [],\n themeFontsConfigured,\n };\n};\n",
|
|
176
|
+
"import { inferDeploymentSite } from \"../deploy/platforms/index.ts\";\nimport type { ResolvedConfig } from \"./schema.ts\";\n\n/**\n * Fill in the deployment `site` from platform env vars (Vercel, Netlify,\n * Cloudflare Pages) when the config hasn't set one. Explicit config always\n * wins. Each adapter's platform declares its own detection and URL vars (see\n * `deploy/platforms/*`); the configured adapter is asked first, then every\n * other platform, so a static build deployed to a known host gets a working\n * canonical origin for free, mirroring Astro's platform auto-detection.\n */\nexport const applyDeploymentEnv = (\n config: ResolvedConfig,\n env: NodeJS.ProcessEnv = process.env\n): ResolvedConfig => {\n const { deployment } = config;\n if (deployment.options.site) {\n return config;\n }\n const site = inferDeploymentSite(deployment, env);\n if (!site) {\n return config;\n }\n return {\n ...config,\n deployment: {\n ...deployment,\n options: { ...deployment.options, site },\n },\n };\n};\n",
|
|
177
|
+
"import { createJiti } from \"jiti\";\n\n/**\n * Create a loader for user-authored ESM/TS modules (`blume.config.ts`,\n * `meta.ts`). One jiti instance is reused across every file the returned loader\n * is called with. `moduleCache: false` ensures edits are picked up on each load,\n * which is what makes dev-server regeneration reflect config/meta changes.\n */\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- user-authored modules can export anything; callers validate the loaded value at their own boundary\nexport const createModuleLoader = (): ((file: string) => Promise<unknown>) => {\n const jiti = createJiti(import.meta.url, { moduleCache: false });\n return async (file: string) => {\n const loaded = await jiti.import<{ default?: unknown }>(file);\n return loaded?.default ?? loaded;\n };\n};\n"
|
|
178
|
+
],
|
|
179
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AAiBA,IAAM,YAAY,CAAC,YAAY;AAS/B,IAAM,gBAAgB,CAAC,QACrB,IAAI,MAAM,GAAG,EAAE,KAAK,CAAC,YAAY,QAAQ,WAAW,GAAG,CAAC;AAG1D,IAAM,eAAe,CACnB,WACA,UACsB;AAAA,EACtB,MAAM,KAAK;AAAA,EACX,MAAM,SAA4B,CAAC;AAAA,EACnC,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,MAAM,SAAS,WAAW,IAAI;AAAA,IACpC,IAAI,cAAc,GAAG,GAAG;AAAA,MACtB;AAAA,IACF;AAAA,IACA,MAAM,aAAa,IAAI,MAAM,GAAG,IAAI,SAAS,QAAQ,GAAG,EAAE,MAAM;AAAA,IAChE,MAAM,QAAQ,WAAW,MAAM,GAAG;AAAA,IAGlC,IAAI,MAAM,GAAG,EAAE,MAAM,SAAS;AAAA,MAC5B,MAAM,IAAI;AAAA,IACZ;AAAA,IACA,MAAM,UAAU,MAAM,WAAW,IAAI,MAAM,IAAI,MAAM,KAAK,GAAG;AAAA,IAC7D,OAAO,KAAK,EAAE,YAAY,MAAM,QAAQ,CAAC;AAAA,EAC3C;AAAA,EACA,OAAO;AAAA;AAQF,IAAM,gBAAgB,OAC3B,cAEA,aACE,WACA,MAAM,KAAK,WAAW,EAAE,UAAU,MAAM,KAAK,WAAW,WAAW,KAAK,CAAC,CAC3E;AAGK,IAAM,oBAAoB,CAAC,cAChC,aACE,WACA,SAAS,WAAW,EAAE,UAAU,MAAM,KAAK,WAAW,WAAW,KAAK,CAAC,CACzE;AAGF,IAAM,kBAAkB;AAGjB,IAAM,iBAAiB,CAAC,YAAqC;AAAA,EAClE,MAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,EAClD,OAAO,SAAS,KACd,CAAC,SAAS,gBAAgB,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG,CAC3D,IACI,OACA;AAAA;AAUC,IAAM,qBAAqB,CAAC,UAA2C;AAAA,EAC5E,MAAM,SAAS,IAAI;AAAA,EACnB,aAAa,aAAa,OAAO;AAAA,IAC/B,MAAM,WAAW,eAAe,OAAO;AAAA,IACvC,IAAI,aAAa,MAAM;AAAA,MACrB,OAAO,IAAI,SAAS,WAAW,IAAI,MAAM,IAAI,SAAS,KAAK,GAAG,GAAG;AAAA,IACnE;AAAA,EACF;AAAA,EACA,OAAO,CAAC,GAAG,MAAM;AAAA;;;ACvGnB;;;ACAA,cAAS;;;ACAT;AAgDO,IAAM,0BAA0B,CAIrC,MACA,YAEA,EAAE,aAAa;AAAA,EACb,MAAM,EAAE,QAAQ,IAAI;AAAA,EACpB;AAAA,EACA,iBAAiB,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EACnC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC;AACjC,CAAC;;;AC5DH,cAAS;AAGF,IAAM,uBAAuB;AAmB7B,IAAM,4BAA4B,GAAE,aAAa;AAAA,EACtD,cAAc,GAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC7C,QAAQ,GAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAiBM,IAAM,uBAAuB,GAAE,aAAa;AAAA,EACjD,MAAM,GAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,aAAa,GAAE,OAAO,EAAE,SAAS;AAAA,EACjC,cAAc,GAAE,OAAO,EAAE,SAAS;AAAA,EAClC,MAAM,GAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,OAAO,GAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAGM,IAAM,oBAAoB,GAAE,OAAO,GAAE,OAAO,GAAG,GAAE,OAAO,CAAC;;;AF3CzD,IAAM,0BAA0B,CAAC,oBAAoB;AAErD,IAAM,0BAA0B,CAAC,SAAS,OAAO;AAYjD,IAAM,0BAA0B,0BAA0B,OAAO;AAAA,EACtE,SAAS,GAAE,MAAM,GAAE,OAAO,CAAC,EAAE,QAAQ,uBAAuB;AAAA,EAC5D,SAAS,GAAE,MAAM,GAAE,OAAO,CAAC,EAAE,QAAQ,uBAAuB;AAAA,EAC5D,MAAM,GAAE,OAAO,EAAE,QAAQ,MAAM;AACjC,CAAC;AAOM,IAAM,0BAA0B,wBACrC,cACA,uBACF;AAOO,IAAM,aAAa,CACxB,UAA6B,CAAC,OACP;AAAA,EACvB,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC;AAChB;;;ADxCO,IAAM,oBAAoB,CAAC,aAAqB,SACrD,WAAW,IAAI,IAAI,OAAO,KAAK,QAAQ,WAAW,GAAG,IAAI;AAGpD,IAAM,gBAAgB,CAC3B,QACA,SAEA,OAAO,QAAQ,QAAQ,OACrB,CAAC,WACC,OAAO,SAAS,IACpB;AAsBK,IAAM,wBAAwB,CACnC,QACA,gBACmB;AAAA,EACnB,OAAO,UAAU,QAAQ,cAAc,QAAQ,YAAY;AAAA,EAC3D,IAAI,CAAC,OAAO;AAAA,IACV,OAAO;AAAA,MACL,MAAM,kBAAkB,aAAa,MAAM;AAAA,MAC3C,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,MAAM,UAAU;AAAA,IACd,GAAG,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,QAAQ,CAAC,WAAW,OAAO,QAAQ,OAAO,CAAC;AAAA,EACzE;AAAA,EACA,MAAM,UAAU,MAAM,QAAQ,QAAQ,OAAO,CAAC,YAC5C,KAAK,MAAM,CAAC,WAAW,OAAO,QAAQ,QAAQ,SAAS,OAAO,CAAC,CACjE;AAAA,EACA,OAAO;AAAA,IACL,MAAM,kBAAkB,aAAa,MAAM,QAAQ,IAAI;AAAA,IACvD;AAAA,IACA;AAAA,EACF;AAAA;;;AI5DK,IAAM,wBAAwB;AAU9B,IAAM,oBAAoB,CAC/B,OACA,WAEA,MAAM,KACJ,CAAC,SACC,KAAK,gBAAgB,eACrB,EAAE,KAAK,KAAK,SAAS,KAAK,KAAK,QAAQ,OAC3C,KAAK,cAAc,QAAQ,iBAAiB,EAAE,SAAS;;;ACHlD,IAAM,eAAe,CAC1B,OACA,cACA,UAEA,MAAM,KAAK,CAAC,SAAS,KAAK,YAAY,KAAK,KAC3C,aAAa,KAAK,CAAC,SAAS,KAAK,UAAU,KAAK;AAiB3C,IAAM,wBAAwB,CACnC,SACA,cAEA,kBAAkB,QAAQ,MAAM,OAAO,QAAQ,MAAM,KACrD,CAAC,aAAa,WAAW,QAAQ,MAAM,OAAO,qBAAqB;AAErE,IAAM,kBAAkB,CAAC,YACvB,QACG,MAAM,OAAO,EACb,OAAO,OAAO,EACd,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,GAAG;AAcN,IAAM,iBAAiB,CAC5B,OACA,WACA,SAAiC,CAAC,MACd;AAAA,EAGpB,MAAM,YAAY,IAAI,IACpB,OAAO,QAAQ,MAAM,EAAE,IAAI,EAAE,OAAO,WAAW;AAAA,IAC7C,IAAI,MAAM,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,IAC7C;AAAA,EACF,CAAC,CACH;AAAA,EACA,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,SAA0B,CAAC;AAAA,EAGjC,MAAM,eAAe,CAAC,YAA0B;AAAA,IAC9C,MAAM,WAAW,eAAe,OAAO;AAAA,IACvC,IAAI,aAAa,MAAM;AAAA,MACrB;AAAA,IACF;AAAA,IACA,MAAM,OAAO,SAAS,WAAW,IAAI,UAAU,SAAS,KAAK,GAAG;AAAA,IAChE,IAAI,KAAK,IAAI,IAAI,GAAG;AAAA,MAClB;AAAA,IACF;AAAA,IACA,KAAK,IAAI,IAAI;AAAA,IACb,MAAM,OAAO,SAAS,GAAG,EAAE;AAAA,IAC3B,OAAO,KAAK;AAAA,MACV;AAAA,MACA,OACE,UAAU,IAAI,IAAI,SAAS,KAAK,GAAG,GAAG,MACrC,OAAO,gBAAgB,IAAI,IAAI;AAAA,IACpC,CAAC;AAAA;AAAA,EAEH,aAAa,aAAa,OAAO;AAAA,IAC/B,aAAa,OAAO;AAAA,EACtB;AAAA,EACA,OAAO;AAAA;;;ACxGF,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,gBAAgB;AAAA,EACnC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,YAAY;AAAA,EAC9D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,gBAAgB;AAChC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,2BAA2B;AAAA,EAC9C,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,cAAc;AAAA,EAC/D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,kBAAkB;AAAA,EACrC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,aAAa;AAAA,EAC9D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,cAAc;AAC9B;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,iBAAiB;AAAA,EACpC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,gBAAgB;AAAA,EACnE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,oBAAoB;AACpC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,kBAAkB;AAAA,EACrC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,cAAc;AAAA,EAChE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,kBAAkB;AAClC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,kBAAkB;AAAA,EACrC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,eAAe;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,gBAAgB;AAChC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,wBAAwB;AAAA,EAC3C,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,WAAW,cAAc,kBAAkB;AAAA,EACtE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,uBAAuB;AAAA,EAC1C,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,uBAAuB;AAAA,EAC1E,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,oBAAoB;AACpC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,oBAAoB;AAAA,EACvC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,eAAe;AAAA,EAClE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,eAAe;AAAA,EAClC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,aAAa;AAAA,EAC9D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,cAAc;AAC9B;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,iBAAiB;AAAA,EACpC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,eAAe;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,gBAAgB;AAChC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,mBAAmB;AAAA,EACtC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,cAAc;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,eAAe;AAAA,EAClC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,OAAO,cAAc,YAAY;AAAA,EAC5D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,WAAW;AAC3B;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,iBAAiB;AAAA,EACpC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,gBAAgB;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,YAAY;AAC5B;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,oBAAoB;AAAA,EACvC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,iBAAiB;AAAA,EACnE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,qBAAqB;AAAA,EACxC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,mBAAmB;AAAA,EACrE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,kBAAkB;AAClC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,mBAAmB;AAAA,EACtC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,sBAAsB;AAAA,EACzE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,oBAAoB;AAAA,EACvC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,eAAe;AAAA,EAClE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,WAAW;AAAA,EAC9B,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,MAAM,cAAc,MAAM;AAAA,EACrD,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,WAAW;AAC3B;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,QAAQ;AAAA,EAC3B,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,MAAM,cAAc,UAAU;AAAA,EACzD,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,UAAU;AAC1B;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,uBAAuB;AAAA,EAC1C,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,gBAAgB;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,qBAAqB;AAAA,EACxC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,gBAAgB;AAAA,EAClE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,qBAAqB;AAAA,EACxC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,oBAAoB;AAAA,EACtE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;ACnGO,IAAM,OAA0B;AAAA,EACrC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,mBAAmB;AAAA,EACtC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,gBAAgB;AAAA,EACnE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,eAAe;AAC/B;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,mBAAmB;AAAA,EACtC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,UAAU,cAAc,gBAAgB;AAAA,EACnE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,eAAe;AAC/B;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,kBAAkB;AAAA,EACrC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,WAAW;AAAA,EAC7D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,oBAAoB;AACpC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,qBAAqB;AAAA,EACxC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,gBAAgB;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,oBAAoB;AAAA,EACvC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,cAAc;AAAA,EAChE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,qBAAqB;AAAA,EACxC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,iBAAiB;AAAA,EACnE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,oBAAoB;AAAA,EACvC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,SAAS,cAAc,gBAAgB;AAAA,EAClE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,mBAAmB;AACnC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,YAAY;AAAA,EAC/B,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,eAAe;AAAA,EAChE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,YAAY;AAC5B;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,iBAAiB;AAAA,EACpC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,OAAO,cAAc,cAAc;AAAA,EAC9D,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,aAAa;AAC7B;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBACE;AAAA,IACF,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,qBAAqB;AAAA,EACxC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,QAAQ,cAAc,iBAAiB;AAAA,EAClE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,kBAAkB;AAClC;;;ACnGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,iBAAiB;AAAA,EACpC,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,YAAY,cAAc,YAAY;AAAA,EACjE,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,iBAAiB;AACjC;;;AClGO,IAAM,OAA0B;AAAA,EACrC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,OAAO;AAAA,EAC1B,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,MAAM,cAAc,MAAM;AAAA,EACrD,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,OAAO;AACvB;;;AClGO,IAAM,KAAwB;AAAA,EACnC,SAAS;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,QAAQ,EAAE,SAAS,OAAO;AAAA,EAC1B,WAAW;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,kBAAkB,EAAE,OAAO,MAAM,cAAc,MAAM;AAAA,EACrD,KAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,SAAS;AAAA,IACT,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK,EAAE,OAAO,OAAO;AACvB;;;AC5CO,IAAM,WAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AACX;;;AC/EA,IAAM,gBAAgB,IAAI,IACxB,CAAC,GAAG,OAAO,KAAK,QAAQ,GAAG,IAAI,EAAE,IAAI,CAAC,SAAS,KAAK,YAAY,CAAC,CACnE;AAGO,IAAM,cAAc,CACzB,WAEA,OAAO,SAAS;AAGX,IAAM,cAAc,CAAC,SAC1B,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI;AAcnC,IAAM,wBAAwB,CACnC,SACkB;AAAA,EAClB,IAAI,KAAK,mBAAmB,MAAM;AAAA,IAChC,OAAO;AAAA,EACT;AAAA,EACA,OAAO,KAAK,kBAAkB,KAAK;AAAA;AAe9B,IAAM,eAAe,CAAC,MAAc,SACzC,SAAS,KAAK,iBAAiB,KAAK,0BAA0B,KAAK,IAAI;AAMlE,IAAM,gBAAgB,CAC3B,cACA,MACA,SACW;AAAA,EACX,MAAM,SAAS,aAAa,MAAM,IAAI;AAAA,EACtC,IAAI,CAAC,QAAQ;AAAA,IACX,OAAO;AAAA,EACT;AAAA,EACA,OAAO,iBAAiB,MAAM,SAAS,GAAG,SAAS;AAAA;AAW9C,IAAM,uBAAuB,CAClC,MACA,MACA,SAEA,QAAQ,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,WAAW,IAAI,IACjD,cAAc,MAAM,MAAM,IAAI,IAC9B;AAQC,IAAM,eAAe,CAAC,OAAiB,SAA6B;AAAA,EAIzE,MAAM,QAAQ,MAAM,IAAI,YAAY;AAAA,EACpC,MAAM,UAAU,KAAK,QAAQ,KAC3B,CAAC,WACC,OAAO,SAAS,KAAK,iBAAiB,OAAO,KAAK,YAAY,MAAM,KACxE;AAAA,EACA,IAAI,SAAS;AAAA,IACX,OAAO,EAAE,QAAQ,QAAQ,MAAM,MAAM,MAAM,MAAM,CAAC,EAAE;AAAA,EACtD;AAAA,EACA,OAAO,EAAE,QAAQ,KAAK,eAAe,MAAM,MAAM;AAAA;AAa5C,IAAM,kBAAkB,CAC7B,KACA,KACA,SACG;AAAA,EACH,MAAM,OAAO,IAAI,MAAM,GAAG,IAAI,SAAS,IAAI,MAAM;AAAA,EAOjD,IAAI,KAAK,SAAS,IAAI,GAAG;AAAA,IACvB,MAAM,SAAS,GAAG,KAAK,MAAM,GAAG,EAAE,IAAI;AAAA,IACtC,OAAO;AAAA,MACL,SAAS,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI;AAAA,MACjD,SACE,KAAK,WAAW,QACZ,aAAa,OAAO,MAAM,GAAG,GAAG,IAAI,EAAE,KAAK,KAAK,GAAG,IACnD;AAAA,IACR;AAAA,EACF;AAAA,EAEA,IAAI,KAAK,WAAW,OAAO;AAAA,IACzB,MAAM,UAAU,KAAK,YAAY,GAAG;AAAA,IAKpC,IAAI,UAAU,KAAK,YAAY,GAAG,GAAG;AAAA,MAGnC,MAAM,SAAS,KAAK,MAAM,UAAU,CAAC,EAAE,YAAY;AAAA,MACnD,MAAM,UAAU,KAAK,QAAQ,KAC3B,CAAC,WAAW,OAAO,KAAK,YAAY,MAAM,MAC5C;AAAA,MACA,IAAI,SAAS;AAAA,QACX,OAAO;AAAA,UACL,SAAS,CAAC,QAAQ,IAAI;AAAA,UACtB,SAAS,GAAG,KAAK,MAAM,GAAG,OAAO,IAAI;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,EAAE,SAAS,CAAC,KAAK,aAAa,GAAG,SAAS,IAAI;AAAA,EACvD;AAAA,EAEA,QAAQ,QAAQ,SAAS,aAAa,IAAI,MAAM,GAAG,GAAG,IAAI;AAAA,EAC1D,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,KAAK,KAAK,GAAG,EAAE;AAAA;AAc/C,IAAM,mBAAmB,CAC9B,KACA,KACA,QACA,SACW;AAAA,EACX,IAAI,KAAK,WAAW,OAAO;AAAA,IACzB,IAAI,OAAO,IAAI,MAAM,GAAG,IAAI,SAAS,IAAI,MAAM;AAAA,IAC/C,MAAM,UAAU,KAAK,YAAY,GAAG;AAAA,IACpC,IAAI,UAAU,KAAK,YAAY,GAAG,GAAG;AAAA,MACnC,MAAM,SAAS,KAAK,MAAM,UAAU,CAAC,EAAE,YAAY;AAAA,MACnD,IAAI,KAAK,QAAQ,KAAK,CAAC,UAAU,MAAM,KAAK,YAAY,MAAM,MAAM,GAAG;AAAA,QACrE,OAAO,KAAK,MAAM,GAAG,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,IACA,OAAO,GAAG,QAAQ,SAAS;AAAA,EAC7B;AAAA,EACA,OAAO,GAAG,UAAU;AAAA;AASf,IAAM,kBAAkB,CAC7B,OACA,MACA,aACiB;AAAA,EACjB,MAAM,aAAa,IAAI,IACrB,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,KAAK,YAAY,CAAC,CACxD;AAAA,EACA,MAAM,cAAc,IAAI,IAAI,UAAU,SAAS,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AAAA,EAC3E,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,cAA4B,CAAC;AAAA,EACnC,WAAW,QAAQ,OAAO;AAAA,IAKxB,MAAM,QAAQ,KAAK,OAAO,IAAI,MAAM,GAAG;AAAA,IACvC,MAAM,SACJ,MAAM,MAAM,YAAY,IAAI,MAAM,EAAE,IAAI,MAAM,KAAK,MAAM,KACxD,YAAY;AAAA,IACf,IACE,SACA,CAAC,KAAK,IAAI,KAAK,KACf,cAAc,IAAI,KAAK,KACvB,CAAC,WAAW,IAAI,KAAK,GACrB;AAAA,MACA,KAAK,IAAI,KAAK;AAAA,MACd,YAAY,KAAK;AAAA,QACf,MAAM;AAAA,QACN,SAAS,WAAW,qCAAqC,6DAA6D,KAAK,8BAA8B;AAAA,QACzJ,UAAU;AAAA,QACV,YAAY,gBAAgB;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,OAAO;AAAA;;;AC3PT,uBAAS;AAET,qBAAS,sBAAU,kBAAS,oBAAM,wBAAW,sBAAU;;;ACFvD;AACA,qBAAS;AAET;AAAA;AAAA,aAEE;AAAA,aACA;AAAA;AAAA,cAEA;AAAA,aACA;AAAA;;;ACGF,IAAM,aAAa;AAUZ,IAAM,iBAAiB,CAAC,MAAc,UAAkC;AAAA,EAC7E,MAAM,UAAU,KAAK,UAAU;AAAA,EAC/B,MAAM,MAAM,QAAQ,MAAM,UAAU,GAAG,QAAQ;AAAA,EAC/C,IAAI,QAAQ,WAAW;AAAA,IACrB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,QAAQ,MAAM,IAAI,MAAM;AAAA,EACrC,MAAM,YAAY,IAAI,WAAW,GAAG,IAAK,MAAiB;AAAA,EAC1D,IAAI,UAAU,MAAM;AAAA,IAKlB,IAAI,cAAc,OAAO,KAAK,SAAS,GAAG,GAAG;AAAA,MAC3C,OAAO;AAAA,IACT;AAAA,IACA,OAAO,EAAE,WAAW,QAAQ,IAAI,OAAO;AAAA,EACzC;AAAA,EAGA,OAAO,MAAM,cAAc,aACzB,IAAI,UAAU,MAAM,UACpB,KAAK,KAAK,MAAM,KACd,OACA;AAAA;;;AC9CN;AACA;AAEA,iBAAS;AAaF,IAAM,WAAW,CAAC,SACvB,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAGtD,IAAM,gBAAgB,CAAC,YAC5B,SACE,QACG,IAAI,CAAC,UAAU,GAAG,MAAM,OAAO,MAAM,QAAQ,SAAS,MAAM,KAAK,IAAI,GAAG,EACxE,KAAK,GAAG,CACb;AAaK,IAAM,eACX,CACE,MACA,iBACA,SAEF,CAAC,aAAa;AAAA,EACZ,IAAI,OAAO;AAAA,EACX,IAAI,MAAM;AAAA,IACR,MAAM,eAAe,YAA2B;AAAA,MAC9C,IAAI;AAAA,QACF,QAAQ,YAAY,MAAM,KAAK;AAAA,QAC/B,SAAS,cAAc,OAAO;AAAA,QAC9B,MAAM;AAAA;AAAA,IAIL,aAAa;AAAA,EACpB;AAAA,EACA,MAAM,OAAO,YAA2B;AAAA,IACtC,IAAI;AAAA,MACF,QAAQ,YAAY,MAAM,KAAK;AAAA,MAC/B,MAAM,OAAO,cAAc,OAAO;AAAA,MAClC,IAAI,QAAQ,SAAS,MAAM;AAAA,QACzB,SAAS;AAAA,MACX;AAAA,MACA,OAAO;AAAA,MACP,MAAM;AAAA;AAAA,EAIV,MAAM,QAAQ,YAAY,MAAM;AAAA,IACzB,KAAK;AAAA,KACT,kBAAkB,IAAI;AAAA,EACzB,OAAO,MAAM,cAAc,KAAK;AAAA;AAU7B,IAAM,gBAAgB,CAAC,aAAoC;AAAA,EAChE,MAAM,OAAO,MAAK,UAAU,cAAc;AAAA,EAC1C,OAAO;AAAA,IACL,MAAM,YAAY;AAAA,MAChB,IAAI;AAAA,QAIF,OAAO,KAAK,MAAM,MAAM,SAAS,MAAM,OAAO,CAAC;AAAA,QAC/C,MAAM;AAAA,QACN,OAAO,CAAC;AAAA;AAAA;AAAA,IAGZ,OAAO,OAAO,YAAY;AAAA,MACxB,IAAI;AAAA,QACF,MAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,QACzC,MAAM,UAAU,MAAM,GAAG,KAAK,UAAU,OAAO;AAAA,GAAO,OAAO;AAAA,QAC7D,MAAM;AAAA;AAAA,EAIZ;AAAA;AASK,IAAM,gBAAgB,OAC3B,MACA,OACA,cACA,UAAU,SACoB;AAAA,EAC9B,IAAI,CAAC,SAAS;AAAA,IACZ,MAAM,SAAS,MAAM,MAAM,KAAK;AAAA,IAChC,IAAI,OAAO,SAAS,GAAG;AAAA,MACrB,OAAO,EAAE,aAAa,CAAC,GAAG,SAAS,OAAO;AAAA,IAC5C;AAAA,EACF;AAAA,EACA,IAAI;AAAA,IACF,MAAM,UAAU,MAAM,aAAa;AAAA,IACnC,MAAM,MAAM,MAAM,OAAO;AAAA,IACzB,OAAO,EAAE,aAAa,CAAC,GAAG,QAAQ;AAAA,IAClC,OAAO,OAAO;AAAA,IACd,MAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAClC,IAAI,SAAS,SAAS,GAAG;AAAA,MAGvB,MAAM,aAAyB;AAAA,QAC7B,MAAM;AAAA,QACN,SAAS,WAAW,+BAAgC,MAAgB,oBAAoB,SAAS;AAAA,QACjG,UAAU;AAAA,MACZ;AAAA,MACA,OAAO,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,SAAS;AAAA,IACxD;AAAA,IAEA,MAAM,IAAI,WAAW;AAAA,MACnB,MAAM;AAAA,MACN,SAAS,WAAW,mDAAoD,MAAgB;AAAA,MACxF,UAAU;AAAA,IACZ,CAAC;AAAA;AAAA;;;ACjJL;AAEA;AACA,oBAAS;;;ACsBF,IAAM,iBAAiB;AAUvB,IAAM,aAAa,CAAC,SAAwB,OAAqB;AAAA,EACtE,QAAQ,YAAY,QAAQ;AAAA;AAI9B,IAAM,SACJ;AAuBK,IAAM,sBAAsB,CACjC,MACA,iBACmB;AAAA,EACnB,IAAI,YAAY;AAAA,EAChB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,SACM,QAAQ,OAAO,KAAK,SAAS,EACjC,OAAO,QACP,QAAQ,OAAO,KAAK,SAAS,GAC7B;AAAA,IACA,MAAM,aAAa,MAAM,OAAO,WAAW,MAAM,OAAO;AAAA,IACxD,MAAM,QACJ,eAAe,YACX,GAAG,MAAM,OAAO,QAAQ,UACxB,IAAI;AAAA,IAEV,IAAI,MAAM,OAAO,YAAY,aAAa,eAAe,KAAK,GAAG;AAAA,MAC/D;AAAA,IACF;AAAA,IACA,YAAY,UAAU,MAAM,GAAG,MAAM,KAAK;AAAA,IAC1C,IAAI,eAAe,WAAW;AAAA,MAG5B,QAAQ,MAAM,OAAO,SAAS,YAAY,SAAS;AAAA,IACrD,EAAO;AAAA,MACL,OAAO;AAAA;AAAA,EAEX;AAAA,EACA,OAAO,EAAE,IAAI,MAAM,WAAW,IAAI;AAAA;;;AC7FpC,cAAS;;;ACDT,cAAS;;;ACMF,IAAM,0BAA0B,CAAC,SACtC,mBAAmB,KAAK,SAAS,IAAI,MAAM,OAAO,KAC/C,IAAI,CAAC,QAAQ,KAAK,UAAU,GAAG,CAAC,EAChC,KAAK,IAAI;;;ADEP,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA4CA,IAAM,wBAAwB,GAAE,OAC9B,GAAE,OAAO,GACT,GAAE,OAAO,GAAE,OAAO,GAAG,GAAE,KAAK,CAAC,CAC/B;AAGA,IAAM,gBAAgB,CAAC,eAAuB;AAAA,EAC5C,WAAW,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,SAAS;AAAA,EAC9C,SAAS,GAAE,OAAO,GAAE,OAAO,GAAG,GAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACnD,iBAAiB,sBAAsB,SAAS;AAClD;AAEA,IAAM,kBAAkB,GAAE,KAAK,kBAAkB,EAAE,SAAS;AAM5D,IAAM,sBAAsB;AAE5B,IAAM,wBAAwB;AAe9B,IAAM,uBAAuB,GAAE,aAAa;AAAA,KACvC,cAAc,mBAAmB;AAAA,EACpC,OAAO,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,qBAAqB;AAAA,EACtD,WAAW;AACb,CAAC;AAIM,IAAM,uBAAuB,wBAClC,WACA,oBACF;AAQO,IAAM,UAAU,CACrB,UAA6B,CAAC,OACP;AAAA,EACvB,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,QAAQ,aAAa,mBAAmB;AAAA,EAC1D,aAAa,CAAC;AAChB;AAMA,IAAM,yBAAyB;AAc/B,IAAM,0BAA0B,GAAE,aAAa;AAAA,KAC1C,cAAc,sBAAsB;AAAA,EACvC,OAAO,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,WAAW;AACb,CAAC;AAOM,IAAM,0BAA0B,wBACrC,cACA,uBACF;AAmBA,IAAM,yBAAyB;AAe/B,IAAM,0BAA0B,GAAE,aAAa;AAAA,KAC1C,cAAc,sBAAsB;AAAA,EACvC,SAAS,GAAE,IAAI,EAAE,QAAQ,8BAA8B;AAAA,EACvD,OAAO,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,WAAW;AACb,CAAC;AAOM,IAAM,0BAA0B,wBACrC,cACA,uBACF;AAmBA,IAAM,qBAAqB;AAa3B,IAAM,sBAAsB,GAAE,aAAa;AAAA,KACtC,cAAc,kBAAkB;AAAA,EACnC,SAAS,GAAE,IAAI,EAAE,QAAQ,2BAA2B;AAAA,EACpD,OAAO,GAAE,OAAO,EAAE,IAAI,CAAC;AACzB,CAAC;AAIM,IAAM,sBAAsB,wBACjC,UACA,mBACF;AAoCA,IAAM,gCAAgC,GAAE,aAAa;AAAA,KAChD,cAAc,SAAS;AAAA,EAE1B,WAAW,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,SAAS,GAAE,IAAI;AAAA,EACf,OAAO,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,MAAM,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,mBAAmB;AAAA,EACnD,WAAW;AACb,CAAC;AAOM,IAAM,gCAAgC,wBAC3C,qBACA,6BACF;AAoCA,IAAM,sBAAsB,IAAI,IAAI;AAAA,EAClC,CAAC,WAAW,SAAS;AAAA,EACrB,CAAC,UAAU,QAAQ;AAAA,EACnB,CAAC,cAAc,YAAY;AAAA,EAC3B,CAAC,qBAAqB,kBAAkB;AAAA,EACxC,CAAC,cAAc,YAAY;AAC7B,CAAC;AAGD,IAAM,oBAAyC,IAAI,IAAI;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,IAAM,uBAAuB,GAAE,YAAY;AAAA,EACzC,UAAU,GAAE,MAAM;AAAA,IAChB,GAAE,OAAO;AAAA,IACT,GAAE,YAAY,EAAE,MAAM,GAAE,OAAO,EAAE,CAAC,EAAE,UAAU,GAAG,WAAW,IAAI;AAAA,EAClE,CAAC;AACH,CAAC;AAGD,IAAM,kBAAkB,CAAC,UAAuC;AAAA,EAC9D,MAAM,QAAQ,qBAAqB,UAAU,MAAM,KAAK;AAAA,EACxD,OACG,MAAM,WAAW,oBAAoB,IAAI,MAAM,KAAK,QAAQ,KAAM;AAAA;AAUhE,IAAM,qBAAqB;AAAA,EAChC,OAAO,CAAC,UAAmD;AAAA,IACzD,IAAI,MAAM,SAAS,qBAAqB;AAAA,MACtC;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,MAAM,KAAK,OAAO,CAAC,QAAQ,kBAAkB,IAAI,GAAG,CAAC;AAAA,IACnE,IAAI,MAAM,WAAW,GAAG;AAAA,MACtB;AAAA,IACF;AAAA,IACA,MAAM,SAAS,MAAM,IAAI,CAAC,QAAQ,UAAU,KAAK,EAAE,KAAK,IAAI;AAAA,IAC5D,MAAM,OAAO,GAAG,uDAAuD,gBAAgB,KAAK,OAAO,MAAM,KAAK,IAAI;AAAA,IAClH,MAAM,SAAS,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,kBAAkB,IAAI,GAAG,CAAC;AAAA,IACrE,OAAO,OAAO,SAAS,IACnB,GAAG,QAAQ,wBAAwB,MAAM,MACzC;AAAA;AAER;AAGA,IAAM,oBAAoB,GAAE,OAAO;AAMnC,IAAM,4BAA4B,CAAC,UAAuC;AAAA,EACxE,MAAM,OAAO,kBAAkB,UAAU,MAAM,KAAK;AAAA,EACpD,MAAM,UAAU,KAAK,UAAU,oBAAoB,IAAI,KAAK,IAAI,IAAI;AAAA,EACpE,OAAO,UACH,sFAAsF,+GACtF;AAAA;AAQC,IAAM,mBAAmB,GAAE,mBAChC,QACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GACA;AAAA,EAIE,OAAO,CAAC,UACN,MAAM,SAAS,kBACX,YACA,0BAA0B,KAAK;AACvC,CACF;AAOO,IAAM,uBAAmC,QAAQ;AA2CxD,IAAM,aAAa,CAAC,QAAwB,aAAa,KAAK,UAAU,GAAG;AAS3E,IAAM,cAAc,CAAC,YACnB,WAAW,OAAO,KAAK,OAAO,EAAE,SAAS,IACrC;AAAA,aAAgB,KAAK,UAAU,OAAO,OACtC;AAGN,IAAM,WAAW,CAAC,QAAwB,UAAU,WAAW,GAAG;AAAA;AAAA,QAE1D,KAAK,UAAU,iCAAiC,MAAM;AAAA;AAAA;AAAA;AAS9D,IAAM,aAAa,CAAC,YAGJ;AAAA,EACd,MAAM,SAAmB,CAAC;AAAA,EAC1B,IAAI,QAAQ,WAAW;AAAA,IACrB,OAAO,KAAK,cAAc,KAAK,UAAU,QAAQ,SAAS,GAAG;AAAA,EAC/D;AAAA,EACA,IAAI,QAAQ,iBAAiB;AAAA,IAC3B,OAAO,KAAK,oBAAoB,KAAK,UAAU,QAAQ,eAAe,GAAG;AAAA,EAC3E;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,iBAAiB,CACrB,aACgB;AAAA,EAChB,UAAU;AAAA,EACV,MAAM;AAAA,EACN,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,UAAU;AAAA,IAGR,QAAQ,WAAW,OAAO;AAAA,IAI1B,SAAS;AAAA,MACP;AAAA,IACF;AAAA,IACA,UAAU;AAAA,UACJ,WAAW,QAAQ,SAAS;AAAA;AAAA,QAE9B,KAAK,UAAU,iCAAiC,QAAQ,4CAA4C;AAAA;AAAA;AAAA;AAAA,IAIxG,OAAO,WAAW,KAAK,UAAU,QAAQ,KAAK;AAAA,IAC9C,OAAO;AAAA;AAAA,YACC,WAAW,QAAQ,SAAS,KAAK,YAAY,QAAQ,OAAO;AAAA;AAAA;AAAA,EAEtE;AACF;AAEA,IAAM,oBAAoB,CACxB,YACe;AAAA,EAIf,MAAM,WAAW,QAAQ,YACrB,4BAA4B,KAAK,UAAU,QAAQ,SAAS,UAC5D;AAAA,EACJ,OAAO;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU;AAAA,MACR,QAAQ,WAAW,EAAE,iBAAiB,QAAQ,gBAAgB,CAAC;AAAA,MAC/D,SAAS;AAAA,QACP;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU,SAAS,QAAQ,SAAS;AAAA,MACpC,OAAO,cAAc,KAAK,UAAU,QAAQ,KAAK,IAAI;AAAA,MACrD,OAAO;AAAA;AAAA,YACD,WAAW,QAAQ,SAAS,KAAK,YAAY,QAAQ,OAAO;AAAA;AAAA;AAAA,IAEpE;AAAA,EACF;AAAA;AAQF,IAAM,0BAA0B,CAC9B,MACA,OACA,UACA,aASgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,IACR,QAAQ,WAAW,OAAO;AAAA,IAC1B,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU,SAAS,QAAQ,SAAS;AAAA,IACpC,OAAO,YAAY,KAAK,UAAU,QAAQ,KAAK;AAAA,IAG/C,OAAO;AAAA;AAAA,YACC,WAAW,QAAQ,SAAS;AAAA,aAC3B,KAAK,UAAU,QAAQ,OAAO,KAAK,YAAY,QAAQ,OAAO;AAAA,UACjE,KAAK,UAAU,QAAQ,IAAI;AAAA;AAAA;AAAA,EAEnC;AACF;AAGO,IAAM,oBAAoB,CAC/B,WAA6B,iBAAiB,MAAM,oBAAoB,MACzD;AAAA,EACf,QAAQ,SAAS;AAAA,SACV,WAAW;AAAA,MACd,OAAO,eAAe,SAAS,OAAO;AAAA,IACxC;AAAA,SACK,cAAc;AAAA,MACjB,OAAO,kBAAkB,SAAS,OAAO;AAAA,IAC3C;AAAA,SACK,cAAc;AAAA,MACjB,OAAO,wBAAwB,cAAc,cAAc,MAAM;AAAA,WAC5D,SAAS;AAAA,QACZ,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,SACK,UAAU;AAAA,MAGb,OAAO,wBAAwB,UAAU,UAAU,OAAO;AAAA,WACrD,SAAS;AAAA,QACZ,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,aACS;AAAA,MACP,OAAO,wBACL,qBACA,qBACA,MACA,SAAS,OACX;AAAA,IACF;AAAA;AAAA;;;AE/oBJ,cAAS;;;ACAT,cAAS;AAeF,IAAM,qBAAqB,GAAE,aAAa;AAAA,EAC/C,KAAK,GAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC;AAIM,IAAM,qBAAqB,wBAChC,SACA,kBACF;;;ACxBA,cAAS;;;ACmBF,IAAM,eAAe,CAAC,MAAc,YACzC,uEAAuE,mDAAmD,mCAAmC;;;ADExJ,IAAM,yBAAyB,GACnC,OAAO;AAAA,EACN,KAAK,GAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC,EACA,SAAS,GAAE,KAAK,CAAC;AAIb,IAAM,yBAAyB,wBACpC,aACA,sBACF;;;AEjCA,cAAS;AAaF,IAAM,uBAAuB,GAAE,aAAa;AAAA,EACjD,IAAI,GAAE,OAAO,EAAE,IAAI,CAAC;AACtB,CAAC;AAIM,IAAM,uBAAuB,wBAClC,WACA,oBACF;;;ACtBA,cAAS;AAYF,IAAM,wBAAwB,GAAE,aAAa;AAAA,EAClD,KAAK,GAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC;AAIM,IAAM,wBAAwB,wBACnC,YACA,qBACF;;;ACrBA,cAAS;AAwBF,IAAM,0BAA0B,GACpC,OAAO;AAAA,EACN,OAAO,GAAE,OAAO,EAAE,IAAI,CAAC;AACzB,CAAC,EACA,SAAS,GAAE,KAAK,CAAC;AAOb,IAAM,0BAA0B,wBACrC,cACA,uBACF;;;ACtCA,cAAS;AAwBF,IAAM,sBAAsB,IAChC,OAAO;AAAA,EACN,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC,EACA,SAAS,IAAE,OAAO,CAAC;AAIf,IAAM,sBAAsB,wBACjC,UACA,mBACF;;;ACnCA,cAAS;AAsBF,IAAM,+BAA+B,IACzC,OAAO;AAAA,EACN,IAAI,IAAE,OAAO,EAAE,IAAI,CAAC;AACtB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAOb,IAAM,+BAA+B,wBAC1C,oBACA,4BACF;;;ACpCA,cAAS;AAeF,IAAM,gCAAgC,IAAE,aAAa;AAAA,EAC1D,WAAW,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACtC,IAAI,IAAE,OAAO,EAAE,IAAI,CAAC;AACtB,CAAC;AAOM,IAAM,gCAAgC,wBAC3C,sBACA,6BACF;;;AC5BA,cAAS;AAsBF,IAAM,oBAAoB,IAC9B,OAAO;AAAA,EACN,IAAI,IAAE,OAAO,EAAE,IAAI,CAAC;AACtB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,oBAAoB,wBAC/B,QACA,iBACF;;;ACjCA,cAAS;AA0BF,IAAM,yBAAyB,IACnC,OAAO;AAAA,EACN,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACjC,KAAK,IAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,yBAAyB,wBACpC,aACA,sBACF;AAmBA,IAAM,0BAA0B,aAC9B,wBACA,kBACF;;;AC5DA,cAAS;AAiBF,IAAM,sBAAsB,IAAE,aAAa;AAAA,EAChD,IAAI,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAC9B,SAAS,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAChD,CAAC;AAIM,IAAM,sBAAsB,wBACjC,UACA,mBACF;;;AC3BA,cAAS;AA0BF,IAAM,yBAAyB,IACnC,OAAO;AAAA,EACN,IAAI,IAAE,OAAO,EAAE,IAAI,CAAC;AACtB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,yBAAyB,wBACpC,aACA,sBACF;;;ACrCA,cAAS;AAiCF,IAAM,wBAAwB,IAClC,OAAO;AAAA,EACN,QAAQ,IAAE,KAAK,CAAC,MAAM,MAAM,IAAI,CAAC,EAAE,SAAS;AAAA,EAC5C,OAAO,IAAE,OAAO,EAAE,IAAI,CAAC;AACzB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,wBAAwB,wBACnC,YACA,qBACF;;;AC7CA,cAAS;AAwBF,IAAM,sBAAsB,IAChC,OAAO;AAAA,EACN,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC,EACA,SAAS,IAAE,OAAO,CAAC;AAIf,IAAM,sBAAsB,wBACjC,UACA,mBACF;;;ACnCA,cAAS;AA6BF,IAAM,yBAAyB,IACnC,OAAO;AAAA,EACN,QAAQ,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AACnC,CAAC,EACA,SAAS,IAAE,OAAO,CAAC;AAIf,IAAM,yBAAyB,wBACpC,aACA,sBACF;;;ACzCA,cAAS;AA2BF,IAAM,uBAAuB,IACjC,OAAO;AAAA,EACN,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,KAAK,IAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,uBAAuB,wBAClC,WACA,oBACF;AAmBA,IAAM,wBAAwB,aAC5B,sBACA,+BACF;;;AC7DA,cAAS;AAkBF,IAAM,sBAAsB,IAChC,aAAa;AAAA,EACZ,YAAY,IAAE,OAAO,IAAE,OAAO,GAAG,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACtD,SAAS,IAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,KAAK,IAAE,OAAO,EAAE,SAAS;AAAA,EACzB,UAAU,IAAE,KAAK,CAAC,SAAS,OAAO,CAAC,EAAE,SAAS;AAChD,CAAC,EACA,OAAO,CAAC,UAAU,QAAQ,MAAM,GAAG,MAAM,QAAQ,MAAM,OAAO,GAAG;AAAA,EAChE,SAAS;AACX,CAAC;AAII,IAAM,sBAAsB,wBACjC,UACA,mBACF;;;AClCA,cAAS;AA8BF,IAAM,uBAAuB,IACjC,OAAO;AAAA,EACN,KAAK,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAChC,KAAK,IAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,uBAAuB,wBAClC,WACA,oBACF;AAeA,IAAM,wBAAwB,aAC5B,sBACA,mBACF;;;AC5DA,cAAS;AAwBF,IAAM,sBAAsB,IAChC,OAAO;AAAA,EACN,OAAO,IAAE,QAAQ,EAAE,SAAS;AAAA,EAC5B,MAAM,IAAE,KAAK,CAAC,QAAQ,eAAe,YAAY,CAAC,EAAE,SAAS;AAC/D,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAIb,IAAM,sBAAsB,wBACjC,UACA,mBACF;;;ApBbO,IAAM,yBAAyB,IAAE,mBAAmB,QAAQ;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAID,IAAM,aACJ;AAOK,IAAM,wBAAwB,IAClC,MAAM,wBAAwB;AAAA,EAC7B,OAAO,CAAC,UAAW,MAAM,SAAS,iBAAiB,aAAa;AAClE,CAAC,EACA,QAAQ,CAAC,CAAC;;;AqB3Db,cAAS;;;ACAT,cAAS;AA8DF,IAAM,sBAAsB,IAChC,OAAO;AAAA,EACN,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,QAAQ,IAAE,KAAK,CAAC,UAAU,QAAQ,CAAC,EAAE,SAAS;AAAA,EAC9C,MAAM,IAAE,IAAI,EAAE,SAAS;AACzB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAEpB,IAAM,gBAAgB,IAAI,IAAI,CAAC,QAAQ,UAAU,MAAM,CAAC;AAMjD,IAAM,oBAAoB,CAC/B,YAEA,OAAO,YACL,OAAO,QAAQ,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,cAAc,IAAI,GAAG,CAAC,CACnE;AAOK,IAAM,oBAAoB,CAC/B,SACA,mBACc,QAAQ,WAAW,WAAW,CAAC,IAAI,CAAC,cAAc;;;ACtF3D,IAAM,6BAA6B;AAYnC,IAAM,2BAA0B;AAEhC,IAAM,2BAA0B,wBACrC,cACA,wBACF;AASO,IAAM,aAAa,CACxB,UAA6B,CAAC,OACP;AAAA,EACvB,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,kBAAkB,SAAS,0BAA0B;AACpE;;;ACjCO,IAAM,0BAA0B;AAWhC,IAAM,uBAAuB;AAE7B,IAAM,uBAAuB,wBAClC,WACA,oBACF;AAOO,IAAM,UAAU,CAAC,UAA0B,CAAC,OAAuB;AAAA,EACxE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,kBAAkB,SAAS,uBAAuB;AACjE;;;AC5BO,IAAM,uBAAuB;AAW7B,IAAM,oBAAoB;AAE1B,IAAM,oBAAoB,wBAC/B,QACA,iBACF;AAOO,IAAM,OAAO,CAAC,UAAuB,CAAC,OAAoB;AAAA,EAC/D,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,kBAAkB,SAAS,oBAAoB;AAC9D;;;AC5BO,IAAM,yBAAyB;AAW/B,IAAM,uBAAsB;AAE5B,IAAM,uBAAsB,wBACjC,UACA,oBACF;AAQO,IAAM,SAAS,CAAC,UAAyB,CAAC,OAAsB;AAAA,EACrE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,kBAAkB,SAAS,sBAAsB;AAChE;;;ALYA,IAAM,OACJ;AAOF,IAAM,yBAAyB,IAAE,aAC/B;AAAA,EACE,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,MAAM,IAAE,QAAQ,QAAQ,EAAE,SAAS;AAAA,EACnC,MAAM,IAAE,IAAI,EAAE,SAAS;AACzB,GACA;AAAA,EACE,OAAO,CAAC,UAAW,MAAM,SAAS,sBAAsB,OAAO;AACjE,CACF;AAGA,IAAM,wBAAwB,IAAE,mBAC9B,QACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GACA;AAAA,EACE,OAAO,CAAC,UACN,MAAM,SAAS,mBAAmB,MAAM,SAAS,iBAC7C,OACA;AACR,CACF;AAGA,IAAM,cAAc,CAAC,aAAmD;AAAA,KACnE;AAAA,EACH,SAAS,KAAK,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,UAAU,SAAS;AAC5E;AAQO,IAAM,2BAA2B,sBAAsB,UAC5D,CAAC,UAA8B;AAAA,EAC7B,QAAQ,MAAM;AAAA,SACP,cAAc;AAAA,MACjB,OAAO,YAAY,WAAW,MAAM,OAAO,CAAC;AAAA,IAC9C;AAAA,SACK,WAAW;AAAA,MACd,OAAO,YAAY,QAAQ,MAAM,OAAO,CAAC;AAAA,IAC3C;AAAA,SACK,QAAQ;AAAA,MACX,OAAO,YAAY,KAAK,MAAM,OAAO,CAAC;AAAA,IACxC;AAAA,SACK,UAAU;AAAA,MACb,OAAO,YAAY,OAAO,MAAM,OAAO,CAAC;AAAA,IAC1C;AAAA,aACS;AAAA,MAIP;AAAA,IACF;AAAA;AAAA,EAEF,MAAM,UAAiC,EAAE,QAAQ,SAAS;AAAA,EAC1D,IAAI,MAAM,SAAS,WAAW;AAAA,IAC5B,QAAQ,OAAO,MAAM;AAAA,EACvB;AAAA,EACA,IAAI,MAAM,SAAS,WAAW;AAAA,IAC5B,QAAQ,OAAO,MAAM;AAAA,EACvB;AAAA,EACA,OAAO,EAAE,MAAM,UAAU,SAAS,iBAAiB,CAAC,GAAG,aAAa,CAAC,EAAE;AAAA,CAE3E;;;AMhCA,IAAM,mBAAmB,CAAC,QACxB,IAAI,SAAS;AAOf,IAAM,WAAW;AAIjB,IAAM,eAAe;AAIrB,IAAM,gBAAgB;AASf,IAAM,WAAU,CAAC,SACtB,SACE,KACG,UAAU,KAAK,EACf,YAAY,EACZ,QAAQ,cAAc,EAAE,EACxB,QAAQ,UAAU,GAAG,GACxB,GACF,EAAE,QAAQ,eAAe,EAAE;AAG7B,IAAM,YAAY,CAAC,UACjB,SAAQ,SAAS,OAAO,GAAG,CAAC,KAAK;AAGnC,IAAM,iBAAgD;AAAA,EACpD,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAGA,IAAM,aAA+B;AAAA,EACnC,aAAa,CAAC;AAAA,EACd,eAAe;AAAA,EACf,YAAY,EAAE,SAAS,OAAO,OAAO,MAAM;AAC7C;AAEA,IAAM,YAAY,CAAC,YAAwD;AAAA,EACzE,IAAI,QAAQ,SAAS,UAAU;AAAA,IAC7B,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA,IACL,aAAa,QAAQ,QAAQ;AAAA,IAG7B,eACE,QAAQ,SAAS,YAAY,QAAQ,QAAQ,QAAQ;AAAA,IACvD,YAAY,QAAQ,QAAQ;AAAA,EAC9B;AAAA;AAQF,IAAM,kBAAkB,CACtB,YAEA,OAAO,YACL,OAAO,QAAQ,OAAO,EAAE,OACtB,EAAE,SAAS,QAAQ,WAAW,QAAQ,SACxC,CACF;AAsBF,IAAM,eAAe,CAAC,YAAmD;AAAA,EACvE,IAAI,QAAQ,SAAS,WAAW;AAAA,IAC9B,OAAO,QAAQ,QAAQ,QAAQ,IAAI,CAAC,YAAY;AAAA,SAC3C;AAAA,MACH,UAAU,OAAO,YAAY,QAAQ,QAAQ;AAAA,IAC/C,EAAE;AAAA,EACJ;AAAA,EACA,IAAI,QAAQ,SAAS,UAAU;AAAA,IAC7B,OAAO,QAAQ,QAAQ,QAAQ,IAAI,CAAC,YAAY;AAAA,SAC3C;AAAA,MACH,eAAe;AAAA,MACf,iBAAiB;AAAA,MACjB,sBAAsB;AAAA,IACxB,EAAE;AAAA,EACJ;AAAA,EACA,OAAO,QAAQ,QAAQ;AAAA;AAGzB,IAAM,gBAAgB,CACpB,SACA,aACsB;AAAA,EACtB,MAAM,UAAU,aAAa,OAAO;AAAA,EACpC,MAAM,OAAO,eAAe,QAAQ,QAAQ,KAAK;AAAA,EACjD,MAAM,eAAe,eAAe,QAAQ;AAAA,EAC5C,MAAM,UAAU,UAAU,OAAO;AAAA,EAEjC,OAAO,QAAQ,IAAI,CAAC,QAAQ,UAAU;AAAA,IACpC,MAAM,QACJ,OAAO,UACN,QAAQ,SAAS,IAAI,GAAG,gBAAgB,QAAQ,MAAM;AAAA,IAEzD,IAAI;AAAA,IACJ,IAAI,OAAO,OAAO;AAAA,MAChB,QAAQ,eAAe,OAAO,KAAK;AAAA,IACrC,EAAO,SAAI,QAAQ,WAAW,GAAG;AAAA,MAC/B,QAAQ;AAAA,IACV,EAAO;AAAA,MACL,MAAM,SAAS,OAAO,QAAQ,SAAQ,OAAO,KAAK,IAAI;AAAA,MACtD,QAAQ,eAAe,GAAG,QAAQ,UAAU,QAAQ,GAAG;AAAA;AAAA,IAGzD,MAAM,YAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA,eAAe,OAAO;AAAA,MACtB,iBAAiB,OAAO;AAAA,MACxB,MAAM,QAAQ;AAAA,MACd;AAAA,MACA,SAAS,OAAO;AAAA,MAChB;AAAA,MACA,sBAAsB,OAAO;AAAA,MAC7B,MAAM,UAAU,KAAK;AAAA,MACrB,MAAM,OAAO;AAAA,IACf;AAAA,IACA,IAAI,QAAQ,SAAS,UAAU;AAAA,MAC7B,UAAU,SAAS,gBAAgB,QAAQ,OAAO;AAAA,IACpD;AAAA,IACA,IAAI,OAAO,aAAa,WAAW;AAAA,MACjC,UAAU,WAAW,OAAO;AAAA,IAC9B;AAAA,IACA,OAAO;AAAA,GACR;AAAA;AAQI,IAAM,oBAAoB,CAAC,WAChC,OAAO,UAAU,QAAQ,CAAC,YACxB,cAAc,SAAS,OAAO,QAAQ,CACxC;AASK,IAAM,kBAAkB,CAAC,WAC9B,kBAAkB,MAAM,EAAE,IAAI,CAAC,QAI7B,IAAI,SAAS,WAAW,IAAI,QAAQ,aAAa,OAAO,UAAU,IAAI,KAAK,CAC7E;AAQF,IAAM,mBAAmB,CACvB,KACA,MACA,cACgC;AAAA,EAChC,IAAI,CAAC,iBAAiB,GAAG,GAAG;AAAA,IAC1B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,KAAK,IAAI,IAAI,KAAK;AAAA,EAC/B,IAAI,MAAM;AAAA,KACP,KAAK,eAAe,CAAC,GAAG,KACvB,wCAAwC,IAAI,2BAC9C;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EAKA,MAAM,SAAS;AAAA,EACf,IAAI,IAAI;AAAA,EACR,OAAO,UAAU,IAAI,IAAI,GAAG;AAAA,IAC1B,OAAO,GAAG,IAAI,QAAQ;AAAA,IACtB,KAAK;AAAA,EACP;AAAA,EACA,UAAU,IAAI,IAAI;AAAA,EAClB,MAAM,WAAW,SAAS,IAAI,OAAO,MAAM,KAAK,KAAK,KAAK;AAAA,EAG1D,KAAK,IAAI,IAAI,OAAO,QAAQ;AAAA,EAC5B,OAAO;AAAA;AAIF,IAAM,kBAAkB,CAC7B,WAC2B;AAAA,EAC3B,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,YAAY,IAAI;AAAA,EACtB,MAAM,SAAiC,CAAC;AAAA,EACxC,WAAW,OAAO,kBAAkB,MAAM,GAAG;AAAA,IAC3C,MAAM,WAAW,iBAAiB,KAAK,MAAM,SAAS;AAAA,IACtD,IAAI,UAAU;AAAA,MACZ,OAAO,KAAK,QAAQ;AAAA,IACtB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAIF,IAAM,sBAAsB,CAAC,WAClC,kBAAkB,MAAM,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS,QAAQ;AAYxD,IAAM,yBAAyB,CACpC,WAEA,gBAAgB,MAAM,EAAE,OACtB,CAAC,QACC,IAAI,SAAS,cACb,IAAI,QAAQ,WAAW,WACvB,IAAI,QAAQ,WAAW,UAAU,IACrC;AAQK,IAAM,uBAAuB,CAAC,WACnC,uBAAuB,MAAM,EAAE,SAAS;;;ACpX1C,cAAS;;;ACAT,cAAS;;;ACAT,cAAS;AAWT,IAAM,YAAY,CAAQ,UACxB,OAAO,UAAU;AAOZ,IAAM,wBAAwB,IAAE,aAAa;AAAA,EAElD,eAAe,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAEvC,iBAAiB,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAEzC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAElC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAQ3B,sBAAsB,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAE9C,MAAM,IAAE,OAAO;AACjB,CAAC;AAgCM,IAAM,sBAAsB,sBAAsB,OAAO;AAAA,EAE9D,UAAU,IAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAsBM,IAAM,mBAAmB,IAC7B,MAAM;AAAA,EACL,IAAE,QAAQ;AAAA,EACV,IAAE,aAAa;AAAA,IACb,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACjC,OAAO,IAAE,MAAM,CAAC,IAAE,QAAQ,GAAG,IAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,KAAK;AAAA,EACzD,CAAC;AACH,CAAC,EACA,QAAQ,IAAI,EACZ,UAAU,CAAC,UACV,UAAU,KAAK,IAAI,EAAE,SAAS,OAAO,OAAO,MAAM,IAAI,KACxD;AAmBK,IAAM,wBACX;AAOK,IAAM,sBAAsB;AAAA,EACjC,OAAO,CAAC,UAAmD;AAAA,IACzD,IACE,MAAM,SAAS,uBACf,CAAC,MAAM,KAAK,SAAS,UAAU,GAC/B;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM,SAAS,MAAM,KAAK,OAAO,CAAC,QAAQ,QAAQ,UAAU;AAAA,IAC5D,OAAO,OAAO,SAAS,IACnB,GAAG,yBAAyB,wBAAwB,MAAM,MAC1D;AAAA;AAER;AAOO,IAAM,iBAAgB,CAAC,cAGvB;AAAA,EAEL,aAAa,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,QAAQ,SAAS,WAAW;AAAA,EAE7D,YAAY;AAAA,EAEZ,OAAO,IAAE,OAAO,EAAE,QAAQ,SAAS,KAAK;AAAA,EAExC,MAAM,IAAE,OAAO,EAAE,SAAS;AAC5B;AAUO,IAAM,WACX,CACE,iBAEF;AAAA,EACE;AAAA,KACG;AAAA,OACkC;AAAA,KAClC;AAAA,EACH,SACE,SAAS,YACL,QAAQ,UACR,CAAC,aAAa,MAAM,EAAE,KAAK,CAAC,GAAG,GAAG,QAAQ,OAAO;AACzD;AAGK,IAAM,aAAa,CAAC,YACzB,QAAQ,QAAQ,SAAS;AAGpB,IAAM,sBAAsB,CAAC,aAAqB;AAAA,EACvD,SAAS,GAAG;AAAA,EACZ,MAAM,CAAC,SAAS;AAClB;;;ADnKO,IAAM,wBAAwB,IAClC,aACC;AAAA,KAGK,eAAc,EAAE,aAAa,CAAC,GAAG,OAAO,UAAU,CAAC;AAAA,EAEtD,eAAe,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAExC,SAAS,IAAE,MAAM,qBAAqB,EAAE,QAAQ,CAAC,CAAC;AACpD,GACA,mBACF,EACC,UAAU,SAAS,qBAAqB,CAAC,EACzC,OAAO,YAAY,oBAAoB,UAAU,CAAC;AAa9C,IAAM,wBAAwB,wBACnC,YACA,qBACF;;;AEnEA,cAAS;AA6CF,IAAM,uBAAuB,IACjC,aAAa;AAAA,KACT,eAAc;AAAA,IACf,aAAa,CAAC,QAAQ,MAAM,QAAQ;AAAA,IACpC,OAAO;AAAA,EACT,CAAC;AAAA,EAED,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAE9B,SAAS,IAAE,MAAM,mBAAmB,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC,EACA,UAAU,SAAS,mBAAmB,CAAC,EACvC,OAAO,YAAY,oBAAoB,SAAS,CAAC;AAa7C,IAAM,uBAAuB,wBAClC,WACA,oBACF;;;ACzEA,cAAS;AAoCF,IAAM,uBAAuB,IACjC,aACC;AAAA,KACK,eAAc;AAAA,IACf,aAAa,CAAC,QAAQ,MAAM,QAAQ;AAAA,IACpC,OAAO;AAAA,EACT,CAAC;AAAA,EAED,eAAe,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAExC,SAAS,IAAE,MAAM,qBAAqB,EAAE,QAAQ,CAAC,CAAC;AACpD,GACA,mBACF,EACC,UAAU,SAAS,qBAAqB,CAAC,EACzC,OAAO,YAAY,oBAAoB,SAAS,CAAC;AAa7C,IAAM,uBAAuB,wBAClC,WACA,oBACF;;;ACnEA,cAAS;AAWF,IAAM,sBAAyC,CAAC,eAAe;AAQ/D,IAAM,qBAAqB,IAAE,aAAa;AAAA,EAE/C,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAElC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,MAAM,IAAE,OAAO;AACjB,CAAC;AA2DM,IAAM,sBAAsB,IAChC,OAAO;AAAA,EAEN,OAAO,IAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,EAEtC,SAAS,IAAE,MAAM,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAE/C,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAE1B,OAAO,IAAE,OAAO,EAAE,SAAS;AAC7B,CAAC,EACA,SAAS,IAAE,KAAK,CAAC,EACjB,UAAU,GAAG,MAAM,YAAY,eAAsC;AAAA,KACjE;AAAA,EACH,SACE,SAAS,YACL,UACA,CAAC,mBAAmB,MAAM,EAAE,KAAK,CAAC,GAAG,GAAG,OAAO;AACvD,EAAE,EACD,OAAO,YAAY,oBAAoB,QAAQ,CAAC;AAU5C,IAAM,sBAAsB,wBACjC,UACA,mBACF;;;ALvFO,IAAM,yBAAyB,IACnC,mBAAmB,QAAQ;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC,EACA,UAAU,CAAC,WAAqC;AAAA,KAC5C;AAAA,EACH,iBAAiB,CAAC;AAAA,EAGlB,aAAa,MAAM,SAAS,WAAW,CAAC,GAAG,mBAAmB,IAAI,CAAC;AACrE,EAAE;AAEJ,IAAM,YACJ;AAOK,IAAM,wBAAwB,IAClC,MAAM,wBAAwB;AAAA,EAC7B,OAAO,CAAC,UAAW,MAAM,SAAS,iBAAiB,YAAY;AACjE,CAAC,EACA,QAAQ,CAAC,CAAC;AAGb,IAAM,eAAkC,CAAC,YAAY,WAAW,SAAS;AAWlE,IAAM,2BAA2B,CACtC,SACuB;AAAA,EACvB,MAAM,UAAU,aAAa,OAAO,CAAC,QAAQ,KAAK,SAAS,GAAG,CAAC;AAAA,EAC/D,IAAI,QAAQ,WAAW,GAAG;AAAA,IACxB;AAAA,EACF;AAAA,EACA,MAAM,OAAO,QAAQ,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,KAAK,IAAI;AAAA,EACzD,MAAM,YAAY,QAAQ,IAAI,CAAC,QAAQ,GAAG,YAAY,EAAE,KAAK,IAAI;AAAA,EACjE,MAAM,OAAO,iBAAiB,gHAAgH;AAAA,EAC9I,MAAM,SAAS,KAAK,OAAO,CAAC,QAAQ,CAAC,aAAa,SAAS,GAAG,CAAC;AAAA,EAC/D,OAAO,OAAO,SAAS,IACnB,GAAG,QAAQ,wBAAwB,MAAM,MACzC;AAAA;;;AMtFN,cAAS;AASF,IAAM,qBAAqB,IAAE,aAAa,CAAC,CAAC;AAQ5C,IAAM,QAAQ,CAAC,UAAwB,CAAC,OAAqB;AAAA,EAClE,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC,cAAc;AAC9B;;;ACvBA,cAAS;;;ACAT,cAAS;AA2BF,IAAM,uBAAuB,IACjC,OAAO;AAAA,EACN,QAAQ,IAAE,OAAO;AAAA,EACjB,OAAO,IAAE,OAAO;AAAA,EAChB,WAAW,IAAE,OAAO;AACtB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAMb,IAAM,UAAU,CAAC,aAA6C;AAAA,EACnE,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC,eAAe;AAC/B;;;AC7CA,cAAS;AAaF,IAAM,0BAA0B,IAAE,aAAa,CAAC,CAAC;AAOjD,IAAM,aAAa,CACxB,UAA6B,CAAC,OACP;AAAA,EACvB,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC,YAAY;AAC5B;;;AC5BA,cAAS;AAoBF,IAAM,0BAA0B,IACpC,OAAO;AAAA,EACN,SAAS,IAAE,OAAO;AACpB,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAQb,IAAM,aAAa,CAAC,aAAmD;AAAA,EAC5E,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,oBAAoB;AAAA,EACtC,aAAa,CAAC,iBAAiB;AACjC;;;ACtCA,cAAS;AAgCF,IAAM,0BAA0B,IACpC,OAAO;AAAA,EACN,QAAQ,IAAE,OAAO;AAAA,EACjB,UAAU,IAAE,OAAO;AAAA,EACnB,SAAS,IAAE,OAAO,EAAE,SAAS;AAC/B,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAMb,IAAM,aAAa,CAAC,aAAmD;AAAA,EAC5E,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC,oBAAoB;AACpC;;;AClDA,cAAS;AAaF,IAAM,wBAAwB,IAAE,aAAa,CAAC,CAAC;AAO/C,IAAM,WAAW,CAAC,UAA2B,CAAC,OAAwB;AAAA,EAC3E,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC;AAChB;;;AC1BA,cAAS;AAoCF,IAAM,yBAAyB,IACnC,OAAO;AAAA,EACN,QAAQ,IAAE,OAAO;AAAA,EACjB,YAAY,IAAE,OAAO;AAAA,EACrB,MAAM,IAAE,OAAO;AAAA,EACf,MAAM,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAC3C,UAAU,IAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,EAAE,SAAS;AAC/C,CAAC,EACA,SAAS,IAAE,KAAK,CAAC;AAMb,IAAM,YAAY,CAAC,aAAiD;AAAA,EACzE,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC,WAAW;AAC3B;;;ANVO,IAAM,sBAAyC;AAAA,EACpD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS,CAAC;AAAA,EACV,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC;AAChB;AASA,IAAM,aAAa,CAKjB,MACA,MACA,YACG,wBAAwB,MAAM,OAAO,EAAE,OAAO,EAAE,MAAM,IAAE,QAAQ,IAAI,EAAE,CAAC;AAG5E,IAAM,kBAAkB;AAAA,EACtB,WAAW,WAAW,UAAU,oBAAoB;AAAA,EACpD,WAAW,cAAc,UAAU,uBAAuB;AAAA,EAC1D,WAAW,cAAc,UAAU,uBAAuB;AAAA,EAC1D,WAAW,SAAS,UAAU,kBAAkB;AAAA,EAChD,WAAW,eAAe,UAAU,uBAAuB;AAAA,EAC3D,WAAW,YAAY,YAAY,qBAAqB;AAAA,EACxD,WAAW,aAAa,UAAU,sBAAsB;AAC1D;AAaO,IAAM,8BAA8B,IACxC,mBAAmB,QAAQ;AAAA,EAC1B,GAAG;AAAA,EACH,WAAW,QAAQ,QAAQ,IAAE,aAAa,CAAC,CAAC,CAAC;AAC/C,CAAC,EACA,UAAU,CAAC,UAAiC;AAAA,EAC3C,QAAQ,MAAM;AAAA,SACP,WAAW;AAAA,MACd,OAAO,QAAQ,MAAM,OAAO;AAAA,IAC9B;AAAA,SACK,cAAc;AAAA,MACjB,OAAO,WAAW,MAAM,OAAO;AAAA,IACjC;AAAA,SACK,cAAc;AAAA,MACjB,OAAO,WAAW,MAAM,OAAO;AAAA,IACjC;AAAA,SACK,QAAQ;AAAA,MACX,OAAO;AAAA,IACT;AAAA,SACK,SAAS;AAAA,MACZ,OAAO,MAAM,MAAM,OAAO;AAAA,IAC5B;AAAA,SACK,eAAe;AAAA,MAClB,OAAO,WAAW,MAAM,OAAO;AAAA,IACjC;AAAA,SACK,YAAY;AAAA,MACf,OAAO,SAAS,MAAM,OAAO;AAAA,IAC/B;AAAA,aACS;AAAA,MAKP;AAAA,IACF;AAAA;AAAA,EAEF,OAAO,UAAU,MAAM,OAAO;AAAA,CAC/B;;;AOjIH,IAAM,WAAW,CAAQ,UACvB,OAAO,UAAU;AAcZ,IAAM,mBAAmB,CAAQ,UAAqC;AAAA,EAC3E,IAAI,CAAC,SAAS,KAAK,GAAG;AAAA,IACpB;AAAA,EACF;AAAA,EACA,MAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,QAAQ,EAAE;AAAA,EAC9C,OAAO,SAAS,IAAI,WAAW;AAAA;;;ACrBjC,cAAS;;;ACAT,cAAS;AA+BF,IAAM,0BAA0B,0BAA0B,OAAO;AAAA,EACtE,aAAa,IAAE,OAAO;AAAA,EACtB,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,EACjC,QAAQ,qBAAqB,SAAS;AAAA,EACtC,QAAQ,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,QAAQ,kBAAkB,SAAS;AAAA,EACnC,OAAO,IAAE,OAAO;AAClB,CAAC;AAOM,IAAM,0BAA0B,wBACrC,cACA,uBACF;AASO,IAAM,aAAa,CAAC,aAAmD;AAAA,EAC5E,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,yBAAyB;AAAA,EAC3C,aAAa,CAAC;AAChB;;;AC9DA,cAAS;AAOF,IAAM,sBAAsB,IAAE,OACnC,CAAC,UACC,OAAO,UAAU,YACjB,UAAU,SACV,UAAU,UACV,OAAO,MAAM,SAAS,eACtB,UAAU,UACV,OAAO,MAAM,SAAS,UACxB,EAAE,SAAS,8DAA8D,CAC3E;AAIO,IAAM,sBAAsB,wBACjC,UACA,mBACF;AASO,IAAM,SAAS,CAAC,YAA0C;AAAA,EAC/D,MAAM;AAAA,EACN,SAAS;AAAA,EACT,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC;AAChB;;;ACrCA,cAAS;AAqBF,IAAM,8BAA8B,0BAA0B,OAAO;AAAA,EAC1E,QAAQ,IAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,OAAO,IAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACtC,OAAO,IAAE,OAAO;AAAA,EAChB,aAAa,IAAE,QAAQ,EAAE,SAAS;AAAA,EAClC,MAAM,IAAE,OAAO;AACjB,CAAC;AAOM,IAAM,8BAA8B,wBACzC,mBACA,2BACF;AAOO,IAAM,iBAAiB,CAC5B,aAC2B;AAAA,EAC3B,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,cAAc;AAAA,EAChC,aAAa,CAAC;AAChB;;;ACnDA,cAAS;AA4BF,IAAM,yBAAyB,0BAA0B,OAAO;AAAA,EACrE,OAAO,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACpC,QAAQ,IACL,aAAa;AAAA,IACZ,OAAO,IAAE,OAAO;AAAA,IAChB,MAAM,IAAE,OAAO,EAAE,QAAQ,EAAE;AAAA,IAC3B,KAAK,IAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,IAC9B,MAAM,IAAE,OAAO;AAAA,EACjB,CAAC,EACA,SAAS;AAAA,EACZ,SAAS,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC;AAAA,EAC3D,KAAK,IAAE,OAAO,EAAE,SAAS;AAC3B,CAAC;AAOM,IAAM,yBAAyB,wBACpC,cACA,sBACF;AAKA,IAAM,eAAe,IAAI,IAAI,CAAC,kBAAkB,2BAA2B,CAAC;AAE5E,IAAM,kBAAkB,CAAC,YACvB,QAAQ,WAAW,aAClB,QAAQ,QAAQ,aACf,IAAI,SAAS,QAAQ,GAAG,KACxB,aAAa,IAAI,IAAI,IAAI,QAAQ,GAAG,EAAE,QAAQ;AAS3C,IAAM,YAAY,CAAC,aAAiD;AAAA,EACzE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,gBAAgB,OAAO,IAAI,CAAC,cAAc,IAAI,CAAC;AAAA,EAChE,aAAa,CAAC;AAChB;;;AC3EA,cAAS;AA8BF,IAAM,sBAAsB,0BAA0B,OAAO;AAAA,EAClE,aAAa,IAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC5C,UAAU,IAAE,OAAO;AAAA,EACnB,YAAY,IACT,aAAa;AAAA,IACZ,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,IACjC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,QAAQ,IAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,CAAC,EACA,SAAS;AAAA,EACZ,gBAAgB,IAAE,OAAO,EAAE,SAAS;AACtC,CAAC;AAIM,IAAM,sBAAsB,wBACjC,UACA,mBACF;AAOO,IAAM,SAAS,CAAC,aAA2C;AAAA,EAChE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,cAAc;AAAA,EAChC,aAAa,CAAC,kBAAkB;AAClC;;;AC9DA,cAAS;AAeF,IAAM,wBAAwB,0BAA0B,OAAO;AAAA,EACpE,SAAS,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACtC,OAAO,IAAE,OAAO,EAAE,IAAI,CAAC;AACzB,CAAC;AAIM,IAAM,wBAAwB,wBACnC,YACA,qBACF;AAOO,IAAM,WAAW,CAAC,aAA+C;AAAA,EACtE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC;AAChB;;;ACrCA,cAAS;AAiCF,IAAM,uBAAuB,0BAA0B,OAAO;AAAA,EACnE,gBAAgB,IAAE,OAAO,EAAE,SAAS;AAAA,EACpC,YAAY,IAAE,OAAO;AAAA,EACrB,OAAO,IAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EAC/C,QAAQ,qBAAqB,SAAS;AAAA,EACtC,QAAQ,kBAAkB,SAAS;AAAA,EACnC,KAAK,IAAE,OAAO;AAChB,CAAC;AAIM,IAAM,uBAAuB,wBAClC,WACA,oBACF;AAOO,IAAM,UAAU,CAAC,aAA6C;AAAA,EACnE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,iBAAiB;AAAA,EACnC,aAAa,CAAC;AAChB;;;AC3DA,cAAS;AAgCF,IAAM,sBAAsB,0BAA0B,OAAO;AAAA,EAClE,YAAY,IAAE,OAAO,EAAE,SAAS;AAAA,EAChC,SAAS,IAAE,OAAO;AAAA,EAClB,QAAQ,IACL,aAAa;AAAA,IACZ,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,IACjC,cAAc,IAAE,OAAO,EAAE,SAAS;AAAA,IAClC,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,CAAC,EACA,SAAS;AAAA,EACZ,WAAW,IAAE,OAAO;AAAA,EACpB,OAAO,IAAE,OAAO;AAClB,CAAC;AAIM,IAAM,sBAAsB,wBACjC,UACA,mBACF;AAOO,IAAM,SAAS,CAAC,aAA2C;AAAA,EAChE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,cAAc;AAAA,EAChC,aAAa,CAAC,gBAAgB;AAChC;;;ACjEA,cAAS;AA8BF,IAAM,sBAAsB,0BAA0B,OAAO;AAAA,EAClE,aAAa,IAAE,OAAO;AAAA,EACtB,QAAQ,qBAAqB,SAAS;AAAA,EACtC,QAAQ,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,QAAQ,kBAAkB,SAAS;AAAA,EACnC,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,KAAK,IAAE,OAAO;AAChB,CAAC;AAIM,IAAM,sBAAsB,wBACjC,UACA,mBACF;AAQO,IAAM,SAAS,CAAC,aAA2C;AAAA,EAChE,MAAM;AAAA,EACN;AAAA,EACA,iBAAiB,CAAC,kBAAkB;AAAA,EACpC,aAAa,CAAC;AAChB;;;ATdA,IAAM,mBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,qBAAqB,IAAE,mBAAmB,QAAQ,gBAAe;AAcvE,IAAM,mBAAmB,IAAI,IAAI;AAAA,EAC/B,CAAC,UAAU,QAAQ;AAAA,EACnB,CAAC,cAAc,YAAY;AAAA,EAC3B,CAAC,mBAAmB,gBAAgB;AAAA,EACpC,CAAC,cAAc,WAAW;AAAA,EAC1B,CAAC,UAAU,QAAQ;AAAA,EACnB,CAAC,YAAY,UAAU;AAAA,EACvB,CAAC,UAAU,QAAQ;AACrB,CAAC;AAED,IAAM,iBACJ;AAEF,IAAM,cAAa;AAEnB,IAAM,eAAe,CAAC,UACpB,OAAO,UAAU,YAAY,UAAU;AAGzC,IAAM,oBAAoB,IAAE,YAAY,EAAE,MAAM,IAAE,OAAO,EAAE,CAAC;AAO5D,IAAM,YAAY,CAAC,SAAqC;AAAA,EACtD,IAAI,SAAS,WAAW;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,UAAU,iBAAiB,IAAI,IAAI;AAAA,EACzC,IAAI,CAAC,SAAS;AAAA,IACZ,OAAO,GAAG,mCAAmC;AAAA,EAC/C;AAAA,EACA,MAAM,OACJ,SAAS,WACL,0DACA,GAAG;AAAA,EACT,OAAO,GAAG,mCAAmC,kDAAkD;AAAA;AAQ1F,IAAM,8BAA8B,mBAAmB,UAC5D,CAAC,UAAgC;AAAA,EAC/B,QAAQ,MAAM;AAAA,SACP,cAAc;AAAA,MACjB,OAAO,KAAK,WAAW,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAChE;AAAA,SACK,mBAAmB;AAAA,MACtB,OAAO,KAAK,eAAe,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IACpE;AAAA,SACK,cAAc;AAAA,MACjB,OAAO,KAAK,UAAU,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAC/D;AAAA,SACK,UAAU;AAAA,MACb,OAAO,KAAK,OAAO,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAC5D;AAAA,SACK,cAAc;AAAA,MACjB,OAAO,KAAK,WAAW,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAChE;AAAA,SACK,WAAW;AAAA,MACd,OAAO,KAAK,QAAQ,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAC7D;AAAA,SACK,UAAU;AAAA,MACb,OAAO,KAAK,OAAO,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAC5D;AAAA,SACK,YAAY;AAAA,MACf,OAAO,KAAK,SAAS,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAC9D;AAAA,SACK,UAAU;AAAA,MACb,OAAO,KAAK,OAAO,MAAM,OAAO,GAAG,SAAS,MAAM,QAAQ;AAAA,IAC5D;AAAA,aACS;AAAA,MAKP;AAAA,IACF;AAAA;AAAA,EAEF,OAAO,OAAO,MAAM,OAAO;AAAA,CAE/B;AAOA,IAAM,oBAAoB,IACvB,OACC,CAAC,UAAU,aAAa,KAAK,MAAK,UAAU,QAC5C;AAAA,EACE,OAAO,CAAC,UAAU;AAAA,IAChB,MAAM,SAAS,kBAAkB,UAAU,MAAM,KAAK;AAAA,IACtD,OAAO,UAAU,OAAO,UAAU,OAAO,KAAK,OAAO,SAAS;AAAA;AAElE,CACF,EACC,KAAK,2BAA2B;AAM5B,IAAM,uBAAuB,IAAE,MAAM,mBAAmB;AAAA,EAC7D,OAAO,CAAC,UAAW,MAAM,SAAS,iBAAiB,cAAa;AAClE,CAAC;;;AUpFD,IAAM,YAAY;AAAA,EAChB,MAAM,CAAC,gBAAgB,WAAW,SAAS,WAAW;AAAA,EACtD,MAAM,CAAC,iBAAiB,aAAa,YAAY;AAAA,EACjD,OAAO,CAAC,YAAY,WAAW,OAAO;AACxC;AAGO,IAAM,eAAe;AAAA,EAC1B,WAAW,EAAE,UAAU,QAAQ,QAAQ,WAAW,SAAS,CAAC,UAAU,EAAE;AAAA,EACxE,SAAS;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,OAAO,EAAE,UAAU,QAAQ,QAAQ,SAAS,SAAS,CAAC,UAAU,EAAE;AAAA,EAClE,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,KAAK,KAAK,GAAG;AAAA,EACzB;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,kBAAkB;AAAA,IAChB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,KAAK,KAAK,GAAG;AAAA,EACzB;AAAA,EACA,OAAO,EAAE,UAAU,QAAQ,QAAQ,SAAS,SAAS,CAAC,UAAU,EAAE;AAAA,EAClE,eAAe;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,kBAAkB;AAAA,IAChB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,MAAM,EAAE,UAAU,SAAS,QAAQ,QAAQ,SAAS,CAAC,UAAU,EAAE;AAAA,EACjE,SAAS;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,oBAAoB;AAAA,IAClB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,qBAAqB;AAAA,IACnB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,QAAQ,EAAE,UAAU,QAAQ,QAAQ,UAAU,SAAS,CAAC,UAAU,EAAE;AAAA,EACpE,eAAe;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,kBAAkB;AAAA,IAChB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,iBAAiB;AAAA,IACf,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AAAA,EACA,cAAc,EAAE,UAAU,QAAQ,QAAQ,cAAc,SAAS,CAAC,KAAK,GAAG,EAAE;AAAA,EAC5E,aAAa;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS,CAAC,UAAU;AAAA,EACtB;AACF;AAKO,IAAM,aAAa,OAAO,KAAK,YAAY;AAG3C,IAAM,aAAa,CAAC,UACzB,OAAO,OAAO,cAAc,KAAK;AAGnC,IAAM,yBAA8C,CAAC,KAAK,KAAK,KAAK,GAAG;AAQvE,IAAM,iBAAiB;AAAA,EACrB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,UAAU;AAAA,EACf,IAAI,CAAC,UAAU;AAAA,EACf,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,OAAO;AAAA,EACZ,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,UAAU;AAAA,EACf,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,UAAU;AAAA,EACf,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,YAAY,WAAW;AAAA,EAC5B,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,WAAW;AAAA,EAChB,IAAI,CAAC,YAAY,cAAc;AAAA,EAC/B,IAAI,CAAC,UAAU;AAAA,EACf,IAAI,CAAC,YAAY,WAAW;AAAA,EAC5B,IAAI,CAAC,YAAY;AAAA,EACjB,IAAI,CAAC,WAAW;AAClB;AAGA,IAAM,mBAAmB,CACvB,aAEA,OAAO,OAAO,gBAAgB,QAAQ;AAMxC,IAAM,iBAAiB;AAAA,EACrB,MAAM,CAAC,UAAU;AAAA,EACjB,MAAM,CAAC,WAAW;AACpB;AAGA,IAAM,iBAAiB,CACrB,WAEA,OAAO,OAAO,gBAAgB,MAAM;AAGtC,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,IAAM,kBAAkB,CAAC,SAC9B,MAAM,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI,KAAK,CAAC;AAO1C,IAAM,oBAAoB,CAAC,YAAgC;AAAA,EAChE,MAAM,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC;AAAA,EAChC,WAAW,UAAU,SAAS;AAAA,IAC5B,OAAO,WAAW,OAAO,WAAW,OAAO,YAAY,EAAE,MAAM,GAAG;AAAA,IAClE,IAAI,iBAAiB,QAAQ,GAAG;AAAA,MAC9B,WAAW,UAAU,eAAe,WAAW;AAAA,QAC7C,OAAO,IAAI,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,IACA,WAAW,UAAU,SAAS;AAAA,MAC5B,IAAI,eAAe,MAAM,GAAG;AAAA,QAC1B,WAAW,UAAU,eAAe,SAAS;AAAA,UAC3C,OAAO,IAAI,MAAM;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,aAAa,OAAO,CAAC,WAAW,OAAO,IAAI,MAAM,CAAC;AAAA;AAQ3D,IAAM,mBAAmB,IAAI,IAAwB;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,IAAM,kBAAkB,CAAC,SAC9B,KACG,YAAY,EACZ,WAAW,gBAAgB,GAAG,EAG9B,WAAW,WAAW,EAAE;AAG7B,IAAM,UAAU,CAAC,SAAyB,cAAc;AAExD,IAAM,QAAoB,CAAC,WAAW,QAAQ,MAAM;AAGpD,IAAM,eAAe,CAAC,SACpB,SAAS,SAAS,SAAS;AAG7B,IAAM,cAAc,CAAC,UACnB,OAAO,UAAU;AAOnB,IAAM,mBAAmB,CACvB,MACA,OACA,YACqB;AAAA,EACrB,IAAI,YAAY,KAAK,GAAG;AAAA,IACtB,IAAI,CAAC,WAAW,KAAK,GAAG;AAAA,MACtB,OAAO;AAAA,IACT;AAAA,IACA,MAAM,MAAM,aAAa;AAAA,IACzB,OAAO;AAAA,MACL,aAAa,QAAQ,KAAK;AAAA,MAC1B,WAAW,UAAU,IAAI;AAAA,MACzB,MAAM;AAAA,MACN,MAAM,IAAI;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA,SAAS,IAAI;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,OAAO,gBAAgB,MAAM,IAAI;AAAA,EACvC,MAAM,YAAY,UAAU,MAAM,YAAY,aAAa,IAAI;AAAA,EAC/D,IAAI,cAAc,OAAO;AAAA,IACvB,OAAO;AAAA,MACL,aAAa,QAAQ,IAAI;AAAA,MACzB;AAAA,MACA,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,IAClB;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,aAAa,QAAQ,IAAI;AAAA,IACzB;AAAA,IACA,MAAM;AAAA,IACN,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM,YAAY;AAAA,IAC5B,SAAS,MAAM,WAAW;AAAA,IAC1B,SAAS,MAAM,WAAW;AAAA,EAC5B;AAAA;AASF,IAAM,mBAAmB,CAAC,SAAoB,SAA+B;AAAA,EAC3E,IACE,QAAQ,SAAS,YACjB,KAAK,SAAS,YACd,QAAQ,aAAa,KAAK,YAC1B,QAAQ,SAAS,KAAK,MACtB;AAAA,IACA,OAAO;AAAA,SACF;AAAA,MACH,SAAS,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,SAAS,GAAG,KAAK,OAAO,CAAC,CAAC;AAAA,MAC3D,SAAS,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,SAAS,GAAG,KAAK,OAAO,CAAC,CAAC;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,IACE,QAAQ,SAAS,WACjB,KAAK,SAAS,WACd,QAAQ,SAAS,KAAK,QACtB,KAAK,UAAU,QAAQ,QAAQ,MAAM,KAAK,UAAU,KAAK,QAAQ,GACjE;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,MAAM,IAAI,MACR,iBAAiB,KAAK,yBAAyB,QAAQ,6CAA6C,QAAQ,wFAC9G;AAAA;AAQK,IAAM,mBAAmB,CAC9B,OACA,UAAoB,CAAC,MACL;AAAA,EAChB,IAAI,CAAC,OAAO;AAAA,IACV,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,UAAU,kBAAkB,OAAO;AAAA,EACzC,MAAM,UAAU,IAAI;AAAA,EACpB,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,QAAQ,MAAM;AAAA,IACpB,IAAI,UAAU,WAAW;AAAA,MACvB;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,iBAAiB,MAAM,OAAO,OAAO;AAAA,IACnD,IAAI,CAAC,OAAO;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM,UAAU,QAAQ,IAAI,MAAM,WAAW;AAAA,IAC7C,QAAQ,IACN,MAAM,aACN,UAAU,iBAAiB,SAAS,KAAK,IAAI,KAC/C;AAAA,EACF;AAAA,EACA,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC;AAAA;AAI7B,IAAM,WAAW,CAAC,UAAoC;AAAA,EACpD,IAAI,YAAY,KAAK,GAAG;AAAA,IACtB,OAAO,WAAW,KAAK,IAAI,QAAQ;AAAA,EACrC;AAAA,EACA,OAAO,gBAAgB,MAAM,IAAI;AAAA;AAQ5B,IAAM,gBAAgB,CAAC,UAA+B;AAAA,EAC3D,IAAI,CAAC,OAAO;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,MAAM,QAAQ,CAAC,SAAS;AAAA,IACpC,MAAM,QAAQ,MAAM;AAAA,IACpB,IAAI,UAAU,WAAW;AAAA,MACvB,OAAO,CAAC;AAAA,IACV;AAAA,IACA,MAAM,OAAO,SAAS,KAAK;AAAA,IAC3B,OAAO,OAAO,CAAC,kBAAkB,iBAAiB,QAAQ,IAAI,KAAK,IAAI,CAAC;AAAA,GACzE;AAAA,EACD,OAAO,MAAM,SAAS,IAClB;AAAA;AAAA,EAAwD,MAAM,KAAK;AAAA,CAAI;AAAA;AAAA,IACvE;AAAA;AAUN,IAAM,kBAAkB;AAAA,EACtB,MAAM,CAAC,KAAK,GAAG;AAAA,EACf,SAAS,CAAC,KAAK,GAAG;AAAA,EAClB,MAAM,CAAC,GAAG;AACZ;AAeA,IAAM,eAAe,CAAC,UACpB,MAAM,SAAS,WACX,MAAM,UACN,MAAM,SAAS,IAAI,CAAC,YAAY,QAAQ,MAAM;AASpD,IAAM,oBAAoB,CAAC,MAAgB,UAA+B;AAAA,EACxE,MAAM,YAAY,gBAAgB;AAAA,EAClC,MAAM,UAAU,aAAa,KAAK;AAAA,EAClC,MAAM,UAAU,QAAQ,OACtB,CAAC,WAA6B,OAAO,WAAW,QAClD;AAAA,EACA,MAAM,OAAO,UAAU,OAAO,CAAC,WAAW,QAAQ,SAAS,MAAM,CAAC;AAAA,EAClE,IAAI,KAAK,SAAS,GAAG;AAAA,IACnB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,QAAQ,WAAW,QAAQ,SAAS,UAAU;AAAA;AAQhD,IAAM,kBAAkB,CAC7B,OACA,UAAoB,CAAC,MACN;AAAA,EACf,IAAI,CAAC,OAAO;AAAA,IACV,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,iBAAiB,kBAAkB,OAAO;AAAA,EAChD,MAAM,QAAQ,IAAI;AAAA,EAIlB,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,QAAQ,MAAM;AAAA,IACpB,IAAI,UAAU,WAAW;AAAA,MACvB;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,iBAAiB,MAAM,OAAO,cAAc;AAAA,IAC1D,IAAI,CAAC,OAAO;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM,OAAO,MAAM,IAAI,MAAM,WAAW,KAAK;AAAA,MAC3C,SAAS;AAAA,MACT,SAAS,IAAI;AAAA,IACf;AAAA,IACA,WAAW,UAAU,kBAAkB,MAAM,KAAK,GAAG;AAAA,MACnD,KAAK,QAAQ,IAAI,MAAM;AAAA,IACzB;AAAA,IACA,IAAI,MAAM,SAAS,YAAY,iBAAiB,IAAI,MAAM,QAAQ,GAAG;AAAA,MACnE,KAAK,YAAY,IAAI;AAAA,MACrB,WAAW,UAAU,MAAM,SAAS;AAAA,QAClC,KAAK,QAAQ,IAAI,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,IACA,MAAM,IAAI,MAAM,aAAa,IAAI;AAAA,EACnC;AAAA,EACA,OAAO,CAAC,GAAG,KAAK,EAAE,IAAI,EAAE,aAAa,UAAU;AAAA,IAC7C,MAAM,OAAiB;AAAA,MACrB;AAAA,MACA,gBAAgB,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,IAC5D;AAAA,IACA,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,iBAAiB,CAAC,GAAG,KAAK,OAAO;AAAA,IACxC;AAAA,IACA,OAAO;AAAA,GACR;AAAA;;;ACvkBI,IAAM,kBAAkB;AAExB,IAAM,iBAAiB;AAC9B,IAAM,kBAAkB;AAExB,IAAM,wBAAwB;AAG9B,IAAM,WAAW,CAAC,WAChB,GAAG,OAAO,SAAS,OAAO;AAGrB,IAAM,UAAU,CACrB,WACW,GAAG,OAAO,QAAQ,SAAS,MAAM;AAGvC,IAAM,cAAc,CACzB,WACW,GAAG,QAAQ,MAAM,UAAU,OAAO;AAQxC,IAAM,SAAS,CAAC,WAAuD;AAAA,EAC5E,IAAI,OAAO,KAAK;AAAA,IACd,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,MAAM,MAAM,IAAI,IAAI,OAAO,IAAI;AAAA,EAC/B,QAAQ,aAAa;AAAA,EACrB,IACE,aAAa,mBACb,SAAS,SAAS,IAAI,iBAAiB,GACvC;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,IAAI,SAAS,SAAS,qBAAqB,GAAG;AAAA,IAG5C,IAAI,WAAW,OAAO;AAAA,IACtB,OAAO,IAAI;AAAA,EACb;AAAA,EACA,OAAO,GAAG,OAAO;AAAA;;;ACrEnB,cAAS;AAYT,IAAM,kBAAkB,IAAE,OAAO;AAAA,EAC/B,SAAS,IACN,OAAO;AAAA,IACN,aAAa,IAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,IAC/C,aAAa,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IAChD,OAAO,IAAE,OAAO,EAAE,QAAQ,wBAAwB;AAAA,IAClD,YAAY,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IAC/C,QAAQ,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,IACpC,gBAAgB,IAAE,OAAO,EAAE,QAAQ,0BAA0B;AAAA,IAC7D,UAAU,IAAE,OAAO,EAAE,QAAQ,WAAW;AAAA,IACxC,WAAW,IAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,IAClD,YAAY,IAAE,OAAO,EAAE,QAAQ,aAAa;AAAA,IAC5C,cAAc,IAAE,OAAO,EAAE,QAAQ,kBAAkB;AAAA,IACnD,eAAe,IAAE,OAAO,EAAE,QAAQ,iBAAiB;AAAA,IACnD,MAAM,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IACzC,QAAQ,IAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,IACnC,YAAY,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IAC/C,WAAW,IAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,IAC7C,YAAY,IAAE,OAAO,EAAE,QAAQ,aAAa;AAAA,IAE5C,QAAQ,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IAC3C,YAAY,IAAE,OAAO,EAAE,QAAQ,cAAc;AAAA,IAG7C,kBAAkB,IACf,OAAO,EACP,QAAQ,wDAAwD;AAAA,IACnE,aAAa,IAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,EACjD,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,KAAK,IACF,OAAO;AAAA,IACN,IAAI,IAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,IAC3B,OAAO,IAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,IAC9C,OAAO,IAAE,OAAO,EAAE,QAAQ,OAAO;AAAA,IACjC,MAAM,IAAE,OAAO,EAAE,QAAQ,mBAAmB;AAAA,IAC5C,OAAO,IAAE,OAAO,EAAE,QAAQ,gCAAgC;AAAA,IAC1D,OAAO,IAAE,OAAO,EAAE,QAAQ,8BAA8B;AAAA,IACxD,OAAO,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IAC1C,aAAa,IAAE,OAAO,EAAE,QAAQ,iBAAiB;AAAA,IACjD,MAAM,IAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,IAC/B,KAAK,IAAE,OAAO,EAAE,QAAQ,uCAAuC;AAAA,IAC/D,OAAO,IAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,IAClC,KAAK,IAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EAC/B,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,QAAQ,IACL,OAAO;AAAA,IACN,SAAS,IAAE,OAAO,EAAE,QAAQ,sBAAsB;AAAA,EACpD,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,WAAW,IACR,OAAO;AAAA,IACN,aAAa,IACV,OAAO,EACP,QACC,8DACF;AAAA,IACF,OAAO,IAAE,OAAO,EAAE,QAAQ,WAAW;AAAA,EACvC,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,SAAS,IACN,OAAO;AAAA,IAGN,WAAW,IAAE,OAAO,EAAE,QAAQ,2BAA2B;AAAA,IACzD,YAAY,IAAE,OAAO,EAAE,QAAQ,aAAa;AAAA,IAC5C,cAAc,IAAE,OAAO,EAAE,QAAQ,gCAAgC;AAAA,EACnE,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,UAAU,IACP,OAAO;AAAA,IACN,IAAI,IAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,IAC3B,UAAU,IAAE,OAAO,EAAE,QAAQ,wBAAwB;AAAA,IACrD,QAAQ,IAAE,OAAO,EAAE,QAAQ,2BAA2B;AAAA,IACtD,KAAK,IAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EAC/B,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,kBAAkB,IACf,OAAO;AAAA,IACN,OAAO,IAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,IACpC,cAAc,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,EACnD,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,KAAK,IACF,OAAO;AAAA,IACN,MAAM,IAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,IAC/B,YAAY,IAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,IAC3C,iBAAiB,IAAE,OAAO,EAAE,QAAQ,kBAAkB;AAAA,IACtD,YAAY,IAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,IAC3C,UAAU,IAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,IACvC,kBAAkB,IAAE,OAAO,EAAE,QAAQ,mBAAmB;AAAA,IACxD,YAAY,IAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,IAE3C,eAAe,IAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,IACtD,SAAS,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,IACrC,UAAU,IAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,IACvC,kBAAkB,IAAE,OAAO,EAAE,QAAQ,mBAAmB;AAAA,IACxD,aAAa,IAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,EACtD,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,UAAU,IACP,OAAO;AAAA,IAEN,KAAK,IAAE,OAAO,EAAE,QAAQ,qCAAqC;AAAA,IAC7D,aAAa,IACV,OAAO,EACP,QAAQ,+CAA+C;AAAA,IAC1D,MAAM,IAAE,OAAO,EAAE,QAAQ,cAAc;AAAA,IAEvC,MAAM,IAAE,OAAO,EAAE,QAAQ,qCAAqC;AAAA,IAE9D,SAAS,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,IAErC,aAAa,IAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,IACpD,OAAO,IAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,EAC5C,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,MAAM,IACH,OAAO;AAAA,IACN,aAAa,IAAE,OAAO,EAAE,QAAQ,iBAAiB;AAAA,IACjD,MAAM,IAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,IAC/B,YAAY,IAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,IAC3C,UAAU,IAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,IACvC,eAAe,IAAE,OAAO,EAAE,QAAQ,iBAAiB;AAAA,EACrD,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,QAAQ,IACL,OAAO;AAAA,IACN,KAAK,IAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,IAC7B,cAAc,IAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,IAChD,aAAa,IAAE,OAAO,EAAE,QAAQ,cAAc;AAAA,IAC9C,OAAO,IAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,IAClC,WAAW,IAAE,OAAO,EAAE,QAAQ,+BAA+B;AAAA,IAC7D,QAAQ,IAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,IACnC,SAAS,IACN,OAAO,EACP,QAAQ,8CAA8C;AAAA,IACzD,OAAO,IAAE,OAAO,EAAE,QAAQ,yCAAyC;AAAA,IACnE,OAAO,IAAE,OAAO,EAAE,QAAQ,aAAa;AAAA,IACvC,UAAU,IAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,IACvC,WAAW,IAAE,OAAO,EAAE,QAAQ,mBAAmB;AAAA,IACjD,MAAM,IAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,IAC/B,aAAa,IAAE,OAAO,EAAE,QAAQ,uBAAuB;AAAA,IACvD,SAAS,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,IACrC,SAAS,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,IACrC,SAAS,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,EACvC,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,KAAK,IACF,OAAO;AAAA,IACN,OAAO,IAAE,OAAO,EAAE,QAAQ,cAAc;AAAA,EAC1C,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,UAAU,IACP,OAAO;AAAA,IACN,QAAQ,IAAE,OAAO,EAAE,QAAQ,cAAc;AAAA,IAEzC,QAAQ,IACL,OAAO,EACP,QACC,oEACF;AAAA,IACF,UAAU,IAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,EACxC,CAAC,EACA,SAAS,CAAC,CAAC;AAChB,CAAC;AAEM,IAAM,kBAAkB,gBAAgB,SAAS,CAAC,CAAC;AAYnD,IAAM,QAAmB,gBAAgB,MAAM,CAAC,CAAC;AAOjD,IAAM,0BAA0B,IAAE,OACvC,IAAE,OAAO,GACT,IAAE,OAAO,IAAE,OAAO,GAAG,IAAE,OAAO,CAAC,CACjC;AAKO,IAAM,0BAA0B,IAAE,OACvC,IAAE,OAAO,GACT,uBACF;AAGA,IAAM,UAAU,CAAC,MAAiB,aAA4C;AAAA,EAC5E,IAAI,CAAC,UAAU;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,MAAM,MAAiB,gBAAgB,IAAI;AAAA,EAC3C,YAAY,OAAO,WAAW,OAAO,QAAQ,QAAQ,GAAG;AAAA,IAGtD,MAAM,SAAU,IAA+C;AAAA,IAC/D,IAAI,UAAU,QAAQ;AAAA,MACpB,OAAO,OAAO,QAAQ,MAAM;AAAA,IAC9B;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAYT,IAAM,iBAAoD,OAAO,YAC/D,OAAO,QAAQ,QAAQ,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC,KAAK,YAAY,GAAG,IAAI,CAAC,CAC3E;AAQA,IAAM,UAAU,CAAC,SAAgD;AAAA,EAC/D,MAAM,QAAQ,KAAK,YAAY;AAAA,EAC/B,OACE,SAAS,SACT,eAAe,UACf,eAAe,MAAM,MAAM,OAAO,EAAE,MAAM;AAAA;AAUvC,IAAM,mBAAmB,CAC9B,QACA,YAIc;AAAA,EACd,QAAQ,eAAe,cAAc;AAAA,EACrC,IAAI,OAAO;AAAA,EACX,OAAO,QAAQ,MAAM,QAAQ,aAAa,CAAC;AAAA,EAC3C,OAAO,QAAQ,MAAM,YAAY,cAAc;AAAA,EAC/C,IAAI,WAAW,eAAe;AAAA,IAC5B,OAAO,QAAQ,MAAM,QAAQ,MAAM,CAAC;AAAA,IACpC,OAAO,QAAQ,MAAM,YAAY,OAAO;AAAA,EAC1C;AAAA,EACA,OAAO;AAAA;;;AC/QF,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACuCO,IAAM,mBAAmB,CAAI,UAClC,OAAO,UAAU,YACjB,UAAU,QAGV,OAAQ,MAAmD,cACvD,aAAa;;;A5DdnB,IAAM,gBAAgB,IAAE,IAAI,EAAE,UAAU,YAAY,CAAC;AAerD,IAAM,YAAW,CAAQ,UACvB,OAAO,UAAU;AAEnB,IAAM,aAAY,CAAQ,UACxB,OAAO,UAAU;AAEnB,IAAM,gBAAe,CAAQ,UAC3B,OAAO,UAAU,YAAY,UAAU;AAGzC,IAAM,WAAW,IAAE,OAAO,EAAE,IAAI,CAAC;AAQjC,IAAM,kBAAkB,CAAC,WAAmC;AAAA,EAC1D,OAAO,CAAC,UAAmD;AAAA,IACzD,IAAI,MAAM,SAAS,qBAAqB;AAAA,MACtC;AAAA,IACF;AAAA,IACA,MAAM,WAAW,MAAM,KAAK,QAAQ,CAAC,QACnC,OAAO,OAAO,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAC9C;AAAA,IACA,IAAI,SAAS,WAAW,GAAG;AAAA,MACzB;AAAA,IACF;AAAA,IAGA,MAAM,SAAS,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,OAAO,OAAO,OAAO,GAAG,CAAC;AAAA,IACpE,IAAI,OAAO,SAAS,GAAG;AAAA,MACrB,SAAS,KAAK,wBAAwB,MAAM,CAAC;AAAA,IAC/C;AAAA,IACA,OAAO,SAAS,KAAK,GAAG;AAAA;AAE5B;AAGA,IAAM,gBAAgB,IAAE,KAAK,CAAC,QAAQ,QAAQ,WAAW,SAAS,MAAM,CAAC;AAOzE,IAAM,aAAa,IAChB,MAAM,CAAC,IAAE,OAAO,GAAG,IAAE,KAAK,CAAC,CAAC,EAC5B,UAAU,CAAC,UAAW,iBAAiB,OAAO,MAAM,YAAY,IAAI,KAAM;AAS7E,IAAM,uBAAuB,IAAE,KAAK,CAAC,QAAQ,SAAS,MAAM,CAAC;AAO7D,IAAM,oBAAoB,IAAE,aAAa;AAAA,EACvC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAM3B,SAAS,qBAAqB,SAAS;AAAA,EACvC,QAAQ,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACjC,MAAM,SAAS,SAAS;AAAA,EACxB,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,OAAO,IAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAQD,IAAM,gBAAgB,IAAE,OAAO,EAAE,UAAU,gBAAgB,EAAE,SAAS;AAEtE,IAAM,gBAAgB,IAAE,aAAa;AAAA,EACnC,WAAW,IAAE,IAAI,EAAE,SAAS;AAAA,EAC5B,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,EACjC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAClC,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,GAAG,IAAE,aAAa,EAAE,SAAS,cAAc,CAAC,EAAE,SAAS;AACzD,CAAC;AAED,IAAM,mBAAmB,IAAE,aACzB;AAAA,EACE,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAClC,MAAM,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,SAAS;AACrC,GACA,gBAAgB;AAAA,EACd,OACE;AACJ,CAAC,CACH;AAEA,IAAM,eAAe,IAAE,aAAa;AAAA,EAElC,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AACpC,CAAC;AAED,IAAM,sBAAsB,IAAE,aAAa;AAAA,EACzC,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,MAAM,WAAW,SAAS;AAAA,EAC1B,SAAS,IAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AASD,IAAM,eAAe,IAAE,MAAM;AAAA,EAC3B,IAAE,OAAO;AAAA,EACT,IACG,OAAO;AAAA,IACN,QAAQ,IAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,MAAM,IAAE,OAAO;AAAA,IACf,KAAK,IAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,CAAC,EACA,SAAS,IAAE,QAAQ,CAAC;AACzB,CAAC;AAQD,IAAM,qBAAqB,IAAE,aAAa;AAAA,EACxC,IAAI,aAAa,SAAS,CAAC,CAAC;AAAA,EAE5B,SAAS,IAAE,MAAM,CAAC,cAAc,IAAE,MAAM,YAAY,CAAC,CAAC,EAAE,SAAS;AAAA,EACjE,WAAW,oBAAoB,SAAS;AAAA,EAExC,MAAM,WAAW,SAAS;AAAA,EAC1B,YAAY,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACrC,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,EACjC,OAAO,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAChC,QAAQ,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACjC,MAAM,SAAS,SAAS;AAAA,EAExB,cAAc,WAAW,SAAS;AAAA,EAClC,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAClC,QAAQ,iBAAiB,SAAS,CAAC,CAAC;AAAA,EACpC,KAAK,cAAc,SAAS,CAAC,CAAC;AAAA,EAC9B,SAAS,kBAAkB,SAAS,CAAC,CAAC;AAAA,EACtC,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,MAAM,IAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAEM,IAAM,iBAAiB;AAM9B,IAAM,kBAA4B,mBAAmB,MAAM,CAAC,CAAC;AAatD,IAAM,uBAAuB,mBACjC,MAAM,EAEN,MAAM,MAAM,eAAe;AAG9B,IAAM,0BAA0B,IAAI,IAClC,mBAAmB,MAAM,EAAE,OAC7B;AAWA,IAAM,wBAAwB,CAAC,UAC7B,IACG,OACC,IAAE,OAAO,GACT,IAAE,OAAuB,kBAAkB;AAAA,EACzC,SACE;AACJ,CAAC,CACH,EACC,QAAQ,CAAC,CAAC,EACV,YAAY,CAAC,OAAO,QAAQ;AAAA,EAC3B,WAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AAAA,IACpC,IAAI,wBAAwB,IAAI,GAAG,GAAG;AAAA,MACpC,IAAI,SAAS;AAAA,QACX,MAAM,IAAE,aAAa;AAAA,QACrB,SAAS,IAAI,qEAAqE;AAAA,QAClF,MAAM,CAAC,GAAG;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAAA,CACD;AAME,IAAM,mBAAmB,IAAE,aAAa;AAAA,EAC7C,WAAW,IAAE,QAAQ,EAAE,SAAS;AAAA,EAEhC,SAAS,qBAAqB,SAAS;AAAA,EACvC,MAAM,SAAS,SAAS;AAAA,EACxB,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,OAAO,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACpC,OAAO,IAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AASD,IAAM,kBAAkB,IAAE,MAAM;AAAA,EAC9B,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,KAAK,IAAE,OAAO,EAAE,SAAS;AAAA,IACzB,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,CAAC;AACH,CAAC;AASD,IAAM,mBAAmB,IAAE,MAAM;AAAA,EAC/B,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,OAAO,gBAAgB,SAAS;AAAA,IAChC,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC;AACH,CAAC;AAGD,IAAM,qBAAqB,IAAE,MAAM;AAAA,EACjC,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,SAAS,IAAE,OAAO;AAAA,IAElB,aAAa,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAEtC,IAAI,IAAE,OAAO,EAAE,SAAS;AAAA,IACxB,MAAM,IAAE,aAAa,EAAE,MAAM,IAAE,OAAO,GAAG,MAAM,IAAE,OAAO,EAAE,CAAC,EAAE,SAAS;AAAA,EACxE,CAAC;AACH,CAAC;AAUD,IAAM,0BAA0B,IAAE,aAAa;AAAA,EAS7C,QAAQ,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAOtC,aAAa,sBAAsB,eAAe;AACpD,CAAC;AAGD,IAAM,4BAA4B,CAAC,WAAW,WAAW,MAAM;AAS/D,IAAM,sBAAsB,IACzB,aAAa;AAAA,EACZ,aAAa,IAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EACrC,SAAS,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACtC,SAAS,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACtC,OAAO,IAAE,OAAO,EAAE,QAAQ,OAAO;AAAA,EACjC,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,SAAS,qBAAqB,SAAS;AAAA,EAKvC,OAAO,IAAE,OAAO,IAAE,OAAO,GAAG,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AACjE,CAAC,EACA,YAAY,CAAC,OAAO,QAAQ;AAAA,EAC3B,IAAI,CAAC,MAAM,SAAS;AAAA,IAClB;AAAA,EACF;AAAA,EACA,WAAW,OAAO,2BAA2B;AAAA,IAC3C,IAAI,MAAM,SAAS,WAAW;AAAA,MAC5B,IAAI,SAAS;AAAA,QACX,MAAM,IAAE,aAAa;AAAA,QACrB,SAAS,WAAW,8HAA8H;AAAA,QAClJ,MAAM,CAAC,GAAG;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAAA,CACD,EACA,UAAU,GAAG,SAAS,SAAS,MAAM,YAAY,YAAY;AAAA,KACzD;AAAA,EACH,SAAS,WAAW;AAAA,IAElB,4BAA4B,MAAM,WAAW,EAAE,SAAS,SAAS,KAAK,CAAC,CAAC;AAAA,EAC1E;AACF,EAAE;AAUJ,IAAM,yBAAyB,IAAE,MAAM;AAAA,EACrC,IAAE,OAAO;AAAA,EACT,IACG,OAAO,IAAE,OAAO,GAAG,IAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,UAAU,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG;AAAA,IAChD,SAAS;AAAA,EACX,CAAC;AACL,CAAC;AAID,IAAM,eAAe,IAAE,aAAa;AAAA,EAIlC,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACjC,MAAM,SAAS,SAAS;AAAA,EACxB,OAAO,IACJ,MACC,IAAE,aAAa;AAAA,IACb,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,IACjC,MAAM,SAAS,SAAS;AAAA,IACxB,OAAO;AAAA,IACP,MAAM,IAAE,OAAO;AAAA,IACf,KAAK,IAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,CAAC,CACH,EACC,SAAS;AAAA,EACZ,OAAO;AAAA,EACP,MAAM,IAAE,OAAO;AACjB,CAAC;AAED,IAAM,wBAAwB,IAAE,aAAa;AAAA,EAC3C,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,EACjC,MAAM,SAAS,SAAS;AAAA,EACxB,OAAO,IAAE,OAAO;AAAA,EAChB,MAAM,IAAE,OAAO;AAAA,EACf,KAAK,IAAE,OAAO,EAAE,SAAS;AAC3B,CAAC;AAED,IAAM,oBAAoB,IAAE,aAAa;AAAA,EACvC,OAAO,IAAE,MAAM,qBAAqB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAChD,MAAM,IAAE,KAAK,CAAC,YAAY,YAAY,WAAW,SAAS,CAAC;AAAA,EAC3D,OAAO,IAAE,OAAO;AAClB,CAAC;AAED,IAAM,sBAAsB,IAAE,KAAK,CAAC,aAAa,QAAQ,MAAM,CAAC;AAqBhE,IAAM,oBACJ,IAAE,KAAK,MACL,IAAE,MAAM;AAAA,EACN,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,WAAW,IAAE,QAAQ,EAAE,SAAS;AAAA,IAChC,WAAW,oBAAoB,SAAS;AAAA,IACxC,SAAS,qBAAqB,SAAS;AAAA,IACvC,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,MAAM,SAAS,SAAS;AAAA,IACxB,OAAO,IAAE,MAAM,iBAAiB,EAAE,SAAS;AAAA,IAC3C,OAAO,IAAE,OAAO;AAAA,IAChB,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC;AACH,CAAC,CACH;AAEF,IAAM,qBAAqB,IAAE,KAAK,CAAC,QAAQ,SAAS,MAAM,CAAC;AAG3D,IAAM,mBAAmB,IAAE,aAAa;AAAA,EACtC,UAAU,mBAAmB,SAAS;AAAA,EACtC,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,UAAU,IACP,KAAK,CAAC,UAAU,cAAc,SAAS,WAAW,CAAC,EACnD,QAAQ,QAAQ;AAAA,EAEnB,SAAS,IAAE,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACxD,SAAS,IACN,MACC,IAAE,MAAM,CAAC,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,IAAE,OAAO,EAAE,MAAM,eAAe,CAAC,CAAC,CAC1E,EACC,SAAS,EACT,SAAS;AACd,CAAC;AAGD,IAAM,yBAAyB,IAAE,aAAa;AAAA,EAC5C,KAAK,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACrB,OAAO,IAAE,KAAK,CAAC,UAAU,UAAU,SAAS,CAAC,EAAE,SAAS;AAAA,EACxD,QAAQ,IACL,MAAM;AAAA,IACL,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,IAC1B,IAAE,OAAO,EAAE,MAAM,oBAAoB;AAAA,EACvC,CAAC,EACA,SAAS;AACd,CAAC;AAGD,IAAM,kBAAkB,IAAE,aAAa;AAAA,EACrC,UAAU,mBAAmB,SAAS;AAAA,EACtC,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,UAAU,IAAE,MAAM,sBAAsB,EAAE,SAAS;AACrD,CAAC;AAOD,IAAM,kBAAkB,IACrB,MAAM,CAAC,IAAE,OAAO,GAAG,kBAAkB,eAAe,CAAC,EACrD,YAAY,CAAC,OAAO,QAAQ;AAAA,EAC3B,IAAI,UAAS,KAAK,KAAK,CAAC,WAAW,KAAK,GAAG;AAAA,IACzC,IAAI,SAAS;AAAA,MACX,MAAM,IAAE,aAAa;AAAA,MACrB,SAAS,iBAAiB,4BAA4B,WAAW,KAAK,IAAI;AAAA,IAC5E,CAAC;AAAA,EACH;AAAA,CACD;AAOH,IAAM,qBAAqB,IACxB,MAAM;AAAA,EACL,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,CAAC;AACH,CAAC,EACA,SAAS,EACT,UAAU,CAAC,UACV,UAAS,KAAK,IAAI,EAAE,MAAM,OAAO,OAAO,MAAM,IAAI,KACpD;AAEF,IAAM,oBAAoB;AAAA,EACxB,QAAQ,IACL,MAAM;AAAA,IACL,IAAE,OAAO;AAAA,IACT,IAAE,aAAa,EAAE,MAAM,IAAE,OAAO,GAAG,OAAO,IAAE,OAAO,EAAE,CAAC;AAAA,EACxD,CAAC,EACA,QAAQ,MAAM,EACd,UAAU,CAAC,UACV,UAAS,KAAK,IAAI,EAAE,MAAM,OAAO,OAAO,MAAM,IAAI,KACpD;AAAA,EACF,QAAQ,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,OAAO,IACJ,aAAa;AAAA,IACZ,MAAM,gBAAgB,QAAQ,OAAO;AAAA,IACrC,SAAS,gBAAgB,QAAQ,OAAO;AAAA,IACxC,MAAM,gBAAgB,QAAQ,eAAe;AAAA,EAC/C,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EACd,MAAM,IAAE,KAAK,CAAC,UAAU,SAAS,MAAM,CAAC,EAAE,QAAQ,QAAQ;AAAA,EAC1D,QAAQ,IAAE,KAAK,CAAC,QAAQ,MAAM,MAAM,IAAI,CAAC,EAAE,QAAQ,IAAI;AACzD;AAEA,IAAM,oBAAoB,IAAE,aAC1B,mBACA,gBAAgB;AAAA,EACd,QACE;AACJ,CAAC,CACH;AAGA,IAAM,0BAA0B,IAAE,aAAa;AAAA,EAC7C,MAAM,IAAE,OAAO;AAAA,EACf,MAAM,SAAS,SAAS;AAAA,EACxB,OAAO,IAAE,OAAO;AAClB,CAAC;AAQD,IAAM,uBAAuB,IAC1B,OAGC,CAAC,UAAU,UAAU,SAAS,cAAa,KAAK,GAChD;AAAA,EACE,SACE;AACJ,CACF,EACC,UAAU,CAAC,UAAW,UAAU,QAAQ,sBAAsB,KAAM,EACpE,KAAK,2BAA2B;AAGnC,IAAM,uBAAuB,IAC1B,aAAa;AAAA,EACZ,mBAAmB,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAC5C,oBAAoB,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAC/C,CAAC,EACA,SAAS,CAAC,CAAC;AAGd,IAAM,sBAAsB,IAAE,aAC5B;AAAA,EACE,UAAU;AAAA,EAEV,SAAS,IAAE,MAAM,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpD,UAAU,qBAAqB,QAAQ,MAAM,MAAM,CAAC;AACtD,GAEA,gBAAgB;AAAA,EACd,SACE;AAAA,EACF,YACE;AAAA,EACF,YACE;AAAA,EACF,WACE;AACJ,CAAC,CACH;AAgBA,IAAM,qBAAqB,IACxB,OAGC,CAAC,UAAU,UAAU,SAAS,cAAa,KAAK,GAChD;AAAA,EACE,SACE;AACJ,CACF,EACC,UAAU,CAAC,UACV,UAAU,UAAS,UAAU,SAAQ,EAAE,UAAU,MAAM,IAAI,KAC7D,EACC,KAAK,mBAAmB;AAQ3B,IAAM,qBAAqB,CAAC,KAAK,KAAK,KAAK,MAAM,MAAM,MAAM,OAAO,GAAG;AAOvE,IAAM,kBAAkB,IACrB,OAAO,IAAE,OAAO,GAAG,IAAE,QAAQ,CAAC,EAC9B,YAAY,CAAC,KAAK,QAAQ;AAAA,EACzB,IAAI,CAAC,UAAS,IAAI,GAAG,KAAK,IAAI,IAAI,WAAW,GAAG;AAAA,IAC9C,IAAI,SAAS;AAAA,MACX,MAAM,IAAE,aAAa;AAAA,MACrB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EACA,MAAM,SAAS,mBAAmB,OAAO,CAAC,WAAU,SAAS,IAAG;AAAA,EAChE,IAAI,OAAO,SAAS,GAAG;AAAA,IACrB,IAAI,SAAS;AAAA,MACX,MAAM,IAAE,aAAa;AAAA,MACrB,SAAS,2CAA2C,OAAO,KAAK,MAAM;AAAA,IACxE,CAAC;AAAA,EACH;AAAA,CACD;AAEH,IAAM,kBAAkB,IAAE,aAAa;AAAA,EACrC,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAElC,cAAc,IAAE,OAAO,EAAE,SAAS;AAAA,EAElC,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAK1B,OAAO,IAAE,OAAO,EAAE,QAAQ,MAAM,EAAE,UAAU,cAAc;AAC5D,CAAC;AAED,IAAM,oBAAoB,IACvB,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,OACC,CAAC,UAAU;AAAA,EACT,IAAI,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,WAAW,IAAI,GAAG;AAAA,IACpD,OAAO;AAAA,EACT;AAAA,EACA,IAAI;AAAA,IACF,MAAM,MAAM,IAAI,IAAI,KAAK;AAAA,IACzB,OAAO,IAAI,aAAa,WAAW,IAAI,aAAa;AAAA,IACpD,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,GAGX;AAAA,EACE,SACE;AACJ,CACF;AAGF,IAAM,sBAAsB,IAAE,aAAa;AAAA,EAMzC,SAAS,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC3C,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AACnC,CAAC;AAKD,IAAM,wBAAwB,IAAE,aAAa;AAAA,EAC3C,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAQjC,SAAS,IACN,OAAO,IAAE,OAAO,EAAE,IAAI,CAAC,GAAG,IAAE,MAAM,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAClE,QAAQ,CAAC,CAAC;AACf,CAAC;AASD,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,qBAAqB,CAAC,SAC1B,OAAO,YACL,gBAAgB,IAAI,CAAC,QAAQ;AAAA,EAC3B;AAAA,EACA,GAAG,QAAQ,uBAAuB;AACpC,CAAC,CACH;AAGF,IAAM,iBAAiB;AAAA,EACrB,KAAK,IACF,aACC;AAAA,IAME,MAAM,IACH,MACC,IAAE,MAAM;AAAA,MACN,IAAE,QAAQ,GAAG;AAAA,MACb,IACG,IAAI,EAAE,UAAU,YAAY,CAAC,EAC7B,UAAU,CAAC,UAAU,IAAI,IAAI,KAAK,EAAE,MAAM;AAAA,IAC/C,CAAC,CACH,EACC,SAAS;AAAA,IACZ,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAIlC,UAAU,kBAAkB,SAAS;AAAA,IAIrC,cAAc,IAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IAMhD,UAAU,iBAAiB,SAAS,oBAAoB;AAAA,IAOxD,WAAW,IACR,aAAa;AAAA,MACZ,eAAe,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,MACpD,cAAc,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,MACnD,YAAY,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,IACnD,CAAC,EACA,SAAS;AAAA,IAGZ,aAAa,IACV,MACC,IAAE,aAAa;AAAA,MACb,MAAM,SAAS,SAAS;AAAA,MACxB,OAAO,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACzB,CAAC,CACH,EACC,QAAQ,CAAC,CAAC;AAAA,EACf,GACA,kBACF,EACC,YAAY,CAAC,OAAO,QAAQ;AAAA,IAG3B,IAAI,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC,IAAI,SAAS;AAAA,QACX,MAAM,IAAE,aAAa;AAAA,QACrB,SACE;AAAA,QACF,MAAM,CAAC,MAAM;AAAA,MACf,CAAC;AAAA,IACH;AAAA,GACD,EACA,SAAS;AAAA,EAOZ,YAAY,IACT,MAAM;AAAA,IACL,IAAE,QAAQ;AAAA,IACV,IACG,MAAM,IAAE,KAAK,mBAAmB,CAAC,EACjC,OAAO,CAAC,UAAU,IAAI,IAAI,KAAK,EAAE,SAAS,MAAM,QAAQ;AAAA,MACvD,SAAS;AAAA,IACX,CAAC;AAAA,EACL,CAAC,EACA,QAAQ,IAAI,EACZ,UAAU,CAAC,UAAU;AAAA,IACpB,IAAI,WAAU,KAAK,GAAG;AAAA,MACpB,OAAO,QAAQ,CAAC,GAAG,mBAAmB,IAAI,CAAC;AAAA,IAC7C;AAAA,IACA,OAAO;AAAA,GACR;AACL;AAEA,IAAM,iBAAiB,IAAE,aACvB,gBACA,gBAAgB,mBAAmB,IAAI,CAAC,CAC1C;AAOA,IAAM,qBAAqB,IAAE,aAAa;AAAA,EACxC,MAAM,IAAE,OAAO;AAAA,EACf,MAAM,SAAS,SAAS;AAAA,EACxB,OAAO,IAAE,OAAO;AAClB,CAAC;AAOD,IAAM,qBAAqB,IAAE,aAAa;AAAA,EACxC,MAAM,IAAE,OAAO;AAAA,EACf,OAAO,IAAE,OAAO;AAClB,CAAC;AAED,IAAM,yBAAyB,IAAE,aAAa;AAAA,EAE5C,SAAS,IAAE,MAAM,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAQ/C,KAAK,mBAAmB,SAAS;AAAA,EAEjC,UAAU,IAAE,MAAM,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAQhD,MAAM,IAAE,MAAM,CAAC,IAAE,QAAQ,GAAG,aAAa,CAAC,EAAE,QAAQ,IAAI;AAAA,EACxD,WAAW,IAAE,MAAM,iBAAiB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAOhD,SAAS,IACN,MAAM;AAAA,IACL,IAAE,MAAM,iBAAiB;AAAA,IACzB,IAAE,aAAa;AAAA,MACb,SAAS,qBAAqB,QAAQ,MAAM;AAAA,MAC5C,OAAO,IAAE,MAAM,iBAAiB,EAAE,SAAS;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC,EACA,SAAS,CAAC,CAAC,EACX,UAAU,CAAC,UACV,MAAM,QAAQ,KAAK,IAAI,EAAE,SAAS,QAAiB,OAAO,MAAM,IAAI,KACtE;AAAA,EACF,MAAM,IAAE,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAYD,IAAM,qBAAqB,IACxB,MAAM;AAAA,EACL,IAAE,QAAQ;AAAA,EACV,IAAE,aAAa;AAAA,IACb,MAAM,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAC/B,KAAK,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAChC,CAAC;AACH,CAAC,EACA,UAAU,CAAC,UACV,WAAU,KAAK,IAAI,EAAE,MAAM,OAAO,KAAK,MAAM,IAAI,KACnD;AAGF,IAAM,eAAe,IAAE,aAAa;AAAA,EAClC,MAAM,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAEtB,KAAK,IAAE,KAAK,CAAC,OAAO,KAAK,CAAC,EAAE,QAAQ,KAAK;AAAA,EACzC,OAAO,IAAE,OAAO;AAAA,EAMhB,OAAO,IAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAOD,IAAM,mBAAmB,IACtB,aAAa;AAAA,EACZ,eAAe,IAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,EAEtC,gBAAgB,IAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAE/C,yBAAyB,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjD,SAAS,IAAE,MAAM,YAAY,EAAE,IAAI,CAAC;AAAA,EAEpC,QAAQ,IAAE,KAAK,CAAC,OAAO,KAAK,CAAC,EAAE,QAAQ,KAAK;AAAA,EAE5C,IAAI,wBAAwB,SAAS;AACvC,CAAC,EACA,YAAY,CAAC,OAAO,QAAQ;AAAA,EAC3B,MAAM,QAAQ,IAAI,IAAI,MAAM,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI,CAAC;AAAA,EAChE,IAAI,CAAC,MAAM,IAAI,MAAM,aAAa,GAAG;AAAA,IACnC,IAAI,SAAS;AAAA,MACX,MAAM,IAAE,aAAa;AAAA,MACrB,SAAS,uBAAuB,MAAM;AAAA,MACtC,MAAM,CAAC,eAAe;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EACA,IACE,MAAM,mBAAmB,QACzB,MAAM,mBAAmB,aACzB,CAAC,MAAM,IAAI,MAAM,cAAc,GAC/B;AAAA,IACA,IAAI,SAAS;AAAA,MACX,MAAM,IAAE,aAAa;AAAA,MACrB,SAAS,wBAAwB,MAAM;AAAA,MACvC,MAAM,CAAC,gBAAgB;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,CACD;AAQI,IAAM,aAAa;AAG1B,IAAM,wBAAwB,IAAE,aAAa;AAAA,EAK3C,QAAQ,IAAE,MAAM,CAAC,IAAE,QAAQ,GAAG,IAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,IAAI;AAAA,EAOvD,WAAW,IAAE,KAAK,CAAC,UAAU,MAAM,CAAC,EAAE,QAAQ,QAAQ;AAAA,EAEtD,IAAI,IACD,OAAO,EACP,MACC,YACA,sHACF;AAAA,EAEF,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,EAE3B,SAAS,IAAE,QAAQ,EAAE,QAAQ,KAAK;AACpC,CAAC;AAQD,IAAM,uBAAuB,IAC1B,aAAa;AAAA,EAEZ,UAAU,IAAE,MAAM,qBAAqB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAEnD,SAAS,IAAE,aAAa;AAAA,IAEtB,OAAO,IAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,OAAO,IAAE,OAAO;AAAA,EAClB,CAAC;AAAA,EACD,UAAU,IACP,aAAa;AAAA,IAMZ,UAAU,IAAE,KAAK,CAAC,aAAa,MAAM,CAAC,EAAE,QAAQ,WAAW;AAAA,EAC7D,CAAC,EACA,SAAS,CAAC,CAAC;AAChB,CAAC,EACA,YAAY,CAAC,OAAO,QAAQ;AAAA,EAC3B,MAAM,OAAO,IAAI;AAAA,EACjB,YAAY,UAAU,YAAY,MAAM,SAAS,QAAQ,GAAG;AAAA,IAC1D,IAAI,KAAK,IAAI,QAAQ,EAAE,GAAG;AAAA,MACxB,IAAI,SAAS;AAAA,QACX,MAAM,IAAE,aAAa;AAAA,QACrB,SAAS,+BAA+B,QAAQ;AAAA,QAChD,MAAM,CAAC,YAAY,UAAU,IAAI;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,IACA,KAAK,IAAI,QAAQ,EAAE;AAAA,EACrB;AAAA,CACD;AAQH,IAAM,mBAAmB;AACzB,IAAM,aAAa;AAEnB,IAAM,oBAAoB,CAAC,QACzB,IACG,OAAO,EACP,OAAO,CAAC,SAAS,CAAC,iBAAiB,KAAK,KAAK,QAAQ,YAAY,EAAE,CAAC,GAAG;AAAA,EACtE,SAAS,iCAAiC;AAC5C,CAAC;AAEL,IAAM,iBAAiB,IAAE,aAAa;AAAA,EACpC,MAAM,kBAAkB,MAAM;AAAA,EAC9B,QAAQ,IACL,MAAM,CAAC,IAAE,QAAQ,GAAG,GAAG,IAAE,QAAQ,GAAG,GAAG,IAAE,QAAQ,GAAG,GAAG,IAAE,QAAQ,GAAG,CAAC,CAAC,EACtE,QAAQ,GAAG;AAAA,EACd,IAAI,kBAAkB,IAAI;AAC5B,CAAC;AAQD,IAAM,2BAA2B,IAAE,aAAa;AAAA,EAC9C,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,UAAU,IAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AASD,IAAM,oBAAoB,IAAE,aAAa;AAAA,EAEvC,SAAS,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAEvC,gBAAgB,IAAE,MAAM,wBAAwB,EAAE,QAAQ,CAAC,CAAC;AAC9D,CAAC;AAQD,IAAM,gBAAgB,IAAE,aAAa;AAAA,EAEnC,SAAS;AAAA,EAET,QAAQ;AACV,CAAC;AASD,IAAM,gBAAgB,IAAE,OAAO;AAE/B,IAAM,kBAAkB,IAAE,aAAa;AAAA,EACrC,QAAQ,cAAc,SAAS;AAAA,EAC/B,YAAY,cAAc,SAAS;AAAA,EACnC,QAAQ,cAAc,SAAS;AAAA,EAC/B,YAAY,cAAc,SAAS;AAAA,EACnC,OAAO,cAAc,SAAS;AAChC,CAAC;AAUD,IAAM,qBAAqB,IAAE,MAAM;AAAA,EACjC,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAC1B,IAAE,MAAM,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC;AAAA,EACnC,IAAE,OAAO,EAAE,MAAM,eAAe;AAClC,CAAC;AACD,IAAM,oBAAoB,IAAE,KAAK,CAAC,UAAU,QAAQ,CAAC;AACrD,IAAM,eAAe,IAAE,MAAM;AAAA,EAC3B,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,MAAM,IAAE,OAAO;AAAA,IACf,OAAO,IAAE,MAAM,CAAC,mBAAmB,IAAE,MAAM,iBAAiB,CAAC,CAAC,EAAE,SAAS;AAAA,IACzE,QAAQ,mBAAmB,SAAS;AAAA,EACtC,CAAC;AAAA,EAED,IAAE,aAAa;AAAA,IACb,MAAM,IAAE,OAAO;AAAA,IACf,KAAK,IAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACrB,OAAO,kBAAkB,SAAS;AAAA,IAClC,QAAQ,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAC/C,CAAC;AACH,CAAC;AAED,IAAM,iBAAiB,IAAE,aAAa;AAAA,EAMpC,aAAa,IAAE,MAAM,CAAC,IAAE,OAAO,GAAG,IAAE,QAAQ,KAAK,CAAC,CAAC,EAAE,SAAS;AAAA,EAO9D,SAAS,IAAE,QAAQ,EAAE,SAAS;AAAA,EAM9B,OAAO,IAAE,MAAM,YAAY,EAAE,SAAS;AAAA,EAKtC,MAAM,IAAE,MAAM,CAAC,IAAE,OAAO,GAAG,IAAE,QAAQ,KAAK,CAAC,CAAC,EAAE,SAAS;AAAA,EAEvD,SAAS,gBAAgB,SAAS;AAAA,EAMlC,MAAM,IAAE,MAAM,CAAC,IAAE,OAAO,GAAG,IAAE,QAAQ,KAAK,CAAC,CAAC,EAAE,SAAS;AAAA,EAOvD,QAAQ,IAAE,OAAO,IAAE,OAAO,GAAG,IAAE,OAAO,CAAC,EAAE,SAAS;AACpD,CAAC;AAED,IAAM,kBAAkB,IAAE,aAAa;AAAA,EACrC,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAEjC,OAAO,IAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE;AAAA,EAE7C,OAAO,IAAE,MAAM,IAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,QAAQ,WAAW,CAAC;AAC1D,CAAC;AAUD,IAAM,6BAA6B,IAAE,aAAa;AAAA,EAChD,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,QAAQ,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAClC,CAAC;AASD,IAAM,uBAAuB,IAC1B,MAAM,CAAC,IAAE,QAAQ,GAAG,0BAA0B,CAAC,EAC/C,UAAU,CAAC,UAAU;AAAA,EACpB,IAAI,UAAU,MAAM;AAAA,IAClB,OAAO,2BAA2B,MAAM,CAAC,CAAC;AAAA,EAC5C;AAAA,EACA,IAAI,UAAU,OAAO;AAAA,IACnB,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA,CACR;AAGH,IAAM,sBAAsB,IAAE,aAAa;AAAA,EACzC,gBAAgB,IAAE,OAAO,EAAE,SAAS;AAAA,EACpC,iBAAiB,IAAE,OAAO,EAAE,SAAS;AAAA,EACrC,eAAe,IAAE,OAAO,EAAE,SAAS;AAAA,EACnC,YAAY,IAAE,OAAO,EAAE,SAAS;AAAA,EAChC,eAAe,IAAE,OAAO,EAAE,SAAS;AACrC,CAAC;AAQD,IAAM,2BAA2B,IAAE,aAAa;AAAA,EAC9C,SAAS,oBAAoB,SAAS;AAAA,EACtC,aAAa,IAAE,OAAO,EAAE,QAAQ,kBAAkB;AAAA,EAClD,OAAO,IAAE,MAAM,EAAE,SAAS;AAAA,EAC1B,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,QAAQ,IAAE,MAAM,IAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACnC,WAAW,IAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,KAAK,IAAE,IAAI,EAAE,SAAS;AACxB,CAAC;AAOD,IAAM,uBAAuB,IAAE,aAAa;AAAA,EAC1C,qBAAqB,IAAE,OAAO,EAAE,QAAQ,sBAAsB;AAAA,EAC9D,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,EACjC,SAAS,IAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,MAAM,IAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,iBAAiB,IAAE,OAAO,EAAE,SAAS;AAAA,EACrC,OAAO,IAAE,MAAM,CAAC,IAAE,OAAO,EAAE,YAAY,GAAG,IAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AAAA,EAChE,eAAe,IAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EACvC,QAAQ,IAAE,MAAM,IAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC;AAKD,IAAM,kBAAkB;AAAA,EACtB,IAAI,eAAe,QAAQ,CAAC,CAAC;AAAA,EAE7B,cAAc,yBAAyB,SAAS;AAAA,EAEhD,QAAQ,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAChC,KAAK,gBAAgB,SAAS,CAAC,CAAC;AAAA,EAEhC,SAAS,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAEjC,UAAU,IACP,MAAM,CAAC,IAAE,QAAQ,GAAG,oBAAoB,CAAC,EACzC,SAAS,EACT,UAAU,CAAC,UAAwC;AAAA,IAClD,IAAI,UAAU,MAAM;AAAA,MAClB,OAAO,qBAAqB,MAAM,CAAC,CAAC;AAAA,IACtC;AAAA,IACA,OAAO,UAAU,QAAQ,YAAY;AAAA,GACtC;AAAA,EAEH,gBAAgB,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAExC,GAAG,cAAc,QAAQ,CAAC,CAAC;AAC7B;AAEA,IAAM,kBAAkB,IAAE,aACxB,iBACA,gBAAgB;AAAA,EACd,kBAAkB;AAAA,EAClB,gBAAgB;AAClB,CAAC,CACH;AAQA,IAAM,qBAAqB,IAAE,aAAa;AAAA,EAMxC,kBAAkB,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAO1C,KAAK,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAU7B,SAAS,IACN,MAAM,CAAC,IAAE,QAAQ,GAAG,qBAAqB,CAAC,EAC1C,QAAQ,IAAI,EACZ,UAAU,CAAC,UACV,WAAU,KAAK,IAAI,EAAE,SAAS,OAAO,SAAS,CAAC,EAAE,IAAI,KACvD;AAAA,EAEF,gBAAgB,qBAAqB,SAAS,IAAI;AAAA,EAQlD,SAAS,IACN,MAAM,CAAC,IAAE,QAAQ,GAAG,mBAAmB,CAAC,EACxC,QAAQ,IAAI,EACZ,UAAU,CAAC,UACV,WAAU,KAAK,IAAI,EAAE,SAAS,OAAO,SAAS,KAAK,IAAI,KACzD;AAAA,EAQF,oBAAoB,IACjB,OACC,IAAE,OAAO,GACT,IAAE,OACA,CAAC,UAAsC,OAAO,UAAU,YACxD;AAAA,IACE,SAAS;AAAA,EACX,CACF,CACF,EACC,QAAQ,CAAC,CAAC;AAAA,EAEb,KAAK,gBAAgB,SAAS,CAAC,CAAC;AAAA,EAShC,QAAQ,IAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAQnC,YAAY,IACT,aAAa;AAAA,IACZ,MAAM,IAAE,MAAM,eAAe,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC3C,CAAC,EACA,SAAS,CAAC,CAAC;AAAA,EAOd,QAAQ,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAClC,CAAC;AAQD,IAAM,qBAAqB,cAAc,UACvC,CAAC,UAAU,IAAI,IAAI,KAAK,EAAE,MAC5B;AASA,IAAM,kBAAkB,cAAc,UAAU,CAAC,UAAU;AAAA,EACzD,QAAQ,QAAQ,aAAa,IAAI,IAAI,KAAK;AAAA,EAC1C,OAAO,QAAQ,GAAG,SAAS,YAAY,GAAG;AAAA,CAC3C;AAED,IAAM,qBAAqB,IAAE,aAAa;AAAA,EAExC,KAAK,gBAAgB,SAAS;AAAA,EAC9B,QAAQ,IAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,EAEjC,KAAK,IAAE,OAAO,EAAE,SAAS;AAAA,EAEzB,MAAM,mBAAmB,QAAQ,eAAe;AAAA,EAChD,OAAO,IAAE,OAAO;AAAA,EAChB,MAAM,IAAE,OAAO;AACjB,CAAC;AAUD,IAAM,gBAAgB,CAAQ,UAC5B,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,IAAM,kBAAkB,IAAE,OAAkB,CAAC,UAAU;AAAA,EACrD,IAAI,UAAS,KAAK,GAAG;AAAA,IACnB,OAAO;AAAA,EACT;AAAA,EACA,IAAI,CAAC,cAAc,KAAK,GAAG;AAAA,IACzB,OAAO;AAAA,EACT;AAAA,EAMA,MAAM,gBACJ,MAAM,aAAa,aAAa,MAAM,QAAQ,MAAM,QAAQ;AAAA,EAC9D,MAAM,mBACJ,MAAM,gBAAgB,aAAa,MAAM,QAAQ,MAAM,WAAW;AAAA,EACpE,MAAM,cAAc,MAAM,WAAW,aAAa,cAAc,MAAM,MAAM;AAAA,EAC5E,MAAM,aACJ,MAAM,aAAa,aACnB,MAAM,gBAAgB,aACtB,MAAM,WAAW;AAAA,EACnB,OAAO,iBAAiB,oBAAoB,eAAe;AAAA,GAC1D,oDAAoD;AAEvD,IAAM,uBAAuB,IAAE,aAAa;AAAA,EAC1C,MAAM,gBAAgB,QAAQ,aAAa;AAAA,EAC3C,OAAO,gBAAgB,QAAQ,cAAc;AAC/C,CAAC;AAmBD,IAAM,uBAAuB,IAC1B,MAAM;AAAA,EACL,IAAE,OAAO;AAAA,EACT,IAAE,aAAa;AAAA,IACb,KAAK,IAAE,OAAO,EAAE,SAAS;AAAA,IACzB,QAAQ,IAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,EACvC,CAAC;AACH,CAAC,EACA,UAAU,CAAC,UACV,UAAS,KAAK,IAAI,EAAE,QAAQ,MAAM,IAAI,KACxC;AASF,IAAM,2BAA2B,IAAE,MACjC,CAAC,IAAE,QAAQ,KAAK,GAAG,IAAE,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC,GACjD;AAAA,EACE,OAAO,CAAC,UACN,MAAM,SAAS,kBACX,uHACA;AACR,CACF;AAUA,IAAM,yBAAyB,IAC5B,aAAa;AAAA,EAEZ,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAE9B,WAAW,IAAE,KAAK,CAAC,QAAQ,QAAQ,UAAU,OAAO,CAAC,EAAE,SAAS;AAAA,EAEhE,KAAK,IAAE,KAAK,CAAC,WAAW,SAAS,CAAC,EAAE,SAAS;AAAA,EAE7C,KAAK,IAAE,KAAK,CAAC,QAAQ,SAAS,QAAQ,CAAC,EAAE,SAAS;AAAA,EAElD,OAAO,IAAE,KAAK,CAAC,WAAW,WAAW,QAAQ,SAAS,QAAQ,CAAC,EAAE,SAAS;AAAA,EAE1E,iBAAiB,IAAE,OAAO,EAAE,SAAS;AAAA,EAErC,UAAU,IAAE,OAAO,EAAE,SAAS;AAAA,EAE9B,SAAS,IAAE,KAAK,CAAC,QAAQ,SAAS,QAAQ,CAAC,EAAE,SAAS;AAAA,EAEtD,MAAM,IAAE,KAAK,CAAC,WAAW,SAAS,CAAC,EAAE,SAAS;AAChD,CAAC,EACA,OACC,CAAC,UACC,MAAM,cAAc,aACnB,MAAM,YAAY,aACjB,MAAM,QAAQ,aACd,MAAM,SAAS,aACf,MAAM,UAAU,aAChB,MAAM,QAAQ,WAClB;AAAA,EACE,SACE;AACJ,CACF;AAGF,IAAM,mBAAmB,IAAE,aAAa;AAAA,EAKtC,OAAO,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAK/B,OAAO,qBAAqB,SAAS,CAAC,CAAC;AAAA,EAKvC,MAAM,IAAE,QAAQ,EAAE,QAAQ,KAAK;AACjC,CAAC;AAED,IAAM,uBAAuB;AAAA,EAE3B,MAAM,iBAAiB,SAAS,CAAC,CAAC;AAAA,EAQlC,eAAe,IAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAMxC,gBAAgB,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAKxC,WAAW,IAAE,QAAQ,EAAE,QAAQ,IAAI;AACrC;AAEA,IAAM,uBAAuB,IAAE,aAC7B,sBACA,gBAAgB;AAAA,EACd,YACE;AACJ,CAAC,CACH;AAGA,IAAM,oBAAoB,IAAE,aAAa;AAAA,EAOvC,UAAU,IAAE,QAAQ,EAAE,QAAQ,IAAI;AACpC,CAAC;AAcD,IAAM,0BAA0B,IAAE,aAAa;AAAA,EAC7C,QAAQ,sBAAsB,oBAAoB;AACpD,CAAC;AAQD,IAAM,kBAAkB,IACrB,MAAM;AAAA,EACL,IAAE,QAAQ;AAAA,EACV,IAAE,aAAa;AAAA,IACb,iBAAiB,IAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACzD,iBAAiB,IAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC3D,CAAC;AACH,CAAC,EACA,QAAQ,IAAI,EACZ,UAAU,CAAC,UAAU;AAAA,EACpB,IAAI,WAAU,KAAK,GAAG;AAAA,IACpB,OAAO,EAAE,SAAS,OAAO,UAAU,GAAG,UAAU,EAAE;AAAA,EACpD;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU,MAAM,mBAAmB;AAAA,IACnC,UAAU,MAAM,mBAAmB;AAAA,EACrC;AAAA,CACD,EAGA,OAAO,CAAC,UAAU,MAAM,YAAY,MAAM,UAAU;AAAA,EACnD,SACE;AACJ,CAAC;AAEI,IAAM,oBAAoB,IAC9B,aACC;AAAA,EACE,QAAQ,mBAAmB,SAAS,CAAC,CAAC;AAAA,EACtC,IAAI,eAAe,SAAS,CAAC,CAAC;AAAA,EAE9B,WAAW;AAAA,EACX,QAAQ,mBAAmB,SAAS;AAAA,EAOpC,UAAU,IACP,OAAO,EACP,SAAS,EACT,UAAU,CAAC,UAAU,kBAAkB,KAAK,CAAC;AAAA,EAChD,SAAS,oBAAoB,SAAS,CAAC,CAAC;AAAA,EAKxC,YAAY,uBAAuB,QAAQ,EAAE,WAAW,OAAO,CAAC;AAAA,EAOhE,YAAY,yBAAyB,SAAS,CAAC,CAAC;AAAA,EAChD,aAAa,IAAE,OAAO,EAAE,SAAS;AAAA,EAQjC,UAAU,qBAAqB,SAAS,UAAU;AAAA,EAClD,QAAQ,mBAAmB,SAAS,KAAK;AAAA,EACzC,UAAU,IAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAElC,aAAa,wBAAwB,SAAS,CAAC,CAAC;AAAA,EAChD,QAAQ,mBAAmB,SAAS;AAAA,EACpC,MAAM,iBAAiB,SAAS;AAAA,EAChC,OAAO,kBAAkB,SAAS,CAAC,CAAC;AAAA,EACpC,cAAc,IAAE,MAAM,IAAE,OAAyB,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC9D,cAAc,yBAAyB,QAAQ,KAAK;AAAA,EACpD,MAAM,iBAAiB,SAAS;AAAA,EAChC,UAAU,qBAAqB,SAAS,CAAC,CAAC;AAAA,EAC1C,YAAY,uBAAuB,SAAS,CAAC,CAAC;AAAA,EAC9C,OAAO,kBAAkB,SAAS,CAAC,CAAC;AAAA,EACpC,WAAW,IAAE,MAAM,cAAc,EAAE,QAAQ,CAAC,CAAC;AAAA,EAE7C,WAAW;AAAA,EACX,QAAQ,mBAAmB,SAAS,CAAC,CAAC;AAAA,EACtC,KAAK,gBAAgB,SAAS,CAAC,CAAC;AAAA,EAChC,OAAO,kBAAkB,SAAS,CAAC,CAAC;AAAA,EACpC,OAAO,IAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,EACzC,KAAK;AAAA,EACL,UAAU,qBAAqB,SAAS;AAC1C,GACA;AAAA,EAGE,OAAO,CAAC,UACN,MAAM,SAAS,sBACX,yBAAyB,MAAM,IAAI,IACnC;AACR,CACF,EACC,YAAY,CAAC,QAAQ,QAAQ;AAAA,EAI5B,IAAI,OAAO,YAAY,OAAO,MAAM;AAAA,IAClC,MAAM,cAAc,IAAI,IACtB,OAAO,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,KAAK,YAAY,CAAC,CAC/D;AAAA,IACA,YAAY,UAAU,YAAY,OAAO,SAAS,SAAS,QAAQ,GAAG;AAAA,MACpE,IAAI,YAAY,IAAI,QAAQ,GAAG,YAAY,CAAC,GAAG;AAAA,QAC7C,IAAI,SAAS;AAAA,UACX,MAAM,IAAE,aAAa;AAAA,UACrB,SAAS,eAAe,QAAQ,qEAAqE,QAAQ;AAAA,UAC7G,MAAM,CAAC,YAAY,YAAY,UAAU,IAAI;AAAA,QAC/C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAIA,YAAY,UAAU,eAAe,OAAO,QAAQ,OAAO,QAAQ,KAAK,GAAG;AAAA,IACzE,WAAW,OAAO,OAAO,KAAK,WAAW,WAAW,GAAG;AAAA,MACrD,IAAI,OAAO,OAAO,OAAO,YAAY,QAAQ,GAAG,GAAG;AAAA,QACjD,IAAI,SAAS;AAAA,UACX,MAAM,IAAE,aAAa;AAAA,UACrB,SAAS,IAAI,qFAAqF;AAAA,UAClG,MAAM,CAAC,WAAW,SAAS,UAAU,eAAe,GAAG;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAIA,YAAY,UAAU,UAAU,WAAW,OAAO,QAAQ,GAAG;AAAA,MAC3D,IACE,EACE,OAAO,OAAO,WAAW,aAAa,KAAK,KAC3C,OAAO,OAAO,OAAO,YAAY,QAAQ,KAAK,IAEhD;AAAA,QACA,IAAI,SAAS;AAAA,UACX,MAAM,IAAE,aAAa;AAAA,UACrB,SAAS,UAAU,oBAAoB;AAAA,UACvC,MAAM,CAAC,WAAW,SAAS,UAAU,UAAU,QAAQ;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,CACD;;;A6D31DI,IAAM,eAAe;AAmDrB,IAAM,gBAAgB,CAC3B,OACA,aACoB;AAAA,EACpB,OAAO,SAAS;AAAA,EAChB,IAAI,SAAS,SAAS,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,KAAK,GAAG;AAAA,IACtE,OAAO,EAAE,MAAM,MAAM,MAAM,CAAC,GAAG,SAAS,MAAM;AAAA,EAChD;AAAA,EACA,OAAO,EAAE,MAAM,OAAO,SAAS,GAAG;AAAA;AAQ7B,IAAM,mBAAmB,CAC9B,KACA,aACuB;AAAA,EACvB,QAAQ,SAAS,SAAS,cAAc,IAAI,MAAM,GAAG,GAAG,QAAQ;AAAA,EAChE,OAAO,EAAE,MAAM,KAAK,KAAK,GAAG,GAAG,QAAQ;AAAA;AAQlC,IAAM,kBAAkB,CAC7B,cACA,YACW;AAAA,EACX,IAAI,CAAC,SAAS;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACA,OAAO,iBAAiB,MAAM,IAAI,YAAY,IAAI,UAAU;AAAA;AA0BvD,IAAM,sBAAsB,CACjC,OACA,aACiB;AAAA,EAKjB,MAAM,aAAa,IAAI,IAAI,SAAS,SAAS,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AAAA,EACzE,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,cAA4B,CAAC;AAAA,EACnC,WAAW,QAAQ,OAAO;AAAA,IAGxB,OAAO,SAAS,KAAK,OAAO,IAAI,MAAM,GAAG;AAAA,IACzC,IACE,SACA,CAAC,KAAK,IAAI,KAAK,KACf,aAAa,KAAK,KAAK,KACvB,CAAC,WAAW,IAAI,KAAK,GACrB;AAAA,MACA,KAAK,IAAI,KAAK;AAAA,MACd,YAAY,KAAK;AAAA,QACf,MAAM;AAAA,QACN,SAAS,WAAW,sCAAsC,6FAA6F;AAAA,QACvJ,UAAU;AAAA,QACV,YAAY,cAAc;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,OAAO;AAAA;;;A/DlJT,IAAM,iBAAiB;AACvB,IAAM,eAAe;AACrB,IAAM,aAAa;AAGnB,IAAM,qBAAqB,CAAC,YAC1B,QAAQ,QAAQ,gBAAgB,EAAE;AAGpC,IAAM,aAAa,CAAC,YAClB,QAAQ,MAAM,YAAY,GAAG,QAAQ,SAAS;AAczC,IAAM,UAAU,CAAC,SACtB,KACG,UAAU,KAAK,EACf,YAAY,EACZ,KAAK,EACL,WAAW,4BAA4B,EAAE,EACzC,WAAW,YAAY,GAAG,EAC1B,WAAW,QAAQ,GAAG,EACtB,WAAW,WAAW,EAAE;AAQtB,IAAM,cAAc,CAAC,SAC1B,KAAK,MAAM,GAAG,EAAE,IAAI,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAGvD,IAAM,YAAY,CAAC,UACjB,MACG,MAAM,UAAU,EAChB,OAAO,OAAO,EACd,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,GAAG;AAWb,IAAM,kBAAkB,CAAC,YACvB,QAAQ,WAAW,eAAe,EAAE;AAGtC,IAAM,kBAAkB,CACtB,MACA,UACA,WACS;AAAA,EAGT,IAAI,SAAS,IAAI;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,QAAQ,WAAW,IAAI;AAAA,EAC7B,IAAI,UAAU,MAAM;AAAA,IAClB,OAAO,KAAK,KAAK;AAAA,IACjB;AAAA,EACF;AAAA,EACA,MAAM,QAAQ,mBAAmB,IAAI;AAAA,EACrC,IAAI,UAAU,SAAS;AAAA,IACrB;AAAA,EACF;AAAA,EACA,MAAM,OAAO,gBAAgB,KAAK;AAAA,EAElC,IAAI,SAAS,IAAI;AAAA,IACf;AAAA,EACF;AAAA,EACA,SAAS,KAAK,IAAI;AAAA;AAepB,IAAM,WAAW,CAAC,iBAAsC;AAAA,EACtD,MAAM,aAAa,aAAa,MAC9B,GACA,aAAa,SAAS,SAAQ,YAAY,EAAE,MAC9C;AAAA,EACA,MAAM,WAAW,WAAW,MAAM,GAAG;AAAA,EAErC,MAAM,WAAqB,CAAC;AAAA,EAC5B,MAAM,SAAmB,CAAC;AAAA,EAE1B,WAAW,QAAQ,UAAU;AAAA,IAC3B,gBAAgB,MAAM,UAAU,MAAM;AAAA,EACxC;AAAA,EAEA,MAAM,QAAQ,SAAS,WAAW,IAAI,MAAM,IAAI,SAAS,KAAK,GAAG;AAAA,EACjE,OAAO,EAAE,QAAQ,OAAO,SAAS;AAAA;AAMnC,IAAM,cAAc;AAIpB,IAAM,mBAAmB;AAKzB,IAAM,sBAAsB;AAC5B,IAAM,iBACJ;AACF,IAAM,qBAAqB;AAY3B,IAAM,cAAc;AAGpB,IAAM,eAAe;AAWrB,IAAM,0BAA0B,CAAC,SAAiB;AAAA,EAChD,MAAM,QAAQ,KAAK,MAAM;AAAA,CAAI;AAAA,EAC7B,IAAI,CAAC,aAAa,KAAK,MAAM,MAAM,EAAE,GAAG;AAAA,IACtC,OAAO,EAAE,OAAO,QAAQ,EAAE;AAAA,EAC5B;AAAA,EAKA,KAAK,MAAM,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA,IAClC,OAAO,EAAE,OAAO,QAAQ,EAAE;AAAA,EAC5B;AAAA,EACA,MAAM,QAAQ,MAAM,UAClB,CAAC,MAAM,UAAU,QAAQ,KAAK,mBAAmB,KAAK,IAAI,CAC5D;AAAA,EACA,OAAO,UAAU,KACb,EAAE,OAAO,QAAQ,EAAE,IACnB,EAAE,OAAO,MAAM,MAAM,QAAQ,CAAC,GAAG,QAAQ,QAAQ,EAAE;AAAA;AASzD,IAAM,oBACJ;AASF,IAAM,UACJ;AAIK,IAAM,eAAe;AACrB,IAAM,cAAc;AA4C3B,IAAM,kBAAkB,CACtB,MACA,OACA,UACS;AAAA,EACT,MAAM,MAAM,KAAK,QAAQ,KAAK,KAAK;AAAA,EACnC,IAAI,QAAQ,IAAI;AAAA,IACd,MAAM,YAAY;AAAA,IAClB;AAAA,EACF;AAAA,EACA,MAAM,YAAY;AAAA,EAClB,IAAI,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS,aAAa,GAAG,GAAG;AAAA,IAC5D;AAAA,EACF;AAAA,EACA,MAAM,eAAe;AAAA;AAsBvB,IAAM,sBAAsB;AAa5B,IAAM,iBACJ;AAgBF,IAAM,sBAAsB,CAAC,UAA0C;AAAA,EACrE,MAAM,SAAS,IAAI;AAAA,EACnB,IAAI,QAAoB;AAAA,EACxB,YAAY,OAAO,SAAS,MAAM,QAAQ,GAAG;AAAA,IAC3C,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,IACvC,IAAI,UAAU,QAAQ,SAAS,MAAM;AAAA,MACnC,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,IACA,MAAM,SAAS,KAAK,MAAM,cAAc,GAAG;AAAA,IAC3C,IAAI,QAAQ,UAAU,aAAa,OAAO,MAAM,KAAK,MAAM,IAAI;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,MAAM,cAAc,OAAO,QAAQ;AAAA,IACnC,IAAI,gBAAgB,OAAO,MAAM,QAAQ,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA,MAChE;AAAA,IACF;AAAA,IACA,OAAO,IAAI,OAAO,MAAM,KAAK,EAAE,WAAW,SAAS,GAAG,EAAE,YAAY,CAAC;AAAA,EACvE;AAAA,EACA,OAAO;AAAA;AAmBT,IAAM,YAAY,CAChB,OACA,KACA,SACA,iBACmB;AAAA,EACnB,MAAM,YAAY,IAAI,WAAW,qBAAqB,SAAS;AAAA,EAC/D,MAAM,UAAU,oBAAoB,WAAW,YAAY;AAAA,EAC3D,MAAM,OAAO,QAAQ,KAAK,KAAK;AAAA,EAC/B,IAAI,SAAS,OAAO,QAAQ,OAAO,aAAa,QAAQ,QAAQ,YAAY;AAAA,IAC1E,OAAO;AAAA,MACL,SAAS,EAAE,OAAO,MAAM,QAAQ,KAAK,SAAS,GAAG,MAAM,UAAU;AAAA,MACjE,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EACA,IAAI,QAAQ,OAAO,WAAW;AAAA,IAC5B,WAAW,SAAS,QAAQ,EAAE;AAAA,IAC9B,OAAO,EAAE,SAAS,EAAE,OAAO,MAAM,QAAQ,IAAI,KAAK,GAAG,QAAQ,KAAK;AAAA,EACpE;AAAA,EACA,OAAO,EAAE,SAAS,EAAE,OAAO,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,GAAG,QAAQ,MAAM;AAAA;AAI7E,IAAM,cAAc,CAClB,UACA,OACA,SACA,SACS;AAAA,EACT,SAAS,KAAK,QAAQ,OAAO;AAAA,EAC7B,MAAM,MAAM,KAAK,EAAE,MAAM,QAAQ,QAAQ,OAAO,CAAC;AAAA;AAInD,IAAM,kBAAkB,CACtB,MACA,MACA,UACS;AAAA,EACT,MAAM,KAAK,KAAK,MAAM,iBAAiB,GAAG,QAAQ;AAAA,EAClD,IAAI,OAAO,WAAW;AAAA,IACpB,MAAM,aAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,EACtC;AAAA;AAIF,IAAM,kBAAkB,CACtB,MACA,OACA,SACA,UACA,iBACS;AAAA,EAET,MAAM,YAAY,KAAK,KAAK,WAAW,aAAa,EAAE,CAAC;AAAA,EACvD,MAAM,MAAM,KAAK,MAAM,WAAW;AAAA,EAClC,IAAI,KAAK,QAAQ;AAAA,IACf,MAAM,QAAQ,IAAI,OAAO,QAAQ,UAAU;AAAA,IAC3C,MAAM,QAAQ,IAAI,OAAO,QAAQ,IAAI,KAAK;AAAA,IAC1C,YACE,UACA,OACA,UAAU,OAAO,MAAM,SAAS,YAAY,GAC5C,MAAM,IACR;AAAA,IACA,gBAAgB,MAAM,MAAM,MAAM,KAAK;AAAA,IACvC,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EACA,MAAM,SAAS,KAAK,MAAM,gBAAgB;AAAA,EAC1C,IAAI,QAAQ,UAAU,MAAM,UAAU,SAAS,GAAG;AAAA,IAGhD,MAAM,QAAQ,OAAO,OAAO,QAAQ,WAAW,GAAG,IAAI,IAAI;AAAA,IAC1D,MAAM,OAAO,MAAM,UAAU,KAAK,GAAG,EAAE,KAAK;AAAA,IAG5C,YACE,UACA,OACA,UAAU,OAAO,MAAM,SAAS,YAAY,GAC5C,MAAM,OAAO,CACf;AAAA,IACA,gBAAgB,MAAM,MAAM,gBAAgB,KAAK;AAAA,IACjD,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EACA,IACE,KAAK,KAAK,MAAM,MAChB,eAAe,KAAK,IAAI,KACxB,oBAAoB,KAAK,IAAI,GAC7B;AAAA,IACA,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EACA,IAAI,MAAM,UAAU,WAAW,GAAG;AAAA,IAChC,MAAM,iBAAiB,MAAM;AAAA,EAC/B;AAAA,EACA,MAAM,UAAU,KAAK,KAAK,KAAK,CAAC;AAAA;AAIlC,IAAM,kBAAkB,CACtB,MACA,OACA,SACA,UACA,iBACS;AAAA,EACT,MAAM,OAAO,eAAe,MAAM,MAAM,KAAK;AAAA,EAG7C,IAAI,MAAM,UAAU,QAAQ,SAAS,MAAM;AAAA,IACzC,MAAM,QAAQ;AAAA,IACd,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EAKA,MAAM,UAAU,KAAK,UAAU;AAAA,EAC/B,IAAI,MAAM,WAAW;AAAA,IACnB,gBAAgB,SAAS,GAAG,KAAK;AAAA,IACjC,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EACA,IAAI,YAAY,KAAK,OAAO,GAAG;AAAA,IAC7B,gBAAgB,SAAS,UAAU,QAAQ,KAAK;AAAA,IAChD,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EACA,IAAI,MAAM,cAAc,GAAG;AAAA,IACzB,IAAI,aAAa,KAAK,IAAI,GAAG;AAAA,MAC3B,MAAM,eAAe;AAAA,IACvB;AAAA,IACA,MAAM,YAAY,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EACA,gBAAgB,MAAM,OAAO,SAAS,UAAU,YAAY;AAAA;AAgCvD,IAAM,WAAW,CAAC,SAA2B;AAAA,EAClD,MAAM,WAAsB,CAAC;AAAA,EAC7B,MAAM,UAAU,IAAI;AAAA,EACpB,MAAM,QAA0B;AAAA,IAC9B,aAAa,CAAC;AAAA,IACd,cAAc,CAAC;AAAA,IACf,OAAO;AAAA,IACP,MAAM;AAAA,IACN,WAAW,CAAC;AAAA,IACZ,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,WAAW;AAAA,IACX,OAAO,CAAC;AAAA,EACV;AAAA,EAEA,QAAQ,OAAO,WAAW,wBAAwB,IAAI;AAAA,EACtD,MAAM,gBAAgB,oBAAoB,KAAK;AAAA,EAC/C,MAAM,eAAe,CAAC,UACpB,cAAc,IAAI,MAAM,YAAY,CAAC;AAAA,EACvC,YAAY,OAAO,SAAS,MAAM,QAAQ,GAAG;AAAA,IAC3C,MAAM,OAAO,QAAQ,SAAS;AAAA,IAC9B,gBAAgB,MAAM,OAAO,SAAS,UAAU,YAAY;AAAA,EAC9D;AAAA,EAEA,MAAM,UAAU,IAAI;AAAA,EAIpB,MAAM,SAAS,MAAM,YAAY,KAAK;AAAA,CAAI,EAAE,WAAW,cAAc,GAAG;AAAA,EACxE,WAAW,SAAS,OAAO,SAAS,OAAO,GAAG;AAAA,IAC5C,MAAM,KAAK,MAAM,QAAQ,UAAU,MAAM,QAAQ,OAAO,MAAM,QAAQ;AAAA,IACtE,IAAI,OAAO,WAAW;AAAA,MACpB,QAAQ,IAAI,EAAE;AAAA,IAChB;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,SAAS,CAAC,GAAG,OAAO;AAAA,IACpB,cAAc,MAAM;AAAA,IACpB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AAAA;AAGK,IAAM,kBAAkB,CAAC,SAC9B,SAAS,IAAI,EAAE;AAOjB,IAAM,UACJ;AAGK,IAAM,WACX;AAGK,IAAM,iBAAiB,CAC5B,SACA,QACA,UACW,QAAQ,SAAS,KAAK,OAAO,UAAU,KAAK,OAAO;AAShE,IAAM,eAAe,CACnB,MACA,YACA,OACA,UACe;AAAA,EACf,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,EAEvC,IAAI,UAAU,QAAQ,SAAS,MAAM;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EAGA,MAAM,SAAS,KAAK,WAAW,aAAa,CAAC,SAC3C,IAAI,OAAO,KAAK,MAAM,CACxB;AAAA,EACA,WAAW,SAAS,OAAO,SAAS,OAAO,GAAG;AAAA,IAC5C,MAAM,SAAS,MAAM,QAAQ;AAAA,IAC7B,IAAI,WAAW,aAAa,MAAM,UAAU,WAAW;AAAA,MACrD;AAAA,IACF;AAAA,IAIA,MAAM,eAAe,eAAe,MAAM,IAAI,QAAQ,MAAM,QAAQ,KAAK;AAAA,IACzE,MAAM,QAAkB;AAAA,MACtB,QAAQ,MAAM,QAAQ,eAAe;AAAA,MACrC,MAAM;AAAA,MACN;AAAA,IACF;AAAA,IAIA,IAAI,OAAO,MAAM,QAAQ,OAAO,KAAK;AAAA,MACnC,MAAM,QAAQ;AAAA,IAChB;AAAA,IACA,MAAM,KAAK,KAAK;AAAA,IAGhB,MAAM,QAAQ,MAAM,GAAG,MAAM,GAAG,eAAe,KAAK,MAAM;AAAA,IAC1D,WAAW,SAAS,MAAM,SAAS,QAAQ,GAAG;AAAA,MAC5C,MAAM,cAAc,MAAM,QAAQ;AAAA,MAClC,IAAI,gBAAgB,aAAa,MAAM,UAAU,WAAW;AAAA,QAC1D;AAAA,MACF;AAAA,MACA,MAAM,KAAK;AAAA,QACT,QACE,MAAM,QACN,MAAM,QACN,eAAe,MAAM,IAAI,aAAa,MAAM,QAAQ,KAAK,IACzD;AAAA,QACF,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAUT,IAAM,iBACJ;AAGF,IAAM,WAAW,CAAC,UAAqC;AAAA,EACrD,IAAI,QAAoB;AAAA,EACxB,MAAM,SAAS,MAAM,IAAI,CAAC,SAAS;AAAA,IACjC,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,IACvC,MAAM,UAAU,UAAU,QAAQ,SAAS;AAAA,IAC3C,QAAQ;AAAA,IACR,OAAO,UACH,IAAI,OAAO,KAAK,MAAM,IACtB,KAAK,WAAW,aAAa,CAAC,SAAS,IAAI,OAAO,KAAK,MAAM,CAAC;AAAA,GACnE;AAAA,EACD,OAAO,OAAO,KAAK;AAAA,CAAI;AAAA;AAIzB,IAAM,iBAAiB,CACrB,OACA,eACe;AAAA,EACf,MAAM,QAAoB,CAAC;AAAA,EAC3B,MAAM,OAAO,SAAS,KAAK;AAAA,EAC3B,WAAW,SAAS,KAAK,SAAS,cAAc,GAAG;AAAA,IACjD,MAAM,SAAS,MAAM,QAAQ,UAAU,MAAM,QAAQ,UAAU;AAAA,IAE/D,MAAM,KAAK,MAAM,QAAQ,MAAM,GAAG,SAAS,OAAO,SAAS;AAAA,IAC3D,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE;AAAA,IAC/B,MAAM,YAAY,OAAO,YAAY;AAAA,CAAI,IAAI;AAAA,IAC7C,MAAM,KAAK;AAAA,MACT,QAAQ,KAAK,YAAY;AAAA,MACzB,MAAM,aAAa,OAAO,MAAM;AAAA,CAAI,EAAE;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAGF,IAAM,eAAe,CAAC,MAAc,aAAa,MAAkB;AAAA,EACxE,MAAM,QAAoB,CAAC;AAAA,EAC3B,IAAI,QAAoB;AAAA,EACxB,IAAI,aAAa;AAAA,EAEjB,MAAM,QAAQ,KAAK,MAAM;AAAA,CAAI;AAAA,EAC7B,WAAW,QAAQ,OAAO;AAAA,IACxB,cAAc;AAAA,IACd,QAAQ,aAAa,MAAM,YAAY,OAAO,KAAK;AAAA,EACrD;AAAA,EAEA,OAAO,KAAK,SAAS,OAAO,IACxB,CAAC,GAAG,OAAO,GAAG,eAAe,OAAO,UAAU,CAAC,IAC/C;AAAA;AAON,IAAM,gBAAgB;AACtB,IAAM,WAAW;AASjB,IAAM,cAAc,CAClB,MACA,OACA,SACe;AAAA,EACf,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,EAEvC,IAAI,UAAU,QAAQ,SAAS,MAAM;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,KAAK,WAAW,aAAa,EAAE,EAAE,WAAW,eAAe,EAAE;AAAA,EAC3E,WAAW,SAAS,MAAM,SAAS,QAAQ,GAAG;AAAA,IAC5C,MAAM,MAAM,MAAM,QAAQ;AAAA,IAC1B,IAAI,KAAK;AAAA,MACP,KAAK,IAAI,GAAG;AAAA,IACd;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAGF,IAAM,uBAAuB,CAAC,SAA2B;AAAA,EAC9D,MAAM,OAAO,IAAI;AAAA,EACjB,IAAI,QAAoB;AAAA,EACxB,WAAW,QAAQ,KAAK,MAAM;AAAA,CAAI,GAAG;AAAA,IACnC,QAAQ,YAAY,MAAM,OAAO,IAAI;AAAA,EACvC;AAAA,EACA,OAAO,CAAC,GAAG,IAAI;AAAA;AASV,IAAM,qBAAqB,CAChC,KACA,SAEA,MAAM,KAAK,IAAI,GAAG,IAAI,MAAM;AAAA,CAAI,EAAE,SAAS,KAAK,MAAM;AAAA,CAAI,EAAE,MAAM,IAAI;AAQxE,IAAM,qBAAqB,CACzB,OACA,SACA,eAEA,MAAM,IAAI,CAAC,SAAS;AAAA,EAClB,MAAM,SAAS,QAAQ,KAAK,OAAO;AAAA,EACnC,IAAI,CAAC,QAAQ;AAAA,IACX,OAAO;AAAA,EACT;AAAA,EACA,MAAM,WAAqB,KAAK,MAAM,MAAM,OAAO,KAAK;AAAA,EACxD,IAAI,OAAO,SAAS,YAAY;AAAA,IAC9B,SAAS,OAAO,OAAO;AAAA,EACzB;AAAA,EACA,OAAO;AAAA,CACR;AAGH,IAAM,gBAAgB,CAAC,UACrB,MAAM,YAAY,MAAM,SAAS,SAAS,SAAS,IAC/C,MAAM,SAAS,WACf;AAQN,IAAM,aAAa,CAAC,UAClB,MAAM,WACF,mBACE,aAAa,MAAM,SAAS,IAAI,GAChC,MAAM,SAAS,SACf,MAAM,UACR,IACA,aACE,MAAM,KAAK,MACX,mBAAmB,MAAM,KAAK,MAAM,KAAK,IAAI,CAC/C;AAWN,IAAM,yBAAyB,CAC7B,OACA,SACA,eAEA,QAAQ,IAAI,GAAG,IAAI,WAAW;AAAA,EAC5B,MAAM,SAAS,MAAM,UAAU,QAAQ,OAAO;AAAA,EAC9C,MAAM,OAAO,MAAM,cAAc,GAAG,cAAc,MAAM;AAAA,EACxD,MAAM,YAAY,WAAW,aAAa,OAAO,SAAS,MAAM;AAAA,EAChE,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,QAAQ,QAAQ;AAAA,IACtB,MACE,QAAQ,QAAQ,OAAO,mBAAmB,MAAM,KAAK,MAAM,KAAK,IAAI;AAAA,IACtE,SAAS,YACL,OAAO,8DAA8D,gDACrE,OAAO;AAAA,IACX,UAAU;AAAA,IACV,YAAY,aAAa,+BAA+B;AAAA,EAC1D;AAAA,CACD;AAEH,IAAM,cAAc,CAClB,MACA,UACA,OACW;AAAA,EACX,IAAI,KAAK,OAAO;AAAA,IACd,OAAO,KAAK;AAAA,EACd;AAAA,EACA,MAAM,eAAe,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,SAAS;AAAA,EACrE,IAAI,cAAc;AAAA,IAChB,OAAO,aAAa;AAAA,EACtB;AAAA,EACA,MAAM,OAAO,GAAG,MAAM,GAAG,EAAE,IAAI,KAAK;AAAA,EACpC,OAAO,UAAU,mBAAmB,KAAK,QAAQ,SAAQ,IAAI,GAAG,EAAE,CAAC,CAAC;AAAA;AAItE,IAAM,cAAc,CAAC,UAA0B,SAAS,OAAO,GAAG;AAG3D,IAAM,gBAAgB,CAC3B,UACoB,OAAO,UAAU;AAGvC,IAAM,aAAa,CAAC,QAA4B,SAAyB;AAAA,EACvE,MAAM,QAAQ,SAAS,YAAY,MAAM,IAAI;AAAA,EAC7C,OAAO,QAAQ,GAAG,SAAS,SAAS;AAAA;AAgC/B,IAAM,gBAAgB,CAC3B,KACA,KACA,QACmB;AAAA,EACnB,QAAQ,SAAS,SAAS,IAAI,WAC1B,iBAAiB,KAAK,IAAI,QAAQ,IAClC,EAAE,MAAM,KAAK,SAAS,GAAG;AAAA,EAC7B,QAAQ,SAAS,YAAY,IAAI,OAC7B,gBAAgB,MAAM,KAAK,IAAI,IAAI,IACnC,EAAE,SAAS,CAAC,EAAE,GAAG,SAAS,KAAK;AAAA,EACnC,OAAO,EAAE,SAAS,SAAS,QAAQ;AAAA;AAsC9B,IAAM,oBAAoB,CAC/B,OACA,KACA,iBACA,QACe;AAAA,EACf,QAAQ,SAAS,SAAS,YAAY,cAAc,MAAM,KAAK,KAAK,GAAG;AAAA,EACvE,MAAM,YAAY,mBAAmB,MAAM;AAAA,EAC3C,MAAM,OAAO,YAAY,YAAY,SAAS,IAAI;AAAA,EAClD,MAAM,aAAa,WAAW,IAAI,QAAQ,OAAO,GAAG,OAAO,QAAQ,OAAO;AAAA,EAC1E,QAAQ,UAAU,QAAQ,OAAO,eAAe,SAAS,UAAU;AAAA,EACnE,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,cAAc,gBAAgB,YAAY,OAAO;AAAA,IACjD,SAAS,WAAW,IAAI,QAAQ,OAAO;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAIK,IAAM,iBAAiB,CAC5B,cACA,QACA,SACY,OAAO,cAAc,cAAc,QAAQ,IAAI,IAAI;AAejE,IAAM,eAAe,CACnB,YAEA,OAAO,YAAY,YAAY,YAAY;AAE7C,IAAM,cAAc,CAAC,QACnB,OAAO,QAAQ;AAGjB,IAAM,aAAa,CACjB,YACoB;AAAA,EACpB,MAAM,MAAM,aAAa,OAAO,IAAI,QAAQ,MAAM;AAAA,EAClD,OAAO,YAAY,GAAG,IAAI,OAAO,GAAG,IAAI;AAAA;AAY1C,IAAM,qBAAqB,CACzB,MACA,WACwB;AAAA,EACxB,MAAM,SAA4C,CAAC;AAAA,EACnD,MAAM,SAA2B,CAAC;AAAA,EAClC,YAAY,KAAK,WAAW,OAAO,QAAQ,MAAM,GAAG;AAAA,IAClD,MAAM,UAAU,OAAO,aAAa,SAAS,KAAK,IAAI;AAAA,IACtD,IAAI,mBAAmB,SAAS;AAAA,MAC9B,OAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM,CAAC,GAAG;AAAA,MACZ,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,WAAW,WAAW;AAAA,MAChC,OAAO,KACL,GAAG,QAAQ,OAAO,IAAI,CAAC,WAAW;AAAA,QAChC,SAAS,MAAM;AAAA,QACf,MAAM,CAAC,KAAK,IAAI,MAAM,QAAQ,CAAC,GAAG,IAAI,UAAU,CAAC;AAAA,MACnD,EAAE,CACJ;AAAA,MACA;AAAA,IACF;AAAA,IAGA,IAAI,QAAQ,UAAU,aAAa,OAAO,OAAO,MAAM,GAAG,GAAG;AAAA,MAC3D,OAAO,OAAO,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,SAAS;AAAA,IAClD;AAAA,EACF;AAAA;AAYF,IAAM,iBAAiB,CACrB,OACA,QAGiD;AAAA,EAIjD,MAAM,YAAY,cAAc,MAAM,KAAK,IAAI,IAC3C,MAAM,KAAK,OACX,IAAI;AAAA,EACR,MAAM,aAAa,IAAI,kBAAkB;AAAA,EAGzC,MAAM,SACJ,IAAI,qBAAqB,aACrB,KAAK,IAAI,sBAAsB,WAAW,IAC1C;AAAA,EACN,MAAM,QAAQ,SACV,OAAO,YACL,OAAO,QAAQ,MAAM,IAAI,EAAE,OACzB,EAAE,SAAS,CAAC,OAAO,OAAO,QAAQ,GAAG,CACvC,CACF,IACA,MAAM;AAAA,EAEV,MAAM,SAAS,eAAe,UAAU,KAAK;AAAA,EAC7C,MAAM,eAAe,SAAS,mBAAmB,MAAM,MAAM,MAAM,IAAI;AAAA,EAEvE,IAAI,OAAO,YAAY,cAAc,OAAO,UAAU,OAAO,GAAG;AAAA,IAC9D,OAAO,EAAE,QAAQ,cAAc,QAAQ,MAAM,OAAO,KAAK;AAAA,EAC3D;AAAA,EAKA,MAAM,SACJ,MAAM,QACL,MAAM,cAAc,WAAW,MAAM,UAAU,IAC5C,aAAa,MAAM,YAAY,OAAO,IACtC;AAAA,EACN,MAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,MAAM,MAAM,cAAc,GAAG,IAAI,OAAO,QAAQ,MAAM;AAAA,IACtD;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,aAAa;AAAA,MACX,GAAI,OAAO,UAAU,CAAC,IAAI,mBAAmB,OAAO,OAAO,QAAQ;AAAA,MACnE,GAAI,eACA,sBAAsB,aAAa,QAAQ,QAAQ,IACnD,CAAC;AAAA,IACP;AAAA,EACF;AAAA;AAcK,IAAM,iBAAiB,CAC5B,OACA,QACoB;AAAA,EACpB,QAAQ,WAAW,MAAM;AAAA,EACzB,MAAM,MAAM,WAAW,QAAQ,SAAS;AAAA,EAExC,MAAM,SAAS,eAAe,OAAO,GAAG;AAAA,EACxC,IAAI,OAAO,aAAa;AAAA,IACtB,OAAO,EAAE,aAAa,OAAO,aAAa,OAAO,CAAC,EAAE;AAAA,EACtD;AAAA,EAEA,QAAQ,SAAS;AAAA,EAKjB,IAAI,KAAK,QAAQ;AAAA,IACf,KAAK,QAAQ,SAAS;AAAA,EACxB;AAAA,EACA,IAAI,KAAK,SAAS;AAAA,IAChB,KAAK,IAAI,UAAU;AAAA,EACrB;AAAA,EAEA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,MACE,kBAAkB,OAAO,KAAK,KAAK,MAAM;AAAA,IAC3C,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI,OAAO;AAAA,IACnB,UAAU,IAAI;AAAA,EAChB,CAAC;AAAA,EAID,MAAM,WAAW,MAAM,UAAU,QAAQ,MAAM,KAAK;AAAA,EACpD,QAAQ,SAAS,cAAc,aAAa,SAAS,QAAQ;AAAA,EAC7D,QAAQ,WAAW,IAAI;AAAA,EAEvB,MAAM,OAAO;AAAA,IACX;AAAA,IACA,MAAM,SAAS,EAAE,QAAQ,MAAM,MAAM,OAAO,MAAM,KAAK,KAAK,IAAI;AAAA,IAChE,YAAY,SAAS,WAAW;AAAA,IAChC,gBACE,WAAW,QAAQ,qBAAqB,QAAQ,IAAI;AAAA,IACtD,aAAa,KAAK,QAAQ,IAAI;AAAA,IAC9B,QAAQ,OAAO;AAAA,IACf,aAAa,KAAK;AAAA,IAClB,SAAS,MAAM;AAAA,IACf,SAAS,SAAS,GAAG,IAAI,OAAO,QAAQ,MAAM,QAAQ;AAAA,IACtD;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI,GAAG,IAAI,OAAO,QAAQ,MAAM;AAAA,IAChC,UAAU,cAAc,KAAK;AAAA,IAC7B,cAAc,KAAK,gBAAgB,MAAM;AAAA,IACzC,OAAO,WAAW,KAAK;AAAA,IACvB;AAAA,IACA,aAAa,IAAI,OAAO;AAAA,IACxB;AAAA,IACA;AAAA,IACA,QAAQ,EAAE,MAAM,IAAI,OAAO,MAAM,KAAK,MAAM,IAAI;AAAA,IAChD,YAAY,MAAM;AAAA,IAClB,OAAO,YAAY,MAAM,UAAU,OAAO;AAAA,IAC1C,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AAAA,EAOA,MAAM,QAAQ,QAAQ,IAAI,CAAC,YAAY;AAAA,OAClC;AAAA,IACH;AAAA,IACA,OAAO,aACL,IAAI,YAAY,IAChB,eAAe,cAAc,QAAQ,IAAI,IAAI,CAC/C;AAAA,EACF,EAAE;AAAA,EAEF,OAAO;AAAA,IACL,aACE,WAAW,QACP,uBAAuB,OAAO,cAAc,IAAI,OAAO,IAAI,IAC3D,CAAC;AAAA,IACP;AAAA,EACF;AAAA;;;AgEtuCF,qBAAS;;;ACAT,qBAAS;AAET,6BAAkB,kBAAS,mBAAM,sBAAU;;;ACF3C;AACA;;;ACDA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBO,IAAM,cAAc,YAAY,SACrC,cACA,UACA,WACA,SACA,UACA,MACF;;;ADJA,IAAM,aAAa;AAAA,EAKjB,OAAO,CAAC,UACL,KAAK,OAAO,EAAE,QAAQ,YAAY,CAAC,KAAK,CAAC;AAAA,EAC5C,WAAW,CAAC,SAAkC,KAAK,IAAI;AACzD;AAEA,IAAM,iBAAiB,CACrB,aAKC;AAAA,KACI;AAAA,EACH,SAAS;AAAA,IACP,MAAM;AAAA,OACH,SAAS;AAAA,EACd;AACF;AAaF,IAAM,yBAAyB,CAAC,UAA2B;AAAA,EACzD,OAAO,QAAQ,IAAI,UAAU,MAAM,MAAM,UAAU,CAAC;AAAA,EACpD,IAAI,CAAC,aAAa,KAAK,KAAK,GAAG;AAAA,IAC7B,OAAO;AAAA,EACT;AAAA,EACA,IAAI,WAAW,aAAa,OAAO,KAAK,MAAM,IAAI;AAAA,IAChD,OAAO;AAAA,EACT;AAAA,EAGA,OAAO,CAAC,MAAM,SAAS;AAAA,MAAS,CAAC;AAAA;AAgBnC,IAAM,cAAc,CAAC,UAAiD;AAAA,EACpE,MAAM,OAAqB;AAAA,IACzB,SAAS;AAAA,IACT,MAAM,CAAC;AAAA,IACP,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,MAAM;AAAA,IAEN,WAAW,MAAc;AAAA,EAC3B;AAAA,EACA,OAAO;AAAA;AAIT,IAAM,gBAAgB,CAAC,UACrB,OAAO,UAAU;AAMnB,IAAM,SAAS,OAAO,OACpB,CAAC,OAAoB,YACnB,cAAc,KAAK,KAAK,uBAAuB,KAAK,IAChD,YAAY,KAAK,IACjB,WAAW,OAAO,eAAe,OAAO,CAAC,GAC/C,YACA;AAAA,EACE,MAAM,CAAC,UAAuB,YAC5B,WAAW,KAAK,UAAU,eAAe,OAAO,CAAC;AAAA,EAKnD,WAAW,CACT,MACA,MACA,YAEA,WAAW,UACT,cAAc,IAAI,IAAI,EAAE,SAAS,KAAK,IAAI,MAC1C,MACA,eAAe,OAAO,CACxB;AACJ,CACF;AAEA,IAAe;;;ADxGf,IAAM,qBAAqB,IAAI,IAAI,CAAC,OAAO,MAAM,CAAC;AAelD,IAAM,oBACJ;AAGF,IAAM,oBACJ;AAMK,IAAM,uBAAuB,CAAC,SACnC,KAAK,SAAS,UAAU;AAI1B,IAAM,gBAAgB;AAItB,IAAM,oBAAmB;AAGzB,IAAM,qBAAqB;AAAA,EACzB,IAAI,EAAE,OAAO,OAAO,MAAM,OAAO;AAAA,EACjC,KAAK,EAAE,OAAO,OAAO,MAAM,MAAM;AACnC;AAQA,IAAM,sBAAsB,CAC1B,MACA,YACA,cACY;AAAA,EACZ,IAAI,SAAS;AAAA,EACb,IAAI,SAAS;AAAA,EACb,UAAS;AAAA,IACP,MAAM,SAAS,SAAS,WAAW,QAAQ,WAAW;AAAA,IACtD,MAAM,QAAQ,KAAK,QAAQ,QAAQ,MAAM;AAAA,IACzC,IAAI,UAAU,IAAI;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IACA,SAAS,CAAC;AAAA,IACV,SAAS,QAAQ,OAAO;AAAA,EAC1B;AAAA;AAsBK,IAAM,wBAAwB,CACnC,SAC4B;AAAA,EAC5B,MAAM,QAAQ,kBAAkB,KAAK,IAAI;AAAA,EACzC,IAAI,CAAC,OAAO,QAAQ;AAAA,IAClB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,aAAgC,CAAC;AAAA,EACvC,WAAW,SAAS,MAAM,OAAO,SAAS,IAAI,SAAS,iBAAiB,GAAG;AAAA,IACzE,MAAM,OAAO,KAAK,QAAQ;AAAA,IAC1B,MAAM,QAAQ,KAAK,QAAQ,UAAU,KAAK,QAAQ;AAAA,IAClD,IAAI,SAAS,UAAU,OAAO;AAAA,MAC5B,WAAW,OAAO;AAAA,IACpB;AAAA,IACA,IAAI,SAAS,UAAU,OAAO;AAAA,MAC5B,WAAW,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EACA,OAAO,EAAE,YAAY,QAAQ,MAAM,OAAO,UAAU,GAAG;AAAA;AAazD,IAAM,eAAe;AAGrB,IAAM,gBAAgB;AAOtB,IAAM,sBAAsB;AA8BrB,IAAM,wBAAwB,CACnC,OACA,OACA,WACiB;AAAA,EACjB,MAAM,QAAQ,MAAM,UAAU;AAAA,EAC9B,IAAI,WAAW,QAAQ,cAAc,KAAK,KAAK,GAAG;AAAA,IAChD,OAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AAAA,EACA,MAAM,UAAU,MAAM,KAAK;AAAA,EAC3B,IAAI,CAAC,aAAa,KAAK,OAAO,GAAG;AAAA,IAC/B,OAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AAAA,EACA,MAAM,SAAS,sBAAsB,OAAO;AAAA,EAC5C,IAAI,QAAQ;AAAA,IACV,OAAO,EAAE,KAAK,OAAO,MAAM,aAAa,WAAW,OAAO;AAAA,EAC5D;AAAA,EACA,MAAM,QAAQ,CAAC,OAAO;AAAA,EACtB,MAAM,OAAO,KAAK,IAAI,MAAM,QAAQ,QAAQ,mBAAmB,IAAI;AAAA,EACnE,SAAS,MAAM,QAAQ,EAAG,OAAO,MAAM,OAAO,GAAG;AAAA,IAC/C,MAAM,QAAQ,MAAM,QAAQ,IAAI,KAAK;AAAA,IACrC,IAAI,SAAS,IAAI;AAAA,MACf;AAAA,IACF;AAAA,IACA,MAAM,KAAK,IAAI;AAAA,IACf,IAAI,cAAc,KAAK,IAAI,GAAG;AAAA,MAC5B,MAAM,YAAY,sBAAsB,MAAM,KAAK,GAAG,CAAC;AAAA,MACvD,OAAO,YACH,EAAE,KAAK,MAAM,aAAa,UAAU,IACpC,EAAE,MAAM,YAAY;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,OAAO,EAAE,MAAM,YAAY;AAAA;AAOtB,IAAM,6BAA6B,CACxC,MACA,UACgB;AAAA,EAChB,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA,SACE;AAAA,EACF,UAAU;AAAA,EACV,YACE;AACJ;AAwCA,IAAM,kBACJ;AAEF,IAAM,eAAe,CACnB,MACA,SACA,MACA,MACA,gBACgB,EAAE,MAAM,MAAM,MAAM,SAAS,UAAU,SAAS,WAAW;AAO7E,IAAM,cAAc,CAAC,MAAc,SAA0B;AAAA,EAC3D,MAAM,MAAM,UAAS,MAAM,IAAI;AAAA,EAC/B,OAAO,QAAQ,QAAQ,IAAI,WAAW,KAAK;AAAA;AAY7C,IAAM,qBAAqB,CACzB,QACA,UACA,KACA,SAC6C;AAAA,EAC7C,IAAI,OAAO,WAAW,GAAG,GAAG;AAAA,IAC1B,IAAI,CAAC,IAAI,aAAa;AAAA,MACpB,OAAO;AAAA,QACL,OAAO,aACL,8BACA,kBAAkB,oEAClB,UACA,MACA,oDACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,MAAK,IAAI,aAAa,MAAM;AAAA,IACzC,IAAI,YAAY,IAAI,aAAa,IAAI,GAAG;AAAA,MACtC,OAAO;AAAA,QACL,OAAO,aACL,8BACA,kBAAkB,6CAClB,UACA,MACA,sFACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,EAAE,KAAK;AAAA,EAChB;AAAA,EACA,MAAM,OAAO,SAAQ,QAAQ,QAAQ,GAAG,MAAM;AAAA,EAC9C,IAAI,IAAI,eAAe,YAAY,IAAI,aAAa,IAAI,GAAG;AAAA,IACzD,OAAO;AAAA,MACL,OAAO,aACL,8BACA,kBAAkB,6CAClB,UACA,MACA,oGACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,EAAE,KAAK;AAAA;AAUhB,IAAM,kBAAkB,CACtB,MACA,SACA,UACW;AAAA,EACX,MAAM,SAAS,KAAK,WAAW,aAAa,CAAC,SAC3C,IAAI,OAAO,KAAK,MAAM,CACxB;AAAA,EACA,IAAI,MAAM;AAAA,EACV,IAAI,SAAS;AAAA,EACb,WAAW,SAAS,OAAO,SAAS,QAAQ,GAAG;AAAA,IAC7C,MAAM,SAAS,MAAM,QAAQ,UAAU;AAAA,IAGvC,IACE,OAAO,WAAW,GAAG,KACrB,OAAO,WAAW,GAAG,KACrB,IAAI,SAAS,MAAM,GACnB;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM,UAAU,UAAS,OAAO,SAAQ,SAAS,MAAM,CAAC;AAAA,IACxD,MAAM,MAAM,QAAQ,WAAW,GAAG,IAAI,UAAU,KAAK;AAAA,IACrD,MAAM,UACH,MAAM,SAAS,KAChB,eAAe,MAAM,IAAI,QAAQ,MAAM,QAAQ,KAAK;AAAA,IACtD,OAAO,KAAK,MAAM,QAAQ,MAAM,IAAI;AAAA,IACpC,SAAS,SAAS,OAAO;AAAA,EAC3B;AAAA,EACA,OAAO,MAAM,KAAK,MAAM,MAAM;AAAA;AAIhC,IAAM,eAAe,CACnB,OACA,SACA,UACa;AAAA,EACb,IAAI,YAAY,OAAO;AAAA,IACrB,OAAO;AAAA,EACT;AAAA,EACA,IAAI,QAAoB;AAAA,EACxB,OAAO,MAAM,IAAI,CAAC,SAAS;AAAA,IACzB,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,IACvC,MAAM,UAAU,UAAU,QAAQ,SAAS;AAAA,IAC3C,QAAQ;AAAA,IACR,OAAO,UAAU,OAAO,gBAAgB,MAAM,SAAS,KAAK;AAAA,GAC7D;AAAA;AAKH,IAAM,iBAAiB,CACrB,SACA,MACA,eACa;AAAA,EACb,MAAM,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AAAA,EACvC,IAAI,aAAa;AAAA,EACjB,WAAW,OAAO,KAAK,MAAM,MAAM,KAAK,CAAC,GAAG;AAAA,IAC1C,aAAa,KAAK,IAAI,YAAY,IAAI,MAAM;AAAA,EAC9C;AAAA,EACA,MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI,GAAG,aAAa,CAAC,CAAC;AAAA,EACpD,MAAM,MAAM,SAAQ,IAAI;AAAA,EACxB,MAAM,OAAO,WAAW,SAAS,MAAM,IAAI,MAAM,CAAC,IAAI;AAAA,EACtD,MAAM,OAAO,WAAW,OAAO,IAAI,WAAW,SAAS;AAAA,EACvD,OAAO,CAAC,GAAG,QAAQ,OAAO,QAAQ,GAAG,KAAK,MAAM;AAAA,CAAI,GAAG,KAAK;AAAA;AAc9D,IAAM,kBAAkB,OACtB,WACA,UACA,MACA,KACA,UACmD;AAAA,EACnD,MAAM,WAAW,mBAAmB,UAAU,QAAQ,UAAU,KAAK,IAAI;AAAA,EACzE,IAAI,WAAW,UAAU;AAAA,IACvB,OAAO;AAAA,EACT;AAAA,EACA,QAAQ,SAAS;AAAA,EACjB,IAAI,MAAM,SAAS,IAAI,GAAG;AAAA,IACxB,OAAO;AAAA,MACL,OAAO,aACL,uBACA,qBAAqB,CAAC,GAAG,OAAO,IAAI,EACjC,IAAI,CAAC,UAAU,UAAS,IAAI,eAAe,QAAQ,IAAI,GAAG,KAAK,CAAC,EAChE,KAAK,MAAM,MACd,UACA,MACA,oDACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,UAAU,MAAM,UAAS,MAAM,OAAO;AAAA,IACtC,OAAO,OAAO;AAAA,IACd,OAAO;AAAA,MACL,OAAO,aACL,2BACA,kBAAkB,UAAU,mCAAmC,UAC7D,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,MAEvD,UACA,MACA,eACF;AAAA,IACF;AAAA;AAAA,EAEF,IAAI,SAAS,IAAI,IAAI;AAAA,EAErB,MAAM,YACJ,CAAC,UAAU,WAAW,QACtB,mBAAmB,IAAI,SAAQ,IAAI,EAAE,YAAY,CAAC;AAAA,EACpD,IAAI,CAAC,WAAW;AAAA,IACd,MAAM,QAAQ,eAAe,SAAS,MAAM,UAAU,UAAU;AAAA,IAGhE,OAAO;AAAA,MACL;AAAA,MACA,SAAS,MAAM,IAAI,CAAC,GAAG,OAAO,EAAE,MAAM,MAAM,MAAM,KAAK,IAAI,GAAG,CAAC,EAAE,EAAE;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,oBAAO,OAAO;AAAA,EAC7B,MAAM,OAAO,OAAO;AAAA,EACpB,MAAM,iBAAiB,KAAK,IAC1B,GACA,QAAQ,MAAM;AAAA,CAAI,EAAE,SAAS,KAAK,MAAM;AAAA,CAAI,EAAE,MAChD;AAAA,EAIA,MAAM,WAAW,MAAM,YAAY,MAAM,MAAM,gBAAgB,KAAK;AAAA,IAClE,GAAG;AAAA,IACH;AAAA,EACF,CAAC;AAAA,EAID,MAAM,QAAQ,CAAC,GAAG,SAAS,KAAK;AAAA,EAChC,MAAM,UAAU,CAAC,GAAG,SAAS,OAAO;AAAA,EACpC,OAAO,MAAM,GAAG,EAAE,GAAG,KAAK,MAAM,IAAI;AAAA,IAClC,MAAM,IAAI;AAAA,IACV,QAAQ,IAAI;AAAA,EACd;AAAA,EACA,OAAO,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA,IAC9B,MAAM,MAAM;AAAA,IACZ,QAAQ,MAAM;AAAA,EAChB;AAAA,EACA,OAAO;AAAA,IACL,OAAO,aAAa,OAAO,QAAQ,IAAI,GAAG,QAAQ,QAAQ,CAAC;AAAA,IAC3D;AAAA,EACF;AAAA;AAWF,IAAM,iBAAiB,CACrB,aACA,UAC4B;AAAA,EAC5B,MAAM,aAAa,mBAAmB,QAAQ,QAAQ;AAAA,EACtD,MAAM,SAAS,QAAQ,QAAQ;AAAA,EAC/B,MAAM,UAAmC,YAAY,IAAI,MAAM,IAAI;AAAA,EACnE,IAAI,QAAoB;AAAA,EACxB,IAAI,YAAY;AAAA,EAChB,SAAS,QAAQ,EAAG,QAAQ,YAAY,QAAQ,SAAS,GAAG;AAAA,IAC1D,MAAM,OAAO,YAAY,UAAU;AAAA,IACnC,IAAI,WAAW;AAAA,MACb,YAAY,oBAAoB,MAAM,YAAY,IAAI;AAAA,MACtD;AAAA,IACF;AAAA,IACA,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,IACvC,MAAM,UAAU,UAAU,QAAQ,SAAS;AAAA,IAC3C,QAAQ;AAAA,IACR,IAAI,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,YAAY,oBAAoB,MAAM,YAAY,KAAK;AAAA,IACvD,IAAI,aAAa,CAAC,qBAAqB,IAAI,GAAG;AAAA,MAC5C;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,sBAAsB,aAAa,OAAO,MAAM;AAAA,IAG9D,IACE,MAAM,SAAS,eACf,CAAC,SACD,kBAAiB,KAAK,YAAY,MAAM,MAAM,MAAM,EAAE,GACtD;AAAA,MACA;AAAA,IACF;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,IAAI,MAAM,SAAS,aAAa;AAAA,MAE9B,QAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAUT,IAAM,cAAc,OAClB,MACA,UACA,YACA,KACA,UAC2B;AAAA,EAC3B,MAAM,cAAc,KAAK,MAAM;AAAA,CAAI;AAAA,EACnC,MAAM,QAAQ,SAAQ,QAAQ,EAAE,YAAY,MAAM;AAAA,EAClD,MAAM,UAAU,eAAe,aAAa,KAAK;AAAA,EAIjD,MAAM,aAAa,MAAM,QAAQ,IAC/B,QAAQ,IAAI,CAAC,OAAO,UAClB,OAAO,SAAS,cACZ,gBACE,MAAM,WACN,UACA,aAAa,QAAQ,GACrB,KACA,KACF,IACA,IACN,CACF;AAAA,EAIA,MAAM,QAAkB,CAAC;AAAA,EACzB,MAAM,UAAwB,CAAC;AAAA,EAC/B,SAAS,QAAQ,EAAG,QAAQ,YAAY,QAAQ,SAAS,GAAG;AAAA,IAC1D,MAAM,OAAO,YAAY,UAAU;AAAA,IACnC,MAAM,UAAU,aAAa,QAAQ;AAAA,IACrC,MAAM,QAAQ,QAAQ;AAAA,IACtB,MAAM,WAAW,WAAW;AAAA,IAC5B,IAAI,OAAO,SAAS,aAAa;AAAA,MAC/B,IAAI,OAAO,KAAK,2BAA2B,UAAU,OAAO,CAAC;AAAA,IAC/D;AAAA,IACA,IAAI,CAAC,YAAY,WAAW,UAAU;AAAA,MACpC,IAAI,UAAU;AAAA,QACZ,IAAI,OAAO,KAAK,SAAS,KAAK;AAAA,MAChC;AAAA,MACA,MAAM,KAAK,IAAI;AAAA,MACf,QAAQ,KAAK,EAAE,MAAM,UAAU,MAAM,QAAQ,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,IACA,MAAM,MAAM,MAAY;AAAA,MACtB,MAAM,KAAK,EAAE;AAAA,MACb,QAAQ,KAAK,EAAE,MAAM,UAAU,MAAM,QAAQ,CAAC;AAAA;AAAA,IAEhD,IAAI,MAAM,GAAG,EAAE,GAAG,KAAK,GAAG;AAAA,MACxB,IAAI;AAAA,IACN;AAAA,IACA,MAAM,KAAK,GAAG,SAAS,KAAK;AAAA,IAC5B,QAAQ,KAAK,GAAG,SAAS,OAAO;AAAA,IAEhC,IAAI,OAAO,SAAS,aAAa;AAAA,MAC/B,QAAQ,MAAM;AAAA,IAChB;AAAA,IACA,IAAI,YAAY,QAAQ,IAAI,KAAK,GAAG;AAAA,MAClC,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EACA,OAAO,EAAE,OAAO,QAAQ;AAAA;AAUnB,IAAM,iBAAiB,OAC5B,MACA,YAQ8B;AAAA,EAC9B,MAAM,MAAqB;AAAA,IACzB,aAAa,QAAQ;AAAA,IACrB,QAAQ,CAAC;AAAA,IACT,UAAU,IAAI;AAAA,EAChB;AAAA,EACA,QAAQ,OAAO,YAAY,MAAM,YAC/B,MACA,QAAQ,YACR,QAAQ,cAAc,GACtB,KACA,CAAC,QAAQ,UAAU,CACrB;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ,UAAU,CAAC,GAAG,IAAI,QAAQ;AAAA,IAC1B;AAAA,IACA,MAAM,MAAM,KAAK;AAAA,CAAI;AAAA,EACvB;AAAA;AAwCK,IAAM,oBAAoB,CAC/B,UACG;AAAA,EACH,MAAM,QAAkC,CAAC;AAAA,EACzC,WAAW,QAAQ,OAAO;AAAA,IACxB,QAAQ,eAAe;AAAA,IACvB,IAAI,CAAC,YAAY;AAAA,MACf;AAAA,IACF;AAAA,IACA,WAAW,WAAW,KAAK,YAAY,CAAC,GAAG;AAAA,MACzC,MAAM,YAAY,MAAM,YAAY,CAAC;AAAA,MACrC,MAAM,WAAW;AAAA,MACjB,IAAI,CAAC,UAAU,SAAS,UAAU,GAAG;AAAA,QACnC,UAAU,KAAK,UAAU;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA;;;ADvtBF,IAAM,gBAAgB,OAC3B,KACA,SACoB;AAAA,EACpB,IAAI,KAAK,MAAM;AAAA,IACb,OAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EACA,MAAM,OAAO,KAAK,QAAQ;AAAA,EAC1B,MAAM,SAAS,OACX,IAAI,SAAS,KAAK,CAAC,cAAc,UAAU,SAAS,IAAI,IACxD;AAAA,EACJ,IAAI,QAAQ,MAAM;AAAA,IAChB,OAAO,MAAM,OAAO,KAAK,KAAK,OAAO,GAAG;AAAA,EAC1C;AAAA,EACA,IAAI,KAAK,YAAY;AAAA,IACnB,OAAO,MAAM,UAAS,KAAK,YAAY,OAAO;AAAA,EAChD;AAAA,EACA,OAAO;AAAA;AAWF,IAAM,wBAAwB,OACnC,KACA,SACoB;AAAA,EACpB,MAAM,MAAM,MAAM,cAAc,KAAK,IAAI;AAAA,EACzC,IAAI,EAAE,KAAK,cAAc,qBAAqB,GAAG,IAAI;AAAA,IACnD,OAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS,IAAI,SAAS,KAC1B,CAAC,cAAc,UAAU,SAAS,KAAK,OAAO,IAChD;AAAA,EAMA,IAAI,CAAC,UAAU,OAAO,UAAU,CAAC,OAAO,aAAa;AAAA,IACnD,OAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY,MAAM,eAAe,KAAK;AAAA,IAC1C,aAAa,OAAO;AAAA,IACpB,YAAY,KAAK;AAAA,EACnB,CAAC;AAAA,EACD,OAAO,UAAU;AAAA;;;AnEnCZ,IAAM,wBAAwB;AAIrC,IAAM,mBAAmB,IAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,IAAM,mBAAmB,CAAC,WACxB,EAAE,OAAO,WAAW,GAAG,KAAK,OAAO,WAAW,GAAG,MAAM,CAAC,IAAI,SAAS,MAAM;AAQtE,IAAM,oBAAoB,CAC/B,aACA,YACW;AAAA,EACX,MAAM,MAAM,UAAS,aAAa,OAAO;AAAA,EACzC,IAAI,IAAI,WAAW,IAAI,GAAG;AAAA,IACxB,OAAO,KAAK,SAAS,OAAO,IAAI,SAAQ,OAAO;AAAA,EACjD;AAAA,EACA,OAAO;AAAA;AAIT,IAAM,eAAe,CAAC,WAA2B;AAAA,EAC/C,IAAI;AAAA,IACF,OAAO,UAAU,MAAM;AAAA,IACvB,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAWJ,IAAM,wBAAwB,CAAC,WACpC,iBAAiB,MAAM,KACvB,iBAAiB,IAAI,SAAQ,aAAa,MAAM,CAAC,EAAE,YAAY,CAAC;AASlE,IAAM,kBAAkB,CAAC,KAAa,aAA8B;AAAA,EAClE,IAAI,UAAU;AAAA,EACd,SAAS,IAAI,EAAG,IAAI,UAAU,KAAK,GAAG;AAAA,IACpC,MAAM,SAAS,SAAQ,OAAO;AAAA,IAC9B,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,UAAU,YAAY,MAAM;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,IAET,IAAI,CAAC,QAAQ,SAAS,SAAS,OAAO,CAAC,GAAG;AAAA,MACxC,OAAO;AAAA,IACT;AAAA,IACA,UAAU;AAAA,EACZ;AAAA,EACA,MAAM,OAAO,SAAS,KAAK,EAAE,gBAAgB,MAAM,CAAC;AAAA,EACpD,OAAO,SAAS,aAAa,KAAK,OAAO;AAAA;AAUpC,IAAM,uBAAuB,CAClC,WACA,WACkB;AAAA,EAClB,IAAI,CAAC,sBAAsB,MAAM,GAAG;AAAA,IAClC,OAAO;AAAA,EACT;AAAA,EACA,MAAM,UAAU,aAAa,MAAM;AAAA,EAGnC,MAAM,WAAW,UAAU,OAAO,EAC/B,MAAM,GAAG,EACT,OAAO,CAAC,SAAS,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,EAClD,MAAM,MAAM,SAAQ,WAAW,OAAO;AAAA,EACtC,OAAO,gBAAgB,KAAK,QAAQ,IAAI,MAAM;AAAA;AAIhD,IAAM,eAAe,CAAC,UACpB,MAAM,MAAM,GAAG,EAAE,IAAI,kBAAkB,EAAE,KAAK,GAAG;AAQnD,IAAM,cAAc,CAClB,MACA,UACW;AAAA,EACX,MAAM,SAAS,KAAK,WAAW,aAAa,CAAC,SAC3C,IAAI,OAAO,KAAK,MAAM,CACxB;AAAA,EACA,IAAI,MAAM;AAAA,EACV,IAAI,SAAS;AAAA,EACb,WAAW,SAAS,OAAO,SAAS,QAAQ,GAAG;AAAA,IAC7C,MAAM,SAAS,MAAM,QAAQ,UAAU;AAAA,IACvC,MAAM,MAAM,MAAM,MAAM;AAAA,IACxB,IAAI,QAAQ,MAAM;AAAA,MAChB;AAAA,IACF;AAAA,IACA,MAAM,UACH,MAAM,SAAS,KAChB,eAAe,MAAM,IAAI,QAAQ,MAAM,QAAQ,KAAK;AAAA,IACtD,OAAO,KAAK,MAAM,QAAQ,MAAM,IAAI;AAAA,IACpC,SAAS,SAAS,OAAO;AAAA,EAC3B;AAAA,EACA,OAAO,MAAM,KAAK,MAAM,MAAM;AAAA;AAUzB,IAAM,wBAAwB,CAAC,YAMxB;AAAA,EACZ,QAAQ,QAAQ,YAAY,aAAa,YAAY,aAAa;AAAA,EAClE,MAAM,YAAY,SAAQ,UAAU;AAAA,EACpC,MAAM,SAAS,GAAG,kBAAkB,UAAU,IAAI;AAAA,EAClD,MAAM,QAAQ,CAAC,WAAkC;AAAA,IAC/C,MAAM,MAAM,qBAAqB,WAAW,MAAM;AAAA,IAClD,IAAI,QAAQ,MAAM;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IACA,MAAM,QAAQ,kBAAkB,aAAa,GAAG;AAAA,IAChD,WAAW,OAAO,GAAG;AAAA,IACrB,OAAO,GAAG,UAAU,aAAa,KAAK;AAAA;AAAA,EAGxC,IAAI,QAAoB;AAAA,EACxB,MAAM,QAAQ,OAAO,MAAM;AAAA,CAAI,EAAE,IAAI,CAAC,SAAS;AAAA,IAC7C,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,IACvC,MAAM,UAAU,UAAU,QAAQ,SAAS;AAAA,IAC3C,QAAQ;AAAA,IACR,OAAO,UAAU,OAAO,YAAY,MAAM,KAAK;AAAA,GAChD;AAAA,EACD,OAAO,MAAM,KAAK;AAAA,CAAI;AAAA;AAYjB,IAAM,uBAAuB,OAAO,YAKJ;AAAA,EACrC,MAAM,WAAW,IAAI,IAAI,QAAQ,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAAA,EAC3E,MAAM,QAAgC,CAAC;AAAA,EACvC,MAAM,QAAQ,IACZ,QAAQ,SAAS,OAAO,IAAI,OAAO,UAAU;AAAA,IAC3C,IAAI,CAAC,MAAM,YAAY;AAAA,MACrB;AAAA,IACF;AAAA,IACA,MAAM,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA,IAClC,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,SAAS,OACL,MAAM,sBAAsB,SAAS,IAAI,IACzC,MAAM,UAAS,MAAM,YAAY,OAAO;AAAA,MAC5C,MAAM;AAAA,MACN;AAAA;AAAA,IAEF,sBAAsB;AAAA,MACpB,aAAa,QAAQ,QAAQ;AAAA,MAC7B,UAAU,CAAC,OAAO,QAAQ;AAAA,QACxB,MAAM,SAAS;AAAA;AAAA,MAEjB;AAAA,MACA,YAAY,MAAM;AAAA,IACpB,CAAC;AAAA,GACF,CACH;AAAA,EACA,OAAO;AAAA;;;AuEzMT,IAAM,gBAAgB,CAAC,UAA0B;AAAA,EAC/C,IAAI;AAAA,IACF,OAAO,mBAAmB,KAAK;AAAA,IAC/B,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAKX,IAAM,kBAAkB,CAAC,MAAc,SACrC,KAAK,QAAQ,KAAK,CAAC,WAAW;AAAA,EAC5B,MAAM,SAAS,aAAa,OAAO,MAAM,IAAI;AAAA,EAC7C,OAAO,WAAW,OAAO,SAAS,UAAU,KAAK,WAAW,GAAG,SAAS;AAAA,CACzE;AAOI,IAAM,mBAAmB,CAC9B,MACA,YACW;AAAA,EACX,QAAQ,UAAU,MAAM,QAAQ,WAAW;AAAA,EAC3C,IAAI,aAAa,QAAQ,IAAI,MAAM,IAAI;AAAA,IACrC,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,cAAc,cAAc,UAAU,IAAI,CAAC;AAAA,EACxD,IAAI,gBAAgB,MAAM,IAAI,GAAG;AAAA,IAC/B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY,aAAa,UAAU,cAAc,MAAM,QAAQ,IAAI,CAAC;AAAA,EAG1E,OAAO,OAAO,IAAI,SAAS,KAAK,OAAO,IAAI,cAAc,SAAS,CAAC,IAC/D,YACA;AAAA;AA2DN,IAAM,YAAY,IAAI;;;ACtJtB;AAIO,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AAEhC,IAAM,mBAAmB;AACzB,IAAM,cAAc;AACpB,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAqB/B,IAAM,UAAU,OACd,KACA,QACA,cACyB;AAAA,EACzB,MAAM,aAAa,IAAI;AAAA,EACvB,MAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAAA,EAC5D,MAAM,UAAU,YAAY,IAAI;AAAA,EAChC,IAAI;AAAA,IACF,MAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,WAAW;AAAA,IACrB,CAAC;AAAA,IACD,OAAO;AAAA,MACL,UAAU,SAAS,QAAQ,IAAI,kBAAkB;AAAA,MACjD,UAAU,SAAS;AAAA,MACnB,IAAI,KAAK,MAAM,YAAY,IAAI,IAAI,OAAO;AAAA,MAC1C,IAAI,SAAS;AAAA,MACb,YAAY,SAAS;AAAA,MACrB,WAAW,SAAS,QAAQ,IAAI,cAAc;AAAA,MAC9C,QAAQ,SAAS;AAAA,IACnB;AAAA,IACA,OAAO,OAAO;AAAA,IACd,IAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AAAA,MACzD,OAAO,EAAE,IAAI,OAAO,UAAU,KAAK;AAAA,IACrC;AAAA,IACA,OAAO;AAAA,MACL,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC5D,IAAI;AAAA,IACN;AAAA,YACA;AAAA,IACA,aAAa,KAAK;AAAA;AAAA;AAUf,IAAM,QAAQ,OACnB,KACA,UAAkC,CAAC,MACV;AAAA,EACzB,MAAM,YAAY,QAAQ,aAAa;AAAA,EACvC,MAAM,OAAO,MAAM,QAAQ,KAAK,QAAQ,SAAS;AAAA,EACjD,MAAM,cAAc,CAAC,KAAK,MAAM,KAAK,WAAW,aAAa,CAAC,KAAK;AAAA,EACnE,MAAM,QACJ,KAAK,WAAW,6BAChB,KAAK,WAAW,0BAChB;AAAA,EACF,OAAO,QAAQ,MAAM,QAAQ,KAAK,OAAO,SAAS,IAAI;AAAA;AAIjD,IAAM,gBAAgB,CAC3B,WAC4D;AAAA,EAC5D,IAAI,OAAO,IAAI;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EACA,IAAI,OAAO,UAAU;AAAA,IACnB,OAAO,EAAE,QAAQ,qBAAqB,UAAU,UAAU;AAAA,EAC5D;AAAA,EACA,IAAI,OAAO,WAAW,WAAW;AAAA,IAC/B,OAAO,EAAE,QAAQ,OAAO,SAAS,eAAe,UAAU,QAAQ;AAAA,EACpE;AAAA,EAGA,IAAI,OAAO,WAAW,oBAAoB,OAAO,WAAW,aAAa;AAAA,IACvE,OAAO,EAAE,QAAQ,QAAQ,OAAO,UAAU,UAAU,QAAQ;AAAA,EAC9D;AAAA,EACA,OAAO,EAAE,QAAQ,QAAQ,OAAO,UAAU,UAAU,UAAU;AAAA;AAOzD,IAAM,WAAW,OACtB,MACA,UAAwD,CAAC,MACnB;AAAA,EACtC,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC;AAAA,EAChC,MAAM,UAAU,MAAM,KACpB,QACA,OAAO,QAAQ,CAAC,KAAK,MAAM,MAAM,KAAK,OAAO,CAAC,GAC9C,EAAE,aAAa,KAAK,IAAI,GAAG,QAAQ,eAAe,iBAAiB,EAAE,CACvE;AAAA,EACA,OAAO,IAAI,IAAI,OAAO;AAAA;;;AzEvGxB,IAAM,OAAO;AACb,IAAM,oBAAoB;AAC1B,IAAM,SAAS;AAGf,IAAM,iBAAgB,CAAC,UAA0B;AAAA,EAC/C,IAAI;AAAA,IACF,OAAO,mBAAmB,KAAK;AAAA,IAC/B,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAGX,IAAM,UAAU;AAChB,IAAM,WAAW;AAgBjB,IAAM,mBAAmB,CAAC,MAAgB,SACxC,KAAK,OAAO,iBAAiB,UAAS,KAAK,cAAc,KAAK,EAAE,OAAO;AAQzE,IAAM,sBAAsB,CAC1B,QACA,UACA,gBACW;AAAA,EACX,MAAM,WAAW,UACf,SAAQ,WAAW,GACnB,SAAQ,SAAQ,QAAQ,GAAG,MAAM,CACnC;AAAA,EACA,OAAO,SAAS,WAAW,GAAG,IAAI,WAAW,KAAK;AAAA;AA2BpD,IAAM,iBAAiB,CAAC,UAAkB,QACxC,IAAI,cAAc,QAAQ,YAAW,MAAK,IAAI,WAAW,QAAQ,CAAC;AAOpE,IAAM,kBAAiB;AAYvB,IAAM,cAAc,CAAC,SACnB,wBAAwB,KACtB,UAAS,KAAK,OAAO,EAAE,QAAQ,iBAAgB,EAAE,CACnD;AAGF,IAAM,oBAAoB,CAAC,UAAoB,SAAuB;AAAA,EACpE,IAAI,SAAS,MAAM,SAAS,KAAK;AAAA,IAC/B;AAAA,EACF;AAAA,EACA,IAAI,SAAS,MAAM;AAAA,IACjB,SAAS,IAAI;AAAA,IACb;AAAA,EACF;AAAA,EACA,SAAS,KAAK,IAAI;AAAA;AAIpB,IAAM,kBAAkB,CACtB,WACA,QACA,YACW;AAAA,EACX,MAAM,WAAW,UAAU,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,EAGpD,IAAI,CAAC,SAAS;AAAA,IACZ,SAAS,IAAI;AAAA,EACf;AAAA,EACA,WAAW,QAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,IACpC,kBAAkB,UAAU,IAAI;AAAA,EAClC;AAAA,EACA,OAAO,IAAI,SAAS,KAAK,GAAG;AAAA;AAI9B,IAAM,UAAU,CAAC,SAAyB;AAAA,EACxC,IAAI,QAAQ,KAAK,QAAQ,SAAS,EAAE;AAAA,EACpC,IAAI,MAAM,SAAS,QAAQ,GAAG;AAAA,IAC5B,QAAQ,MAAM,MAAM,GAAG,CAAC,SAAS,MAAM;AAAA,EACzC;AAAA,EACA,IAAI,MAAM,SAAS,KAAK,MAAM,SAAS,GAAG,GAAG;AAAA,IAC3C,QAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,EAC3B;AAAA,EACA,OAAO,UAAU,KAAK,MAAM;AAAA;AAY9B,IAAM,eAAe;AAyBd,IAAM,sBAAsB,CACjC,MACA,MACA,aACA,aACuB;AAAA,EACvB,IAAI,SAAS,MAAM,aAAa,KAAK,IAAI,GAAG;AAAA,IAC1C;AAAA,EACF;AAAA,EACA,MAAM,WAAW,KAAK,OAAO,OAAO;AAAA,EACpC,MAAM,OAAO,aAAa,KAAK,OAAO,KAAK,MAAM,GAAG,QAAQ;AAAA,EAC5D,MAAM,SAAS,aAAa,KAAK,KAAK,KAAK,MAAM,QAAQ;AAAA,EACzD,IAAI,SAAS,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,GAAG;AAAA,IAC9C,MAAM,QAAQ,QAAQ,gBAAgB,KAAK,OAAO,MAAM,KAAK,OAAO,CAAC;AAAA,IACrE,OAAO,WAAW,eAAc,KAAK,CAAC,IAAI,GAAG,QAAQ,WAAW;AAAA,EAClE;AAAA,EACA,MAAM,YAAY,QAAQ,KAAK,IAAI,IAC/B,cAAc,eAAc,IAAI,CAAC,IACjC;AAAA,EACJ,OAAO,GAAG,aAAa,QAAQ,gBAAgB,KAAK,OAAO,MAAM,KAAK,OAAO,CAAC,IAAI;AAAA;AAS7E,IAAM,kBAAkB,CAC7B,MACA,eAAkC,CAAC,MACvB;AAAA,EACZ,MAAM,OAAO,UAAS,IAAI,EAAE,QAAQ,iBAAgB,EAAE;AAAA,EACtD,MAAM,QAAQ,+CAA+C,KAAK,IAAI;AAAA,EACtE,IAAI,CAAC,OAAO;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,MAAM,QAAQ;AAAA,EAC5B,OAAO,UAAU,aAAa,aAAa,SAAS,KAAK;AAAA;AAI3D,IAAM,mBAAmB,CAAC,UAAkD;AAAA,EAC1E,MAAM,UAAU,IAAI;AAAA,EACpB,WAAW,QAAQ,OAAO;AAAA,IACxB,QAAQ,IACN,KAAK,OACL,IAAI,IAAI;AAAA,MACN,GAAG,KAAK,SAAS,IAAI,CAAC,YAAY,QAAQ,IAAI;AAAA,MAC9C,GAAG,KAAK;AAAA,IACV,CAAC,CACH;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAIT,IAAM,cAAc,CAClB,OACA,UACA,MACA,KACA,MAAM,OACgB;AAAA,EACtB,MAAM,UAAU,IAAI,QAAQ,IAAI,KAAK;AAAA,EAGrC,IAAI,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,SAAS,YAAY,CAAC,GAAG;AAAA,IAClE,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA,OACF;AAAA,IACH,MAAM;AAAA,IACN,SAAS,uBAAuB,kBAAkB,WAAW;AAAA,IAC7D,UAAU;AAAA,EACZ;AAAA;AAWF,IAAM,cAAc,CAClB,UACA,MACA,QAEA,IAAI,OACA,iBAAiB,UAAU;AAAA,EACzB,UAAU,IAAI;AAAA,EACd,MAAM,IAAI;AAAA,EACV,QAAQ,KAAK;AAAA,EACb,QAAQ;AAAA,IACN,KAAK,CAAC,UAAU,IAAI,OAAO,IAAI,KAAK,KAAK,IAAI,YAAY,IAAI,KAAK;AAAA,EACpE;AACF,CAAC,IACD;AAGN,IAAM,gBAAgB,CACpB,UACA,UACA,MACA,MACA,MACA,KACA,MAAM,OACS;AAAA,EAMf,MAAM,gBAAgB,QAAQ,aAAa,IAAI,UAAU,QAAQ,CAAC;AAAA,EAClE,MAAM,QAAQ,YAAY,eAAe,MAAM,GAAG;AAAA,EAClD,IAAI,IAAI,OAAO,IAAI,KAAK,GAAG;AAAA,IACzB,OAAO,WAAW,YAAY,OAAO,UAAU,MAAM,KAAK,GAAG,IAAI;AAAA,EACnE;AAAA,EAGA,IAAI,IAAI,YAAY,IAAI,KAAK,GAAG;AAAA,IAC9B,OAAO;AAAA,EACT;AAAA,EAIA,IAAI,IAAI,UAAU,IAAI,KAAK,GAAG;AAAA,IAC5B,OAAO;AAAA,EACT;AAAA,EAIA,MAAM,YAAY,cAAc,IAAI,UAAU,QAAQ;AAAA,EACtD,IAAI,SAAS,KAAK,SAAS,KAAK,CAAC,QAAQ,KAAK,SAAS,GAAG;AAAA,IACxD,IAAI,eAAe,WAAW,GAAG,GAAG;AAAA,MAClC,OAAO;AAAA,IACT;AAAA,IASA,IAAI,KAAK,SAAS,KAAK,cAAc,sBAAsB,KAAK,MAAM,GAAG;AAAA,MACvE,IAAI,qBAAqB,SAAQ,KAAK,UAAU,GAAG,KAAK,MAAM,GAAG;AAAA,QAC/D,OAAO;AAAA,MACT;AAAA,MAIA,MAAM,WAAW,KAAK,OAClB,oBAAoB,KAAK,QAAQ,KAAK,YAAY,KAAK,IAAI,IAC3D,KAAK;AAAA,MACT,OAAO;AAAA,WACF;AAAA,QACH,MAAM;AAAA,QACN,SAAS,SAAS,kCAAkC,UAAS,KAAK,QAAQ,KAAK,UAAU;AAAA,QACzF,UAAU;AAAA,QACV,YACE;AAAA,MACJ;AAAA,IACF;AAAA,IAEA,IAAI,IAAI,cAAc,MAAM;AAAA,MAC1B,OAAO;AAAA,IACT;AAAA,IACA,OAAO;AAAA,SACF;AAAA,MACH,MAAM;AAAA,MACN,SAAS,SAAS;AAAA,MAClB,UAAU;AAAA,MACV,YAAY,yBAAyB;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,OAAO;AAAA,OACF;AAAA,IACH,MAAM;AAAA,IACN,SAAS,kBAAkB,KAAK,SAAS,4BAA4B;AAAA,IACrE,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AAAA;AAIF,IAAM,qBAAqB,OACzB,SAC0B;AAAA,EAC1B,MAAM,UAAU,MAAM,SAAS,KAAK,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC;AAAA,EAEzD,MAAM,cAA4B,CAAC;AAAA,EACnC,WAAW,OAAO,MAAM;AAAA,IACtB,MAAM,SAAS,QAAQ,IAAI,IAAI,GAAG;AAAA,IAClC,MAAM,QAAQ,SAAS,cAAc,MAAM,IAAI;AAAA,IAC/C,IAAI,OAAO;AAAA,MACT,YAAY,KAAK;AAAA,QACf,MAAM;AAAA,QACN,QAAQ,IAAI;AAAA,QACZ,MAAM,IAAI;AAAA,QACV,MAAM,IAAI;AAAA,QACV,SAAS,iBAAiB,IAAI,uBAAuB,MAAM;AAAA,QAC3D,UAAU,MAAM;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AA6BF,IAAM,sBAAsB,CACjC,OACA,SACmB;AAAA,EACnB,MAAM,WAAW,IAAI;AAAA,EACrB,MAAM,mBAAmB,IAAI;AAAA,EAC7B,WAAW,QAAQ,OAAO;AAAA,IACxB,QAAQ,eAAe;AAAA,IACvB,IAAI,CAAC,cAAc,KAAK,UAAU;AAAA,MAChC;AAAA,IACF;AAAA,IACA,MAAM,YAAY,KAAK,WAAW,MAAM;AAAA,IACxC,IAAI,CAAC,SAAS,IAAI,UAAU,KAAK,WAAW;AAAA,MAC1C,SAAS,IAAI,YAAY,KAAK,KAAK;AAAA,IACrC;AAAA,IACA,IAAI,WAAW;AAAA,MACb,iBAAiB,IAAI,WAAU,KAAK,OAAO,GAAG,KAAK,KAAK;AAAA,IAC1D;AAAA,EACF;AAAA,EACA,OAAO,EAAE,kBAAkB,SAAS;AAAA;AAQ/B,IAAM,oBAAoB,CAC/B,OACA,MACA,SAEA,MAAM,SAAS,IAAI,SAAQ,SAAQ,KAAK,UAAU,GAAG,IAAI,CAAC,KAC1D,MAAM,iBAAiB,IAAI,WAAU,MAAK,SAAQ,KAAK,OAAO,GAAG,IAAI,CAAC,CAAC;AASzE,IAAM,iBAAiB,CACrB,MACA,SACA,QACW;AAAA,EACX,MAAM,OAAO,EAAE,SAAS,YAAY,IAAI,GAAG,OAAO,KAAK,MAAM;AAAA,EAC7D,QAAQ,SAAS,eAAe;AAAA,EAChC,MAAM,cAAc,aAChB,CAAC,SACC,kBAAkB,IAAI,YAAY,EAAE,SAAS,WAAW,GAAG,IAAI,IACjE;AAAA,EACJ,OACE,oBAAoB,SAAS,MAAM,aAAa,CAAC,UAC/C,IAAI,OAAO,IAAI,KAAK,CACtB,KAAK,gBAAgB,KAAK,OAAO,SAAS,KAAK,OAAO;AAAA;AAK1D,IAAM,eAAe,CACnB,MACA,MACA,KACA,eACe;AAAA,EACf,QAAQ,WAAW;AAAA,EACnB,MAAM,OAAiB;AAAA,IACrB,QAAQ,KAAK;AAAA,IAGb,MAAM,KAAK,QAAQ,KAAK,cAAc,KAAK;AAAA,IAC3C,MAAM,KAAK;AAAA,EACb;AAAA,EAEA,IAAI,KAAK,KAAK,MAAM,KAAK,kBAAkB,KAAK,MAAM,GAAG;AAAA,IACvD,WAAW;AAAA,SACN;AAAA,MACH,KAAK,kBAAkB,KAAK,MAAM,IAAI,SAAS,WAAW;AAAA,IAC5D,CAAC;AAAA,IACD,OAAO;AAAA,EACT;AAAA,EACA,IAAI,OAAO,KAAK,MAAM,GAAG;AAAA,IAEvB,OAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,OAAO,QAAQ,GAAG;AAAA,EAIpC,MAAM,WAAW,eACf,cAAc,KAAK,KAAK,OAAO,MAAM,YAAY,CAAC,CACpD;AAAA,EACA,IAAI,UAAU,cAAc,KAAK,SAAS,OAAO,MAAM,GAAG,SAAS;AAAA,EACnE,MAAM,aAAa,QAAQ,QAAQ,GAAG;AAAA,EACtC,IAAI,eAAe,IAAI;AAAA,IACrB,UAAU,QAAQ,MAAM,GAAG,UAAU;AAAA,EACvC;AAAA,EACA,UAAU,eAAc,OAAO;AAAA,EAM/B,MAAM,MAAM,QAAQ,WAAW,GAAG,IAAI,KAAK,iBAAiB,MAAM,IAAI;AAAA,EACtE,IAAI,YAAY,IAAI;AAAA,IAClB,OAAO,WAAW,YAAY,KAAK,OAAO,UAAU,MAAM,KAAK,GAAG,IAAI;AAAA,EACxE;AAAA,EAEA,MAAM,WAAW,QAAQ,WAAW,GAAG,IACnC,UACA,eAAe,MAAM,SAAS,GAAG;AAAA,EACrC,OAAO,cAAc,UAAU,UAAU,MAAM,MAAM,MAAM,KAAK,GAAG;AAAA;AAQ9D,IAAM,gBAAgB,OAC3B,OACA,YAiB0B;AAAA,EAC1B,MAAM,WAAW,QAAQ,YAAY;AAAA,EACrC,MAAM,MAAmB;AAAA,IACvB,SAAS,iBAAiB,MAAM,KAAK;AAAA,IACrC;AAAA,IACA,aAAa,IAAI,KAAK,QAAQ,eAAe,CAAC,GAAG,IAAI,OAAO,CAAC;AAAA,IAC7D,YAAY,oBAAoB,MAAM,OAAO,QAAQ,QAAQ,IAAI;AAAA,IACjE,MAAM,QAAQ,QAAQ;AAAA,IACtB,WAAW,QAAQ;AAAA,IACnB,WAAW,IAAI,KACZ,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,aAC7B,QAAQ,aAAa,UAAU,SAAS,IAAI,CAAC,CAC/C,CACF;AAAA,IACA,QAAQ,IAAI,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,EACrC;AAAA,EACA,MAAM,cAA4B,CAAC;AAAA,EACnC,MAAM,WAA0B,CAAC;AAAA,EACjC,IAAI,kBAAkB;AAAA,EAEtB,WAAW,QAAQ,MAAM,OAAO;AAAA,IAC9B,WAAW,QAAQ,KAAK,OAAO;AAAA,MAC7B,MAAM,SAAS,aAAa,MAAM,MAAM,KAAK,CAAC,QAAQ,SAAS,KAAK,GAAG,CAAC;AAAA,MACxE,IAAI,WAAW,mBAAmB;AAAA,QAChC,mBAAmB;AAAA,MACrB,EAAO,SAAI,QAAQ;AAAA,QACjB,YAAY,KAAK,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAI,kBAAkB,GAAG;AAAA,IACvB,YAAY,KAAK;AAAA,MACf,MAAM;AAAA,MACN,SAAS,GAAG;AAAA,MACZ,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,QAAQ,iBAAiB,SAAS,SAAS,GAAG;AAAA,IAChD,YAAY,KAAK,GAAI,MAAM,mBAAmB,QAAQ,CAAE;AAAA,EAC1D;AAAA,EAKA,MAAM,OAAO,IAAI;AAAA,EACjB,OAAO,YAAY,OAAO,CAAC,eAAe;AAAA,IACxC,MAAM,MAAM;AAAA,MACV,WAAW;AAAA,MACX,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,WAAW,UAAU;AAAA,MACrB,WAAW;AAAA,IACb,EAAE,KAAK;AAAA,CAAI;AAAA,IACX,IAAI,KAAK,IAAI,GAAG,GAAG;AAAA,MACjB,OAAO;AAAA,IACT;AAAA,IACA,KAAK,IAAI,GAAG;AAAA,IACZ,OAAO;AAAA,GACR;AAAA;;;A0E3nBH,uBAAS,6BAAY;AACrB,kBAAS,oBAAO,wBAAU;AAE1B;AACA,qBAAS,sBAAU,wBAAS,qBAAY,mBAAM;;;ACEvC,IAAM,gBAAgB,CAAC,QAC5B,IACG,YAAY,EACZ,WAAW,mBAAmB,GAAG,EACjC,WAAW,qBAAqB,EAAE,KAAK;AASrC,IAAM,mBAAmB,CAC9B,MACA,YAAoC,CAAC,MAC1B;AAAA,EACX,MAAM,eAAe,OAAO,QAAQ;AAAA,IAClC,OAAO,IAAI,gBAAgB;AAAA,OACxB;AAAA,EACL,CAAC,EACE,SAAS,EAAE,KAAK,OAAQ,IAAI,IAAI,KAAK,CAAE,EACvC,IACC,EAAE,KAAK,WAAW,OAAO,KAAK,UAAU,GAAG,MAAM,KAAK,UAAU,KAAK,GACvE,EACC,KAAK;AAAA,CAAK;AAAA,EACb,OAAO;AAAA,YACG,KAAK,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS7B;AAAA;AAAA;AAAA;AAAA;;;ADzBK,IAAM,YAAY,CAAC,QAAQ,OAAO,OAAO,WAAW;AAGpD,IAAM,mBAAmB,CAAC,OAAO,QAAQ,QAAQ,KAAK;AAItD,IAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAkCA,IAAM,OAAO,CAAC,OAAe,aAAqB,SAChD;AAAA,SAAe;AAAA,eAAuB;AAAA;AAAA;AAAA,EAAuB;AAAA;AAExD,IAAM,WAAW;AAAA,EACtB,KAAK;AAAA,IACH,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYb,eAAe,CAAC,4CAA4C;AAAA,IAC5D,OAAO,CAAC,QAAQ;AAAA,MACd;AAAA,QACE,SAAS,KACP,iBACA,6IACA,uGACF;AAAA,QACA,MAAM,MAAK,KAAK,WAAW;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOb,eAAe,CAAC;AAAA,IAChB,OAAO,CAAC,QAAQ;AAAA,MACd;AAAA,QACE,SAAS,KACP,gBACA,0IACA,wHACF;AAAA,QACA,MAAM,MAAK,KAAK,WAAW;AAAA,MAC7B;AAAA,MACA;AAAA,QACE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAA2O;AAAA;AAAA,QACpP,MAAM,MAAK,KAAK,aAAa,YAAY;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,eAAe,CAAC;AAAA,IAChB,OAAO,CAAC,QAAQ;AAAA,MACd;AAAA,QACE,SAAS,KACP,gBACA,kIACA;AAAA;AAAA,SAAyF,gEAC3F;AAAA,QACA,MAAM,MAAK,KAAK,WAAW;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH,aAAa;AAAA,IACb,eAAe,CAAC;AAAA,IAChB,OAAO,CAAC,QAAQ;AAAA,MACd;AAAA,QACE,SAAS,KACP,gBACA,uIACA,8EACF;AAAA,QACA,MAAM,MAAK,KAAK,WAAW;AAAA,MAC7B;AAAA,MACA;AAAA,QACE,SAAS,KACP,gBACA,0IACA,mCACF;AAAA,QACA,MAAM,MAAK,KAAK,kBAAkB;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAOO,IAAM,cAAc,CAAC,QAAwB;AAAA,EAElD,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AAAA,EAGvC,OAAO,OAAO,SAAS,OAAO,QAAQ,GAAG,iBAAiB,GAAG;AAAA,EAC7D,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AAAA,EACvC,MAAM,EAAE,KAAK,QAAQ,KAAK,OAAO,MAAM,aAAa,MAAM,OAAO,EAAE;AAAA,EACnE,SAAS,GAAG;AACd;AAEA,IAAM,mBAAmB,CAAC,UACxB,iBAAiB,KAAK,CAAC,OAAO,OAAO,KAAK;AAQrC,IAAM,uBAAuB,CAAC,cAAuC;AAAA,EAC1E,MAAM,OAAO,WAAW,MAAM,GAAG,EAAE;AAAA,EACnC,OAAO,SAAS,aAAa,iBAAiB,IAAI,IAAI,OAAO;AAAA;AAU/D,IAAM,mBAAmB,CAAC,SAAgC;AAAA,EACxD,IAAI,MAAM;AAAA,EACV,OAAO,CAAC,YAAW,MAAK,KAAK,MAAM,CAAC,GAAG;AAAA,IACrC,MAAM,SAAS,SAAQ,GAAG;AAAA,IAC1B,IAAI,WAAW,KAAK;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA,MAAM;AAAA,EACR;AAAA,EACA,OAAO;AAAA;AAWF,IAAM,8BAA8B,OACzC,SAC4B;AAAA,EAM5B,MAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,KAAK;AAAA,IACL,SAAS,iBAAiB,IAAI,KAAK;AAAA,EACrC,CAAC;AAAA,EACD,MAAM,OAAO,UAAU;AAAA,EACvB,OAAO,SAAS,aAAa,iBAAiB,IAAI,IAC9C,OACA,qBAAqB,QAAQ,IAAI,qBAAqB;AAAA;AAQrD,IAAM,qBAAqB,CAChC,MACA,QAEA,YAAW,GAAG,KAAK,UAAS,MAAM,MAAK,MAAM,GAAG,CAAC,EAAE,WAAW,IAAI,IAC9D,gDACA;AAGC,IAAM,WAAW,CAAC,QAAwB;AAAA,EAC/C,MAAM,QAAQ,IACX,WAAW,YAAY,GAAG,EAC1B,MAAM,MAAM,EACZ,OAAO,OAAO;AAAA,EACjB,OAAO,MAAM,WAAW,IACpB,YACA,MACG,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,GAAG;AAAA;AAQjB,IAAM,uBAAuB,CAAC,YAC5B,QAAQ,KAAK,CAAC,WAAW,WAAW,YAAY;AAGlD,IAAM,mBAAmB;AAAA,EACvB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AACV;AAOA,IAAM,qBAAqB;AAAA,EACzB,YAAY,WAAW;AAAA,IACrB,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,OAAO;AAAA,EACT,CAAC;AAAA,EACD,mBAAmB,eAAe;AAAA,IAChC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,EACR,CAAC;AAAA,EACD,cAAc,UAAU;AAAA,IACtB,QAAQ,EAAE,OAAO,YAAY,MAAM,QAAQ,MAAM,YAAY;AAAA,IAC7D,QAAQ;AAAA,EACV,CAAC;AAAA,EACD,QAAQ,OAAO,EAAE,UAAU,oBAAoB,QAAQ,SAAS,CAAC;AAAA,EACjE,UAAU,SAAS,EAAE,QAAQ,SAAS,OAAO,QAAQ,CAAC;AAAA,EACtD,SAAS,QAAQ;AAAA,IACf,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,EACP,CAAC;AAAA,EACD,QAAQ,OAAO;AAAA,IACb,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,EACT,CAAC;AAAA,EACD,QAAQ,OAAO;AAAA,IACb,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,KAAK;AAAA,EACP,CAAC;AACH;AAMA,IAAM,kBAAkB;AAAA,EACtB,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOZ,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMd,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAKR,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOV,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQR,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOV;AAGA,IAAM,iBAAiB,CAAC,YACtB,aAAa,OAAO,CAAC,SAAS,QAAQ,SAAS,IAAI,CAAC;AAGtD,IAAM,mBAAmB,CAAC,YACxB,YAAY,eAAe,OAAO,EAC/B,IAAI,CAAC,SAAS,iBAAiB,KAAK,EACpC,KAAK,IAAI;AAAA;AAGd,IAAM,kBAAkB,CAAC,YACvB,QAAQ,QAAQ,WAAW,IAAI,CAAC,YAAY,IAAI,QAAQ;AAO1D,IAAM,kBAAkB,CAAC,YAAiC;AAAA,EACxD,MAAM,UAAU,gBAAgB,OAAO;AAAA,EACvC,IAAI,CAAC,qBAAqB,OAAO,GAAG;AAAA,IAClC,OAAO,QAAQ,eAAe,SAC1B,KACA;AAAA;AAAA,YAEI,KAAK,UAAU,QAAQ,UAAU;AAAA;AAAA,EAE3C;AAAA,EAGA,MAAM,UAAU,eAAe,OAAO,EAAE,IAAI,CAAC,SAC3C,SAAS,eACL,4BAA4B,KAAK,UAAU,QAAQ,UAAU,UAC7D,gBAAgB,KACtB;AAAA,EACA,OAAO;AAAA;AAAA;AAAA,EAGP,QAAQ,KAAK;AAAA,CAAI;AAAA;AAAA;AAAA;AAMZ,IAAM,cAAc,CAAC,YAAiC;AAAA,EAC3D,MAAM,UAAU,SAAS,QAAQ;AAAA,EACjC,MAAM,UAAU,gBAAgB,OAAO;AAAA,EAGvC,MAAM,gBAAgB,qBAAqB,OAAO,IAC9C,iBAAiB,OAAO,IACxB;AAAA,EACJ,MAAM,UAAU;AAAA,IACd;AAAA,IACA,GAAG,QAAQ;AAAA,EACb,EAAE,KAAK;AAAA,CAAI;AAAA,EACX,OAAO,GAAG;AAAA,EACV;AAAA;AAAA,WAES,KAAK,UAAU,QAAQ,KAAK;AAAA,mDACY,QAAQ,cAAc,gBAAgB,OAAO;AAAA;AAAA;AAAA;AAMhG,IAAM,eAAe,IAAI,IAAI;AAAA,EAC3B,CAAC,oBAAoB,SAAS;AAAA,EAC9B,CAAC,kBAAkB,QAAQ;AAC7B,CAAC;AAGD,IAAM,iBAAiB,CAAC,YACtB,eAAe,OAAO,EAAE,QAAQ,CAAC,SAC/B,SAAS,eAAe,CAAC,IAAI,CAAC,mBAAmB,KAAK,CACxD;AAGF,IAAM,eAAe,CAAC,YAA0B;AAAA,EAC9C,MAAM,OAA+B,CAAC;AAAA,EACtC,WAAW,cAAc,eAAe,OAAO,GAAG;AAAA,IAChD,WAAW,OAAO,WAAW,aAAa;AAAA,MACxC,KAAK,OAAO,aAAa,IAAI,GAAG,KAAK;AAAA,IACvC;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAUT,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAUvB,IAAM,SAAS;AAAA;AAAA;AAAA;AAUf,IAAM,kBAAkB,CACtB,MACA,UACkB;AAAA,EAClB,MAAM,OAAO,iBAAiB,IAAI;AAAA,EAClC,IAAI,MAAM;AAAA,EACV,OAAO,CAAC,MAAM,GAAG,GAAG;AAAA,IAClB,MAAM,SAAS,SAAQ,GAAG;AAAA,IAC1B,IAAI,QAAQ,QAAQ,WAAW,KAAK;AAAA,MAClC,OAAO;AAAA,IACT;AAAA,IACA,MAAM;AAAA,EACR;AAAA,EACA,OAAO;AAAA;AAIT,IAAM,WAAW,CAAC,SAAyB;AAAA,EACzC,IAAI;AAAA,IACF,OAAO,cAAa,MAAM,OAAO;AAAA,IACjC,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAKX,IAAM,oBAAoB,CAAC,SACzB,gBAAgB,MAAM,CAAC,QAAQ,YAAW,MAAK,KAAK,qBAAqB,CAAC,CAAC;AAM7E,IAAM,kBAAkB,CAAC,SACvB,gBACE,MACA,CAAC,QACC,YAAW,MAAK,KAAK,WAAW,CAAC,KACjC,YAAW,MAAK,KAAK,aAAa,CAAC,KACnC,oBAAoB,KAAK,SAAS,MAAK,KAAK,cAAc,CAAC,CAAC,CAChE;AAMK,IAAM,YAAY,CAAC,cAA2C;AAAA,EACnE,MAAM,QAAQ,0BAA0B,KAAK,aAAa,EAAE;AAAA,EAC5D,OAAO,OAAO,QAAQ,UAAU,YAC5B,YACA,OAAO,MAAM,OAAO,KAAK;AAAA;AAgB/B,IAAM,0BAA0B,CAC9B,MACA,SACA,QACmB;AAAA,EACnB,IAAI,YAAW,MAAK,MAAM,cAAc,CAAC,GAAG;AAAA,IAC1C,OAAO,CAAC;AAAA,EACV;AAAA,EACA,IAAI,QAAQ,mBAAmB,UAAU,kBAAkB,IAAI,MAAM,MAAM;AAAA,IACzE,OAAO;AAAA,MACL,EAAE,SAAS,gBAAgB,MAAM,MAAK,MAAM,qBAAqB,EAAE;AAAA,IACrE;AAAA,EACF;AAAA,EACA,IACE,QAAQ,mBAAmB,UAC3B,UAAU,IAAI,SAAS,MAAM,KAC7B,gBAAgB,IAAI,MAAM,MAC1B;AAAA,IACA,OAAO,CAAC,EAAE,SAAS,QAAQ,MAAM,MAAK,MAAM,aAAa,EAAE,CAAC;AAAA,EAC9D;AAAA,EACA,OAAO,CAAC;AAAA;AAUH,IAAM,gBAAgB,CAC3B,MACA,SACA,MAAuB,CAAC,MACD;AAAA,EACvB,IAAI,QAAQ,mBAAmB,QAAQ;AAAA,IACrC,MAAM,YAAY,kBAAkB,IAAI;AAAA,IACxC,MAAM,OAAO,aAAa,MAAK,WAAW,qBAAqB;AAAA,IAC/D,IAAI,CAAC,QAAQ,SAAS,IAAI,EAAE,SAAS,SAAS,GAAG;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,OAAO,4CAA4C;AAAA;AAAA;AAAA;AAAA,EACrD;AAAA,EACA,IAAI,QAAQ,mBAAmB,UAAU,UAAU,IAAI,SAAS,MAAM,GAAG;AAAA,IACvE;AAAA,EACF;AAAA,EACA,MAAM,UAAU,gBAAgB,IAAI;AAAA,EACpC,MAAM,KAAK,WAAW,MAAK,SAAS,aAAa;AAAA,EACjD,IAAI,CAAC,MAAM,8CAA8C,KAAK,SAAS,EAAE,CAAC,GAAG;AAAA,IAC3E;AAAA,EACF;AAAA,EACA,OAAO,0CAA0C,oDAAoD;AAAA;AAAA;AAAA;AAIhG,IAAM,YAAY,CACvB,MACA,SACA,MAAuB,CAAC,MACL;AAAA,EACnB,MAAM,QAAwB;AAAA,IAC5B;AAAA,MACE,SAAS,iBACP,cAAc,UAAS,IAAI,CAAC,GAC5B,aAAa,QAAQ,OAAO,CAC9B;AAAA,MACA,MAAM,MAAK,MAAM,cAAc;AAAA,IACjC;AAAA,IACA,GAAG,wBAAwB,MAAM,SAAS,GAAG;AAAA,IAC7C,EAAE,SAAS,YAAY,OAAO,GAAG,MAAM,MAAK,MAAM,iBAAiB,EAAE;AAAA,EACvE;AAAA,EAEA,IAAI,QAAQ,QAAQ,WAAW,KAAK,QAAQ,QAAQ,SAAS,YAAY,GAAG;AAAA,IAC1E,MAAM,KACJ,GAAG,SAAS,QAAQ,UACjB,MAAM,QAAQ,UAAU,EACxB,IAAI,CAAC,UAAU,KAAK,MAAM,MAAM,MAAK,MAAM,KAAK,IAAI,EAAE,EAAE,CAC7D;AAAA,EACF;AAAA,EAIA,IAAI,QAAQ,QAAQ,SAAS,UAAU,GAAG;AAAA,IACxC,MAAM,KAAK;AAAA,MACT,SACE;AAAA,MACF,MAAM,MAAK,MAAM,SAAS,YAAY;AAAA,IACxC,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,gBAAgB,OACpB,MACA,QACqB;AAAA,EACrB,IAAI,YAAW,KAAK,IAAI,GAAG;AAAA,IACzB,IAAI,KAAK,oBAAoB,KAAK,MAAM;AAAA,IACxC,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAM,SAAQ,KAAK,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,EACnD,MAAM,WAAU,KAAK,MAAM,KAAK,SAAS,OAAO;AAAA,EAChD,IAAI,QAAQ,WAAW,KAAK,MAAM;AAAA,EAClC,OAAO;AAAA;AAOF,IAAM,YAAY,OACvB,OACA,QACyC;AAAA,EACzC,MAAM,UAAU,MAAM,QAAQ,IAC5B,MAAM,IAAI,CAAC,SAAS,cAAc,MAAM,GAAG,CAAC,CAC9C;AAAA,EACA,MAAM,iBAAiB,MAAM,KAC3B,CAAC,MAAM,UAAU,QAAQ,UAAU,UAAS,KAAK,IAAI,MAAM,cAC7D;AAAA,EACA,OAAO,EAAE,eAAe;AAAA;AAI1B,IAAM,aAAa,CAAC,YAAoC;AAAA,EACtD,GAAG,IAAI,IACL,eAAe,OAAO,EAAE,QAAQ,CAAC,eAAe,WAAW,eAAe,CAC5E;AACF;AAiBA,IAAM,gBAAgB,CAAC,SAA0B;AAAA,EAC/C,IAAI,MAAM;AAAA,EACV,OAAO,CAAC,YAAW,MAAK,KAAK,gBAAgB,SAAS,cAAc,CAAC,GAAG;AAAA,IACtE,MAAM,SAAS,SAAQ,GAAG;AAAA,IAC1B,IAAI,WAAW,KAAK;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA,MAAM;AAAA,EACR;AAAA,EACA,OAAO;AAAA;AAOF,IAAM,sBAAsB,OACjC,SAC6B;AAAA,EAC7B,IAAI;AAAA,IAGF,MAAM,MAAM,KAAK,MACf,MAAM,UAAS,MAAK,MAAM,cAAc,GAAG,OAAO,CACpD;AAAA,IAKA,OAAO;AAAA,MACL,gBAAgB,cAAc,IAAI;AAAA,MAClC,cAAc,OAAO,KAAK;AAAA,WACrB,IAAI;AAAA,WACJ,IAAI;AAAA,MACT,CAAC;AAAA,MACD,cAAc,OAAO,IAAI,SAAS,OAAO,EAAE,EAAE,SAAS,OAAO;AAAA,IAC/D;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA,MACL,gBAAgB,cAAc,IAAI;AAAA,MAClC,cAAc,CAAC;AAAA,MACf,cAAc;AAAA,IAChB;AAAA;AAAA;AAaG,IAAM,YAAY,CACvB,SACA,cACA,UACA,SACW;AAAA,EACX,MAAM,WAAW,YAAY,QAAQ,cAAc;AAAA,EACnD,MAAM,QAAkB,CAAC;AAAA,EACzB,IAAI,QAAQ,cAAc,KAAK;AAAA,IAC7B,MAAM,KAAK,MAAM,QAAQ,WAAW;AAAA,EACtC;AAAA,EACA,IAAI,cAAc;AAAA,IAChB,MAAM,KAAK,SAAS,OAAO;AAAA,EAC7B;AAAA,EACA,IAAI,UAAU;AAAA,IACZ,MAAM,UAAU;AAAA,MACd;AAAA,MACA,GAAG,OAAO,KAAK,aAAa,QAAQ,OAAO,CAAC;AAAA,IAC9C,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS,aAAa,SAAS,GAAG,CAAC;AAAA,IACtD,IAAI,QAAQ,SAAS,GAAG;AAAA,MACtB,MAAM,KAAK,GAAG,SAAS,OAAO,QAAQ,KAAK,GAAG,GAAG;AAAA,IACnD,EAAO,SAAI,EAAE,gBAAgB,SAAS,iBAAiB;AAAA,MACrD,MAAM,KAAK,SAAS,OAAO;AAAA,IAC7B;AAAA,EACF;AAAA,EACA,MAAM,KACJ,YAAY,CAAC,SAAS,eAClB,GAAG,SAAS,mBACZ,SAAS,GACf;AAAA,EACA,MAAM,UAAU,WAAW,QAAQ,OAAO;AAAA,EAC1C,MAAM,OACJ,QAAQ,SAAS,IACb;AAAA,MAAS,QAAQ,KAAK,OAAO;AAAA,IAC7B;AAAA,EACN,MAAM,YAAY,OAAO;AAAA,EAAK;AAAA,IAAW;AAAA,EACzC,OAAO;AAAA;AAAA,IAAoB,MAAM,KAAK;AAAA,GAAM;AAAA,EAAM,OAAO;AAAA;;;AEhyB3D,uBAAS;AACT,kBAAS,oBAAO,wBAAU;AAE1B,qBAAS,sBAAU,kBAAS,mBAAM,sBAAU;;;ACKrC,IAAM,eAAe;AACrB,IAAM,WAAW;AACjB,IAAM,iBAAiB,GAAG;AAC1B,IAAM,gBAAgB,GAAG;AACzB,IAAM,sBAAsB,GAAG;AAC/B,IAAM,kBAAkB,GAAG;AAG3B,IAAM,YAAY,CAAC,UACxB,UAAU,MAAM,UAAU,MAAM,MAAM,CAAC;AAGlC,IAAM,eAAe,CAAC,UAC3B,GAAG,kBAAkB,UAAU,KAAK;;;ACftC,IAAM,eAAe;AAQd,IAAM,gBAAgB,CAAC,SAAyB;AAAA,EACrD,MAAM,UAAU,KAAK,KAAK;AAAA,EAC1B,OAAO,aAAa,KAAK,OAAO,IAAI,UAAU,GAAG;AAAA;;;ACE5C,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAShC,IAAM,WAAW;AAGjB,IAAM,iBAAiB,CAAC,WAA2C;AAAA,EACjE,MAAM,OAAO,OAAO,WAAW,QAAQ,QAAQ;AAAA,EAC/C,MAAM,aAAa,kBAAkB,OAAO,WAAW,QAAQ,IAAI;AAAA,EACnE,MAAM,MAAM,CAAC,SAAyB;AAAA,IACpC,MAAM,QAAQ,aAAa,YAAY,IAAI;AAAA,IAC3C,OAAO,OAAO,aAAY,MAAM,KAAK,IAAI;AAAA;AAAA,EAG3C,MAAM,UAA0B,CAAC;AAAA,EACjC,WAAW,aAAa,kBAAkB,MAAM,GAAG;AAAA,IAGjD,MAAM,WACJ,UAAU,SAAS,WACf,UAAU,QACV,aAAa,UAAU,UAAU,UAAU,KAAK;AAAA,IACtD,MAAM,QAAsB;AAAA,MAC1B,QAAQ,IAAI,QAAQ;AAAA,MACpB,eAAe,CAAC,EAAE,MAAM,IAAI,QAAQ,GAAG,MAAM,YAAY,CAAC;AAAA,IAC5D;AAAA,IAGA,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,MACjC,MAAM,kBAAkB,CAAC,EAAE,MAAM,UAAU,KAAK,CAAC;AAAA,IACnD;AAAA,IACA,QAAQ,KAAK,KAAK;AAAA,EACpB;AAAA,EAEA,IAAI,OAAO,OAAO,KAAK;AAAA,IACrB,QAAQ,KAAK;AAAA,MACX,QAAQ,IAAI,QAAQ;AAAA,MACpB,gBAAgB,CAAC,EAAE,MAAM,IAAI,YAAY,GAAG,MAAM,mBAAmB,CAAC;AAAA,MACtE,eAAe,CAAC,EAAE,MAAM,IAAI,GAAG,GAAG,MAAM,YAAY,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,OAAO,OAAO,IAAI,SAAS;AAAA,IAC7B,QAAQ,KAAK;AAAA,MACX,QAAQ,IAAI,OAAO,OAAO,IAAI,KAAK;AAAA,MACnC,gBAAgB;AAAA,QACd,EAAE,MAAM,IAAI,uBAAuB,GAAG,MAAM,mBAAmB;AAAA,MACjE;AAAA,MACA,eAAe,CAAC,EAAE,MAAM,IAAI,GAAG,GAAG,MAAM,YAAY,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAIF,IAAM,gBAAgB,CAAC,WAC5B,eAAe,MAAM,EAAE,SAAS;;;AChElC,IAAM,YAAY,CAAC,UAAqC;AAAA,EAGtD,MAAM,OAAO,aAAa,MAAM,MAAM,MAAM,KAAK;AAAA,EAGjD,OAAO,MAAM,OAAO,aAAY,MAAM,MAAM,IAAI,IAAI;AAAA;AAO/C,IAAM,oBAAoB,CAAC,WAA8B;AAAA,EAC9D,SAAS;AAAA,IACP;AAAA,MACE,MAAM,MAAM;AAAA,MACZ,WAAW;AAAA,MACX,KAAK,UAAU,KAAK;AAAA,IACtB;AAAA,EACF;AACF;AAGA,IAAM,qBACJ;AAGF,IAAM,gBAAgB;AAEtB,IAAM,WAAW,CAAC,SAChB,KAAK,SAAS,gBAAgB,GAAG,KAAK,MAAM,GAAG,gBAAgB,CAAC,OAAO;AAOzE,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAEjB,IAAM,eAAe,CAAC,SAC3B,SACE,KACG,UAAU,MAAM,EAChB,QAAQ,iBAAiB,EAAE,EAC3B,YAAY,EACZ,QAAQ,gBAAgB,GAAG,GAC9B,GACF;AAQF,IAAM,iBAAiB,CAAC,UAAqC;AAAA,EAC3D,IAAI,YAAY;AAAA,EAChB,IAAI,MAAM,MAAM;AAAA,IACd,IAAI;AAAA,MACF,YAAY,IAAI,IAAI,MAAM,IAAI,EAAE,SAC7B,MAAM,GAAG,EACT,WAAW,EACX,KAAK,GAAG;AAAA,MACX,MAAM;AAAA,EAGV;AAAA,EACA,OAAO,GAAG,aAAa,aAAa,MAAM,IAAI,KAAK;AAAA;AAGrD,IAAM,YAAW;AAkCV,IAAM,qBAAqB,CAAC,UAA4C;AAAA,EAC7E,MAAM,MAAM,UAAU,KAAK;AAAA,EAC3B,MAAM,OAAsB;AAAA,IAC1B,SAAS;AAAA,IAGT,cAAc;AAAA,MACZ,WAAW,EAAE,aAAa,OAAO,WAAW,MAAM;AAAA,MAClD,OAAO,EAAE,aAAa,MAAM;AAAA,IAC9B;AAAA,IACA,aAAa,SACX,yCAAyC,MAAM,qBACjD;AAAA,IACA,MAAM,eAAe,KAAK;AAAA,IAC1B,YAAY,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ;AAAA,IACvD,OAAO,SAAS,MAAM,IAAI;AAAA,IAC1B,OAAO,UAAU,IAAI,CAAC,UAAU;AAAA,MAC9B,aAAa,KAAK;AAAA,MAClB,aAAa,KAAK;AAAA,MAClB,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,IACd,EAAE;AAAA,IACF,WAAW;AAAA,IACX,YAAY,CAAC,EAAE,UAAU,KAAK,MAAM,kBAAkB,CAAC;AAAA,IACvD;AAAA,IACA,SAAS,MAAM;AAAA,EACjB;AAAA,EACA,IAAI,UAAS,KAAK,GAAG,GAAG;AAAA,IACtB,KAAK,UAAU,CAAC,EAAE,MAAM,mBAAmB,IAAI,CAAC;AAAA,EAClD;AAAA,EACA,IAAI,MAAM,MAAM;AAAA,IACd,KAAK,aAAa,SAAS,MAAM,IAAI;AAAA,EACvC;AAAA,EACA,OAAO;AAAA;;;ACzJT,iBAAS;;;ACDT;AAyBA,IAAM,UAAU,IAAI;;;ADNb,IAAM,mBAAmB;AACzB,IAAM,0BAA0B;;;AEWhC,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AA2CxB,IAAM,eAAe,CAAC,WAC3B,OAAO,OAAO,QAAQ,WACtB,QAAQ,OAAO,WAAW,QAAQ,IAAI,MACrC,OAAO,OAAO,IAAI,WACjB,OAAO,OAAO,OACd,OAAO,OAAO,QAAQ,WACtB,QAAQ,OAAO,OAAO,MAAM,KAC5B,kBAAkB,MAAM,EAAE,SAAS;AAQhC,IAAM,4BAA4B,CAAC,WAAqC;AAAA,EAC7E,MAAM,QAAkB,CAAC;AAAA,EACzB,IAAI,aAAa,MAAM,GAAG;AAAA,IACxB,MAAM,KAAK,iBAAiB,iBAAiB;AAAA,EAC/C;AAAA,EACA,IAAI,cAAc,MAAM,GAAG;AAAA,IACzB,MAAM,KAAK,gBAAgB;AAAA,EAC7B;AAAA,EACA,IAAI,OAAO,OAAO,IAAI,SAAS;AAAA,IAC7B,MAAM,KAAK,yBAAyB,mCAAmC;AAAA,EACzE;AAAA,EACA,OAAO;AAAA;;;ACxEF,IAAM,sBAAsB,CACjC,QACA,eACkB;AAAA,EAClB,MAAM,aAAa,kBAAkB,OAAO,WAAW,QAAQ,IAAI;AAAA,EACnE,MAAM,QAAkB,CAAC;AAAA,EAGzB,IAAI,cAAc,MAAM,GAAG;AAAA,IACzB,MAAM,KACJ,IAAI,aAAa,uEACnB;AAAA,EACF;AAAA,EAGA,IAAI,aAAa,MAAM,GAAG;AAAA,IACxB,MAAM,KACJ,IAAI,aAAa,6CAA6C,kBAChE;AAAA,EACF;AAAA,EAGA,IAAI,OAAO,OAAO,KAAK;AAAA,IACrB,MAAM,KACJ,IAAI,aAAa,4DACnB;AAAA,EACF;AAAA,EACA,IAAI,OAAO,OAAO,kBAAkB;AAAA,IAClC,MAAM,KACJ,IAAI,gFACN;AAAA,EACF;AAAA,EACA,IAAI,OAAO,OAAO,QAAQ,SAAS;AAAA,IACjC,MAAM,KACJ,IAAI,4DACN;AAAA,EACF;AAAA,EAKA,IAAI,WAAW,SAAS,GAAG,GAAG;AAAA,IAC5B,MAAM,KACJ,IAAI,6DACN;AAAA,EACF;AAAA,EACA,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAAA;;;AC9E/C,qBAAS;;;ACoBT,IAAM,YAAY,CAAC,UAA2C;AAAA,EAC5D,IAAI,UAAU,WAAW;AAAA,IACvB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,IAAI,KAAK,KAAK;AAAA,EAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAAA;AAI/C,IAAM,WAAW,CAAC,SAAuB,UAA0B;AAAA,EACjE,QAAQ,MAAM,SAAS,QAAQ,OAAO,WAAW;AAAA,EACjD,MAAM,OAAO,aAAa,kBAAkB,IAAI,GAAG,KAAK;AAAA,EACxD,OAAO,UAAU,OAAO,aAAY,MAAM,IAAI,IAAI,IAAI;AAAA;AAGxD,IAAM,UAAU,CAAC,WAAyB,MAAM,WAA6B;AAAA,EAC3E,MAAM,UAAU;AAAA,IACd,OAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE,IAAI;AAAA,IACzC,KAAK,KAAK,WAAW,YAAY;AAAA,EACnC,EAAE,OAAO,OAAO;AAAA,EAChB,MAAM,QAAQ,KAAK,MAAM,WAAW,WAAW,OAAO,QAAQ;AAAA,EAC9D,MAAM,OAAO,QAAQ,SAAS,IAAI,MAAM,QAAQ,KAAK,IAAI,MAAM;AAAA,EAC/D,OAAO,MAAM,UAAU,SAAS,SAAS,KAAK,KAAK,KAAK;AAAA;AAGnD,IAAM,8BAA8B,CAAC,YAAkC;AAAA,EAC5E,QAAQ,SAAS,QAAQ;AAAA,EACzB,MAAM,KAAK,OACP,iBAAiB,KAAK,eAAe;AAAA,IACnC,eAAe,KAAK;AAAA,IACpB,WAAW,KAAK;AAAA,EAClB,CAAC,IACD;AAAA,EACJ,MAAM,OAAmB,QAAQ,MAAM,MACpC,OACC,CAAC,SACC,KAAK,gBAAgB,eACrB,CAAC,KAAK,KAAK,SACX,CAAC,KAAK,KAAK,QAAQ,UACnB,CAAC,KAAK,YACN,KAAK,YAAY,OAChB,CAAC,QAAQ,KAAK,WAAW,KAAK,cACnC,EACC,IAAI,CAAC,UAAU;AAAA,IACd,MAAM,UAAU,KAAK,KAAK,QAAQ,KAAK,KAAK,WAAW,IAAI;AAAA,IAC3D;AAAA,EACF,EAAE,EACD,SAAS,CAAC,GAAG,OAAO,EAAE,MAAM,QAAQ,KAAK,MAAM,EAAE,MAAM,QAAQ,KAAK,EAAE;AAAA,EAEzE,MAAM,SAAS,CAAC,KAAK,GAAG,UAAU,SAAS,GAAG,UAAU,WAAW;AAAA,EACnE,IAAI;AAAA,EACJ,IAAI,QAAkB,CAAC;AAAA,EACvB,MAAM,QAAQ,MAAY;AAAA,IACxB,IAAI,MAAM,SAAS,GAAG;AAAA,MACpB,OAAO,KAAK,MAAM,KAAK;AAAA,CAAI,CAAC;AAAA,MAC5B,QAAQ,CAAC;AAAA,IACX;AAAA;AAAA,EAEF,WAAW,OAAO,MAAM;AAAA,IACtB,MAAM,UAAU,IAAI,OAAO,IAAI,KAAK,eAAe,IAAI;AAAA,IACvD,IAAI,YAAY,MAAM;AAAA,MACpB,MAAM;AAAA,MACN,OAAO;AAAA,MAEP,OAAO,KAAK,YAAY,OAAO,eAAe,MAAM,SAAS;AAAA,IAC/D;AAAA,IACA,MAAM,KAAK,QAAQ,SAAS,GAAG,CAAC;AAAA,EAClC;AAAA,EACA,MAAM;AAAA,EACN,OAAO,GAAG,OAAO,KAAK;AAAA;AAAA,CAAM;AAAA;AAAA;;;ACzF9B;AACA;;;ACMA,IAAM,UAAU;AAIhB,IAAM,SACJ;AAOK,IAAM,iBAAiB,CAAC,UAAiC;AAAA,EAC9D,MAAM,QAAQ,MAAM,KAAK;AAAA,EACzB,IAAI,CAAC,OAAO;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,IAAI,QAAQ,KAAK,KAAK,GAAG;AAAA,IACvB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,OAAO,KAAK,KAAK,GAAG,QAAQ,MAAM;AAAA;;;ACrBpC,IAAM,oBAAoB;AAAA,EAC/B,WAAW;AAAA,EACX,aAAa;AACf;AAOO,IAAM,eAAe;AAAA,KACvB;AAAA,EACH,WAAW;AAAA,EACX,MAAM,EAAE,sBAAsB,MAAM;AACtC;;;AF8CO,IAAM,YAAW,CAAQ,UAC9B,OAAO,UAAU;AAEnB,IAAM,WAAW,CAAQ,UACvB,OAAO,UAAU;AAGnB,IAAM,aAAa,CACjB,UAEA,OAAO,UAAU,YACjB,UAAU,QACV,CAAC,MAAM,QAAQ,KAAK,KACpB,EAAE,iBAAiB;AAkErB,IAAM,qBAAqB,CACzB,KACA,gBACG;AAAA,EACH,IAAI;AAAA,IAIF,MAAM,QAAwB,IAAI,SAChC,eACA,yBAAyB,OAC3B,EAAE,WAAW;AAAA,IACb,OAAO,EAAE,IAAI,MAAM,MAAM;AAAA,IACzB,MAAM;AAAA,IACN,OAAO,EAAE,IAAI,OAAO,OAAO,UAAU;AAAA;AAAA;AAKzC,IAAM,YAAY,CAChB,MACA,gBACmB;AAAA,EACnB,MAAM,QAAwC,CAAC;AAAA,EAC/C,IAAI,QAAQ;AAAA,EACZ,WAAW,aAAa,KAAK,cAAc,CAAC,GAAG;AAAA,IAE7C,IAAI,UAAU,SAAS,qBAAqB,CAAC,UAAU,MAAM;AAAA,MAC3D,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,IACA,IAAI,UAAU,UAAU,QAAQ,UAAU,UAAU,WAAW;AAAA,MAE7D,MAAM,UAAU,QAAQ;AAAA,IAC1B,EAAO,SAAI,UAAS,UAAU,KAAK,GAAG;AAAA,MACpC,MAAM,UAAU,QAAQ,UAAU;AAAA,IACpC,EAAO;AAAA,MACL,MAAM,SAAS,mBAAmB,UAAU,MAAM,OAAO,WAAW;AAAA,MACpE,IAAI,OAAO,IAAI;AAAA,QACb,MAAM,UAAU,QAAQ,OAAO;AAAA,MACjC,EAAO;AAAA,QACL,QAAQ;AAAA;AAAA;AAAA,EAGd;AAAA,EACA,OAAO,EAAE,OAAO,MAAM;AAAA;AAMxB,IAAM,aAAa,CAAC,SAClB,OAAO,KAAK,UAAU,OAAO,WAAW,YACxC,OAAO,KAAK,UAAU,KAAK,WAAW;AAGxC,IAAM,eAAe,CAAC,MAAc,YAA8B;AAAA,EAChE,IAAI,SAAS;AAAA,EACb,WAAW,UAAU,CAAC,GAAG,OAAO,EAAE,SAAS,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,GAAG;AAAA,IAIvE,MAAM,YAAY,OAAO,YAAY;AAAA,GAAM,OAAO,QAAQ,CAAC,IAAI;AAAA,IAC/D,MAAM,SAAS,OAAO,MAAM,WAAW,OAAO,KAAK;AAAA,IACnD,MAAM,SAAS,YAAY,KAAK,MAAM,IAAI,SAAS;AAAA,IACnD,MAAM,cAAc,SAChB,OAAO,KACJ,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,MAAM,UACV,UAAU,KAAK,SAAS,KAAK,OAAO,GAAG,SAAS,MAClD,EACC,KAAK;AAAA,CAAI,IACZ,OAAO;AAAA,IACX,SACE,OAAO,MAAM,GAAG,OAAO,KAAK,IAAI,cAAc,OAAO,MAAM,OAAO,GAAG;AAAA,EACzE;AAAA,EACA,OAAO;AAAA;AAaT,IAAM,SAAS,CAAC,MAAc,gBAAiC;AAAA,EAC7D,MAAM,QAAQ,KAAK,MAAM;AAAA,CAAI;AAAA,EAC7B,MAAM,OAAO,MAAM,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,KAAK,KAAK,MAAM,EAAE;AAAA,EAC/D,IAAI,KAAK,WAAW,GAAG;AAAA,IACrB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS,KAAK,IAClB,GAAG,KAAK,IAAI,CAAC,SAAS,KAAK,SAAS,KAAK,UAAU,EAAE,MAAM,GAC3D,GAAI,gBAAgB,YAAY,CAAC,IAAI,CAAC,WAAW,CACnD;AAAA,EACA,IAAI,WAAW,GAAG;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAG,MACA,MAAM,CAAC,EACP,IAAI,CAAC,SAAU,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,MAAM,CAAE;AAAA,EACjE,EAAE,KAAK;AAAA,CAAI;AAAA;AAOb,IAAM,WAAW,CAAC,QAAgB,WAAuC;AAAA,EACvE,MAAM,YAAY,OAAO,YAAY;AAAA,GAAM,SAAS,CAAC,IAAI;AAAA,EACzD,MAAM,SAAS,OAAO,MAAM,WAAW,MAAM;AAAA,EAC7C,OAAO,YAAY,KAAK,MAAM,IAAI,OAAO,SAAS;AAAA;AAGpD,IAAM,eAAe,CAAC,SACpB,KAAK,SAAS,uBAAuB,KAAK,SAAS;AAGrD,IAAM,WAAW,CAAC,UAChB,OAAO,SAAS,EAAE,EACf,WAAW,cAAc,GAAG,EAC5B,WAAW,KAAK,KAAK,EACrB,KAAK;AAGV,IAAM,WAAW,CAAC,UAAkC;AAAA,EAClD,MAAM,OAAO,SAAS,KAAK;AAAA,EAC3B,OAAO,QAAQ,CAAC,KAAK,SAAS,GAAG,IAAI,KAAK,WAAW;AAAA;AAsBvD,IAAM,iBAAiB,CACrB,UAEA,OAAO,UAAU,YAAY,UAAU;AAEzC,IAAM,YAA+B,GAAG,UAAU,YAAY;AAAA,EAC5D,QAAQ,SAAS;AAAA,EACjB,IAAI,CAAC,eAAe,IAAI,GAAG;AAAA,IAEzB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,UAAU,OAAO,QAAQ,IAAI;AAAA,EACnC,MAAM,OAAO,QAAQ,IAAI,EAAE,MAAM,UAAU;AAAA,IACzC,MAAM,OAAO,SAAS,GAAG,OAAO,KAAK,WAAW,KAAK,KAAK;AAAA,IAC1D,MAAM,WAAW,KAAK,sBAClB,IAAI,SAAS,KAAK,IAAI,MAAM,SAAS,KAAK,mBAAmB,OAC7D,SAAS,KAAK,IAAI;AAAA,IACtB,MAAM,cACJ,KAAK,YAAY,YAAY,MAAM,SAAS,KAAK,OAAO;AAAA,IAC1D,MAAM,cAAc,SAClB,CAAC,KAAK,aAAa,KAAK,eAAe,EACpC,OAAO,CAAC,SAAS,UAAS,IAAI,KAAK,SAAS,EAAE,EAC9C,KAAK,GAAG,CACb;AAAA,IACA,OAAO,CAAC,MAAM,UAAU,aAAa,WAAW;AAAA,GACjD;AAAA,EACD,MAAM,QACJ,KAAK,SAAS,IACV,cAAc,CAAC,CAAC,QAAQ,QAAQ,WAAW,aAAa,GAAG,GAAG,IAAI,GAAG;AAAA,IAGnE,iBAAiB;AAAA,EACnB,CAAC,IACD;AAAA,EAEN,OAAO,CAAC,OAAO,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA;AAGtD,IAAM,UAA6B,GAAG,UAAU,YAAY;AAAA,EAC1D,MAAM,OAAO,UAAS,MAAM,IAAI,IAAI,MAAM,OAAO;AAAA,EACjD,MAAM,QACJ,UAAS,MAAM,KAAK,KAAK,MAAM,UAAU,KACrC,MAAM,QACN,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;AAAA,EACjD,IAAI,CAAC,UAAU;AAAA,IACb,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,MAAM,OAAO,SACV,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,SAAU,KAAK,KAAK,MAAM,KAAK,MAAM,KAAK,MAAO,EACtD,KAAK;AAAA,CAAI;AAAA,EACZ,OAAO,OAAO;AAAA;AAAA,EAAe;AAAA;AAI/B,IAAM,YAAW,CAAC,OAAe,YAA4B;AAAA,EAC3D,MAAM,SAAS,GAAG;AAAA,EAClB,OAAO,QACJ,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,MAAM,cAAc;AAAA,IACxB,IAAI,cAAc,GAAG;AAAA,MACnB,OAAO,GAAG,SAAS;AAAA,IACrB;AAAA,IACA,OAAO,SAAS,KAAK,KAAK,OAAO;AAAA,GAClC,EACA,KAAK;AAAA,CAAI;AAAA;AAGd,IAAM,QAA2B,GAAG,iBAAiB,eAAe;AAAA,EAClE,MAAM,QAAQ,gBAAgB,MAAM;AAAA,EACpC,IAAI,MAAM,WAAW,GAAG;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,MACJ,IAAI,CAAC,MAAM,UAAU;AAAA,IACpB,MAAM,QACJ,UAAS,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,UAAU,KAC/C,KAAK,KAAK,MAAM,YAChB;AAAA,IACN,MAAM,UAAU,CAAC,OAAO,KAAK,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA,IAClE,OAAO,UAAS,QAAQ,GAAG,OAAO;AAAA,GACnC,EACA,KAAK;AAAA;AAAA,CAAM;AAAA;AAGhB,IAAM,OAA0B,GAAG,iBAAiB,eAAe;AAAA,EACjE,MAAM,QAAQ,gBAAgB,KAAK;AAAA,EACnC,IAAI,MAAM,WAAW,GAAG;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,MACJ,IAAI,CAAC,KAAK,UAAU;AAAA,IACnB,MAAM,QACJ,UAAS,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,UAAU,KAC7C,IAAI,MAAM,QACV,OAAO,QAAQ;AAAA,IACrB,OAAO,IAAI,WAAW,KAAK;AAAA;AAAA,EAAc,IAAI,aAAa,KAAK;AAAA,GAChE,EACA,KAAK;AAAA;AAAA,CAAM;AAAA;AAIhB,IAAM,WAAW,CAAC,UAChB,MAAM,WAAW,WAAW,OAAO,QAAQ;AAOtC,IAAM,kBAAkB,CAAC,SAC9B,YAAY,KAAK,IAAI,IACjB,IAAI,KAAK,WAAW,UAAU,OAAO,QAAQ,OAC7C;AAGN,IAAM,WAAW,CAAC,UAAkC;AAAA,EAClD,IAAI,UAAS,KAAK,GAAG;AAAA,IACnB,OAAO,MAAM,KAAK;AAAA,EACpB;AAAA,EACA,OAAO,SAAS,KAAK,IAAI,OAAO,KAAK,IAAI;AAAA;AAgB3C,IAAM,OAA0B,GAAG,UAAU,OAAO,YAAY;AAAA,EAC9D,IAAI,OAAO;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,SAAS,MAAM,KAAK;AAAA,EAClC,MAAM,OAAO,UAAS,MAAM,IAAI,IAAI,MAAM,KAAK,KAAK,IAAI;AAAA,EACxD,MAAM,OAAO,SAAS,KAAK;AAAA,EAC3B,MAAM,MAAM,SAAS,MAAM,GAAG;AAAA,EAC9B,MAAM,QAAQ,SAAS;AAAA,EACvB,IAAI,UAAU,IAAI;AAAA,IAEhB,MAAM,OAAO,CAAC,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA,IAEpD,OAAO,SAAS,KAAK,OAAO;AAAA,EAC9B;AAAA,EACA,MAAM,OACJ,SAAS,KACL,KAAK,YACL,MAAM,SAAS,KAAK,MAAM,gBAAgB,IAAI;AAAA,EACpD,OAAO,CAAC,MAAM,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA;AAkBtD,IAAM,YAA+B,GAAG,kBACtC,YAAY,EACT,IAAI,CAAC,UAAU,MAAM,QAAQ,EAC7B,OAAO,OAAO,EACd,KAAK;AAAA;AAAA,CAAM;AAEhB,IAAM,UAA6B,GAAG,YAAY;AAAA,EAChD,IAAI,QAAQ;AAAA,EACZ,IAAI,UAAS,MAAM,EAAE,GAAG;AAAA,IACtB,QAAQ,MAAM;AAAA,EAChB,EAAO,SAAI,UAAS,MAAM,GAAG,GAAG;AAAA,IAC9B,QAAQ,MAAM;AAAA,EAChB;AAAA,EACA,MAAM,UAAU,eAAe,KAAK;AAAA,EACpC,IAAI,CAAC,SAAS;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QACJ,SAAS,MAAM,KAAK,KAAK,MAAM,QAAQ,IACnC,MAAM,KAAK,MAAM,MAAM,KAAK,OAC5B;AAAA,EACN,MAAM,QACJ,UAAS,MAAM,KAAK,KAAK,MAAM,UAAU,KACrC,MAAM,QACN;AAAA,EACN,OAAO,IAAI,0CAA0C,UAAU;AAAA;AAS1D,IAAM,aAAa,CAAC,SAAyB;AAAA,EAClD,MAAM,OAAO,KAAK,MAAM,MAAM;AAAA,EAC9B,MAAM,UAAU,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI;AAAA,EACpE,MAAM,YAAY,IAAI,OAAO,UAAU,CAAC;AAAA,EACxC,MAAM,SACJ,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,IAAI,IAAI,UAAU;AAAA,EAC7D,OAAO,GAAG,YAAY,SAAS;AAAA;AAIjC,IAAM,cAAc,CAAC,MAAc,SAAyB;AAAA,EAC1D,MAAM,UAAU,KAAK,QAAQ,gBAAgB,EAAE;AAAA,EAC/C,MAAM,OAAO,QAAQ,MAAM,MAAM;AAAA,EACjC,MAAM,UAAU,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI;AAAA,EACpE,MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI,GAAG,UAAU,CAAC,CAAC;AAAA,EACjD,OAAO,GAAG,QAAQ;AAAA,EAAS;AAAA,EAAY;AAAA;AAWlC,IAAM,8BAA8B,CAAC,cACzC;AAAA,EACC,WAAW,GAAG,YAAY;AAAA,IACxB,MAAM,OAAO,UAAS,MAAM,IAAI,IAAI,MAAM,OAAO;AAAA,IACjD,MAAM,UAAU,SAAS,YAAY,YAAY,SAAS;AAAA,IAC1D,OAAO,UAAU,YAAY,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAAA;AAEjE;AAGF,IAAM,UAAU,CAAC,UAAkB,UACjC,CAAC,UAAU,KAAK,KAAK,KAAK,WAAW,GAAG,KAAK,EAC1C,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO,EACd,KAAK;AAAA;AAAA,CAAM;AAOhB,IAAM,aAAa,GACf,UAAU,OAAO,SACnB,kBAEA,QACI,OACA,QACE,SAAS,MAAM,KAAK,KAAK,eACzB,SAAS,MAAM,WAAW,GAC1B,QACF;AAEN,IAAM,gBAAmC,CAAC,YAAY,WAAW,SAAS,EAAE;AAE5E,IAAM,aAAgC,CAAC,YACrC,WAAW,SAAS,WAAW;AAGjC,IAAM,QAA2B,GAAG,UAAU,YAC5C,CAAC,SAAS,MAAM,IAAI,GAAG,UAAU,SAAS,MAAM,OAAO,CAAC,EACrD,OAAO,OAAO,EACd,KAAK;AAAA;AAAA,CAAM;AAGhB,IAAM,OAA0B,GAAG,eAAe;AAGlD,IAAM,QAA2B,GAAG,UAAU,YAC5C,QAAQ,SAAS,MAAM,KAAK,GAAG,QAAQ;AAMzC,IAAM,OAA0B,GAAG,UAAU,OAAO,YAAY;AAAA,EAC9D,IAAI,OAAO;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,SAAS,MAAM,KAAK;AAAA,EAClC,MAAM,OAAO,UAAS,MAAM,IAAI,IAAI,MAAM,KAAK,KAAK,IAAI;AAAA,EACxD,MAAM,QAAQ,SAAS;AAAA,EACvB,MAAM,OACJ,SAAS,KACL,QAAQ,KAAK,IACb,MAAM,SAAS,KAAK,MAAM,gBAAgB,IAAI;AAAA,EACpD,MAAM,OAAO,CAAC,MAAM,SAAS,MAAM,WAAW,GAAG,QAAQ,EACtD,OAAO,OAAO,EACd,KAAK;AAAA;AAAA,CAAM;AAAA,EACd,OAAO,SAAS,KAAK,OAAO;AAAA;AAO9B,IAAM,SAA4B,GAAG,UAAU,OAAO,YAAY;AAAA,EAChE,IAAI,OAAO;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,SAAS,MAAM,KAAK,KAAK,SAAS,MAAM,KAAK,KAAK;AAAA,EAChE,MAAM,OAAO,UAAS,MAAM,IAAI,IAAI,MAAM,KAAK,KAAK,IAAI;AAAA,EACxD,MAAM,OACJ,SAAS,KACL,KAAK,YACL,MAAM,SAAS,KAAK,MAAM,gBAAgB,IAAI;AAAA,EACpD,MAAM,QAAQ,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,OAAO,CAAC,MAAM,IAAI,GAC/D,IAAI,QAAQ,EACZ,OAAO,OAAO;AAAA,EACjB,OAAO;AAAA,IACL;AAAA,IACA,SAAS,MAAM,WAAW;AAAA,IAC1B,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK,IAAI,MAAM;AAAA,IAC/C;AAAA,EACF,EACG,OAAO,OAAO,EACd,KAAK;AAAA;AAAA,CAAM;AAAA;AAOhB,IAAM,SAA4B,GAAG,UAAU,YAAY;AAAA,EACzD,MAAM,SAAS,SACZ,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,SAAU,KAAK,KAAK,MAAM,KAAK,MAAM,KAAK,MAAO,EACtD,KAAK;AAAA,CAAI;AAAA,EACZ,OAAO,QACL,SAAS,MAAM,WAAW,KAAK,UAC/B,WAAW,SAAS,EACtB;AAAA;AAQF,IAAM,aAAgC,GAAG,OAAO,YAAY;AAAA,EAC1D,MAAM,QAAQ,SAAS,MAAM,KAAK;AAAA,EAClC,MAAM,OAAO,SAAS,MAAM,IAAI;AAAA,EAChC,IAAI,SAAS,UAAU,MAAM,SAAS,IAAI;AAAA,IACxC,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,SAAS,MAAM,IAAI,KAAK,sBAAsB,QAC1D,SACA,EACF;AAAA,EACA,OAAO,IAAI,SAAS,GAAG,SAAS,MAAM,MAAM,gBAAgB,GAAG,QAAQ,SAAS,MAAM;AAAA;AAIxF,IAAM,YAA+B,GAAG,OAAO,YAAY;AAAA,EACzD,IAAI,SAAS,CAAC,UAAS,MAAM,IAAI,GAAG;AAAA,IAClC,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,SAAS,MAAM,IAAI,KAAK;AAAA,EACrC,MAAM,QAAQ,SAAS,MAAM,KAAK;AAAA,EAClC,OAAO,YACL,UAAU,KAAK,OAAO,GAAG,cAAc,KAAK,UAAU,KAAK,KAC3D,MAAM,IACR;AAAA;AAQF,IAAM,OAA0B,GAAG,OAAO,YAAY;AAAA,EACpD,IAAI,OAAO;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,IAAI,UAAS,MAAM,KAAK,GAAG;AAAA,IACzB,OAAO,YAAY,QAAQ,MAAM,KAAK;AAAA,EACxC;AAAA,EACA,IAAI,UAAS,MAAM,GAAG,KAAK,UAAS,MAAM,GAAG,GAAG;AAAA,IAC9C,MAAM,OAAO,SAAS,MAAM,IAAI;AAAA,IAChC,OAAO;AAAA,MACL,QAAQ,UAAU,YAAY,MAAM,MAAM,GAAG,CAAC;AAAA,MAC9C,QAAQ,SAAS,YAAY,MAAM,MAAM,GAAG,CAAC;AAAA,IAC/C,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA,EACf;AAAA,EACA,OAAO;AAAA;AAIT,IAAM,OAA0B,GAAG,OAAO,YAAY;AAAA,EACpD,IAAI,SAAS,CAAC,UAAS,MAAM,IAAI,GAAG;AAAA,IAClC,OAAO;AAAA,EACT;AAAA,EACA,OAAO,MAAM,YAAY,OAAO;AAAA,EAAO,MAAM;AAAA,MAAa,IAAI,MAAM;AAAA;AAItE,IAAM,OAA0B,GAAG,YAAY,SAAS,MAAM,KAAK;AAGnE,IAAM,QAA2B,GAAG,eAAe;AAMnD,IAAM,UAA6B,GAAG,UAAU,OAAO,YAAY;AAAA,EACjE,MAAM,MAAM,CAAC,SAAS,MAAM,QAAQ,GAAG,SAAS,MAAM,GAAG,CAAC,EACvD,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,EACZ,IAAI,SAAS,QAAQ,IAAI;AAAA,IACvB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,WAAW,GAAG,aAAa,SAAS;AAAA;AAI7C,IAAM,SAAS,CAAC,UACd,MACG,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,SAAU,SAAS,KAAK,OAAO,KAAK,MAAO,EAChD,KAAK;AAAA,CAAI;AAMd,IAAM,WAA8B,GAAG,kBACrC,YAAY,EACT,IAAI,CAAC,UAAU,MAAM,QAAQ,EAC7B,KAAK;AAAA,CAAI;AAEd,IAAM,aAAgC,GAAG,aAAa,OAAO,YAAY;AAAA,EACvE,MAAM,OAAO,SAAS,MAAM,IAAI;AAAA,EAChC,IAAI,SAAS,SAAS,IAAI;AAAA,IACxB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,UAAU,YAAY,EACzB,IAAI,CAAC,UAAU,OAAO,MAAM,QAAQ,CAAC,EACrC,KAAK;AAAA,CAAI;AAAA,EACZ,OAAO,YAAY,KAAK,KAAK,UAAU,KAAK;AAAA,EAAU;AAAA;AAGxD,IAAM,WAA8B,GAAG,OAAO,YAAY;AAAA,EACxD,MAAM,OAAO,SAAS,MAAM,IAAI;AAAA,EAChC,OAAO,SAAS,SAAS,KAAK,OAAO,KAAK;AAAA;AAO5C,IAAM,YAA+B,GAAG,OAAO,YAAY;AAAA,EACzD,MAAM,OAAO,SAAS,MAAM,IAAI;AAAA,EAChC,QAAQ,UAAU;AAAA,EAClB,IAAI,SAAS,SAAS,IAAI;AAAA,IACxB,OAAO;AAAA,EACT;AAAA,EACA,IAAI,UAAS,KAAK,GAAG;AAAA,IACnB,OAAO,OAAO,WAAW,WAAW,KAAK;AAAA,EAC3C;AAAA,EACA,IAAI,CAAC,WAAW,KAAK,GAAG;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,SAAS,MAAM,KAAK;AAAA,EAClC,MAAM,OAAO,SAAS,MAAM,IAAI;AAAA,EAChC,IAAI,UAAU,MAAM,SAAS,IAAI;AAAA,IAC/B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QACJ,SAAS,QAAQ,UAAU,OACvB,GAAG,WAAW,KAAK,cAAc,WAAW,IAAI,aAChD,WAAW,SAAS,IAAI;AAAA,EAC9B,OAAO,OAAO,WAAW;AAAA;AAG3B,IAAM,WAA8B,GAAG,aAAa,YAClD,QACE,SAAS,MAAM,KAAK,GACpB,YAAY,EACT,IAAI,CAAC,UAAU,MAAM,QAAQ,EAC7B,KAAK;AAAA,CAAI,CACd;AASF,IAAM,cAAc;AAAA,EAClB,WAAW;AAAA,EACX,eAAe;AAAA,EACf,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AAAA,EACP,cAAc;AAAA,EACd,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,aAAa;AAAA,EACb,eAAe;AAAA,EACf,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,SAAS;AACX;AAMA,IAAM,oBAAoB,IAAI,IAAI,CAAC,SAAS,QAAQ,QAAQ,SAAS,CAAC;AAEtE,IAAM,eAAe,CAAC,UACpB,MAAM,WAAW,wBAAwB,OAAO,QAAQ;AAK1D,IAAM,gBAAgB,CAAC,aACrB,IAAI,OACF,OAAO,OAAO,KAAK,QAAQ,EAAE,IAAI,YAAY,EAAE,KAAK,GAAG,aACvD,GACF;AAEF,IAAM,gBAAgB,cAAc,WAAW;AAYxC,IAAM,oBAAoB,CAC/B,eAEA,cAAc,OAAO,KAAK,UAAU,EAAE,SAAS,IAC3C,KAAK,gBAAgB,WAAW,IAChC;AAQN,IAAM,cAAc,CAClB,MACA,OACA,KACA,UACW;AAAA,EACX,MAAM,UAAoB,CAAC;AAAA,EAE3B,eAAe,MAAM,OAAO,OAAO;AAAA,EACnC,MAAM,UAAU,aACd,KAAK,OAAO,MAAM,OAAO,GAAG,GAC5B,QAAQ,IAAI,CAAC,YAAY;AAAA,OACpB;AAAA,IACH,KAAK,OAAO,MAAM;AAAA,IAClB,OAAO,OAAO,QAAQ;AAAA,EACxB,EAAE,CACJ;AAAA,EACA,OAAO,OAAO,SAAS,SAAS,KAAK,QAAQ,KAAK,CAAC,EAAE,KAAK;AAAA;AAI5D,IAAM,iBAAiB,CAAC,MAAY,SAA4B;AAAA,EAC9D,MAAM,YAAY,KAAK,YAAY,CAAC,GAAG,OAAO,UAAU;AAAA,EACxD,OAAO,SAAS;AAAA,EAChB,IAAI,CAAC,OAAO;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,EACnC,OAAO,YACL,MACA,OACA,SAAS,GAAG,EAAE,GAAG,SAAS,IAAI,UAAU,OACxC,QACF;AAAA;AAQF,IAAM,cAAc,CAAC,MAAY,SAA6B;AAAA,EAC5D,MAAM,aACJ,aAAa,IAAI,KAAK,KAAK,OAAO,KAAK,SAAS,KAAK,QAAQ;AAAA,EAC/D,MAAM,OAAO,aAET,iBAAiB,YAAY,MAAM,IAAI,IACvC;AAAA,EACJ,OACE,QACA,YACE,MACA,KAAK,SAAS,MAAM,QACpB,KAAK,SAAS,IAAI,QAClB,KAAK,YAAY,CAAC,CACpB;AAAA;AAKJ,IAAM,mBAAmB,CACvB,YACA,MACA,SAEA,WAAW;AAAA,KACN,UAAU,MAAM,KAAK,WAAW;AAAA,EACnC,aAAa,OACV,KAAK,YAAY,CAAC,GAAG,OAAO,UAAU,EAAE,IAAI,CAAC,WAAW;AAAA,IACvD,UAAU,YAAY,MAAM,KAAK;AAAA,IACjC,MAAM,aAAa,KAAK,IAAI,MAAM,OAAO;AAAA,EAC3C,EAAE;AAAA,EACJ,iBAAiB,CAAC,UACf,KAAK,YAAY,CAAC,GAChB,OAAO,CAAC,UAAU,aAAa,KAAK,KAAK,MAAM,SAAS,IAAI,EAC5D,IAAI,CAAC,WAAW;AAAA,OACZ,UAAU,OAAO,KAAK,WAAW;AAAA,IACpC,UAAU,eAAe,MAAM,KAAK;AAAA,EACtC,EAAE;AAAA,EACN,UAAU,eAAe,MAAM,IAAI;AAAA,EACnC,aAAa,KAAK,eAAe,CAAC;AACpC,CAAC;AAaI,IAAM,yBAAyB,CACpC,MACA,SACkB;AAAA,EAClB,MAAM,QACJ,KAAK,SAAS,uBACb,KAAK,SAAS,uBACb,kBAAkB,IAAI,KAAK,QAAQ,EAAE;AAAA,EACzC,MAAM,aAAa,SAAS,KAAK,OAAO,KAAK,SAAS,KAAK,QAAQ;AAAA,EACnE,OAAO,cAAc,WAAW,IAAI,IAChC,iBAAiB,YAAY,MAAM,IAAI,IACvC;AAAA;AAGN,IAAM,iBAAiB,CACrB,MACA,OACA,QACS;AAAA,EACT,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,OAAO,WAAW,IAAI,IAAI,uBAAuB,MAAM,IAAI,IAAI;AAAA,IACrE,IAAI,SAAS,QAAQ,WAAW,IAAI,GAAG;AAAA,MACrC,IAAI,KAAK;AAAA,QACP,KAAK,KAAK,SAAS,IAAI;AAAA,QACvB,OAAO,KAAK,SAAS,MAAM;AAAA,QAC3B;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IACA,eAAe,MAAM,KAAK,YAAY,CAAC,GAAG,GAAG;AAAA,EAC/C;AAAA;AAiBK,IAAM,sBAAsB,CACjC,QACA,YACA,gBACW;AAAA,EACX,MAAM,WAAW,kBAAkB,UAAU;AAAA,EAC7C,MAAM,OACJ,aAAa,cAAc,gBAAgB,cAAc,QAAQ;AAAA,EACnE,IAAI,CAAC,KAAK,KAAK,MAAM,GAAG;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EACA,IAAI;AAAA,EACJ,IAAI;AAAA,IAGF,OAAO,WAAW,QAAQ,EAAE,UAAU,aAAa,CAAC;AAAA,IACpD,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,EAET,MAAM,UAAoB,CAAC;AAAA,EAC3B,eACE,EAAE,aAAa,UAAU,OAAO,GAChC,KAAK,YAAY,CAAC,GAClB,OACF;AAAA,EACA,OAAO,QAAQ,SAAS,IAAI,aAAa,QAAQ,OAAO,IAAI;AAAA;;;AGrhC9D,mBAAS;AA+BT,IAAM,aAAa,CAAC,UAClB,MAAM,OAAO,CAAC,EAAE,YAAY,IAAI,MAAM,MAAM,CAAC;AAG/C,IAAM,WAAW,CAAC,SAAuC;AAAA,EACvD,MAAM,MAAM,KAAK,KAAK,QAAQ,KAAK,KAAK,WAAW;AAAA,EACnD,IAAI,CAAC,KAAK;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,OAAO,IAAI,KAAK,GAAG;AAAA,EACzB,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,YAAY;AAAA;AAQ7C,IAAM,gBAAgB,CAAC,YAAqC;AAAA,EACjE,QAAQ,WAAW;AAAA,EACnB,QAAQ,QAAQ,OAAO;AAAA,EACvB,QAAQ,SAAS,OAAO,WAAW;AAAA,EACnC,IAAI,EAAE,IAAI,WAAW,OAAO;AAAA,IAC1B,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,OAAO,SAAS,IAAI;AAAA,EAI1B,MAAM,aAAa,kBAAkB,OAAO,WAAW,QAAQ,IAAI;AAAA,EACnE,MAAM,WAAW,GAAG,OAAO;AAAA,EAE3B,MAAM,QAAmB,CAAC;AAAA,EAC1B,WAAW,QAAQ,IAAI,OAAO;AAAA,IAC5B,MAAM,QAAQ,QAAQ,MAAM,MAAM,OAChC,CAAC,SACC,KAAK,gBAAgB,QACrB,EAAE,KAAK,KAAK,SAAS,KAAK,KAAK,QAAQ,OAC3C;AAAA,IACA,IAAI,MAAM,WAAW,GAAG;AAAA,MACtB;AAAA,IACF;AAAA,IAEA,MAAM,QAAmB,MACtB,IAAI,CAAC,UAAU;AAAA,MACd,MAAM,SAAS,IAAI;AAAA,MACnB,aAAa,KAAK;AAAA,MAGlB,MAAM,UAAU,GAAG,OAAO,aAAa,YAAY,KAAK,KAAK,GAAG;AAAA,MAChE,OAAO,KAAK;AAAA,IACd,EAAE,EACD,SAAS,CAAC,GAAG,OAAO,EAAE,MAAM,QAAQ,KAAK,MAAM,EAAE,MAAM,QAAQ,KAAK,EAAE,EACtE,MAAM,GAAG,IAAI,KAAK;AAAA,IAErB,MAAM,KAAK;AAAA,MACT,aAAa,OAAO;AAAA,MACpB;AAAA,MACA,MAAM;AAAA,MACN,MAAM,IAAI;AAAA,MACV,OAAO,GAAG,OAAO,WAAW,WAAW,IAAI;AAAA,MAC3C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,aAAa,CAAC,SAA0B;AAAA,EAC5C,MAAM,QAAQ;AAAA,IACZ,cAAc,UAAU,KAAK,KAAK;AAAA,IAClC,aAAa,UAAU,KAAK,IAAI;AAAA,IAChC,gCAAgC,UAAU,KAAK,IAAI;AAAA,EACrD;AAAA,EACA,IAAI,KAAK,aAAa;AAAA,IACpB,MAAM,KAAK,oBAAoB,UAAU,KAAK,WAAW,iBAAiB;AAAA,EAC5E;AAAA,EACA,IAAI,KAAK,MAAM;AAAA,IACb,MAAM,KAAK,gBAAgB,KAAK,KAAK,YAAY,aAAa;AAAA,EAChE;AAAA,EACA,OAAO;AAAA,EAAa,MAAM,KAAK;AAAA,CAAI;AAAA;AAAA;AAI9B,IAAM,gBAAgB,CAAC,SAA0B;AAAA,EACtD,MAAM,eAAe,GAAG,KAAK,OAAO,KAAK;AAAA,EACzC,MAAM,UAAU;AAAA,IACd,YAAY,UAAU,KAAK,KAAK;AAAA,IAChC,WAAW,UAAU,KAAK,IAAI;AAAA,IAC9B,kBAAkB,UAAU,KAAK,eAAe,KAAK,KAAK;AAAA,IAC1D,sBAAsB,UAAU,YAAY;AAAA,EAC9C;AAAA,EACA,MAAM,QAAQ,KAAK,MAAM,IAAI,UAAU,EAAE,KAAK;AAAA,CAAI;AAAA,EAClD,OAAO;AAAA;AAAA;AAAA,EAGP,QAAQ,KAAK;AAAA,CAAI;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;;;ACjIF,qBAAS;AAqCT,IAAM,aACJ;AAQF,IAAM,iBACJ;AASF,IAAM,aAAa,CAAC,MAAc,YAAuC;AAAA,EACvE,IAAI,MAAM;AAAA,EACV,WAAW,UAAU,QAAQ,SAAS,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG;AAAA,IACpE,MACE,IAAI,MAAM,GAAG,OAAO,MAAM,IAC1B,OAAO,OACP,IAAI,MAAM,OAAO,SAAS,OAAO,MAAM;AAAA,EAC3C;AAAA,EACA,OAAO;AAAA;AAIT,IAAM,mBAAmB,CACvB,MACA,WACuB;AAAA,EACvB,MAAM,SAAS,WAAW,KAAK,IAAI,GAAG;AAAA,EACtC,MAAM,OAAO,QAAQ;AAAA,EACrB,MAAM,SAAS,QAAQ,UAAU,QAAQ;AAAA,EACzC,MAAM,QAAQ,WAAW,YAAY,YAAY,OAAO,MAAM;AAAA,EAC9D,IAAI,SAAS,aAAa,WAAW,aAAa,UAAU,WAAW;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,EAClD,OAAO,EAAE,QAAQ,KAAK,SAAS,QAAQ,QAAQ,OAAO,QAAQ,MAAM,MAAM;AAAA;AAI5E,IAAM,kBAAiB,CACrB,MACA,OACA,WAC0B;AAAA,EAC1B,MAAM,UAAU,IAAI;AAAA,EACpB,MAAM,MAAM,CAAC,OAAe,WAAyB;AAAA,IACnD,QAAQ,IAAI,OAAO,CAAC,GAAI,QAAQ,IAAI,KAAK,KAAK,CAAC,GAAI,MAAM,CAAC;AAAA;AAAA,EAE5D,WAAW,QAAQ,aAAa,IAAI,GAAG;AAAA,IACrC,MAAM,QAAQ,KAAK,QAAQ,YAAY,OAAO,KAAK,MAAM;AAAA,IACzD,IAAI,UAAU,WAAW;AAAA,MACvB,IAAI,KAAK,OAAO,GAAG;AAAA,QACjB,QAAQ,KAAK,SAAS;AAAA,QACtB,QAAQ,KAAK,OAAO;AAAA,QACpB,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,IAAI,QAAoB;AAAA,EACxB,YAAY,OAAO,SAAS,MAAM,QAAQ,GAAG;AAAA,IAC3C,MAAM,OAAO,eAAe,MAAM,KAAK;AAAA,IACvC,MAAM,UAAU,UAAU,QAAQ,SAAS;AAAA,IAC3C,QAAQ;AAAA,IACR,MAAM,SAAS,UAAU,YAAY,iBAAiB,MAAM,MAAM;AAAA,IAClE,IAAI,WAAW,WAAW;AAAA,MACxB,IAAI,OAAO,MAAM;AAAA,IACnB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AASF,IAAM,uBAAuB,CAClC,YACyB;AAAA,EACzB,QAAQ,YAAY,SAAS,QAAQ;AAAA,EACrC,MAAM,aAAa,kBAAkB,WAAW,QAAQ,IAAI;AAAA,EAC5D,MAAM,eAAe,OACjB,CAAC,KAAK,GAAG,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI,CAAC,IAClD,CAAC;AAAA,EACL,MAAM,aAAa,oBAAoB,QAAQ,MAAM,OAAO,QAAQ,IAAI;AAAA,EACxE,MAAM,kBAAkB,IAAI,IAC1B,QAAQ,MAAM,MAAM,IAAI,CAAC,cAAc;AAAA,IACrC,UAAU;AAAA,IACV,UAAU;AAAA,EACZ,CAAC,CACH;AAAA,EACA,MAAM,SAAS,IAAI,IAAI,QAAQ,SAAS,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AAAA,EAEzE,OAAO,CAAC,MAAM,SAAS;AAAA,IACrB,QAAQ,eAAe;AAAA,IACvB,IAAI,CAAC,cAAc,CAAC,eAAe,KAAK,IAAI,GAAG;AAAA,MAC7C,OAAO;AAAA,IACT;AAAA,IACA,MAAM,OAAyB;AAAA,MAC7B,SAAS,gBAAgB,UAAS,UAAU,GAAG,YAAY;AAAA,MAC3D,OAAO,KAAK;AAAA,IACd;AAAA,IACA,MAAM,UAAU,gBAAgB,IAAI,UAAU,KAAK,UAAS,UAAU;AAAA,IACtE,MAAM,cAAc,CAAC,SACnB,kBAAkB,YAAY,EAAE,SAAS,WAAW,GAAG,IAAI;AAAA,IAC7D,MAAM,SAAS,CAAC,WAAuC;AAAA,MACrD,MAAM,QAAQ,oBAAoB,QAAQ,MAAM,aAAa,CAAC,SAC5D,OAAO,IAAI,IAAI,CACjB;AAAA,MACA,OAAO,UAAU,YAAY,YAAY,aAAa,YAAY,KAAK;AAAA;AAAA,IAGzE,MAAM,QAAQ,KAAK,MAAM;AAAA,CAAI;AAAA,IAC7B,MAAM,UAAU,gBAAe,MAAM,OAAO,MAAM;AAAA,IAElD,OAAO,MACJ,IAAI,CAAC,MAAM,UAAU;AAAA,MACpB,MAAM,cAAc,QAAQ,IAAI,KAAK;AAAA,MACrC,OAAO,cAAc,WAAW,MAAM,WAAW,IAAI;AAAA,KACtD,EACA,KAAK;AAAA,CAAI;AAAA;AAAA;;;AC3IT,IAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKA,IAAM,WAAW;AAGjB,IAAM,gBAAgB;AAEtB,IAAM,mBAAmB;AAWzB,IAAM,kBAAkB,CAAC,eACvB,WACG,QAAQ,eAAe,sBAAsB,EAC7C,QAAQ,kBAAkB,oBAAoB;AAG5C,IAAM,eAAe,CAC1B,QACA,MACA,gBACW;AAAA,EACX,MAAM,SAAS,cAAc,SAAQ,gBAAgB,WAAW,CAAC,IAAI;AAAA,EACrE,OAAO,UAAU,SAAQ,GAAG,UAAU,MAAM;AAAA;AAmFvC,IAAM,SAAS,CACpB,OACA,WAEA,OAAO,OAAO,OAAO,MAAM,IAAI,MAAM,UAAU;AAG1C,IAAM,cAAc,CACzB,MACA,OAEA,OAAO,OAAO,KAAK,YAAY,EAAE,IAAI,KAAK,WAAW,MAAM;AAetD,IAAM,gBAAgB,CAAC,SAAqC;AAAA,EACjE,MAAM,YAAsB,CAAC;AAAA,EAC7B,IAAI,KAAK,SAAS,WAAW;AAAA,IAC3B,IAAI,KAAK,UAAU;AAAA,MACjB,UAAU,KAAK,KAAK,QAAQ;AAAA,IAC9B;AAAA,IACA,OAAO,EAAE,WAAW,OAAO,WAAW;AAAA,EACxC;AAAA,EACA,IAAI,KAAK,SAAS,YAAY;AAAA,IAG5B,MAAM,UAAW,KAAK,SAA8B,WAAW,CAAC;AAAA,IAChE,WAAW,UAAU,OAAO,OAAO,OAAO,GAAG;AAAA,MAC3C,IAAI,QAAQ,MAAM;AAAA,QAChB,UAAU,KACR,GAAG,OAAO,WAAW,GAAG,OAAO,gBAAgB,KAAK,OAAO,OAAO,OAAO,YAAY,IACvF;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,EAAE,WAAW,OAAO,UAAU;AAAA,EACvC;AAAA,EAMA,MAAM,WAAY,KAAK,SAA8C;AAAA,EACrE,WAAW,UAAU,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,GAAG;AAAA,IAC5D,IAAI,OAAO,KAAK;AAAA,MACd,UAAU,KAAK,OAAO,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,OAAO,EAAE,WAAW,OAAO,WAAW;AAAA;AAMxC,IAAM,cAAc,CAClB,UAC6B,OAAO,UAAU,YAAY,UAAU;AAGtE,IAAM,aAAa,CAAC,QAClB,OAAO,IAAI,SAAS;AAWf,IAAM,aAAa,MAAkC;AAAA,EAC1D,MAAM,WAAW,IAAI;AAAA,EACrB,MAAM,QAAQ,IAAI;AAAA,EAClB,OAAO,CAAC,SAAS;AAAA,IACf,MAAM,WAAW,SAAS,IAAI,IAAI;AAAA,IAClC,IAAI,UAAU;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IACA,MAAM,OAAO,SAAQ,IAAI,KAAK;AAAA,IAC9B,IAAI,OAAO;AAAA,IACX,SAAS,SAAS,EAAG,MAAM,IAAI,IAAI,GAAG,UAAU,GAAG;AAAA,MACjD,OAAO,GAAG,QAAQ;AAAA,IACpB;AAAA,IACA,MAAM,IAAI,IAAI;AAAA,IACd,SAAS,IAAI,MAAM,IAAI;AAAA,IACvB,OAAO;AAAA;AAAA;AAiCJ,IAAM,qBAAqB,CAChC,WACA,YACuB;AAAA,EACvB,MAAM,aAAgC,CAAC;AAAA,EACvC,MAAM,WAAqB,CAAC;AAAA,EAC5B,MAAM,WAAW,IAAI;AAAA,EACrB,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,aAAa,WAAW;AAAA,EAE9B,MAAM,MAAM,CAAC,UAAoC;AAAA,IAC/C,MAAM,UAAU,WAAW,MAAM,GAAG;AAAA,IACpC,IAAI,CAAC,SAAS,IAAI,MAAM,GAAG,GAAG;AAAA,MAC5B,SAAS,IAAI,MAAM,GAAG;AAAA,MACtB,SAAS,KAAK,MAAM,GAAG;AAAA,IACzB;AAAA,IACA,MAAM,QAAQ;AAAA,IACd,OAAO,KAAK,IAAI,GAAG,GAAG;AAAA,MACpB,MAAM,GAAG,OAAO,MAAM;AAAA,IACxB;AAAA,IACA,KAAK,IAAI,GAAG;AAAA,IACZ,WAAW,KAAK;AAAA,SACX;AAAA,MACH;AAAA,MAEA,OAAO,GAAG,cAAc,MAAM,KAAK,aAAa,WAAW;AAAA,MAC3D;AAAA,IACF,CAAC;AAAA;AAAA,EAGH,MAAM,SAAS,OAA4B;AAAA,IACzC;AAAA,IACA,MAAM,SAAS,IAAI,CAAC,UAAU;AAAA,MAC5B,aAAa,QAAQ,IAAI,IAAI,KAAK;AAAA,MAClC;AAAA,MAGA,MAAM,WAAW,IAAI;AAAA,IACvB,EAAE;AAAA,EACJ;AAAA,EAEA,OAAO,EAAE,KAAK,OAAO;AAAA;AAShB,IAAM,oBAAoB,CAC/B,UACA,cACwB;AAAA,EACxB,MAAM,WAAqB,CAAC;AAAA,EAC5B,MAAM,UAAU,IAAI,KACjB,SAAS,QAAQ,CAAC,GAChB,OAAO,UAAU,EACjB,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,IAAI,eAAe,EAAE,CAAC,CACnD;AAAA,EACA,MAAM,YAAY,mBAAmB,WAAW,OAAO;AAAA,EAEvD,YAAY,MAAM,SAAS,OAAO,QAAQ,SAAS,SAAS,CAAC,CAAC,GAAG;AAAA,IAE/D,IAAI,CAAC,MAAM;AAAA,MACT;AAAA,IACF;AAAA,IACA,IAAI,UAAU,MAAM;AAAA,MAClB,SAAS,KACP,SAAS,mLACX;AAAA,MACA;AAAA,IACF;AAAA,IACA,WAAW,UAAU,cAAc;AAAA,MACjC,MAAM,YAAY,KAAK;AAAA,MACvB,IAAI,CAAC,YAAY,SAAS,GAAG;AAAA,QAC3B;AAAA,MACF;AAAA,MACA,UAAU,IAAI;AAAA,QACZ,YAAY,UAAU,cAAc;AAAA,QACpC,aAAa,UAAU,eAAe;AAAA,QACtC,KAAK,aAAa,QAAQ,MAAM,UAAU,WAAW;AAAA,QACrD;AAAA,QACA,aAAa,UAAU;AAAA,QACvB;AAAA,QACA,SAAS,UAAU,WAAW;AAAA,QAC9B,KAAK,UAAU,OAAO,MAAM;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,OAAO,KAAK,UAAU,OAAO,GAAG,SAAS;AAAA;;;ACtWpC,IAAM,mBAAmB,CAAC,QAAQ,SAAS;AAiFlD,IAAM,kBAAkB,CAAC,UACvB,MAAM,WAAW,MAAM,GAAG,EAAE,WAAW,MAAM,GAAG;AAElD,IAAM,cAAc;AAEpB,IAAM,YAAW,CAAC,UAChB,OAAO,UAAU;AAGZ,IAAM,cAAc,CAAC,YAAkD;AAAA,EAC5E,MAAM,KAAK,YAAY,KAAK,SAAS,QAAQ,EAAE,GAAG,QAAQ;AAAA,EAC1D,OAAO,OAAO,YAAY,YAAY,gBAAgB,EAAE;AAAA;AAQnD,IAAM,iBAAiB,CAC5B,WACA,YACW;AAAA,EACX,MAAM,UAAU,SAAS;AAAA,EACzB,OAAO,UAAS,OAAO,KAAK,YAAY,KAAK,UAAU;AAAA;AAGzD,IAAM,WAAW,CACf,UAEA,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,IAAM,wBACJ;AASF,IAAM,sBAAsB,CAAC,aAAqC;AAAA,EAChE,MAAM,OAAkE;AAAA,IACtE,CAAC,SAAS,UAAU,UAAU;AAAA,IAC9B,CAAC,SAAS,YAAY,YAAY;AAAA,EACpC;AAAA,EACA,YAAY,KAAK,YAAY,MAAM;AAAA,IACjC,IAAI,CAAC,SAAS,GAAG,GAAG;AAAA,MAClB;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,SAAS,aAAa;AAAA,IACpC,YAAY,IAAI,UAAU,OAAO,QAAQ,GAAG,GAAG;AAAA,MAC7C,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,UAAS,MAAM,IAAI,GAAG;AAAA,QAC7C;AAAA,MACF;AAAA,MACA,MAAM,SAAS,sBAAsB,KAAK,MAAM,IAAI,GAAG;AAAA,MACvD,IAAI,QAAQ,YAAY,SAAS;AAAA,QAC/B;AAAA,MACF;AAAA,MACA,MAAM,WAAW,SAAS,KAAK,IAC3B,MAAM,gBAAgB,OAAO,QAAQ,EAAE,KACvC;AAAA,MAIJ,IAAI,SAAS,QAAQ,KAAK,CAAC,UAAS,SAAS,IAAI,GAAG;AAAA,QAClD,IAAI,MAAM,KAAK,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAAA;AAGF,IAAM,YACJ;AAUK,IAAM,sBAAsB,CACjC,aACqB;AAAA,EACrB,MAAM,eAAe,CACnB,UACkD;AAAA,IAClD,IAAI,CAAC,SAAS,KAAK,GAAG;AAAA,MACpB;AAAA,IACF;AAAA,IACA,IAAI,CAAC,UAAS,MAAM,IAAI,GAAG;AAAA,MACzB,OAAO;AAAA,IACT;AAAA,IACA,MAAM,SAAS,UAAU,KAAK,MAAM,IAAI,GAAG;AAAA,IAC3C,MAAM,UAAU,QAAQ,UACpB,SAAS,aAAa,OAAO,WAC7B;AAAA,IACJ,MAAM,WAAW,UAAU,QAAQ,QAAQ;AAAA,IAC3C,OAAO,SAAS,QAAQ,IAAI,WAAW;AAAA;AAAA,EAGzC,MAAM,cAAc,CAAC,SAAkD;AAAA,IACrE,QAAQ,WAAW;AAAA,IACnB,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,OAAO,KAAK;AAAA,IACZ,MAAM,SAA4C,CAAC;AAAA,IACnD,WAAW,SAAS,QAAQ;AAAA,MAC1B,OAAO,OAAO,QAAQ,aAAa,KAAK,CAAC;AAAA,IAC3C;AAAA,IACA,YAAY,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,MACjD,IAAI,EAAE,OAAO,OAAO;AAAA,QAClB,KAAK,OAAO;AAAA,MACd;AAAA,IACF;AAAA;AAAA,EAGF,WAAW,aAAa,OAAO,OAAO,SAAS,cAAc,CAAC,CAAC,GAAG;AAAA,IAChE,IAAI,SAAS,SAAS,GAAG;AAAA,MACvB,YAAY,SAAS;AAAA,IACvB;AAAA,EACF;AAAA,EACA,MAAM,cAAc;AAAA,IAClB,GAAG,OAAO,OAAO,SAAS,YAAY,CAAC,CAAC;AAAA,IAGxC,GAAG,OAAO,OAAO,SAAS,YAAY,YAAY,CAAC,CAAC;AAAA,EACtD;AAAA,EACA,MAAM,cAAc;AAAA,IAClB,GAAG,YAAY,IAAI,CAAC,YAClB,SAAS,OAAO,IAAI,QAAQ,WAAW,SACzC;AAAA,IACA,SAAS,YAAY;AAAA,EACvB;AAAA,EACA,WAAW,YAAY,aAAa;AAAA,IAClC,IAAI,CAAC,SAAS,QAAQ,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,IACA,WAAW,WAAW,OAAO,OAAO,QAAQ,GAAG;AAAA,MAG7C,IAAI,SAAS,OAAO,KAAK,CAAC,UAAS,QAAQ,IAAI,GAAG;AAAA,QAChD,YAAY,OAAO;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAQF,IAAM,4BAA4B,CACvC,aACqB;AAAA,EACrB,oBAAoB,QAAQ;AAAA,EAC5B,OAAO,oBAAoB,QAAQ;AAAA;AAQrC,IAAM,gBAAgB,CACpB,IACA,WACA,aAC4E;AAAA,EAC5E,MAAM,SAAS,iBAAiB,KAAK,CAAC,MAAM,MAAM,UAAU,MAAM;AAAA,EAClE,IAAI,CAAC,QAAQ;AAAA,IACX,OAAO,cAAc;AAAA,EACvB;AAAA,EACA,MAAM,YAAY,YAAY,UAAU,OAAO;AAAA,EAC/C,MAAM,UAAU,cAAc,YAAY,YAAY,SAAS;AAAA,EAG/D,IAAI,cAAc,aAAa,CAAC,SAAS,OAAO,KAAK,UAAS,QAAQ,IAAI,GAAG;AAAA,IAC3E,OAAO,cAAc;AAAA,EACvB;AAAA,EACA,OAAO,EAAE,QAAQ,SAAS,eAAe,WAAW,OAAO,GAAG,UAAU;AAAA;AAsBnE,IAAM,4BAA4B,CACvC,UACA,cAC6B;AAAA,EAC7B,MAAM,WAAqB,CAAC;AAAA,EAC5B,MAAM,UAAU,IAAI,KACjB,SAAS,MAAM,QAAQ,CAAC,GACtB,OACC,CAAC,QACC,OAAO,KAAK,SAAS,QACzB,EACC,IAAI,CAAC,QAA0B,CAAC,IAAI,MAAM,IAAI,eAAe,EAAE,CAAC,CACrE;AAAA,EACA,MAAM,YAAY,mBAAmB,WAAW,OAAO;AAAA,EACvD,MAAM,WAAW,SAAS,YAAY,CAAC;AAAA,EAEvC,YAAY,IAAI,cAAc,OAAO,QAAQ,SAAS,cAAc,CAAC,CAAC,GAAG;AAAA,IACvE,IAAI,CAAC,SAAS,SAAS,GAAG;AAAA,MACxB;AAAA,IACF;AAAA,IAGA,IAAI,UAAS,UAAU,IAAI,GAAG;AAAA,MAC5B,SAAS,KACP,cAAc,sGAChB;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM,OAAO,cAAc,IAAI,WAAW,QAAQ;AAAA,IAClD,IAAI,UAAS,IAAI,GAAG;AAAA,MAClB,SAAS,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,IACA,QAAQ,QAAQ,SAAS,cAAc;AAAA,IACvC,MAAM,MAAM,UAAU,MAAM,KAC1B,CAAC,cACC,OAAO,WAAW,SAAS,QAC/B,GAAG;AAAA,IACH,UAAU,IAAI;AAAA,MACZ;AAAA,MACA,YAAY,UAAU,eAAe;AAAA,MACrC,aAAa,UAAU,eAAe;AAAA,MACtC,KAAK,aAAa,QAAQ,SAAS,EAAE;AAAA,MACrC,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,MAAM;AAAA,MACN,SAAS,UAAU,SAAS,UAAU,WAAW;AAAA,MACjD,KAAK,OAAO;AAAA,IACd,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,KAAK,UAAU,OAAO,GAAG,SAAS;AAAA;;;ACrVpC,IAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,IAAM,uBAAuB;AAAA,EAClC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,OAAO;AACT;AAyEO,IAAM,yBAAyB,CACpC,WAEA,wBAAwB,KAAK,CAAC,SAAS,SAAS,MAAM;AAGxD,IAAM,wBAAwB;AAAA,EAC5B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AACT;AASO,IAAM,mBAAmB,CAC9B,cACW;AAAA,EAGX,MAAM,SAAS,UAAU;AAAA,EACzB,MAAM,UAAU,uBAAuB,MAAM,IACzC,SACA,sBAAsB;AAAA,EAC1B,OAAO,GAAG,WAAW,UAAU;AAAA;AAMjC,IAAM,SAAS,CAAC,GAAmB,MACjC,EAAE,OAAO,EAAE,OAAO,KAAK;AAWlB,IAAM,2BAA2B,CACtC,UACA,cACwB;AAAA,EACxB,MAAM,YAAY,mBAAmB,WAAW,IAAI,GAAK;AAAA,EACzD,MAAM,YAAY,IAAI,IAAI,OAAO,OAAO,SAAS,KAAK,CAAC;AAAA,EAEvD,WAAW,QAAQ,yBAAyB;AAAA,IAC1C,MAAM,WAAW,SAAS,MAAM;AAAA,IAChC,MAAM,OAAO,aAAa,YAAY,YAAY,SAAS,MAAM;AAAA,IACjE,WAAW,SAAS,MAAM,UAAU,CAAC,GAAG;AAAA,MACtC,UAAU,IAAI;AAAA,QACZ,YAAY,MAAM,sBAAsB;AAAA,QACxC,aAAa,MAAM;AAAA,QAGnB,KAAK,aAAa,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,QAC9C,QAAQ;AAAA,QACR,aAAa,MAAM;AAAA,QACnB,MAAM,MAAM;AAAA,QACZ,SAAS;AAAA,QACT,KAAK,qBAAqB;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,WAAW,QAAQ,oBAAoB;AAAA,IACrC,MAAM,UAAU,OAAO,OAAO,SAAS,KAAK,EACzC,OACC,CAAC,SACC,KAAK,SAAS,QAAQ,EAAE,KAAK,WAAW,UAAU,IAAI,KAAK,IAAI,EACnE,EACC,SAAS,MAAM;AAAA,IAClB,WAAW,QAAQ,SAAS;AAAA,MAC1B,UAAU,IAAI;AAAA,QACZ,YAAY;AAAA,QACZ,aAAa,KAAK;AAAA,QAClB,KAAK,aAAa,MAAM,KAAK,MAAM,KAAK,IAAI;AAAA,QAC5C,QAAQ;AAAA,QACR,aAAa,KAAK;AAAA,QAClB,MAAM,KAAK;AAAA,QACX,SAAS;AAAA,QACT,KAAK,qBAAqB;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,OAAO,KAAK,UAAU,OAAO,GAAG,UAAU,CAAC,EAAE;AAAA;;;ACzN/C,kBAAS,oBAAO,wBAAU;AAC1B,uBAAS;AAGT,sBAAS;AACT;AACA,uBAAS,qBAAY;;;ACNrB;AAoBO,IAAM,cAAc,cAAc,YAAY,GAAG;;;ACPxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCA,IAAM,UAAU,CACd,UACoB;AAAA,EACpB,SAAS,OAAO,IAAI;AAAA,EACpB,MAAM,aAAa,IAAI,EAAE;AAC3B;AAQA,IAAM,iBAAiB,CACrB,UACuB;AAAA,EACvB,MAAM,UAAU,MAAM,SAAS;AAAA,EAC/B,OAAO,UAAU,MAAM,OAAO,IAAI;AAAA;AAGpC,IAAM,aAAa,CACjB,UACsB;AAAA,EACtB,MAAM,QAA2B;AAAA,IAC/B,aAAa,MAAM,eAAe;AAAA,IAClC,MAAM,MAAM;AAAA,IACZ,MAAM,QAAQ,MAAM,IAAI;AAAA,EAC1B;AAAA,EACA,MAAM,UAAU,eAAe,KAAK;AAAA,EACpC,IAAI,YAAY,WAAW;AAAA,IACzB,MAAM,UAAU;AAAA,EAClB;AAAA,EAGA,IACE,MAAM,sBAAsB,QAC5B,MAAM,sBAAsB,WAC5B;AAAA,IACA,MAAM,oBAAoB,MAAM;AAAA,EAClC;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,cAAc,CAAC,UAAsD;AAAA,EACzE,MAAM,QAAoB;AAAA,IACxB,MAAM,MAAM,KAAK,IAAI,UAAU;AAAA,IAC/B,aAAa,MAAM,eAAe;AAAA,IAClC,MAAM,MAAM;AAAA,IACZ,MAAM,QAAQ,MAAM,IAAI;AAAA,EAC1B;AAAA,EACA,IACE,MAAM,sBAAsB,QAC5B,MAAM,sBAAsB,WAC5B;AAAA,IACA,MAAM,oBAAoB,MAAM;AAAA,EAClC;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,aAAa,CAAC,SAClB,KAAK,UAAU,EAAE,IAAI,CAAC,UAAU;AAAA,EAC9B,MAAM,SAA2B;AAAA,IAC/B,aAAa,MAAM,eAAe;AAAA,IAClC,MAAM,MAAM;AAAA,EACd;AAAA,EACA,IACE,MAAM,sBAAsB,QAC5B,MAAM,sBAAsB,WAC5B;AAAA,IACA,OAAO,oBAAoB,MAAM;AAAA,EACnC;AAAA,EACA,OAAO;AAAA,CACR;AAEH,IAAM,YAAY,CAChB,MACA,SACmB;AAAA,EACnB,MAAM,aAAa,KAAK,cAAc,EAAE,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EACjE,MAAM,MAAsB;AAAA,IAC1B,aAAa,KAAK,eAAe;AAAA,IACjC,QAAQ,OAAO,OAAO,KAAK,UAAU,CAAC,EAAE,IAAI,WAAW;AAAA,IACvD;AAAA,IACA,MAAM,KAAK;AAAA,EACb;AAAA,EACA,IAAI,WAAW,SAAS,GAAG;AAAA,IACzB,IAAI,aAAa;AAAA,EACnB;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,WAAW,CAAC,UAAkD;AAAA,EAClE,aAAa,KAAK,eAAe;AAAA,EACjC,aAAa,OAAO,OAAO,KAAK,UAAU,CAAC,EAAE,IAAI,UAAU;AAAA,EAC3D,MAAM;AAAA,EACN,MAAM,KAAK;AACb;AAEA,IAAM,WAAW,CAAC,UAA4C;AAAA,EAC5D,aAAa,KAAK,eAAe;AAAA,EACjC,MAAM;AAAA,EACN,MAAM,KAAK;AAAA,EACX,eAAe,KAAK,SAAS,EAAE,IAAI,CAAC,WAAW,OAAO,IAAI;AAC5D;AAEA,IAAM,YAAY,CAAC,SAA4C;AAAA,EAC7D,MAAM,MAAsB;AAAA,IAC1B,aAAa,KAAK,eAAe;AAAA,IACjC,MAAM;AAAA,IACN,MAAM,KAAK;AAAA,EACb;AAAA,EACA,IAAI,KAAK,mBAAmB,QAAQ,KAAK,mBAAmB,WAAW;AAAA,IACrE,IAAI,iBAAiB,KAAK;AAAA,EAC5B;AAAA,EACA,IAAI,sBAAsB,IAAI,GAAG;AAAA,IAC/B,IAAI,UAAU;AAAA,EAChB;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,UAAU,CACd,MACA,WACmB;AAAA,EACnB,IAAI,aAAa,IAAI,GAAG;AAAA,IACtB,OAAO,UAAU,MAAM,QAAQ;AAAA,EACjC;AAAA,EACA,IAAI,gBAAgB,IAAI,GAAG;AAAA,IACzB,MAAM,MAAM,UAAU,MAAM,WAAW;AAAA,IAGvC,MAAM,eAAe,OAClB,mBAAmB,IAAI,EACvB,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI;AAAA,IACtC,IAAI,aAAa,SAAS,GAAG;AAAA,MAC3B,IAAI,gBAAgB;AAAA,IACtB;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,IAAI,kBAAkB,IAAI,GAAG;AAAA,IAC3B,OAAO,SAAS,IAAI;AAAA,EACtB;AAAA,EACA,IAAI,WAAW,IAAI,GAAG;AAAA,IACpB,OAAO;AAAA,MACL,aAAa,KAAK,eAAe;AAAA,MACjC,YAAY,WAAW,IAAI;AAAA,MAC3B,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AAAA,EACA,IAAI,YAAY,IAAI,GAAG;AAAA,IACrB,OAAO,SAAS,IAAI;AAAA,EACtB;AAAA,EAGA,OAAO,UAAU,IAAyB;AAAA;AAI5C,IAAM,aAAa,CAAC,WAA2C;AAAA,EAC7D,MAAM,QAAwC,CAAC;AAAA,EAC/C,YAAY,MAAM,SAAS,OAAO,QAAQ,OAAO,WAAW,CAAC,GAAG;AAAA,IAE9D,IAAI,KAAK,WAAW,IAAI,GAAG;AAAA,MACzB;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,QAAQ,MAAM,MAAM;AAAA,EACpC;AAAA,EACA,MAAM,QAAkC,CAAC;AAAA,EACzC,MAAM,QAAQ,OAAO,aAAa;AAAA,EAClC,MAAM,WAAW,OAAO,gBAAgB;AAAA,EACxC,MAAM,eAAe,OAAO,oBAAoB;AAAA,EAChD,IAAI,OAAO;AAAA,IACT,MAAM,QAAQ,MAAM;AAAA,EACtB;AAAA,EACA,IAAI,UAAU;AAAA,IACZ,MAAM,WAAW,SAAS;AAAA,EAC5B;AAAA,EACA,IAAI,cAAc;AAAA,IAChB,MAAM,eAAe,aAAa;AAAA,EACpC;AAAA,EACA,OAAO;AAAA,IACL,MAAM,EAAE,aAAa,OAAO,eAAe,GAAG;AAAA,IAC9C;AAAA,IACA;AAAA,EACF;AAAA;AAUF,IAAM,eAAe,CACnB,UAEA,OAAO,UAAU,YAAY,UAAU,SAAQ,cAAc;AAG/D,IAAM,kBAAkB,CACtB,UAEA,OAAO,UAAU,YAAY,UAAU,SAAQ,UAAU;AAG3D,IAAM,kBAAkB,CAAQ,WAAsC;AAAA,EACpE,IAAI,aAAa,MAAM,GAAG;AAAA,IACxB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,gBAAgB,MAAM,KAAK,aAAa,OAAO,IAAI,IACtD,OAAO,OACP;AAAA;AASC,IAAM,uBAAuB,CAAC,SAAkC;AAAA,EACrE,IAAI;AAAA,EACJ,IAAI,SAAS;AAAA,EACb,IAAI;AAAA,IACF,SAAS,KAAK,MAAM,IAAI;AAAA,IACxB,MAAM;AAAA,IACN,SAAS;AAAA;AAAA,EAEX,IAAI,QAAQ;AAAA,IACV,MAAM,gBAAgB,gBAAgB,MAAM;AAAA,IAC5C,IAAI,CAAC,eAAe;AAAA,MAClB,MAAM,IAAI,MACR,8EACF;AAAA,IACF;AAAA,IAIA,OAAO,WACL,kBACE,aACF,CACF;AAAA,EACF;AAAA,EACA,OAAO,WAAW,YAAY,IAAI,CAAC;AAAA;;;AC7R9B,MAAM,4BAA4B,MAAM;AAAA,EACpC;AAAA,EAET,WAAW,CAAC,SAAiB,YAAoB;AAAA,IAC/C,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA,IACZ,KAAK,aAAa;AAAA;AAEtB;;;AHsBA,IAAM,WAAW;AAEjB,IAAM,mBAAmB;AACzB,IAAM,eAAe;AACrB,IAAM,kBAAkB;AAGxB,IAAM,oBAAoB;AAC1B,IAAM,YAAY;AAElB,IAAM,mBAAmB,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AACpE,IAAM,aAAa;AACnB,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAAA;AAaO,MAAM,yBAAyB,MAAM;AAAA,EAC1C,WAAW,CAAC,SAAiB;AAAA,IAC3B,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA;AAEhB;AAqBA,IAAI,iBAAiB;AACrB,IAAM,wBAAwB,MAAY;AAAA,EAGxC,IAAI,kBAAkB,CAAC,eAAe,KAAK,CAAC,SAAS,QAAQ,IAAI,KAAK,GAAG;AAAA,IACvE;AAAA,EACF;AAAA,EACA,IAAI;AAAA,IAGF,QAAQ,mBAAmB,wBACzB,YAAY,QAAQ;AAAA,IACtB,oBAAoB,IAAI,iBAAmB;AAAA,IAC3C,iBAAiB;AAAA,IACjB,MAAM;AAAA;AAWV,IAAM,eAAe,CAAC,aAA2C;AAAA,EAC/D,MAAM,SAAS,SAAS,QAAQ,IAAI,aAAa;AAAA,EACjD,IAAI,CAAC,QAAQ;AAAA,IACX;AAAA,EACF;AAAA,EACA,MAAM,UAAU,OAAO,MAAM;AAAA,EAC7B,IAAI,OAAO,SAAS,OAAO,GAAG;AAAA,IAC5B,OAAO,UAAU,IAAI,UAAU,YAAY;AAAA,EAC7C;AAAA,EACA,MAAM,QAAQ,KAAK,MAAM,MAAM,IAAI,KAAK,IAAI;AAAA,EAC5C,OAAO,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;AAAA;AAQvD,IAAM,eAAe,OAAO,SAAmC;AAAA,EAC7D,IAAI;AAAA,IACF,MAAM,WAAW,MAAM,MAAM,MAAM;AAAA,MACjC,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,YAAY,QAAQ,gBAAgB;AAAA,IAC9C,CAAC;AAAA,IACD,IAAI,SAAS,IAAI;AAAA,MACf,OAAO,EAAE,MAAM,MAAM,SAAS,KAAK,EAAE;AAAA,IACvC;AAAA,IACA,OAAO;AAAA,MACL,OAAO,IAAI,MAAM,GAAG,WAAW,SAAS,UAAU,SAAS,YAAY;AAAA,MACvE,YAAY,aAAa,QAAQ;AAAA,MACjC,WAAW,iBAAiB,IAAI,SAAS,MAAM;AAAA,IACjD;AAAA,IACA,OAAO,OAAO;AAAA,IAGd,OAAO;AAAA,MACL,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,MAC/D,WAAW;AAAA,IACb;AAAA;AAAA;AAaJ,IAAM,sBAAsB,CAC1B,OACA,eACwB;AAAA,EACxB,MAAM,UAA+B,IAAI,MAAM,MAAM,SAAS;AAAA,IAC5D,OAAO;AAAA,EACT,CAAC;AAAA,EACD,QAAQ,OAAO;AAAA,EACf,QAAQ,aAAa;AAAA,EACrB,OAAO;AAAA;AAIT,IAAM,gBAAgB,OAAO,SAAkC;AAAA,EAC7D,sBAAsB;AAAA,EACtB,OAAO,MAAM,OACX,YAAY;AAAA,IACV,MAAM,UAAU,MAAM,aAAa,IAAI;AAAA,IACvC,IAAI,UAAU,SAAS;AAAA,MACrB,OAAO,QAAQ;AAAA,IACjB;AAAA,IACA,IAAI,CAAC,QAAQ,WAAW;AAAA,MAEtB,MAAM,IAAI,WAAW,QAAQ,KAAK;AAAA,IACpC;AAAA,IACA,MAAM,oBAAoB,QAAQ,OAAO,QAAQ,UAAU;AAAA,KAE7D;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,IAIZ,iBAAiB,OAAO,YAAY;AAAA,MAGlC,QAAQ,eAAe,QAAQ;AAAA,MAC/B,IAAI,eAAe,aAAa,QAAQ,cAAc,GAAG;AAAA,QACvD,MAAM,MACJ,KAAK,IACH,GACA,KAAK,IAAI,YAAY,iBAAiB,IAAI,QAAQ,UACpD,CACF;AAAA,MACF;AAAA;AAAA,IAEF,SAAS,eAAe;AAAA,EAC1B,CACF;AAAA;AAGF,IAAM,eAAe,CAAC,UAAkB,SACtC,MAAK,UAAU,QAAQ,SAAS,IAAI,SAAS;AAE/C,IAAM,YAAY,OAAO,SAA8C;AAAA,EACrE,IAAI;AAAA,IACF,OAAO,MAAM,UAAS,MAAM,OAAO;AAAA,IACnC,MAAM;AAAA,IACN;AAAA;AAAA;AAIJ,IAAM,aAAa,OACjB,KACA,MACA,SACkB;AAAA,EAClB,IAAI;AAAA,IACF,MAAM,OAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC,MAAM,WAAU,MAAM,MAAM,OAAO;AAAA,IACnC,MAAM;AAAA;AAMV,IAAM,eAAe,OACnB,MACA,MACA,YACkD;AAAA,EAClD,IAAI,CAAC,SAAS,KAAK,IAAI,GAAG;AAAA,IACxB,MAAM,WAAW,YAAW,IAAI,IAAI,OAAO,MAAK,MAAM,IAAI;AAAA,IAC1D,OAAO,EAAE,MAAM,MAAM,UAAS,UAAU,OAAO,GAAG,UAAU,CAAC,EAAE;AAAA,EACjE;AAAA,EAEA,MAAM,YAAY,QAAQ,WACtB,aAAa,QAAQ,UAAU,IAAI,IACnC;AAAA,EAGJ,IAAI,aAAa,QAAQ,YAAY,OAAO;AAAA,IAC1C,MAAM,SAAS,MAAM,UAAU,SAAS;AAAA,IACxC,IAAI,WAAW,WAAW;AAAA,MACxB,OAAO,EAAE,MAAM,QAAQ,UAAU,CAAC,EAAE;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,IAAI;AAAA,IACF,MAAM,OAAO,MAAM,cAAc,IAAI;AAAA,IACrC,IAAI,QAAQ,YAAY,WAAW;AAAA,MACjC,MAAM,WAAW,QAAQ,UAAU,WAAW,IAAI;AAAA,IACpD;AAAA,IACA,OAAO,EAAE,MAAM,UAAU,CAAC,EAAE;AAAA,IAC5B,OAAO,OAAO;AAAA,IAEd,IAAI,WAAW;AAAA,MACb,MAAM,SAAS,MAAM,UAAU,SAAS;AAAA,MACxC,IAAI,WAAW,WAAW;AAAA,QAGxB,OAAO;AAAA,UACL,MAAM;AAAA,UACN,UAAU;AAAA,YACR,mBAAmB,SAAU,MAAgB;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM;AAAA;AAAA;AAeV,IAAM,gBAAgB,CAAQ,UAC5B,OAAO,UAAU,YAAY,UAAU;AAElC,IAAM,YAAY,OACvB,MACA,MACA,UAA4B,CAAC,MACL;AAAA,EACxB,QAAQ,MAAM,aAAa,MAAM,aAAa,MAAM,MAAM,OAAO;AAAA,EACjE,MAAM,aAAa,WAAU,IAAI;AAAA,EACjC,QAAQ,kBAAkB,QAAQ,UAAU;AAAA,EAE5C,IAAI,CAAC,cAAc,aAAa,GAAG;AAAA,IACjC,MAAM,IAAI,iBACR,GAAG,wEACL;AAAA,EACF;AAAA,EACA,OAAO,EAAE,UAAU,eAAe,SAAS;AAAA;AAa7C,IAAM,qBAAqB,CACzB,UAEA,OAAO,UAAU,YACjB,UAAU,SACV,cAAc,UACd,OAAO,MAAM,aAAa,YAC1B,MAAM,aAAa;AAErB,IAAM,YAAY;AAUlB,IAAM,gBAAgB,OACpB,MACA,SACA,SACoC;AAAA,EACpC,IAAI;AAAA,IAEF,MAAM,YAAoC,YAAY,SAAS;AAAA,IAC/D,OAAO;AAAA,IACP,OAAO,OAAO;AAAA,IAGd,QAAQ,MAAM,YAAY;AAAA,IAG1B,IAAI,SAAS,sBAAsB,CAAC,QAAQ,SAAS,IAAI,YAAY,GAAG;AAAA,MACtE,MAAM;AAAA,IACR;AAAA,IACA,QAAQ,QAAQ,YAAY,MAAM,4BAA4B,IAAI,CAAC;AAAA,IACnE,MAAM,IAAI,oBACR,GAAG,oBAAoB,qDAAqD,qCAC5E,qBAAqB,OAAO,mDAC9B;AAAA;AAAA;AAeG,IAAM,oBAAoB,OAC/B,MACA,MACA,UAA4B,CAAC,MACG;AAAA,EAChC,QAAQ,MAAM,aAAa,MAAM,aAAa,MAAM,MAAM,OAAO;AAAA,EACjE,MAAM,aAAa,WAAU,IAAI;AAAA,EACjC,IAAI,CAAC,mBAAmB,UAAU,GAAG;AAAA,IACnC,MAAM,IAAI,iBACR,GAAG,4GACL;AAAA,EACF;AAAA,EACA,MAAM,UAAU,WAAW;AAAA,EAC3B,IAAI,WAA6B;AAAA,EACjC,IAAI,CAAC,QAAQ,WAAW,IAAI,GAAG;AAAA,IAC7B,QAAQ,YAAY,MAAM,cAAc,MAAM,SAAS,IAAI;AAAA,IAI3D,MAAM,WAAqB,CAAC;AAAA,IAC5B,MAAM,eAAe,QAAQ;AAAA,IAC7B,QAAQ,OAAO,IAAI,SAAoB;AAAA,MACrC,SAAS,KAAK,KAAK,IAAI,MAAM,EAAE,KAAK,GAAG,CAAC;AAAA;AAAA,IAE1C,IAAI;AAAA,MAIF,WAAW,QACT,UACA,OACF;AAAA,MACA,OAAO,OAAO;AAAA,MAId,MAAM,IAAI,iBACR,GAAG,gDAAiD,MAAgB,WACtE;AAAA,cACA;AAAA,MACA,QAAQ,OAAO;AAAA;AAAA,IAEjB,SAAS,KACP,GAAG,SAAS,IACV,CAAC,YAAY,cAAc,yBAAyB,SACtD,CACF;AAAA,EACF;AAAA,EACA,OAAO,EAAE,UAAU,0BAA0B,QAAQ,GAAG,SAAS;AAAA;AAiB5D,IAAM,mBAAmB,OAC9B,MACA,MACA,UAA4B,CAAC,MACE;AAAA,EAC/B,QAAQ,MAAM,aAAa,MAAM,aAAa,MAAM,MAAM,OAAO;AAAA,EACjE,IAAI;AAAA,IACF,OAAO,EAAE,UAAU,qBAAqB,IAAI,GAAG,SAAS;AAAA,IACxD,OAAO,OAAO;AAAA,IAId,MAAM,IAAI,iBACR,GAAG,uCAAwC,MAAgB,QAAQ,KAAK,IAC1E;AAAA;AAAA;;;AIzdJ,yBAAS;AACT,qBAAS;AACT;;;ACFA;AACA;;;ACOA,IAAM,eAAe,IAAI,IAAI,CAAC,QAAQ,SAAS,UAAU,KAAK,CAAC;AAE/D,IAAM,UAAS;AAKf,IAAM,cAAc;AAGb,IAAM,aAAa,CAAC,SAA0B;AAAA,EACnD,MAAM,UAAU,KAAK,WAAW,aAAa,EAAE;AAAA,EAC/C,IAAI,QAAQ;AAAA,EACZ,OAAO,QAAQ,QAAQ,WAAW,QAAQ,YAAY,KAAK,KAAK,MAAM,IAAM;AAAA,IAC1E,SAAS;AAAA,EACX;AAAA,EACA,MAAM,SAAS,QAAO,KAAK,QAAQ,MAAM,KAAK,CAAC,GAAG,QAAQ;AAAA,EAC1D,OAAO,WAAW,aAAa,aAAa,IAAI,OAAO,YAAY,CAAC;AAAA;;;ACTtE,IAAM,oBAAoB;AAK1B,IAAM,sBAAsB;AAQ5B,IAAM,cACJ;AAOF,IAAM,YAAY;AAElB,IAAM,mBAAmB,CAAC,SACxB,KAAK,WAAW,aAAa,CAAC,WAAmB;AAAA,EAE/C,MAAM,QAAQ,OAAO,OAAO,OAAO;AAAA,EACnC,OAAO,UAAU,KACb,KAAK,WACL,GAAG,OAAO,MAAM,GAAG,KAAK,MAAM,OAAO,MAAM,KAAK;AAAA,CACrD;AAEH,IAAM,iBAAiB,CAAC,SACtB,KAAK,WACH,WACA,CAAC,YAAoB,KAAK,QAAQ,YAAY,CAAC,KAAK,QAAQ,MAAM,CAAC,GACrE;AAEK,IAAM,qBAAqB,CAAC,SACjC,eACE,iBACE,KACG,WAAW,mBAAmB,OAAO,QAAQ,EAC7C,WAAW,qBAAqB,OAAO,OAAO,CACnD,CACF;AAUF,IAAM,eAAe;AAGrB,IAAM,qBAAqB,CAAC,SAAyB;AAAA,EACnD,IAAI,UAAU;AAAA,EACd,WAAW,OAAO,KAAK,MAAM,YAAY,KAAK,CAAC,GAAG;AAAA,IAChD,UAAU,KAAK,IAAI,SAAS,IAAI,MAAM;AAAA,EACxC;AAAA,EACA,OAAO;AAAA;AAQF,IAAM,WAAW,CAAC,SAAyB;AAAA,EAChD,MAAM,QAAQ,IAAI,OAAO,mBAAmB,IAAI,IAAI,CAAC;AAAA,EACrD,MAAM,MAAM,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,IAAI,MAAM;AAAA,EAC/D,OAAO,GAAG,QAAQ,MAAM,OAAO,MAAM;AAAA;AAGvC,IAAM,aAAa;AASZ,IAAM,eAAe,CAAC,MAAc,UAA+B;AAAA,EACxE,MAAM,QAAQ,WAAW,KAAK,IAAI;AAAA,EAClC,MAAM,OAAO,OAAO,QAAQ,QAAQ;AAAA,EACpC,MAAM,OAAO,OAAO,QAAQ,QAAQ;AAAA,EACpC,MAAM,QAAQ,OAAO,QAAQ,SAAS;AAAA,EACtC,IAAI,SAAS,IAAI;AAAA,IACf,OAAO;AAAA,EACT;AAAA,EACA,IAAI,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,mBAAmB,IAAI;AAAA,EAC/D,IAAI,MAAM,MAAM;AAAA,IACd,MAAM,KAAK;AAAA,EACb;AAAA,EACA,IAAI,MAAM,QAAQ;AAAA,IAChB,MAAM,IAAI;AAAA,EACZ;AAAA,EACA,IAAI,MAAM,QAAQ;AAAA,IAChB,MAAM,KAAK;AAAA,EACb;AAAA,EACA,OAAO,GAAG,OAAO,MAAM;AAAA;AAKzB,IAAM,qBAAqB;AAGpB,IAAM,cAAc,CAAC,QAC1B,mBAAmB,KAAK,GAAG,IAAI,IAAI,SAAS;AAQvC,IAAM,aAAa,CAAC,OAAe,SACxC,QAAQ,WAAW,IAAI,IAAI,IAAI,UAAU,YAAY,IAAI,OAAO;AAG3D,IAAM,gBAAgB,CAAC,UAC5B,GAAG,IAAI,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;AAGpD,IAAM,aAAa,CAAC,SACzB,KACG,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,SAAU,SAAS,KAAK,MAAM,KAAK,MAAO,EAC/C,KAAK;AAAA,CAAI;AAMP,IAAM,WAAW,CAAC,QAAgB,SAAyB;AAAA,EAChE,OAAO,QAAQ,OAAO,QAAQ,KAAK,MAAM;AAAA,CAAI;AAAA,EAC7C,MAAM,MAAM,IAAI,OAAO,OAAO,SAAS,CAAC;AAAA,EACxC,OAAO;AAAA,IACL,GAAG,UAAU;AAAA,IACb,GAAG,KAAK,IAAI,CAAC,SAAU,SAAS,KAAK,KAAK,GAAG,MAAM,MAAO;AAAA,EAC5D,EAAE,KAAK;AAAA,CAAI;AAAA;AAIN,IAAM,SAAS,CAAC,MAAc,UAA0B;AAAA,EAC7D,MAAM,MAAM,IAAI,OAAO,KAAK;AAAA,EAC5B,OAAO,KACJ,MAAM;AAAA,CAAI,EACV,IAAI,CAAC,SAAU,SAAS,KAAK,KAAK,GAAG,MAAM,MAAO,EAClD,KAAK;AAAA,CAAI;AAAA;AAIP,IAAM,YAAY,CAAC,MAAc,WAAW,OAAe;AAAA,EAChE,MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI,GAAG,mBAAmB,IAAI,IAAI,CAAC,CAAC;AAAA,EAClE,OAAO,GAAG,QAAQ;AAAA,EAAa;AAAA,EAAS;AAAA;AAInC,IAAM,QAAQ,CAAC,KAAa,QACjC,KAAK,mBAAmB,GAAG,MAAM,YAAY,GAAG;AAS3C,IAAM,YAAY,CACvB,gBACY,gBAAgB,aAAa,OAAO,KAAK,WAAW,EAAE,SAAS;AAMtE,IAAM,cAAc,CAAC,MAAc,MAAM,UAC9C,MAAM,mBAAmB,aAAa,oBAAoB;AAGrD,IAAM,aAAa,CAAC,WACzB,OAAO,OAAO,CAAC,UAAU,UAAU,EAAE,EAAE,KAAK;AAAA;AAAA,CAAM;AAG7C,IAAM,mBAAmB,CAAC,WAC/B,GAAG,WAAW,MAAM;AAAA;AAEtB,IAAM,WAAW;AAOV,IAAM,cAAc,CAAC,KAAa,SAA0B;AAAA,EACjE,IAAI,IAAI,WAAW,IAAI,GAAG;AAAA,IACxB,OAAO,SAAS;AAAA,EAClB;AAAA,EACA,IAAI,SAAS,KAAK,GAAG,KAAK,SAAS,WAAW;AAAA,IAC5C,OAAO;AAAA,EACT;AAAA,EACA,OAAO,IAAI,IAAI,KAAK,IAAI,EAAE;AAAA;;;AFtMrB,IAAM,kBAAkB,CAAC,SAAiC;AAAA,EAC/D,MAAM,QAA0B,CAAC;AAAA,EACjC,MAAM,QAAQ,CAAC,SAAsB;AAAA,IACnC,KACG,KAAK,SAAS,UAAU,KAAK,SAAS,iBACvC,CAAC,WAAW,KAAK,GAAG,GACpB;AAAA,MAEA,MAAM,QAAQ,KAAK,UAAU,MAAM,UAAU;AAAA,MAC7C,MAAM,MAAM,KAAK,UAAU,IAAI,UAAU;AAAA,MACzC,MAAM,KAAK;AAAA,QACT;AAAA,QACA;AAAA,QACA,MAAM,KAAK,SAAS,SAAS,mBAAmB,SAAS,IAAI,CAAC,IAAI;AAAA,MACpE,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IACA,IAAI,cAAc,MAAM;AAAA,MACtB,WAAW,SAAS,KAAK,UAAU;AAAA,QACjC,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAAA;AAAA,EAEF,MAAM,IAAI;AAAA,EACV,OAAO;AAAA;AAQF,IAAM,wBAAwB,CAAC,aAA6B;AAAA,EACjE,MAAM,QAAQ,gBAAgB,aAAa,QAAQ,CAAC;AAAA,EACpD,IAAI,MAAM;AAAA,EACV,IAAI,SAAS;AAAA,EACb,WAAW,QAAQ,OAAO;AAAA,IACxB,OAAO,SAAS,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK;AAAA,IACjD,SAAS,KAAK;AAAA,EAChB;AAAA,EACA,OAAO,MAAM,SAAS,MAAM,MAAM;AAAA;;;AGlEpC;AAYO,IAAM,gBAAgB,CAAC,MAAc,QAAwB;AAAA,EAClE,IAAI,MAAM;AAAA,EACV,IAAI,OAAO;AAAA,EACX,MAAM,YAAY,IAAI,KAAK,UAAU,WAAW,EAAE,aAAa,WAAW,CAAC;AAAA,EAC3E,aAAa,OAAO,aAAa,UAAU,QAAQ,IAAI,GAAG;AAAA,IACxD,MAAM,QAAQ,YAAY,OAAO;AAAA,IACjC,IAAI,OAAO,QAAQ,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,IACR,MAAM,QAAQ,QAAQ;AAAA,EACxB;AAAA,EACA,OAAO,KAAK,MAAM,GAAG,GAAG;AAAA;;;ACpB1B,IAAM,uBAAuB;AAQtB,IAAM,aAAa,CAAC,SACzB,SAAS,MAAM,qBAAqB,KAAK,IAAI,IAAI,OAAO,GAAG;;;ACFtD,IAAM,qBAAqB,CAChC,MACA,cAEA,KAAK,SAAS,YACV,iBAAiB,SAAS,IAC1B,GAAG,UAAU,OAAO,YAAY,KAAK,UAAU;;;ANcrD,IAAM,aAAa;AACnB,IAAM,WAAW,IAAI,IAAI;AAAA,EACvB,CAAC,KAAK,MAAM;AAAA,EACZ,CAAC,KAAK,QAAQ;AAAA,EACd,CAAC,KAAK,QAAQ;AAChB,CAAC;AAID,IAAM,kBAAkB;AACxB,IAAM,cAAc,CAAC,SACnB,KACG,QAAQ,YAAY,CAAC,SAAS,SAAS,IAAI,IAAI,KAAK,IAAI,EACxD,QACC,iBACA,CAAC,YAAY,KAAK,QAAQ,YAAY,CAAC,KAAK,QAAQ,MAAM,CAAC,GAC7D;AAiBJ,IAAM,YAAY,CAAC,MAAc,SAAmC;AAAA,EAClE,MAAM,QAA4B,CAAC;AAAA,EACnC,MAAM,UAAU,CAAC,SAAsB;AAAA,IACrC,IAAI,KAAK,SAAS,gBAAgB,KAAK,SAAS,QAAQ;AAAA,MAEtD,MAAM,QAAQ,KAAK,UAAU,MAAM,UAAU;AAAA,MAC7C,MAAM,MAAM,KAAK,UAAU,IAAI,UAAU;AAAA,MACzC,MAAM,OAAO,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,EAAE,UAAU;AAAA,MACxE,IACE,SAAS,MACR,KAAK,SAAS,gBACb,KAAK,WAAW,GAAG,KACnB,KAAK,WAAW,GAAG,IACrB;AAAA,QACA,MAAM,KAAK,CAAC,OAAO,GAAG,CAAC;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AAAA,IACA,IAAI,cAAc,MAAM;AAAA,MACtB,WAAW,SAAS,KAAK,UAAU;AAAA,QACjC,QAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA;AAAA,EAEF,QAAQ,IAAI;AAAA,EACZ,OAAO;AAAA;AAST,IAAM,UAAU,CAAC,SAAyB;AAAA,EACxC,MAAM,OAAO,cAAa,IAAI;AAAA,EAC9B,MAAM,SAAS,gBAAgB,IAAI;AAAA,EACnC,MAAM,eAAe,CAAC,WACpB,OAAO,KAAK,CAAC,SAAS,UAAU,KAAK,SAAS,SAAS,KAAK,GAAG;AAAA,EACjE,MAAM,WAAW;AAAA,IACf,GAAG,UAAU,MAAM,IAAI,EACpB,OAAO,EAAE,WAAW,CAAC,aAAa,KAAK,CAAC,EACxC,IAAI,EAAE,OAAO,UAAU,EAAE,KAAK,OAAO,MAAM,KAAK,MAAM,OAAO,GAAG,EAAE,EAAE;AAAA,IACvE,GAAG;AAAA,EACL,EAAE,SAAS,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,EACtC,IAAI,MAAM;AAAA,EACV,IAAI,SAAS;AAAA,EACb,WAAW,WAAW,UAAU;AAAA,IAC9B,OAAO,YAAY,KAAK,MAAM,QAAQ,QAAQ,KAAK,CAAC;AAAA,IACpD,OAAO,QAAQ;AAAA,IACf,SAAS,QAAQ;AAAA,EACnB;AAAA,EACA,OAAO,MAAM,YAAY,KAAK,MAAM,MAAM,CAAC;AAAA;AA4B7C,IAAM,uBAAuB;AAC7B,IAAM,aAAa;AACnB,IAAM,gBAAgB;AAStB,IAAM,aAAa,CAAC,aAA6B;AAAA,EAC/C,MAAM,OAAO,cAAa,QAAQ;AAAA,EAClC,MAAM,QACJ,KAAK,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS;AAAA,EAC3E,OAAO,QAAQ,cAAc,KAAK,EAAE,QAAQ,YAAY,GAAG,EAAE,KAAK,IAAI;AAAA;AAIxE,IAAM,OAAO,CAAC,MAAc,QAAwB;AAAA,EAClD,IAAI,OAAO,GAAG;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACA,IAAI,aAAY,IAAI,KAAK,KAAK;AAAA,IAC5B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,cAAc,MAAM,MAAM,CAAC;AAAA,EACxC,MAAM,iBAAiB,KAAK,QAAQ,eAAe,EAAE;AAAA,EAGrD,OAAO,GAAG,aAAY,cAAc,KAAK,MAAM,IAAI,iBAAiB;AAAA;AAGtE,IAAM,UAAU,CAAC,SAA8B,KAAK,SAAS,KAAK;AAElE,IAAM,YAAY,CAAC,SAA8B,cAAc,QAAQ,IAAI,CAAC;AAG5E,IAAM,yBAAyB;AAAA,EAC7B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,OAAO;AACT;AAWA,IAAM,uBAAuB,CAC3B,MACA,WACA,YACW;AAAA,EACX,IAAI,CAAC,QAAQ,QAAQ;AAAA,IACnB,OAAO,KACL,WAAW,UAAU,eAAe,UAAU,OAAO,KAAK,QAAQ,OAClE,oBACF;AAAA,EACF;AAAA,EAGA,IAAI;AAAA,EACJ,IAAI,KAAK,SAAS,YAAY;AAAA,IAC5B,UAAU,GAAG,UAAU,uBAAuB,UAAU;AAAA,EAC1D,EAAO,SAAI,KAAK,SAAS,WAAW;AAAA,IAGlC,UAAU,GAAG,UAAU,QAAQ,uBAAuB,UAAU;AAAA,EAClE,EAAO;AAAA,IACL,UAAU,GAAG,UAAU,OAAO,YAAY,KAAK,UAAU;AAAA;AAAA,EAE3D,MAAM,SAAS,qBAAqB,kBAAkB,UAAU,IAAI;AAAA,EAGpE,MAAM,QAAQ,KACZ,WAAW,UAAU,eAAe,UAAU,OAAO,GACrD,uBAAuB,aAAY,MAAM,IAAI,CAC/C;AAAA,EACA,OAAO,KACL,CAAC,WAAW,KAAK,GAAG,MAAM,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GACpD,oBACF;AAAA;AAIF,IAAM,kBAAkB,CAAC,aAAqB,cAC5C,YAAY,KAAK,IACb,GAAG,QAAQ,YAAY,KAAK,CAAC;AAAA;AAAA,EAAQ,cACrC;AAEC,IAAM,eAAe,CAC1B,MACA,WACA,cAIiB;AAAA,EACjB,MAAM,SAAS,UAAU,OAAO,YAAY;AAAA,EAC5C,MAAM,UAAU,KAAK,SAAS;AAAA,EAG9B,MAAM,gBAAgB,UAClB,UAAU,OACV,mBAAmB,MAAM,SAAS;AAAA,EACtC,MAAM,QAAQ,UAAU,WAAW;AAAA,EAGnC,MAAM,cACJ,UAAU,YAAY,KAAK,MAAM,UAAU,QAAQ,KAAK,IACpD,KACA,UAAU;AAAA,EAChB,MAAM,QAAqD,CAAC;AAAA,EAC5D,IAAI,WAAW,kBAAkB,OAAO;AAAA,IACtC,MAAM,KAAK,EAAE,SAAS,KAAK;AAAA,EAC7B;AAAA,EACA,IAAI,UAAU,YAAY;AAAA,IACxB,MAAM,aAAa;AAAA,EACrB;AAAA,EACA,MAAM,cAGF,CAAC;AAAA,EACL,IAAI,WAAW,oBAAoB,OAAO;AAAA,IACxC,YAAY,UAAU;AAAA,EACxB;AAAA,EACA,MAAM,MAA+B;AAAA,IACnC,aAAa,qBAAqB,MAAM,WAAW;AAAA,MACjD,QAAQ,WAAW,yBAAyB;AAAA,MAC5C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EACA,IAAI,WAAW,SAAS;AAAA,IACtB,IAAI,UAAU;AAAA,EAChB;AAAA,EACA,MAAM,UAAuC;AAAA,IAC3C,OAAO,UAAU,WAAW,UAAU;AAAA,EACxC;AAAA,EAMA,IAAI,CAAC,WAAW,uBAAuB,UAAU,MAAM,GAAG;AAAA,IACxD,QAAQ,QAAQ;AAAA,EAClB;AAAA,EACA,MAAM,OAAO,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,KAAK,MAAM;AAAA,EAC/D,OAAO;AAAA,IACL,MAAM,gBACJ,aACA,sBAAsB,KAAK,aAAa,UAAU,SACpD;AAAA,IACA,MAAM;AAAA,SACD;AAAA,MACH,QAAQ,KAAK,aAAa,KAAK;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MAEA,MAAM;AAAA,IACR;AAAA,EACF;AAAA;AAGK,IAAM,cAAc,CACzB,MACA,cAIiB;AAAA,EAMjB,MAAM,aAAa,OAAO,OAAO,KAAK,UAAU;AAAA,EAGhD,MAAM,WAA6B,CAAC;AAAA,EACpC,MAAM,QAAQ,IAAI;AAAA,EAClB,WAAW,OAAO,KAAK,MAAM;AAAA,IAC3B,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,GAAG;AAAA,MACxB,MAAM,IAAI,IAAI,IAAI;AAAA,MAClB,SAAS,KAAK,GAAG;AAAA,IACnB;AAAA,EACF;AAAA,EACA,WAAW,aAAa,YAAY;AAAA,IAClC,IAAI,CAAC,MAAM,IAAI,UAAU,OAAO,GAAG;AAAA,MACjC,MAAM,IAAI,UAAU,OAAO;AAAA,MAC3B,SAAS,KAAK;AAAA,QACZ,aAAa;AAAA,QACb,MAAM,UAAU;AAAA,QAChB,MAAM,UAAU;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,MAAM,cAAwB,CAAC;AAAA,EAC/B,WAAW,OAAO,UAAU;AAAA,IAC1B,IAAI,CAAC,WAAW,KAAK,CAAC,cAAc,UAAU,YAAY,IAAI,IAAI,GAAG;AAAA,MACnE;AAAA,IACF;AAAA,IACA,MAAM,cAAc,IAAI,YAAY,KAAK,IACrC,CAAC,QAAQ,IAAI,YAAY,KAAK,CAAC,CAAC,IAChC,CAAC;AAAA,IACL,YAAY,KACV;AAAA,MACE,MAAM,QAAQ,IAAI,IAAI;AAAA,MACtB,GAAG;AAAA,MACH,6BAA6B,KAAK,cAAc,IAAI;AAAA,IACtD,EAAE,KAAK;AAAA;AAAA,CAAM,CACf;AAAA,EACF;AAAA,EACA,MAAM,QAAiD,CAAC;AAAA,EACxD,IAAI,WAAW,kBAAkB,OAAO;AAAA,IACtC,MAAM,KAAK,EAAE,SAAS,KAAK;AAAA,EAC7B;AAAA,EACA,IAAI,WAAW,oBAAoB,OAAO;AAAA,IACxC,MAAM,SAAS,EAAE,SAAS,KAAK;AAAA,EACjC;AAAA,EACA,MAAM,MAA+B;AAAA,IACnC,aACE,KAAK,WAAW,KAAK,WAAW,GAAG,oBAAoB,KACvD,GAAG,UAAU,IAAI;AAAA,EACrB;AAAA,EACA,IAAI,WAAW,SAAS;AAAA,IACtB,IAAI,UAAU;AAAA,EAChB;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,MACJ,gBACE,KAAK,aACL,wBAAwB,KAAK,UAC/B;AAAA,MACA,GAAG;AAAA,IACL,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA,IACb,MAAM;AAAA,SACD;AAAA,MACH;AAAA,MACA,SAAS,EAAE,OAAO,WAAW;AAAA,MAC7B,OAAO,QAAQ,IAAI;AAAA,IACrB;AAAA,EACF;AAAA;;;AOxVK,IAAM,kBAAkB,CAC7B,YAEA,UAAU,WAAU,OAAO,SAAS;AAGtC,IAAM,aAAa,CAAC,UAA0B,MAAM,QAAQ,SAAS,EAAE;AAGvE,IAAM,cAAc;AAAA,EAClB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AACX;AAGA,IAAM,gBAAgB;AAAA,EACpB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AACX;AAOA,IAAM,qBAAqB;AAAA,EACzB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AACX;AAOA,IAAM,gBAAgB;AAAA,EACpB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AACX;AAGA,IAAM,oBAAoB;AAAA,EACxB,UACE;AAAA,EACF,SACE;AAAA,EACF,SACE;AACJ;AAGA,IAAM,sBAAsB;AAAA,EAC1B,UACE;AAAA,EACF,SACE;AAAA,EACF,SACE;AACJ;AAQA,IAAM,oBAAoB,CACxB,OACA,SACW;AAAA,EACX,IAAI,iBAAiB,qBAAqB;AAAA,IACxC,OAAO,MAAM;AAAA,EACf;AAAA,EACA,IAAI,iBAAiB,kBAAkB;AAAA,IACrC,OAAO,oBAAoB;AAAA,EAC7B;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,UAAU,CAAC,UAAwB,QAA6B;AAAA,EACpE,MAAM,MAAM,oBAAO,UAAU,GAAG,SAAS;AAAA,GAAU,SAAS,IAAI;AAAA,EAChE,OAAO;AAAA,IACL,MAAM,EAAE,QAAQ,OAAO,MAAM,SAAS,KAAK;AAAA,IAG3C,MAAM,KAAK,SAAS,KAAK;AAAA,IACzB,MAAM,SAAS,GAAG;AAAA,IAClB;AAAA,IACA;AAAA,EACF;AAAA;AAIF,IAAM,cAAc,CAClB,MACA,YACA,cACkB;AAAA,EAClB,MAAM,UAAU,WAAW,IAAI,CAAC,cAC9B,QACE,aAAa,MAAM,WAAW,SAAS,GACvC,GAAG,WAAW,UAAU,KAAK,OAC/B,CACF;AAAA,EAIA,MAAM,OAAO,WAAW,KAAK,KAAK;AAAA,EAClC,QAAQ,KACN,QACE,YAAY,MAAM,SAAS,GAC3B,OAAO,GAAG,mBAAmB,WAC/B,CACF;AAAA,EACA,OAAO;AAAA;AAWT,IAAM,gBAAgB,CACpB,MACA,SAC+B;AAAA,EAC/B,MAAM,OAAO,WAAW,KAAK,KAAK;AAAA,EAClC,OAAO,OAAO,YACZ,KAAK,IAAI,CAAC,QAAQ;AAAA,IAChB,OAAO,GAAG,QAAQ,IAAI,SAAS,IAAI;AAAA,IACnC,EAAE,OAAO,IAAI,KAAK;AAAA,EACpB,CAAC,CACH;AAAA;AAsBF,IAAM,iBAAiB,OACrB,WACA,QAC6B;AAAA,EAC7B,MAAM,UAAU,EAAE,UAAU,IAAI,UAAU,SAAS,IAAI,QAAQ;AAAA,EAC/D,IAAI,UAAU,SAAS,YAAY;AAAA,IACjC,QAAQ,UAAU,aAAa,MAAM,kBACnC,UAAU,MACV,IAAI,aACJ,OACF;AAAA,IACA,MAAM,YAAY,0BAA0B,UAAU,UAAU,KAAK;AAAA,IACrE,OAAO;AAAA,MACL;AAAA,MACA,iBAAiB,UAAU;AAAA,MAC3B,YAAY,UAAU;AAAA,MACtB,MAAM,UAAU;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAAA,EACA,IAAI,UAAU,SAAS,WAAW;AAAA,IAChC,QAAQ,UAAU,aAAa,MAAM,iBACnC,UAAU,MACV,IAAI,aACJ,OACF;AAAA,IACA,MAAM,YAAY,yBAAyB,UAAU,UAAU,KAAK;AAAA,IACpE,OAAO;AAAA,MACL;AAAA,MACA,iBAAiB,UAAU;AAAA,MAC3B,YAAY,UAAU;AAAA,MACtB,MAAM,UAAU;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAAA,EACA,QAAQ,UAAU,aAAa,MAAM,UACnC,UAAU,MACV,IAAI,aACJ,OACF;AAAA,EACA,MAAM,YAAY,kBAAkB,UAAU,UAAU,KAAK;AAAA,EAC7D,OAAO;AAAA,IACL;AAAA,IACA,iBAAiB,UAAU;AAAA,IAC3B,YAAY,UAAU;AAAA,IACtB,MAAM,UAAU;AAAA,IAChB;AAAA,EACF;AAAA;AAGK,IAAM,gBAAgB,CAC3B,YACA,QACyB;AAAA,EACzB,IAAI,SAAsB,CAAC;AAAA,EAE3B,MAAM,gBAAgB,OACpB,cACqC;AAAA,IAGrC,MAAM,YAAY,YAAY,UAAU;AAAA,IACxC,MAAM,aAAa,cAAc,UAAU;AAAA,IAC3C,IAAI;AAAA,MACF,QAAQ,UAAU,UAAU,YAAY,MAAM,oBAC5C,MAAM,eAAe,WAAW,GAAG;AAAA,MACrC,MAAM,OAAO,SAAS,QAAQ,EAAE,OAAO,UAAU,OAAO,SAAS,GAAG;AAAA,MAMpE,QAAQ,OAAO,oBAAoB,UAAU,QAAQ;AAAA,MACrD,IAAI,QAAwB;AAAA,MAC5B,IAAI,oBAAoB,MAAM;AAAA,QAC5B,QAAQ,aAAa,UAAU,UAAU,aAAa;AAAA,MACxD,EAAO,SAAI,oBAAoB,SAAS,oBAAoB,IAAI;AAAA,QAC9D,QAAQ;AAAA,MACV;AAAA,MACA,MAAM,OAAoB;AAAA,QACxB,aAAa,UAAU,QAAQ;AAAA,QAC/B,aAAa,KAAK,eAAe;AAAA,QACjC;AAAA,QACA,eAAe,UAAU,QAAQ;AAAA,QACjC,MAAM,UAAU;AAAA,QAChB,OAAO,UAAU;AAAA,QAKjB,YAAY,OAAO,YACjB,WAAW,IAAI,CAAC,cAAc;AAAA,UAC5B,UAAU;AAAA,UACV;AAAA,eACK;AAAA,YACH,OAAO,aAAa,UAAU,UAAU,UAAU,KAAK;AAAA,UACzD;AAAA,QACF,CAAC,CACH;AAAA,QACA,YAAY,EAAE,SAAS,UAAU,QAAQ,WAAW,SAAS,MAAM;AAAA,QACnE,OAAO,UAAU;AAAA,QACjB,MAAM,UAAU;AAAA,QAChB;AAAA,QACA,OAAO,KAAK,SAAS,UAAU;AAAA,QAC/B,SAAS,KAAK,WAAW;AAAA,MAC3B;AAAA,MAGA,IAAI,UAAU,aAAa,WAAW;AAAA,QACpC,KAAK,WAAW,UAAU;AAAA,MAC5B;AAAA,MACA,OAAO;AAAA,QACL,aAAa;AAAA,UACX,GAAG,SAAS,IAAI,CAAC,aAAa;AAAA,YAC5B,MAAM,mBAAmB,UAAU;AAAA,YACnC;AAAA,YACA,UAAU;AAAA,UACZ,EAAE;AAAA,UACF,GAAG,gBAAgB,IAAI,CAAC,aAAa;AAAA,YACnC,MAAM,cAAc,UAAU;AAAA,YAC9B,SAAS,MAAM,mBAAmB,UAAU,UAAU;AAAA,YACtD,UAAU;AAAA,UACZ,EAAE;AAAA,UAIF,GAAI,WAAW,WAAW,IACtB;AAAA,YACE;AAAA,cACE,MAAM,GAAG;AAAA,cACT,SAAS,GAAG,mBAAmB,UAAU,aAAa,UAAU;AAAA,cAChE,UAAU;AAAA,cACV,YAAY,kBAAkB,UAAU;AAAA,YAC1C;AAAA,UACF,IACA,CAAC;AAAA,QACP;AAAA,QACA,SAAS,YAAY,MAAM,YAAY,SAAS;AAAA,QAChD,YAAY,cAAc,MAAM,IAAI;AAAA,QACpC,MAAM,UAAU;AAAA,QAChB;AAAA,MACF;AAAA,MACA,OAAO,OAAO;AAAA,MAGd,MAAM,UAAU;AAAA,MAChB,OAAO;AAAA,QACL,MAAM,GAAG;AAAA,QACT,SAAS,kBAAkB,mBAAmB,UAAU,aAAa,UAAU,UAAU,QAAQ;AAAA,QAIjG,UAAU,IAAI,SAAS,UAAU,UAAU;AAAA,QAC3C,YAAY,kBAAkB,SAAS,UAAU,IAAI;AAAA,MACvD;AAAA;AAAA;AAAA,EAIJ,MAAM,OAAO,YAAuC;AAAA,IAClD,MAAM,UAAU,MAAM,QAAQ,IAAI,WAAW,IAAI,aAAa,CAAC;AAAA,IAC/D,MAAM,UAAyB,CAAC;AAAA,IAIhC,MAAM,cAA4B,WAAW,QAAQ,CAAC,eACnD,UAAU,cAAc,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,MAC7C,MAAM;AAAA,MACN;AAAA,MACA,UAAU;AAAA,IACZ,EAAE,CACJ;AAAA,IACA,MAAM,OAAoB,CAAC;AAAA,IAC3B,MAAM,aAAyC,CAAC;AAAA,IAChD,WAAW,UAAU,SAAS;AAAA,MAC5B,IAAI,cAAc,QAAQ;AAAA,QACxB,YAAY,KAAK,MAAM;AAAA,QACvB;AAAA,MACF;AAAA,MACA,KAAK,OAAO,QAAQ,OAAO;AAAA,MAC3B,QAAQ,KAAK,GAAG,OAAO,OAAO;AAAA,MAC9B,OAAO,OAAO,YAAY,OAAO,UAAU;AAAA,MAC3C,YAAY,KAAK,GAAG,OAAO,WAAW;AAAA,IACxC;AAAA,IACA,SAAS;AAAA,IACT,OAAO,EAAE,aAAa,SAAS,WAAW;AAAA;AAAA,EAG5C,OAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,MAAM;AAAA,IACN,aAAa,MAAM;AAAA,IACnB,QAAQ;AAAA,EACV;AAAA;;;ACvYF,IAAM,aAAa,CAAC,SAClB,KACG,KAAK,EACL,WAAW,SAAS,GAAG,EACvB,WAAW,mBAAmB,OAAO,QAAQ;AAGlD,IAAM,YAAW,CACf,WACA,cACW;AAAA,EACX,MAAM,OAAO;AAAA,IAGX,WAAW,WAAW,UAAU,QAAQ,KAAK,CAAC,CAAC;AAAA,IAC/C,UAAU,aAAa,gBAAgB;AAAA,EACzC,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,EACX,OAAO,MAAM,WAAW,SAAS,MAAM,gBAAgB,UAAU,KAAK,KAAK,OAAO,MAAM,SAAS;AAAA;AA6B5F,IAAM,8BAA8B,CAAC,UAAuB;AAAA,EACjE,MAAM,OAAO,CAAC,WACZ,UAAS,MAAM,IAAI,OAAO,OAAO,MAAM,IAAI;AAAA,EAE7C,OAAO;AAAA,IAML,aAAa,GAAG,YAAY;AAAA,MAC1B,MAAM,OAAO,KAAK,MAAM,MAAM;AAAA,MAC9B,IAAI,CAAC,MAAM;AAAA,QACT,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,WAAW,UAAU,cAAc,IAAI;AAAA,MAC/C,MAAM,QAAQ;AAAA,QACZ,KAAK,UAAU,WAAW,WAAW,KAAK,OAAO,MAAM;AAAA,QACvD,UAAU,SAAS,IACf,GAAG,UAAU,UAAU,IAAI,UAAU,EAAE,KAAK,IAAI,MAChD;AAAA,MACN,EAAE,OAAO,OAAO;AAAA,MAChB,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK;AAAA;AAAA,CAAM,IAAI;AAAA;AAAA,IAIjD,kBAAkB,GAAG,YAAY;AAAA,MAC/B,QAAQ,QAAQ;AAAA,MAChB,MAAM,OAAO,KAAK,MAAM,MAAM;AAAA,MAC9B,IAAI,EAAE,QAAQ,UAAS,GAAG,IAAI;AAAA,QAC5B,OAAO;AAAA,MACT;AAAA,MACA,MAAM,QAAQ,OAAO,OAAO,KAAK,UAAU,EACxC,OAAO,CAAC,cAAc,UAAU,YAAY,GAAG,EAC/C,IAAI,CAAC,cACJ,UAAS,mBAAmB,MAAM,SAAS,GAAG,SAAS,CACzD;AAAA,MACF,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK;AAAA,CAAI,IAAI;AAAA;AAAA,IAQ/C,WAAW,GAAG,YAAY;AAAA,MACxB,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO,KAAK,MAAM,MAAM;AAAA,MAC9B,IAAI,EAAE,QAAQ,UAAS,EAAE,IAAI;AAAA,QAC3B,OAAO;AAAA,MACT;AAAA,MACA,MAAM,YAAY,YAAY,MAAM,EAAE;AAAA,MACtC,IAAI,CAAC,WAAW;AAAA,QACd,OAAO;AAAA,MACT;AAAA,MACA,MAAM,YAAY,WAAW,mBAAmB,MAAM,SAAS,CAAC;AAAA,MAChE,OAAO,UAAU,aACb,GAAG;AAAA;AAAA,mBACH;AAAA;AAAA,EAER;AAAA;;;AC9GK,IAAM,8BAA8B,CACzC,aAEC;AAAA,KACI,4BAA4B,QAAQ,YAAY,CAAC,CAAC;AAAA,KAClD,4BACD,QAAQ,QAAQ,KAAK,eAAe,GAAG,YAAY,KAAK,CAAC,CAC3D;AAAA,KACG,QAAQ,OAAO,OAAO;AAC3B;;;ACrBF,IAAM,mBACJ;AAGF,IAAM,cAAc;AASpB,IAAM,kBAAkB,CAAC,aACvB,IAAI,OACF,kCAAkC,cAAc,wDAChD,IACF;AAEF,IAAM,SAAS;AAAA,EACb,QAAQ,gBAAgB,QAAQ;AAAA,EAChC,KAAK,gBAAgB,KAAK;AAC5B;AAUO,IAAM,0BAA0B,CACrC,UACA,aACW;AAAA,EAEX,MAAM,SAAmB,CAAC;AAAA,EAC1B,MAAM,SAAS,SAAS,QAAQ,kBAAkB,CAAC,UAAU;AAAA,IAC3D,OAAO,KAAK,KAAK;AAAA,IACjB,OAAO,mBAAqB,OAAO,SAAS;AAAA,GAC7C;AAAA,EAED,IAAI,UAAU;AAAA,EACd,MAAM,WAAW,OACd,WAAW,OAAO,aAAa,WAAW,QAAQ,WAAW,MAAM;AAAA,IAClE,UAAU;AAAA,IACV,OAAO;AAAA,GACR,EACA,WAAW,OAAO,WAAW,CAAC,QAAQ,UAAkB;AAAA,IACvD,UAAU;AAAA,IACV,OAAO;AAAA,GACR;AAAA,EAKH,MAAM,SAAS,UAAU,SAAS,WAAW,YAAY;AAAA;AAAA,CAAM,IAAI;AAAA,EAEnE,OAAO,OAAO,WACZ,aACA,CAAC,OAAO,UAAU,OAAO,OAAO,KAAK,MAAM,KAC7C;AAAA;AAQK,IAAM,uBAAuB,CAAC,aACnC,wBAAwB,UAAU,QAAQ;;;ACnD5C,IAAM,UAAU,CAAC,OAAe,MAAe,OAAO,OAAe;AAAA,EACnE,MAAM,OAAO,aAAa,MAAM,KAAK;AAAA,EACrC,OAAO,UAAU,OAAO,aAAY,MAAM,IAAI,IAAI,IAAI;AAAA;AAexD,IAAM,UAAU,CAAC,SAAyB,KAAK,WAAW,SAAS,GAAG,EAAE,KAAK;AAW7E,IAAM,qBAAqB,CAAC,YAAoC;AAAA,EAC9D,QAAQ,WAAW;AAAA,EACnB,QAAQ,SAAS,OAAO,WAAW;AAAA,EACnC,MAAM,MAAM,CAAC,SACX,QAAQ,MAAM,MAAM,kBAAkB,OAAO,WAAW,QAAQ,IAAI,CAAC;AAAA,EACvE,MAAM,QAAQ;AAAA,IACZ,qBAAqB,IAAI,gBAAgB;AAAA,IACzC,qBAAqB,IAAI,WAAW;AAAA,EACtC;AAAA,EACA,IAAI,OAAO,OAAO,KAAK;AAAA,IACrB,MAAM,KACJ,gBAAgB,IAAI,cAAc,kIAAkI,IAAI,YAAY,IACtL;AAAA,EACF;AAAA,EACA,IAAI,OAAO,OAAO,IAAI,SAAS;AAAA,IAC7B,MAAM,KACJ,kBAAkB,IAAI,OAAO,OAAO,IAAI,KAAK,0KAA0K,IAAI,uBAAuB,GACpP;AAAA,EACF;AAAA,EACA,IAAI,OAAO,OAAO,QAAQ;AAAA,IACxB,MAAM,KACJ,oBAAoB,IAAI,uBAAuB,qEACjD;AAAA,EACF;AAAA,EACA,IAAI,cAAc,MAAM,GAAG;AAAA,IACzB,MAAM,KACJ,mBAAmB,IAAI,gBAAgB,mDACzC;AAAA,EACF;AAAA,EACA,IAAI,aAAa,MAAM,GAAG;AAAA,IACxB,MAAM,KACJ,kBAAkB,IAAI,eAAe,yFACvC;AAAA,EACF;AAAA,EACA,IAAI,OAAO,OAAO,kBAAkB;AAAA,IAClC,MAAM,KACJ,8BAA8B,IAAI,yBAAyB,2DAC7D;AAAA,EACF;AAAA,EACA,IAAI,QAAQ,OAAO,IAAI,SAAS;AAAA,IAC9B,MAAM,KACJ,eAAe,IAAI,cAAc,2DACnC;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAQT,IAAM,gBAAgB,CACpB,SACA,UAA4C,CAAC,MAE7C,QAAQ,MAAM,MAAM,OAClB,CAAC,SACC,EACE,KAAK,KAAK,GAAG,WACb,KAAK,KAAK,SACV,KAAK,KAAK,QAAQ,UACjB,KAAK,KAAK,IAAI,WAAW,KAAK,OAAO,SAAS,aAC9C,QAAQ,aAAa,aAAa,KAAK,YAAY,QAErD,QAAQ,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,SAAS,UACnE;AASF,IAAM,qBAAqB,CACzB,YAC0C;AAAA,EAC1C,QAAQ,MAAM,aAAa,QAAQ;AAAA,EACnC,MAAM,UAAiD,OACnD,KAAK,QAAQ,QAAQ,GAAG,MAAM,YAAY;AAAA,IACxC,MAAM,MAAM,QAAQ,MAAM,mBAAmB;AAAA,IAC7C,IAAI,CAAC,KAAK;AAAA,MACR,OAAO,CAAC;AAAA,IACV;AAAA,IACA,OAAO;AAAA,MACL,EAAE,OAAO,SAAS,KAAK,gBAAgB,YAAY,OAAO,IAAI;AAAA,IAChE;AAAA,GACD,IACD,CAAC,EAAE,KAAK,QAAQ,MAAM,WAAW,CAAC;AAAA,EAEtC,MAAM,YAAY,UAAU,YAAY,CAAC,GAAG,QAAQ,CAAC,YAAY;AAAA,IAC/D,MAAM,WAAW,QAAQ,MAAM,oBAAoB,QAAQ,OAAO,CAAC;AAAA,IACnE,MAAM,eAAe,GAAG,QAAQ,SAAS,QAAQ;AAAA,IACjD,OAAO,OAAO,QAAQ,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS;AAAA,MACvD,MAAM,SAAS,MAAM,QAAQ,KAAK,CAAC,UAAU,MAAM,SAAS,IAAI;AAAA,MAChE,MAAM,QACJ,UAAU,SAAS,MAAM,gBACrB,GAAG,OAAO,WAAW,iBACrB;AAAA,MACN,OAAO,CAAC,EAAE,OAAO,IAAI,CAAC;AAAA,KACvB;AAAA,GACF;AAAA,EAED,OAAO,CAAC,GAAG,SAAS,GAAG,QAAQ;AAAA;AAU1B,IAAM,iBAAiB,CAC5B,SACA,UAA4B,CAAC,MAClB;AAAA,EACX,QAAQ,WAAW;AAAA,EACnB,QAAQ,SAAS,OAAO,WAAW;AAAA,EACnC,MAAM,OAAO,kBAAkB,OAAO,WAAW,QAAQ,IAAI;AAAA,EAC7D,MAAM,WAAW,cAAc,OAAO;AAAA,EACtC,MAAM,UAAU,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC;AAAA,EAClE,MAAM,OAAO,IAAI;AAAA,EAEjB,MAAM,OAAO,CAAC,SAA6B;AAAA,IACzC,KAAK,IAAI,KAAK,KAAK;AAAA,IACnB,MAAM,UAAU,KAAK,cAAc,KAAK,KAAK,gBAAgB;AAAA,IAC7D,OAAO,MAAM,KAAK,UAAU,QAAQ,KAAK,OAAO,MAAM,IAAI,KAAK;AAAA;AAAA,EAQjE,MAAM,cAAc,CAAC,OAAkB,UAA4B;AAAA,IACjE,MAAM,OAAiB,CAAC;AAAA,IACxB,MAAM,cAAwB,CAAC;AAAA,IAC/B,WAAW,QAAQ,OAAO;AAAA,MACxB,IAAI,KAAK,SAAS,QAAQ;AAAA,QACxB,MAAM,OAAO,QAAQ,IAAI,KAAK,KAAK;AAAA,QACnC,IAAI,QAAQ,CAAC,KAAK,IAAI,KAAK,KAAK,GAAG;AAAA,UACjC,KAAK,KAAK,KAAK,IAAI,CAAC;AAAA,QACtB;AAAA,QACA;AAAA,MACF;AAAA,MAGA,MAAM,WAAW,KAAK,QAAQ,QAAQ,IAAI,KAAK,KAAK,IAAI;AAAA,MACxD,MAAM,SAAS,YAAY,KAAK,UAAU,QAAQ,CAAC;AAAA,MACnD,IAAI,YAAY,CAAC,KAAK,IAAI,SAAS,KAAK,GAAG;AAAA,QACzC,OAAO,QAAQ,KAAK,QAAQ,CAAC;AAAA,MAC/B;AAAA,MACA,IAAI,OAAO,SAAS,GAAG;AAAA,QACrB,YAAY,KACV,GAAG,IAAI,OAAO,KAAK,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,SAC1C,GAAG,MACL;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,KAAK;AAAA,CAAI,GAAG,GAAG,WAAW,IAAI;AAAA;AAAA,EAK/D,MAAM,YAAY,CAAC,KAAiB,UAA4B;AAAA,IAC9D,MAAM,QAAQ,IAAI,QAAQ,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM;AAAA,IAC/D,MAAM,SAAS,IAAI,QAAQ,OAAO,CAAC,SAAS,KAAK,SAAS,OAAO;AAAA,IACjE,MAAM,cAAc,YAAY,OAAO,QAAQ,CAAC;AAAA,IAChD,OAAO;AAAA,MACL,GAAI,YAAY,SAAS,IACrB,CAAC,GAAG,IAAI,OAAO,KAAK,UAAU,GAAG,WAAW,IAC5C,CAAC;AAAA,MACL,GAAG,YAAY,QAAQ,KAAK;AAAA,IAC9B;AAAA;AAAA,EAGF,MAAM,SAAmB,CAAC;AAAA,EAC1B,aAAa,OAAO,SAAS,mBAAmB,OAAO,GAAG;AAAA,IACxD,IAAI,OAAO;AAAA,MACT,MAAM,YAAY,UAAU,KAAK,CAAC;AAAA,MAClC,IAAI,UAAU,SAAS,GAAG;AAAA,QACxB,OAAO,KAAK,MAAM,SAAS,GAAG,SAAS;AAAA,MACzC;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO,KAAK,GAAG,UAAU,KAAK,CAAC,CAAC;AAAA,EAClC;AAAA,EAIA,MAAM,WAAW,SACd,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,EACtC,SAAS,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAAA,EACpD,IAAI,SAAS,SAAS,GAAG;AAAA,IACvB,OAAO,KACL,OAAO,SAAS,IAAI,aAAa,WACjC,SAAS,IAAI,IAAI,EAAE,KAAK;AAAA,CAAI,CAC9B;AAAA,EACF;AAAA,EAMA,MAAM,QAAQ,cAAc,OAAO;AAAA,EACnC,IAAI,MAAM,SAAS,GAAG;AAAA,IACpB,OAAO,KACL,gBACA,MACG,IAAI,CAAC,SAAS,MAAM,KAAK,UAAU,QAAQ,KAAK,MAAM,MAAM,IAAI,IAAI,EACpE,KAAK;AAAA,CAAI,CACd;AAAA,EACF;AAAA,EAIA,MAAM,SAAS,QAAQ,UAAU,CAAC;AAAA,EAClC,IAAI,OAAO,SAAS,GAAG;AAAA,IACrB,OAAO,KACL,mBACA,OACG,IACC,CAAC,UACC,MAAM,MAAM,SAAS,QAAQ,GAAG,oBAAoB,MAAM,QAAQ,MAAM,IAAI,OAAO,QAAQ,MAAM,WAAW,GAChH,EACC,KAAK;AAAA,CAAI,CACd;AAAA,EACF;AAAA,EAEA,OAAO,KAAK,sBAAsB,mBAAmB,OAAO,EAAE,KAAK;AAAA,CAAI,CAAC;AAAA,EAExE,MAAM,SAAS,OAAO,cAClB,KAAK,OAAO;AAAA;AAAA,IAAc,OAAO,gBACjC,KAAK,OAAO;AAAA,EAGhB,QAAQ,YAAY,OAAO,OAAO;AAAA,EAClC,MAAM,OAAO,UAAU,GAAG;AAAA;AAAA,EAAa,YAAY;AAAA,EACnD,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK;AAAA;AAAA,CAAM;AAAA;AAAA;;;AzBnQlC,IAAM,gBAAgB,CAAC,UAC5B,MAAM,MAAM,MAAM;AASb,IAAM,qBAAqB,CAAC,SACjC,KAAK,KAAK,KAAK,SAAS,CAAC;AAcpB,IAAM,mBAAmB,OAC9B,YAC8C;AAAA,EAC9C,MAAM,WAAW,IAAI,IAAI,QAAQ,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAAA,EAE3E,MAAM,aAAa,4BAA4B,OAAO;AAAA,EACtD,MAAM,eAAe,qBAAqB,OAAO;AAAA,EAEjD,MAAM,YAAY,OAAO,UAA+C;AAAA,IACtE,MAAM,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA,IAClC,IAAI,MAAM;AAAA,MACR,OAAO,MAAM,sBAAsB,SAAS,IAAI;AAAA,IAClD;AAAA,IACA,OAAO,MAAM,aAAa,MAAM,UAAS,MAAM,YAAY,OAAO,IAAI;AAAA;AAAA,EAGxE,MAAM,UAAU,MAAM,QAAQ,IAC5B,QAAQ,SAAS,OAAO,IAAI,OAAO,UAAU;AAAA,IAC3C,IAAI,OAAO,MAAM,UAAU,KAAK;AAAA,IAChC,IAAI,MAAM,YAAY;AAAA,MACpB,OAAO,sBAAsB;AAAA,QAC3B,YAAY,QAAQ,OAAO,WAAW,QAAQ;AAAA,QAC9C,aAAa,QAAQ,QAAQ;AAAA,QAC7B,QAAQ;AAAA,QACR,YAAY,MAAM;AAAA,MACpB,CAAC;AAAA,MAGD,OAAO,aAAa,MAAM;AAAA,QACxB,OAAO,MAAM;AAAA,QACb,YAAY,MAAM;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,SAAS,qBAAqB,IAAI;AAAA,IAGxC,MAAM,KAAK,oBAAoB,QAAQ,YAAY,oBAAO,MAAM,EAAE,IAAI;AAAA,IACtE,MAAM,QACJ,OAAO,SAAS,EAAE,KAAK,OAAO,IAAI,EAAE,IAAI,KAAK,OAAO;AAAA,IACtD,OAAO,CAAC,MAAM,MAAM,KAAK;AAAA,GAC1B,CACH;AAAA,EACA,MAAM,MAAM,OAAO,YAAY,OAAO;AAAA,EAMtC,IAAI,CAAC,IAAI,MAAM;AAAA,IACb,IAAI,OAAO,EAAE,KAAK,eAAe,OAAO,EAAE;AAAA,EAC5C;AAAA,EAGA,MAAM,YAAY,QAAQ,QAAQ,YAC9B,MAAM,cAAc,QAAQ,QAAQ,SAAS,IAC7C,CAAC;AAAA,EACL,IAAI,sBAAsB,SAAS,SAAS,GAAG;AAAA,IAC7C,IAAI,yBAAyB,EAAE,KAAK,4BAA4B,OAAO,EAAE;AAAA,EAC3E;AAAA,EACA,OAAO;AAAA;AAWF,IAAM,qBAAqB,CAAC,YAAoC;AAAA,EACrE,MAAM,QAAQ,QAAQ,SAAS,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EAC/D,IAAI,CAAC,MAAM,SAAS,GAAG,GAAG;AAAA,IACxB,MAAM,KAAK,GAAG;AAAA,EAChB;AAAA,EACA,MAAM,YAAY,QAAQ,QAAQ,YAC9B,kBAAkB,QAAQ,QAAQ,SAAS,IAC3C,CAAC;AAAA,EACL,IAAI,sBAAsB,SAAS,SAAS,GAAG;AAAA,IAC7C,MAAM,KAAK,qBAAqB;AAAA,EAClC;AAAA,EACA,OAAO;AAAA;;;A0BhDF,IAAM,0BAA0B;AAQvC,IAAM,YAAY;AAClB,IAAM,kBAAkB;AAoBxB,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,IAAM,aAAa,CAAC,SAClB,QAAQ,SAAS,MAAM,KAAK,QAAQ,QAAQ,EAAE,IAAI;AAYpD,IAAM,eAAe,CACnB,UAEA,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAGrE,IAAM,eAAe,CAAC,UACpB,OAAO,UAAU;AAEnB,IAAM,iBAAiB,CAAC,SAA0B,KAAK,WAAW,GAAG;AAErE,IAAM,WAAW,CAAC,SAChB,eAAe,IAAI,IAAI,KAAK,MAAM,CAAC,IAAI;AAiBlC,IAAM,2BAA2B,CAAC,SAA4B;AAAA,EACnE,MAAM,SAAS,UAAU,WAAW,IAAI,CAAC;AAAA,EACzC,MAAM,aAAa,kBAAkB,IAAI,CAAC,SAAS,IAAI,SAAS,MAAM;AAAA,EACtE,OAAO,SACH,CAAC,QAAQ,GAAG,YAAY,GAAG,UAAU,IACrC,CAAC,MAAM,GAAG,UAAU;AAAA;AAQ1B,IAAM,YAAY,CAAC,MAAc,UAC/B,UAAU,QACV,eAAe,KAAK,MAAM,eAAe,IAAI,KAC7C,SAAS,KAAK,EAAE,SAAS,GAAG,KAC5B,SAAS,IAAI,EAAE,WAAW,SAAS,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;AAUjD,IAAM,2BAA2B,CACtC,UACA,UACoB;AAAA,EACpB,IAAI,aAAa,MAAM;AAAA,IACrB,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,MAAM,QAAQ,QAAQ,IAC/B,SAAS,OAAO,CAAC,SAAyB,OAAO,SAAS,QAAQ,IAClE,CAAC;AAAA,EACL,MAAM,SAAS,CAAC,GAAG,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC;AAAA,EACxE,OAAO,OAAO,OACZ,CAAC,SAAS,CAAC,OAAO,KAAK,CAAC,UAAU,UAAU,MAAM,KAAK,CAAC,CAC1D;AAAA;AAGF,IAAM,uBAAuB,CAAC,UAC5B,UAAU,QACT,MAAM,UAAU,aACf,MAAM,MAAM,CAAC,SAAS,KAAK,UAAU,eAAe;AAmDjD,IAAM,yBAAyB,CACpC,YACW;AAAA,EACX,MAAM,SAAS,KAAK,UAAU,QAAQ,UAAU;AAAA,EAChD,MAAM,WAAW,KAAK,UAAU,QAAQ,iBAAiB,CAAC,CAAC;AAAA,EAC3D,MAAM,UAAU,KAAK,UAAU,QAAQ,aAAa;AAAA,EACpD,MAAM,SAAS,KAAK,UAAU,UAAU,WAAW,QAAQ,IAAI,CAAC,CAAC;AAAA,EACjE,MAAM,iBAAiB,KAAK,UAAU,QAAQ,kBAAkB,IAAI;AAAA,EACpE,MAAM,aAAa,KAAK,UACtB,QAAQ,eAAe,YAAY,OAAO,OAAO,QAAQ,UAAU,CACrE;AAAA,EACA,MAAM,WAAW,KAAK,UAAU;AAAA,IAC9B,MAAM,QAAQ,UAAU,SAAS;AAAA,IACjC,UAAU,QAAQ,UAAU,aAAa;AAAA,EAC3C,CAAC;AAAA,EAKD,MAAM,YAAY,KAAK,UACrB,OAAO,aACJ,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,IAC1C,cAAc,SAAS,IAAI;AAAA,IAC3B,CAAC,UAAU,SAAS,EAAE,GAAG,SAAS,MAAM;AAAA,EAC1C,CAAC,CACH,CACF;AAAA,EACA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAeY,KAAK,UAAU,QAAQ,aAAa;AAAA;AAAA,yBAEhC;AAAA,4BACG;AAAA,sBACN;AAAA,yBACG;AAAA,2BACE;AAAA,sBACL;AAAA,oBACF;AAAA,oBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4Sb,IAAM,0BAA0B,CACrC,cACA,YAC6B;AAAA,EAC7B,IAAI,QAAQ,WAAW,WAAW,GAAG;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EACA,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,SAAS,KAAK,MAAM,YAAY;AAAA,IAChC,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,EAET,IAAI,CAAC,aAAa,MAAM,GAAG;AAAA,IACzB,OAAO;AAAA,EACT;AAAA,EACA,QAAQ,SAAS;AAAA,EACjB,IACE,CAAC,aAAa,IAAI,KAClB,KAAK,WAAW,KAChB,SAAS,yBACT;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,QAAQ,WAAW;AAAA,EACnB,IAAI,CAAC,aAAa,MAAM,KAAK,CAAC,aAAa,OAAO,OAAO,GAAG;AAAA,IAC1D,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,oBAAoB,QAAQ;AAAA,IAC5B,YAAY,CAAC;AAAA,OACV;AAAA,MACD;AAAA,EAIJ,MAAM,eAAe,WAAW,QAAQ,IAAI;AAAA,EAC5C,MAAM,cAAc,IAAI,IACtB,kBAAkB,IAAI,CAAC,UACrB,cACE,gBAAgB,UAAU,MACtB,GAAG,eAAe,UAClB,gBAAgB,KACtB,CACF,CACF;AAAA,EACA,MAAM,kBAAkB,UAAU,OAChC,CAAC,aACC,SAAS,KAAK,WAAW,GAAG,KAC5B,CAAC,YAAY,IAAI,cAAc,SAAS,IAAI,CAAC,CACjD;AAAA,EACA,MAAM,QAAQ,yBACZ,OAAO,kBACP,yBAAyB,QAAQ,IAAI,CACvC;AAAA,EACA,IAAI,CAAC,qBAAqB,KAAK,GAAG;AAAA,IAChC,OAAO;AAAA,EACT;AAAA,EACA,IAAI,UAAU,MAAM;AAAA,IAClB,OAAO,mBAAmB;AAAA,EAC5B;AAAA,EACA,OAAO,OAAO;AAAA,EACd,MAAM,gBACJ,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,IAAI,OAAO,KAAK;AAAA,EAC7D,MAAM,SAAS,uBAAuB;AAAA,OACjC;AAAA,IACH,eAAe,OAAO;AAAA,IACtB;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AAAA,EAED,OAAO,EAAE,QAAQ,UAAU,KAAK,UAAU,MAAM,EAAE;AAAA;;;ACxpB7C,IAAM,4BAA4B,CACvC,WACA,UACA,eACe;AAAA,EAGf,MAAM,OAAO,kBAAkB,UAAU;AAAA,EACzC,OAAO,YAAY,OACf,UAAU,IAAI,CAAC,cAAc;AAAA,OACxB;AAAA,IACH,MAAM,aAAa,UAAU,SAAS,IAAI;AAAA,IAC1C,IAAI,qBAAqB,MAAM,UAAU,SAAS,EAAE;AAAA,EACtD,EAAE,IACF;AAAA;AAQC,IAAM,+BAA+B,CAC1C,WACA,UACA,eACe;AAAA,EACf,MAAM,OAAO,kBAAkB,UAAU;AAAA,EACzC,OAAO,YAAY,OACf,UAAU,IAAI,CAAC,cAAc;AAAA,OACxB;AAAA,IACH,MAAM,qBAAqB,MAAM,UAAU,SAAS,IAAI;AAAA,IACxD,IAAI,qBAAqB,MAAM,UAAU,SAAS,EAAE;AAAA,EACtD,EAAE,IACF;AAAA;AASC,IAAM,oBAAoB,CAAC,WAChC,6BACE,OAAO,WACP,OAAO,UACP,OAAO,WAAW,QAAQ,QAAQ,EACpC;AAGK,IAAM,wBAAwB,CAAC,cACpC,GAAG,UACA,IAAI,CAAC,aAAa,GAAG,SAAS,QAAQ,SAAS,MAAM,SAAS,QAAQ,EACtE,KAAK;AAAA,CAAI;AAAA;AAeP,IAAM,oBAAoB,CAC/B,WACA,UAAmC,CAAC,MACzB;AAAA,EACX,MAAM,SAAuB;AAAA,IAC3B,WAAW,UAAU,IAAI,CAAC,cAAc;AAAA,MACtC,aAAa,SAAS;AAAA,MACtB,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,IACvB,EAAE;AAAA,EACJ;AAAA,EACA,IAAI,QAAQ,SAAS,GAAG;AAAA,IACtB,OAAO,UAAU;AAAA,EACnB;AAAA,EACA,OAAO,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA;AAAA;;;ACrH1C,oBAAS,kBAAS;AAKX,IAAM,UAAU,CAAC,YACtB,QAAQ,WAAW,MAAK,QAAQ,MAAM,MAAM;AASvC,IAAM,YAAY,CAAC,YACxB,MAAK,QAAQ,OAAO,GAAG,QAAQ;AAe1B,IAAM,cAAc,CAAC,YAC1B,SAAQ,QAAQ,OAAO,CAAC;AAGnB,IAAM,YAAY,CAAC,UAA6C;AAAA,EACrE,MAAM,UAAU,OAAO,KAAK;AAAA,EAC5B,IAAI,CAAC,SAAS;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACA,OAAO,gBAAgB,KAAK,OAAO,IAAI,UAAU,WAAW;AAAA;;;AClCvD,IAAM,iBAA+B;AAAA,EAC1C,OAAO;AAAA,EACP,MAAM;AACR;AAWO,IAAM,kBAAkC;AAAA,EAC7C,OAAO;AAAA,IACL,QAAQ,CAAC;AAAA,IACT,SAAS,OAAO,CAAC;AAAA,IACjB,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,IACH,QAAQ,CAAC,QAAQ,QAAQ,IAAI,OAAO;AAAA,IAIpC,MAAM,CAAC,QACL,UAAU,IAAI,GAAG,KACjB,UAAU,IAAI,gBAAgB,KAC9B,UAAU,IAAI,UAAU;AAAA,EAC5B;AAAA,EACA,eAAe;AAAA,EACf,eAAe;AAAA,IACb,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,EACN,oBAAoB;AAAA,EAIpB,kBAAkB,EAAE,QAAQ,OAAO,QAAQ,KAAK;AAAA,EAChD,eAAe,CAAC,cAAc;AAAA,EAC9B,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;;;AtC1BA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF;AAYA,IAAM,iBAAiB,CAAC,YAA4B;AAAA,EAClD,MAAM,UAAU,EAAE,cAAc,WAAW,sBAAsB,OAAO;AAAA,EACxE,MAAM,eAAe,sBAAsB,IAAI,CAAC,SAC9C,MAAK,QAAQ,MAAM,IAAI,CACzB,EAAE,KAAK,CAAC,SAAS,YAAW,IAAI,CAAC;AAAA,EACjC,IAAI,CAAC,cAAc;AAAA,IACjB,OAAO;AAAA,EACT;AAAA,EACA,IAAI,aAAa,UAAS,QAAQ,QAAQ,YAAY;AAAA,EAItD,IAAI,CAAC,WAAW,WAAW,GAAG,KAAK,CAAC,WAAW,WAAW,GAAG,GAAG;AAAA,IAC9D,aAAa,KAAK;AAAA,EACpB;AAAA,EACA,OAAO,KAAK,SAAS,WAAW;AAAA;AAGlC,IAAM,yBAAyB,CAAC,QAC9B,IAAI,KACF,iIACF;AAWK,IAAM,4BAA4B,OACvC,SACA,QACkB;AAAA,EAClB,QAAQ,QAAQ,YAAY;AAAA,EAC5B,MAAM,YAAY,MAAK,QAAQ,OAAO,GAAG,QAAQ;AAAA,EACjD,MAAM,eAAe,MAAK,WAAW,eAAe;AAAA,EACpD,IAAI,CAAC,YAAW,YAAY,GAAG;AAAA,IAC7B,uBAAuB,GAAG;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,MAAM,aAAa,mBAAmB,OAAO;AAAA,EAI7C,MAAM,cAAc,MAAM,iBAAiB,OAAO;AAAA,EAClD,MAAM,OAAO,YAAY;AAAA,EAIzB,MAAM,YAAY,UAAU,OAAO;AAAA,EACnC,MAAM,WAAW,wBACf,MAAM,UAAS,cAAc,OAAO,GACpC;AAAA,IACE,MAAM,OAAO,WAAW,QAAQ;AAAA,IAIhC,mBAAmB,QAAQ,SAAS,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,IACpE,gBAAgB,oBAAoB,QAAQ,UAAU;AAAA,IACtD,YAAY,OAAO,mBAAmB,cAAc,IAAI,CAAC,IAAI;AAAA,IAC7D,UAAU;AAAA,MACR,MAAM,YAAW,MAAK,WAAW,UAAU,CAAC;AAAA,MAC5C,UAAU,YAAW,MAAK,WAAW,QAAQ,CAAC;AAAA,IAChD;AAAA,IAGA,eAAe,OAAO,OAAO,MACzB,QAAQ,SAAS,OACd,OACC,CAAC,UAAU,CAAC,MAAM,UAAU,YAAY,MAAM,UAAU,SAC1D,EACC,IAAI,CAAC,UAAU,aAAa,MAAM,IAAI,CAAC,IAC1C,CAAC;AAAA,IAKL,WAAW,kBAAkB,MAAM;AAAA,IACnC;AAAA,EACF,CACF;AAAA,EACA,IAAI,aAAa,MAAM;AAAA,IACrB,uBAAuB,GAAG;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,MAAM,WACJ,MAAK,WAAW,uBAAuB,GACvC,SAAS,QACT,OACF;AAAA,EACA,MAAM,WAAU,cAAc,SAAS,UAAU,OAAO;AAAA,EACxD,IAAI,QACF,oEACF;AAAA;AAOF,IAAM,gBAAgB,MAAK,aAAa,UAAU,aAAa;AAmBxD,IAAM,6BAA6B,OACxC,YACkB;AAAA,EAClB,MAAM,cAAc,MAAK,QAAQ,OAAO,GAAG,UAAU,eAAe;AAAA,EACpE,IAAI,CAAC,YAAW,WAAW,GAAG;AAAA,IAC5B;AAAA,EACF;AAAA,EACA,MAAM,SAAS,MAAK,QAAQ,QAAQ,aAAa;AAAA,EACjD,MAAM,SAAS,MAAK,QAAQ,MAAM,aAAa;AAAA,EAC/C,MAAM,SAAS,CAAC,SACd,UAAS,SAAQ,MAAM,GAAG,SAAQ,SAAQ,MAAM,GAAG,IAAI,CAAC;AAAA,EAC1D,MAAM,eAA6B,YAAW,MAAM,IAChD,KAAK,MAAM,MAAM,UAAS,QAAQ,OAAO,CAAC,IAC1C,EAAE,YAAY,UAAS,SAAQ,MAAM,GAAG,WAAW,EAAE;AAAA,EACzD,MAAM,UAAwB;AAAA,IAC5B,mBAAmB,aAAa,oBAAoB,CAAC,GAAG,IAAI,CAAC,YAAY;AAAA,MACvE,YAAY,OAAO,OAAO,UAAU;AAAA,IACtC,EAAE;AAAA,IACF,YAAY,OAAO,aAAa,UAAU;AAAA,EAC5C;AAAA,EACA,IAAI,aAAa,2BAA2B;AAAA,IAC1C,QAAQ,4BAA4B,OAClC,aAAa,yBACf;AAAA,EACF;AAAA,EACA,MAAM,OAAM,SAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,EAChD,MAAM,WAAU,QAAQ,GAAG,KAAK,UAAU,OAAO;AAAA,GAAO,OAAO;AAAA;AAQjE,IAAM,sBAAsB;AAO5B,IAAM,eAAe,CAAC,SACpB,KACG,YAAY,EACZ,WAAW,eAAe,GAAG,EAC7B,MAAM,GAAG,EAAE,EACX,WAAW,aAAa,EAAE;AAO/B,IAAM,oBAAoB,OACxB,YACgC;AAAA,EAChC,QAAQ,QAAQ,YAAY;AAAA,EAC5B,MAAM,cAAc,MAAK,QAAQ,MAAM,cAAc;AAAA,EACrD,MAAM,WAA8B,YAAW,WAAW,IACtD,KAAK,MAAM,MAAM,UAAS,aAAa,OAAO,CAAC,IAC/C,CAAC;AAAA,EACL,QAAQ,SAAS,OAAO,WAAW;AAAA,EACnC,OAAO;AAAA,IACL,OAAO,SAAS,QAAQ,EAAE;AAAA,IAC1B,OAAO,IAAI,IAAI,IAAI,EAAE,WAAW;AAAA,IAChC,UAAS,QAAQ,IAAI;AAAA,EACvB,EACG,IAAI,YAAY,EAChB,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;AAAA;AAQ5B,IAAM,uBAAuB,OAClC,SACA,QACkB;AAAA,EAClB,MAAM,eAAe,MACnB,QAAQ,QAAQ,OAAO,GACvB,UACA,eACF;AAAA,EACA,IAAI,CAAC,YAAW,YAAY,GAAG;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,WAAqD,KAAK,MAC9D,MAAM,UAAS,cAAc,OAAO,CACtC;AAAA,EACA,MAAM,OAAO,MAAM,kBAAkB,OAAO;AAAA,EAC5C,IAAI,SAAS,SAAS,uBAAuB,SAAS,WAAW;AAAA,IAC/D;AAAA,EACF;AAAA,EACA,SAAS,OAAO;AAAA,EAChB,IAAI,SAAS,iBAAiB,qBAAqB;AAAA,IACjD,SAAS,eAAe;AAAA,EAC1B;AAAA,EACA,MAAM,WAAU,cAAc,KAAK,UAAU,QAAQ,GAAG,OAAO;AAAA,EAC/D,IAAI,KACF,gCAAgC,8EAClC;AAAA;AAYK,IAAM,qBAAqC;AAAA,EAChD,OAAO;AAAA,IACL,QAAQ,EAAE,SAAS,MAAM;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,IACH,QAAQ,CAAC,QAAQ,QAAQ,IAAI,QAAQ;AAAA,IACrC,MAAM,CAAC,QAAQ,UAAU,IAAI,YAAY;AAAA,EAC3C;AAAA,EACA,eAAe,SAAS,UAAU,KAAK,cAAc;AAAA,IAGnD,IAAI,CAAC,UAAU;AAAA,MACb,MAAM,qBAAqB,SAAS,GAAG;AAAA,MACvC,MAAM,0BAA0B,SAAS,GAAG;AAAA,MAC5C,MAAM,2BAA2B,QAAQ,OAAO;AAAA,IAClD;AAAA,IACA,OAAO;AAAA;AAAA,EAET,eAAe;AAAA,IAGb,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,EACN,oBAAoB;AAAA,EACpB,kBAAkB,EAAE,QAAQ,MAAM,QAAQ,KAAK;AAAA,EAC/C,eAAe,CAAC,cAAc;AAAA,EAC9B,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;;;AuCvTA,uBAAS;AACT,qBAAS,gCAAkB;AAE3B,iBAAS;;;ACQF,IAAM,4BACX;AAKK,IAAM,4BACX;;;ACkDK,IAAM,mBAAmB;;;AF5BzB,IAAM,kBAAkB;AAExB,IAAM,wBAAwB;AAErC,IAAM,iBAAiB;AAGhB,IAAM,kBAAkB,CAAC,WAA6C;AAAA,EAC3E,MAAM,aAAa,kBAAkB,OAAO,WAAW,QAAQ,IAAI;AAAA,EACnE,MAAM,SAAS,IAAI;AAAA,EACnB,MAAM,MAAM,CAAC,MAAc,MAAc,UAAwB;AAAA,IAC/D,OAAO,IAAI,MAAM,KAAK,OAAO,IAAI,IAAI,IAAI,OAAO,MAAM,CAAC;AAAA;AAAA,EAEzD,IAAI,cAAc,MAAM,GAAG;AAAA,IACzB,IAAI,kBAAkB,gBAAgB,gBAAgB;AAAA,EACxD;AAAA,EACA,IAAI,OAAO,OAAO,WAAW,KAAK,SAAS,GAAG;AAAA,IAC5C,IAAI,2BAA2B,gBAAgB,yBAAyB;AAAA,EAC1E;AAAA,EACA,WAAW,QAAQ,0BAA0B,MAAM,GAAG;AAAA,IACpD,IAAI,MAAM,+BAA+B,GAAG;AAAA,EAC9C;AAAA,EACA,OAAO,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc;AAAA,IAC3C;AAAA,IACA,MAAM,GAAG,aAAa;AAAA,EACxB,EAAE;AAAA;AAIJ,IAAM,aAAa,CACjB,UAEA,MACG,OAAO,CAAC,SAAS,CAAC,KAAK,KAAK,SAAS,GAAG,CAAC,EACzC,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,KAAK,OAAO,CAAC;AAM5C,IAAM,eAAe,CACnB,UAEA,MACG,OAAO,CAAC,SAAS,KAAK,KAAK,SAAS,GAAG,CAAC,EACxC,IAAI,CAAC,SAAS;AAAA,EACb,MAAM,OAAO,KAAK,KAAK,QAAQ,GAAG;AAAA,EAClC,OAAO;AAAA,IACL,KAAK,KAAK,MAAM,GAAG,IAAI;AAAA,IACvB,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,IACxB,KAAK;AAAA,EACP;AAAA,CACD;AAaE,IAAM,mBAAmB,CAAC,UAC/B,GAAG;AAAA,2DACsD;AAAA;AAAA;AAAA;AAAA,wBAInC,KAAK,UAAU,WAAW,KAAK,CAAC;AAAA,mBACrC,KAAK,UAAU,aAAa,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAcrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCzB,IAAM,gBAAgB,OAC3B,SACA,QACkB;AAAA,EAIlB,MAAM,YAAY,OAAK,QAAQ,QAAQ,OAAO,GAAG,UAAU,cAAc;AAAA,EACzE,MAAM,QAAQ;AAAA,IACZ,GAAG,gBAAgB,QAAQ,MAAM;AAAA,IACjC,GAAI,YAAW,SAAS,IACpB;AAAA,MACE;AAAA,QACE,SAAS,EAAE,2BAA2B,iBAAiB;AAAA,QACvD,MAAM,GAAG,kBAAkB,QAAQ,OAAO,WAAW,QAAQ,IAAI;AAAA,MACnE;AAAA,IACF,IACA,CAAC;AAAA,EACP;AAAA,EACA,IAAI,MAAM,WAAW,GAAG;AAAA,IACtB;AAAA,EACF;AAAA,EACA,MAAM,YAAY,OAAK,QAAQ,QAAQ,OAAO,GAAG,QAAQ;AAAA,EACzD,MAAM,QAAQ,OAAK,WAAW,eAAe;AAAA,EAC7C,IAAI,CAAC,YAAW,KAAK,GAAG;AAAA,IACtB,IAAI,KACF,2CAA2C,kGAC7C;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM,SAAS,MAAM,UAAS,OAAO,OAAO;AAAA,EAC5C,IAAI,OAAO,WAAW,cAAc,GAAG;AAAA,IACrC;AAAA,EACF;AAAA,EACA,MAAM,OAAO,OAAO,OAAK,WAAW,qBAAqB,CAAC;AAAA,EAC1D,MAAM,WAAU,OAAO,iBAAiB,KAAK,GAAG,OAAO;AAAA,EACvD,IAAI,QACF,oEACF;AAAA;;;AGtLK,IAAM,eAA+B;AAAA,EAC1C,OAAO;AAAA,IACL,QAAQ,CAAC;AAAA,IACT,SAAS,OAAO,EAAE,MAAM,aAAa;AAAA,IACrC,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,EACL,eAAe,SAAS,UAAU,KAAK,cAAc;AAAA,IAEnD,IAAI,CAAC,UAAU;AAAA,MACb,MAAM,cAAc,SAAS,GAAG;AAAA,IAClC;AAAA,IACA,OAAO;AAAA;AAAA,EAET,eAAe;AAAA,IACb,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,EACN,oBAAoB;AAAA,EACpB,kBAAkB,EAAE,QAAQ,OAAO,QAAQ,MAAM;AAAA,EACjD,eAAe,CAAC;AAAA,EAChB,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;;;ACvCA,uBAAS;AACT,qBAAS,yBAAU;AAEnB,iBAAS;;;ACHT,uBAAS,6BAAY;AACrB,8BAAkB;AAClB;AAEA;AACA,oBAAS,kBAAS,oBAAM;AACxB,cAAS;AAwCT,IAAM,WAAW,IAAI,IAAI,cAAc;AAGvC,IAAM,uBAAuB,CAAC,SAAS,UAAU,YAAY,SAAS,MAAI;AAMnE,IAAM,cAAc,CAAC,cAAqC;AAAA,EAC/D,IACE,UAAU,WAAW,GAAG,KACxB,UAAU,WAAW,GAAG,KACxB,qBAAqB,KAAK,CAAC,WAAW,UAAU,WAAW,MAAM,CAAC,KAClE,SAAS,IAAI,SAAS,GACtB;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,MAAM,WAAW,UAAU,MAAM,GAAG;AAAA,EACpC,IAAI,UAAU,WAAW,GAAG,GAAG;AAAA,IAC7B,OAAO,SAAS,UAAU,IAAI,GAAG,SAAS,MAAM,SAAS,OAAO;AAAA,EAClE;AAAA,EACA,OAAO,SAAS,MAAM;AAAA;AASxB,IAAM,gBACJ;AAGF,IAAM,iBAAiB;AAMvB,IAAM,oBAAoB,CAAC,WAA6B;AAAA,EACtD,MAAM,aAAuB,CAAC;AAAA,EAC9B,WAAW,WAAW,CAAC,eAAe,cAAc,GAAG;AAAA,IACrD,WAAW,SAAS,OAAO,SAAS,OAAO,GAAG;AAAA,MAC5C,MAAM,SAAS,MAAM,UAAU,CAAC;AAAA,MAChC,WAAW,KAAK,OAAO,QAAQ,OAAO,QAAQ,OAAO,WAAW,EAAE;AAAA,IACpE;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAYT,IAAM,kBAAkB,CAAC,QAAgB,SAA2B;AAAA,EAClE,OAAO,WAAW,MAAM,QAAQ,IAAI;AAAA,EACpC,MAAM,aAAuB,CAAC;AAAA,EAC9B,WAAW,SAAS,SAAS;AAAA,IAC3B,IAAI,MAAM,SAAS,aAAa,MAAM,MAAM;AAAA,MAC1C;AAAA,IACF;AAAA,IACA,IAAI,MAAM,WAAW;AAAA,MACnB,WAAW,KAAK,MAAM,SAAS;AAAA,IACjC;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAQF,IAAM,mBAAmB,OAC9B,QACA,OAAO,aACe;AAAA,EACtB,MAAM,KAAK;AAAA,EACX,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,aAAa,gBAAgB,QAAQ,IAAI;AAAA,IACzC,MAAM;AAAA,IACN,aAAa,kBAAkB,MAAM;AAAA;AAAA,EAEvC,MAAM,QAAQ,IAAI;AAAA,EAClB,WAAW,aAAa,YAAY;AAAA,IAClC,MAAM,YAAY,YAAY,SAAS;AAAA,IACvC,IAAI,WAAW;AAAA,MACb,MAAM,IAAI,SAAS;AAAA,IACrB;AAAA,EACF;AAAA,EACA,OAAO,CAAC,GAAG,KAAK;AAAA;AAIlB,IAAM,aAAa,CAAC,MAAc,MAAc,SAA0B;AAAA,EACxE,IAAI,MAAM;AAAA,EACV,UAAS;AAAA,IACP,IAAI,YAAW,OAAK,KAAK,gBAAgB,MAAM,cAAc,CAAC,GAAG;AAAA,MAC/D,OAAO;AAAA,IACT;AAAA,IACA,IAAI,QAAQ,MAAM;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IACA,MAAM,SAAS,SAAQ,GAAG;AAAA,IAC1B,IAAI,WAAW,KAAK;AAAA,MAClB,OAAO;AAAA,IACT;AAAA,IACA,MAAM;AAAA,EACR;AAAA;AAGF,IAAM,cAAc;AAGpB,IAAM,iBAAiB,IAAE,YAAY,EAAE,SAAS,IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAGvE,IAAM,cAAc,OAAO,QAAmC;AAAA,EAC5D,MAAM,QAAkB,CAAC;AAAA,EACzB,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EAC1D,WAAW,SAAS,SAAS;AAAA,IAC3B,MAAM,OAAO,OAAK,KAAK,MAAM,IAAI;AAAA,IACjC,IAAI,MAAM,YAAY,GAAG;AAAA,MACvB,IAAI,MAAM,SAAS,gBAAgB;AAAA,QAEjC,MAAM,KAAK,GAAI,MAAM,YAAY,IAAI,CAAE;AAAA,MACzC;AAAA,IACF,EAAO,SAAI,MAAM,OAAO,KAAK,YAAY,KAAK,MAAM,IAAI,GAAG;AAAA,MACzD,MAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AASF,IAAM,sBAAsB,OACjC,YAC8B;AAAA,EAC9B,MAAM,aAAa,OAAK,SAAS,iBAAiB;AAAA,EAClD,IAAI,CAAC,YAAW,UAAU,GAAG;AAAA,IAC3B,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,SAAS,eAAe,UAC5B,KAAK,MAAM,MAAM,WAAS,YAAY,OAAO,CAAC,CAChD;AAAA,EACA,IAAI,CAAC,OAAO,WAAW,CAAC,OAAO,KAAK,SAAS;AAAA,IAC3C,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,YAAY,SAAQ,OAAK,SAAS,OAAO,KAAK,OAAO,CAAC;AAAA,EAC5D,IAAI,CAAC,YAAW,SAAS,GAAG;AAAA,IAC1B,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,UAAU,IAAI;AAAA,EACpB,WAAW,QAAQ,MAAM,YAAY,SAAS,GAAG;AAAA,IAE/C,MAAM,SAAS,MAAM,WAAS,MAAM,OAAO;AAAA,IAE3C,WAAW,QAAQ,MAAM,iBAAiB,QAAQ,IAAI,GAAG;AAAA,MACvD,IAAI,WAAW,MAAM,SAAQ,IAAI,GAAG,OAAO,GAAG;AAAA,QAC5C;AAAA,MACF;AAAA,MACA,MAAM,YAAY,QAAQ,IAAI,IAAI,KAAK,CAAC;AAAA,MACxC,UAAU,KAAK,UAAS,SAAS,IAAI,CAAC;AAAA,MACtC,QAAQ,IAAI,MAAM,SAAS;AAAA,IAC7B;AAAA,EACF;AAAA,EACA,OAAO,CAAC,GAAG,OAAO,EACf,IAAI,EAAE,MAAM,gBAAgB,EAAE,WAAW,KAAK,EAAE,EAChD,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA;AAQ7C,IAAM,uBAAuB,OAClC,cACmC;AAAA,EACnC,MAAM,eAAe,OAAK,WAAW,WAAW;AAAA,EAChD,IAAI,CAAC,YAAW,YAAY,GAAG;AAAA,IAC7B,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,SAAgC,CAAC;AAAA,EACvC,MAAM,UAAU,MAAM,QAAQ,cAAc,EAAE,eAAe,KAAK,CAAC;AAAA,EACnE,WAAW,SAAS,QAAQ,SAAS,CAAC,GAAG,MAAO,EAAE,OAAO,EAAE,OAAO,KAAK,CAAE,GAAG;AAAA,IAC1E,IAAI,EAAE,MAAM,YAAY,KAAK,MAAM,KAAK,SAAS,OAAO,IAAI;AAAA,MAC1D;AAAA,IACF;AAAA,IACA,MAAM,MAAM,OAAK,cAAc,MAAM,IAAI;AAAA,IAEzC,MAAM,UAAU,MAAM,oBAAoB,GAAG;AAAA,IAC7C,IAAI,QAAQ,SAAS,GAAG;AAAA,MACtB,OAAO,KAAK,EAAE,KAAK,QAAQ,CAAC;AAAA,IAC9B;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAIF,IAAM,uBAAuB,MAAmB;AAAA,EACrD,MAAM,WAAsD,KAAK,MAC/D,cAAa,OAAK,YAAY,GAAG,cAAc,GAAG,OAAO,CAC3D;AAAA,EACA,OAAO,IAAI,IAAI,OAAO,KAAK,SAAS,gBAAgB,CAAC,CAAC,CAAC;AAAA;AAoBlD,IAAM,0BAA0B,OAAO,SAC5C,GAAG,YAAY,MAAM,4BAA4B,IAAI,CAAC,EAAE;AASnD,IAAM,wBAAwB,CACnC,OACA,MACA,iBACA,gBAAgB,qBACU;AAAA,EAC1B,MAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EACrD,MAAM,QAAQ,MAAM,QAAQ,IAC1B,CAAC,UAAU,OAAO,MAAM,qBAAqB,MAAM,UAAU,KAAK,IAAI,IACxE;AAAA,EACA,MAAM,QAAQ,MAAM,KAAK,CAAC,SAAS,gBAAgB,IAAI,IAAI,CAAC;AAAA,EAC5D,MAAM,UAAU;AAAA,IACd,iCAAiC,UAAS,MAAM,MAAM,GAAG,KAAK,MAAM;AAAA,IACpE,GAAG;AAAA,IACH;AAAA,IACA,KAAK,iBAAiB,MAAM,KAAK,GAAG;AAAA,EACtC,EAAE,KAAK;AAAA,CAAI;AAAA,EACX,OAAO,EAAE,OAAO,QAAQ;AAAA;;;AC1RnB,IAAM,+BACX;AAQK,IAAM,2BACX;AAkBF,IAAM,YAAW,CAAC,UAChB,OAAO,UAAU;AAEnB,IAAM,4BAAgD;AAAA,EACpD,EAAE,KAAK,UAAU,MAAM,UAAU,OAAO,6BAA6B;AACvE;AAEA,IAAM,wBAA4C;AAAA,EAChD,EAAE,KAAK,UAAU,MAAM,UAAU,OAAO,yBAAyB;AACnE;AAEA,IAAM,cAAc,EAAE,MAAM,SAAS;AAGrC,IAAM,0BAA0B;AAGhC,IAAM,sBAAsB;AAG5B,IAAM,sBAAsB;AAW5B,IAAM,4BAAoD;AAAA,EACxD;AAAA,IACE,MAAM;AAAA,IACN,KAAK;AAAA,IACL,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,EACV;AAAA,EACA,EAAE,MAAM,yBAAyB,KAAK,gBAAgB,QAAQ,IAAI;AACpE;AASA,IAAM,wBAAgD;AAAA,EACpD;AAAA,IACE,MAAM;AAAA,IACN,KAAK;AAAA,IACL,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,EACV;AAAA,EACA,EAAE,MAAM,qBAAqB,KAAK,gBAAgB,QAAQ,IAAI;AAChE;AAaA,IAAM,yBAAyB;AAE/B,IAAM,iBAAiB;AAQvB,IAAM,eAAe,CAAC,UACpB,UAAU,KAAK,EAAE,QAAQ,gBAAgB,MAAM;AAGjD,IAAM,gBAAgB,CAAC,aAA4C;AAAA,EACjE,MAAM,SAAqB,CAAC;AAAA,EAC5B,IAAI,UAAoB,CAAC;AAAA,EACzB,IAAI,SAAS;AAAA,EACb,WAAW,WAAW,UAAU;AAAA,IAC9B,IACE,QAAQ,SAAS,KACjB,SAAS,QAAQ,SAAS,IAAI,wBAC9B;AAAA,MACA,OAAO,KAAK,OAAO;AAAA,MACnB,UAAU,CAAC;AAAA,MACX,SAAS;AAAA,IACX;AAAA,IACA,QAAQ,KAAK,OAAO;AAAA,IACpB,UAAU,QAAQ,SAAS;AAAA,EAC7B;AAAA,EACA,IAAI,QAAQ,SAAS,GAAG;AAAA,IACtB,OAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EACA,OAAO;AAAA;AAgCF,IAAM,yBAAyB,CACpC,YACA,eACsB;AAAA,EACtB,MAAM,OAAO,WAAW,SAAS,GAAG;AAAA,EACpC,MAAM,OAAO,WACV,OAAO,CAAC,SAAS,SAAS,GAAG,EAC7B,IAAI,CAAC,SAAS,aAAa,IAAI,CAAC;AAAA,EACnC,MAAM,SAAS,cAAc,IAAI;AAAA,EAEjC,MAAM,gBAA+B,OACjC;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,KAAK;AAAA,MACL,SACE,eAAe,YACX,cACA,KAAK,aAAa,qBAAqB,OAAO,UAAU,EAAE;AAAA,MAChE,KAAK;AAAA,IACP;AAAA,EACF,IACA,CAAC;AAAA,EACL,WAAW,SAAS,QAAQ;AAAA,IAC1B,cAAc,KAAK;AAAA,MACjB,MAAM;AAAA,MACN,KAAK;AAAA,MACL,SAAS;AAAA,MACT,KAAK,KAAK,MAAM,KAAK,GAAG;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,cAAc,OAAO,CAAC,KAAK,GAAG,IAAI,IAAI,IAAI;AAAA,EAC/D,MAAM,eAA8B,aAAa,IAAI,CAAC,WAAW;AAAA,IAC/D,UAAU;AAAA,IACV,SAAS;AAAA,IACT,KAAK,OAAO,MAAM,KAAK,GAAG;AAAA,EAC5B,EAAE;AAAA,EAEF,OAAO,EAAE,cAAc,cAAc;AAAA;AAIvC,IAAM,WAAW;AAEjB,IAAM,mBAAmB;AAOzB,IAAM,YAAY,CAAC,UAA+B;AAAA,EAChD,UAAU;AAAA,EACV,SAAS,EAAE,+BAA+B,iBAAiB;AAAA,EAC3D,KAAK,IAAI,aAAa,IAAI;AAC5B;AAGA,IAAM,cAAc,CAAC,UACnB,MAAM,aAAa,QACnB,MAAM,UAAU,mCAAmC,oBACnD,UAAS,MAAM,GAAG,KAClB,OAAO,KAAK,KAAK,EAAE,WAAW;AAYhC,IAAM,qBAAqB,CAAC,UAC1B,MAAM,KAAK,KACT,CAAC,cAAc,UAAU,UAAU,4BACrC,MAAM,QACL,MAAM,SAAS,2BAA2B,MAAM,WAAW,OAC3D,MAAM,SAAS,uBAAuB,MAAM,WAAW,OACvD,MAAM,aAAa,QAClB,MAAM,SAAS,SAAS,YACxB,UAAS,MAAM,GAAG,KAClB,OAAO,KAAK,KAAK,EAAE,WAAW,KAC/B,MAAM,aAAa,QAClB,UAAS,MAAM,SAAS,IAAI,KAC5B,MAAM,QAAQ,YACd,OAAO,KAAK,KAAK,EAAE,WAAW,KAChC,YAAY,KAAK;AAuBZ,IAAM,0BAA0B,CACrC,YACA,YACA,gBACA,sBACA,YACA,WAA6B,CAAC,GAC9B,YAA+B,CAAC,MACd;AAAA,EAClB,MAAM,kBAAkB,OAAO,QAAQ,wBAAwB,CAAC,CAAC;AAAA,EACjE,IAAI;AAAA,EAIJ,IAAI;AAAA,IACF,SAAS,KAAK,MAAM,UAAU;AAAA,IAC9B,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,EAET,IAAI,CAAC,MAAM,QAAQ,OAAO,MAAM,GAAG;AAAA,IACjC,OAAO;AAAA,EACT;AAAA,EACA,YAAY,MAAM,gBAAgB,iBAAiB;AAAA,IAGjD,OAAO,YAAY,KAAK,OAAO,YAAY,OAAO,EAAE,YAAY,EAAE;AAAA,EACpE;AAAA,EACA,MAAM,SAAS,OAAO,OAAO,OAAO,CAAC,UAAU,CAAC,mBAAmB,KAAK,CAAC;AAAA,EACzE,MAAM,kBAAkB,OAAO,UAC7B,CAAC,UAAU,MAAM,WAAW,YAC9B;AAAA,EACA,IAAI,oBAAoB,IAAI;AAAA,IAC1B,OAAO;AAAA,EACT;AAAA,EACA,QAAQ,cAAc,kBAAkB,uBACtC,YACA,UACF;AAAA,EACA,IAAI,gBAAgB;AAAA,IAClB,aAAa,KAAK;AAAA,MAChB,UAAU;AAAA,MACV,SAAS,EAAE,MAAM,eAAe;AAAA,MAChC,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EACA,aAAa,KAAK,GAAG,UAAU,IAAI,SAAS,CAAC;AAAA,EAI7C,OAAO,OAAO,iBAAiB,GAAG,GAAG,cAAc,GAAG,aAAa;AAAA,EACnE,MAAM,iBAAiB;AAAA,IACrB,GAAI,SAAS,WAAW,4BAA4B,CAAC;AAAA,IACrD,GAAI,SAAS,OAAO,wBAAwB,CAAC;AAAA,EAC/C;AAAA,EACA,IAAI,eAAe,SAAS,GAAG;AAAA,IAC7B,MAAM,gBAAgB,OAAO,UAC3B,CAAC,UAAU,MAAM,WAAW,OAAO,MAAM,SAAS,mBACpD;AAAA,IACA,IAAI,kBAAkB,IAAI;AAAA,MACxB,OAAO,OAAO,eAAe,GAAG,GAAG,cAAc;AAAA,IACnD;AAAA,EACF;AAAA,EACA,OAAO,SAAS;AAAA,EAChB,OAAO,GAAG,KAAK,UAAU,QAAQ,MAAM,IAAI;AAAA;AAAA;;;AF1UtC,IAAM,mBAAiC;AAAA,EAC5C,OAAO;AAAA,EACP,MAAM;AACR;AAQA,IAAM,iBAAiB,CAAC,YACtB,OAAK,YAAY,OAAO,GAAG,WAAW,QAAQ;AAUzC,IAAM,6BAA6B,OACxC,WACA,MACA,QACqB;AAAA,EACrB,MAAM,SAAS,MAAM,qBAAqB,SAAS;AAAA,EACnD,MAAM,MAAM,qBAAqB;AAAA,EAEjC,MAAM,gBAAgB,MAAM,wBAAwB,IAAI;AAAA,EACxD,IAAI,QAAQ;AAAA,EACZ,WAAW,SAAS,QAAQ;AAAA,IAC1B,MAAM,UAAU,sBAAsB,OAAO,MAAM,KAAK,aAAa;AAAA,IACrE,IAAI,QAAQ,OAAO;AAAA,MACjB,QAAQ;AAAA,MACR,IAAI,MAAM,QAAQ,OAAO;AAAA,IAC3B,EAAO;AAAA,MACL,IAAI,KAAK,QAAQ,OAAO;AAAA;AAAA,EAE5B;AAAA,EACA,OAAO,CAAC;AAAA;AAWH,IAAM,wBAAwB,OACnC,SACA,QACkB;AAAA,EAClB,QAAQ,QAAQ,YAAY;AAAA,EAC5B,MAAM,YAAY,eAAe,OAAO;AAAA,EACxC,MAAM,aAAa,OAAK,WAAW,aAAa;AAAA,EAChD,IAAI,CAAC,YAAW,UAAU,GAAG;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,MAAM,aAAa,mBAAmB,OAAO;AAAA,EAC7C,MAAM,YAAoC,CAAC;AAAA,EAC3C,IAAI,cAAc,MAAM,GAAG;AAAA,IACzB,UAAU,iBAAiB,MAAM,CAAC,KAAK;AAAA,EACzC;AAAA,EACA,IAAI,OAAO,OAAO,WAAW,KAAK,SAAS,GAAG;AAAA,IAC5C,UAAU,0BAA0B,MAAM,CAAC,KAAK;AAAA,EAClD;AAAA,EAIA,MAAM,cAAc,MAAM,iBAAiB,OAAO;AAAA,EAClD,MAAM,OAAO,YAAY;AAAA,EAIzB,MAAM,YAAY,OAAK,WAAW,QAAQ;AAAA,EAC1C,MAAM,WAAW,wBACf,MAAM,WAAS,YAAY,OAAO,GAClC,YACA,oBAAoB,QAAQ,UAAU,GACtC,WACA,OAAO,mBAAmB,cAAc,IAAI,CAAC,IAAI,WACjD;AAAA,IACE,MAAM,YAAW,OAAK,WAAW,UAAU,CAAC;AAAA,IAC5C,UAAU,YAAW,OAAK,WAAW,QAAQ,CAAC;AAAA,EAChD,GACA,0BAA0B,MAAM,CAClC;AAAA,EACA,IAAI,aAAa,MAAM;AAAA,IACrB,IAAI,KACF,kIACF;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM,WAAU,YAAY,UAAU,OAAO;AAAA,EAC7C,IAAI,QACF,wEACF;AAAA;AAYK,IAAM,iBAAiC;AAAA,EAC5C,OAAO;AAAA,IACL,QAAQ,CAAC;AAAA,IACT,SAAS,OAAO,CAAC;AAAA,IACjB,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,IACH,QAAQ,CAAC,QAAQ,QAAQ,IAAI,MAAM;AAAA,IAKnC,MAAM,CAAC,QACL,UAAU,IAAI,6BAA6B,KAAK,UAAU,IAAI,UAAU;AAAA,EAC5E;AAAA,EACA,eAAe,SAAS,UAAU,KAAK,cAAc;AAAA,IACnD,QAAQ,YAAY;AAAA,IACpB,MAAM,KAAK,MAAM,2BACf,eAAe,OAAO,GACtB,QAAQ,MACR,GACF;AAAA,IACA,IAAI,CAAC,IAAI;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,CAAC,UAAU;AAAA,MACb,MAAM,sBAAsB,SAAS,GAAG;AAAA,IAC1C;AAAA,IACA,OAAO;AAAA;AAAA,EAET,eAAe;AAAA,IACb,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,EACN,oBAAoB;AAAA,EACpB,kBAAkB,EAAE,QAAQ,OAAO,QAAQ,MAAM;AAAA,EACjD,eAAe,CAAC,gBAAgB;AAAA,EAChC,iBAAiB;AAAA,EACjB,iBAAiB,CAAC,YAAY,OAAK,eAAe,OAAO,GAAG,QAAQ;AACtE;;;AGnLO,IAAM,iBAAiC;AAAA,EAC5C,OAAO;AAAA,EACP,KAAK;AAAA,EACL,eAAe;AAAA,EACf,eAAe;AAAA,IACb,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,EACN,oBAAoB;AAAA,EACpB,kBAAkB,EAAE,QAAQ,OAAO,QAAQ,KAAK;AAAA,EAChD,eAAe,CAAC,gBAAgB,gBAAgB;AAAA,EAChD,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;;;ACZO,IAAM,mBAA8C;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,SAAS,IAAI,IACjB,iBAAiB,IAAI,CAAC,aAAa,CAAC,SAAS,MAAM,QAAQ,CAAC,CAC9D;AAGO,IAAM,iBAAiB,CAC5B,eACmB;AAAA,EACnB,MAAM,WAAW,OAAO,IAAI,WAAW,IAAI;AAAA,EAC3C,IAAI,CAAC,UAAU;AAAA,IACb,MAAM,IAAI,MAAM,+BAA+B,WAAW,QAAQ;AAAA,EACpE;AAAA,EACA,OAAO;AAAA;AASF,IAAM,sBAAsB,CACjC,YACA,QACkB;AAAA,EAClB,MAAM,MAAM,eAAe,UAAU;AAAA,EACrC,MAAM,aAAa,CAAC,KAAK,GAAG,iBAAiB,OAAO,CAAC,MAAM,MAAM,GAAG,CAAC;AAAA,EACrE,MAAM,WAAW,WAAW,KAC1B,CAAC,aAAa,SAAS,KAAK,OAAO,GAAG,KAAK,KAC7C;AAAA,EAEA,OAAO,UAAU,KAAK,KAAK,GAAG,KAAK;AAAA;;;ACvDrC,uBAAS;AAET,uBAAS,qBAAY,mBAAM;AAM3B,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,kBAAkB,CAAC,WAAW;AACpC,IAAM,uBAAuB,CAAC,kBAAkB,eAAe;AAE/D,IAAM,gBAAgB,CAAC,MAAc,UAAmC;AAAA,EACtE,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,YAAY,OAAK,MAAM,IAAI;AAAA,IACjC,IAAI,YAAW,SAAS,GAAG;AAAA,MACzB,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAIF,IAAM,iBAAiB,CAAC,SAC7B,cAAc,MAAM,gBAAgB;AAG/B,IAAM,qBAAqB,CAAC,SACjC,cAAc,MAAM,oBAAoB;AAOnC,IAAM,oBAAoB,CAC/B,MACA,aAAa,aAEb,YAAW,UAAU,IAAI,aAAa,OAAK,SAAQ,IAAI,GAAG,UAAU;AAQ/D,IAAM,wBAAwB,CACnC,MACA,QACA,YACmB;AAAA,EACnB,MAAM,eAAe,SAAQ,IAAI;AAAA,EAGjC,MAAM,cAAc,sBAAsB,QAAQ,YAAY,EAAE;AAAA,EAEhE,MAAM,YAAY,OAAK,cAAc,OAAO,QAAQ,KAAK;AAAA,EACzD,MAAM,YAAY,YAAW,SAAS,IAAI,YAAY;AAAA,EAEtD,MAAM,SAAS,kBAAkB,cAAc,SAAS,UAAU;AAAA,EAGlE,MAAM,UAAU,SAAS,aACrB,OAAK,QAAQ,MAAM,IACnB,OAAK,cAAc,MAAM;AAAA,EAE7B,OAAO;AAAA,IACL,gBAAgB,mBAAmB,YAAY;AAAA,IAC/C,YAAY,eAAe,YAAY;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,WAAW,cAAc,cAAc,eAAe;AAAA,EACxD;AAAA;;;ACjFF,uBAAS,6BAAY;AAErB,cAAS;;;ACSF,IAAM,qBAAqB,CAChC,QACA,MAAyB,QAAQ,QACd;AAAA,EACnB,QAAQ,eAAe;AAAA,EACvB,IAAI,WAAW,QAAQ,MAAM;AAAA,IAC3B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,oBAAoB,YAAY,GAAG;AAAA,EAChD,IAAI,CAAC,MAAM;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA,OACF;AAAA,IACH,YAAY;AAAA,SACP;AAAA,MACH,SAAS,KAAK,WAAW,SAAS,KAAK;AAAA,IACzC;AAAA,EACF;AAAA;;;AC7BF;AASO,IAAM,qBAAqB,MAA4C;AAAA,EAC5E,MAAM,OAAO,WAAW,YAAY,KAAK,EAAE,aAAa,MAAM,CAAC;AAAA,EAC/D,OAAO,OAAO,SAAiB;AAAA,IAC7B,MAAM,SAAS,MAAM,KAAK,OAA8B,IAAI;AAAA,IAC5D,OAAO,QAAQ,WAAW;AAAA;AAAA;;;AFmKvB,MAAM,8BAA8B,WAAW;AAAA,EAC3C;AAAA,EAET,WAAW,CAAC,YAAwB,QAAsB;AAAA,IACxD,MAAM,UAAU;AAAA,IAChB,KAAK,OAAO;AAAA,IACZ,KAAK,SAAS;AAAA;AAElB;AAiBA,IAAM,qBAAqB,mBAAmB;AAS9C,IAAM,wBAAwB,IAAE,YAAY;AAAA,EAC1C,OAAO,IAAE,YAAY,EAAE,OAAO,IAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,IAAM,gBAAgB,CAAC,YACrB,OAAO,YAAY;AAOrB,IAAM,eAAe,CAAC,UAAiD;AAAA,EACrE,GAAG,MAAM,KAAK,OAAO,aAAa;AAAA,EAClC,GAAI,MAAM,SAAS,sBAAsB,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC;AACrE;AAGA,IAAM,WAAW,CAAC,eAChB,WAAW,QAAQ,OAAO;AAQ5B,IAAM,eAAe,CACnB,OACA,YACiB;AAAA,EACjB,MAAM,OAAO;AAAA,EACb,MAAM,UAAU,sBACd,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,IAC3B,SAAS,MAAM;AAAA,IACf,MAAM,aAAa,KAAK;AAAA,EAC1B,EAAE,GACF,EAAE,MAAM,QAAQ,QAAQ,OAAO,CACjC;AAAA,EACA,OAAO,mBAAmB,OAAO,EAAE,SAAS,QAAQ,CAAC,EAClD,IAAI,CAAC,YAAY,WAAW;AAAA,OACxB;AAAA,IACH,QAAQ,QAAQ,QAAQ;AAAA,IACxB,MAAM,QAAQ,QAAQ;AAAA,EACxB,EAAE,EACD,SACC,CAAC,GAAG,MACF,OAAO,QAAQ,EAAE,UAAU,CAAC,IAAI,OAAO,QAAQ,EAAE,UAAU,CAAC,KAC5D,SAAS,CAAC,IAAI,SAAS,CAAC,CAC5B;AAAA;AAOG,IAAM,aAAa,OACxB,MAMA,UAAqC,CAAC,MACR;AAAA,EAC9B,MAAM,aAAa,eAAe,IAAI;AAAA,EAEtC,IAAI;AAAA,EACJ,IAAI,YAAY;AAAA,IACd,IAAI;AAAA,MACF,MAAM,MAAM,mBAAmB,UAAU;AAAA,MACzC,OAAO,OAAO;AAAA,MAId,MAAM,IAAI,WAAW;AAAA,QACnB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,0BAA2B,MAAgB;AAAA,QACpD,UAAU;AAAA,MACZ,CAAC;AAAA;AAAA,EAEL;AAAA,EAGA,MAAM,QAAQ,sBAAsB,UAAU,GAAG;AAAA,EACjD,MAAM,uBACJ,MAAM,WAAW,MAAM,KAAK,OAAO,UAAU;AAAA,EAE/C,MAAM,SAAS,kBAAkB,UAAU,OAAO,CAAC,CAAC;AAAA,EACpD,IAAI,CAAC,OAAO,SAAS;AAAA,IAEnB,MAAM,SACJ,cAAc,YAAW,UAAU,IAC/B,cAAa,YAAY,OAAO,IAChC;AAAA,IACN,MAAM,cAAc,aAAa,OAAO,OAAO;AAAA,MAC7C,MAAM,cAAc;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,IACD,OAAO,UAAU,QAAQ;AAAA,IACzB,MAAM,UAAU,SAAS;AAAA,MACvB,MAAM;AAAA,MACN,MAAM,cAAc;AAAA,MACpB,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAAA,IAGA,MAAM,aAAa,KAAK,IAAI,CAAC,MAAM,OAAO,EAAE,SAAS,EAAE,KAAK;AAAA,CAAI;AAAA,IAChE,MAAM,SACJ,KAAK,SAAS,IACV;AAAA,SACK;AAAA,MACH,SAAS,GAAG,QAAQ;AAAA,EAAY,KAAK;AAAA,EAAiC;AAAA,IACxE,IACA;AAAA,IACN,MAAM,IAAI,sBAAsB,QAAQ,WAAW;AAAA,EACrD;AAAA,EAKA,MAAM,SAAS,mBAAmB,OAAO,IAAI;AAAA,EAC7C,MAAM,OAAO,OAAO,WAAW,QAAQ,QAAQ,QAAQ;AAAA,EAIvD,MAAM,YAAY,OAAO,IAAI,GAAG,WAAW,QAAQ,IAAI;AAAA,EAEvD,OAAO;AAAA,IACL,QAAQ;AAAA,SACH;AAAA,MACH,YAAY,OACR;AAAA,WACK,OAAO;AAAA,QACV,SAAS,KAAK,OAAO,WAAW,SAAS,KAAK;AAAA,MAChD,IACA,OAAO;AAAA,MACX,KAAK,KAAK,OAAO,KAAK,IAAI,KAAK,OAAO,IAAI,IAAI,SAAS,UAAU,EAAE;AAAA,IACrE;AAAA,IACA;AAAA,IACA,aAAa,CAAC;AAAA,IACd;AAAA,EACF;AAAA;",
|
|
180
|
+
"debugId": "5AE81CD75F92625F64756E2164756E21",
|
|
181
|
+
"names": []
|
|
182
|
+
}
|