blume 2.1.3 → 2.2.1
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 +1 -1
- package/CHANGELOG.md +134 -0
- package/README.md +4 -4
- package/dist/cli/{chunk-y4msrwm9.js → chunk-080mfch6.js} +15 -15
- package/dist/cli/{chunk-gfc5fqvf.js → chunk-1ch3ct3r.js} +18 -18
- package/dist/cli/{chunk-gfc5fqvf.js.map → chunk-1ch3ct3r.js.map} +1 -1
- package/dist/cli/{chunk-32khwcb6.js → chunk-2ssh60qh.js} +42 -69
- package/dist/cli/{chunk-32khwcb6.js.map → chunk-2ssh60qh.js.map} +9 -10
- package/dist/cli/{chunk-9qzgg6mj.js → chunk-34wap3ed.js} +3 -3
- package/dist/cli/{chunk-k3gr1nm9.js → chunk-40vk8kgf.js} +13 -16
- package/dist/cli/{chunk-k3gr1nm9.js.map → chunk-40vk8kgf.js.map} +3 -3
- package/dist/cli/chunk-487b95qy.js +329 -0
- package/dist/cli/chunk-487b95qy.js.map +13 -0
- package/dist/cli/chunk-4zxh25hc.js +157 -0
- package/dist/cli/chunk-4zxh25hc.js.map +10 -0
- package/dist/cli/chunk-69rjf786.js +146 -0
- package/dist/cli/chunk-69rjf786.js.map +11 -0
- package/dist/cli/{chunk-dqhg54mr.js → chunk-9h8mh2tk.js} +3 -3
- package/dist/cli/{chunk-dqhg54mr.js.map → chunk-9h8mh2tk.js.map} +2 -2
- package/dist/cli/{chunk-bqxaqn5p.js → chunk-9jqmq5hv.js} +8 -8
- package/dist/cli/{chunk-bqxaqn5p.js.map → chunk-9jqmq5hv.js.map} +1 -1
- package/dist/cli/{chunk-dv2z0rzf.js → chunk-aafhwx74.js} +38 -13
- package/dist/cli/{chunk-dv2z0rzf.js.map → chunk-aafhwx74.js.map} +5 -4
- package/dist/cli/{chunk-desvm72z.js → chunk-b680sv30.js} +22 -26
- package/dist/cli/chunk-b680sv30.js.map +13 -0
- package/dist/cli/{chunk-0w6hs479.js → chunk-beb0z983.js} +30 -18
- package/dist/cli/chunk-beb0z983.js.map +10 -0
- package/dist/cli/{chunk-1f882900.js → chunk-c5bjxq8v.js} +2 -2
- package/dist/cli/chunk-e1n41w9m.js +155 -0
- package/dist/cli/chunk-e1n41w9m.js.map +11 -0
- package/dist/cli/{chunk-sc93apfs.js → chunk-etckvbrh.js} +17 -17
- package/dist/cli/{chunk-sc93apfs.js.map → chunk-etckvbrh.js.map} +2 -2
- package/dist/cli/{chunk-bxwhtvw8.js → chunk-f260jdrn.js} +5 -5
- package/dist/cli/{chunk-74wfhv79.js → chunk-fnxgtjeq.js} +1 -1
- package/dist/cli/{chunk-ms9z66nz.js → chunk-gwy55cx3.js} +2 -2
- package/dist/cli/{chunk-ms9z66nz.js.map → chunk-gwy55cx3.js.map} +2 -2
- package/dist/cli/{chunk-dhwtqnnd.js → chunk-gxhcf2hs.js} +2 -2
- package/dist/cli/{chunk-tfycddbt.js → chunk-h0qwdbem.js} +2 -2
- package/dist/cli/{chunk-nbyvgnnm.js → chunk-hktq4j5r.js} +109 -49
- package/dist/cli/chunk-hktq4j5r.js.map +36 -0
- package/dist/cli/{chunk-twy7psdz.js → chunk-hn3g2b89.js} +14 -10
- package/dist/cli/chunk-hn3g2b89.js.map +10 -0
- package/dist/cli/{chunk-j1x92mx9.js → chunk-j4nfgn2j.js} +1 -1
- package/dist/cli/{chunk-dpy8qdjf.js → chunk-k45sq16q.js} +74 -183
- package/dist/cli/chunk-k45sq16q.js.map +18 -0
- package/dist/cli/{chunk-5cmts6dv.js → chunk-kmswjxj9.js} +7 -7
- package/dist/cli/{chunk-5cmts6dv.js.map → chunk-kmswjxj9.js.map} +1 -1
- package/dist/cli/{chunk-36bxs9c7.js → chunk-nqna8dzp.js} +27 -23
- package/dist/cli/chunk-nqna8dzp.js.map +10 -0
- package/dist/cli/{chunk-a57yh0h9.js → chunk-p834rkcn.js} +7 -7
- package/dist/cli/{chunk-a57yh0h9.js.map → chunk-p834rkcn.js.map} +1 -1
- package/dist/cli/{chunk-60hz265r.js → chunk-ppa6mg4d.js} +24 -11
- package/dist/cli/chunk-ppa6mg4d.js.map +10 -0
- package/dist/cli/{chunk-s0bdnc7v.js → chunk-q1wwrxzw.js} +5 -4
- package/dist/cli/chunk-q1wwrxzw.js.map +10 -0
- package/dist/cli/{chunk-ave1wcbr.js → chunk-qcyxkj44.js} +1 -1
- package/dist/cli/{chunk-124fvmzq.js → chunk-r5nm9w0c.js} +11183 -8806
- package/dist/cli/{chunk-124fvmzq.js.map → chunk-r5nm9w0c.js.map} +82 -66
- package/dist/cli/{chunk-ckrcm08h.js → chunk-rtvgmg2j.js} +48 -62
- package/dist/cli/{chunk-ckrcm08h.js.map → chunk-rtvgmg2j.js.map} +4 -5
- package/dist/cli/{chunk-297ajdcv.js → chunk-t2h8pwy1.js} +6 -6
- package/dist/cli/{chunk-297ajdcv.js.map → chunk-t2h8pwy1.js.map} +3 -3
- package/dist/cli/{chunk-gxtg6ed2.js → chunk-x60e15st.js} +21 -21
- package/dist/cli/{chunk-gxtg6ed2.js.map → chunk-x60e15st.js.map} +3 -3
- package/dist/cli/{chunk-58bt3hag.js → chunk-x7bh6d9j.js} +4 -4
- package/dist/cli/{chunk-hvcxng5f.js → chunk-ydqzkhjn.js} +6 -6
- package/dist/cli/{chunk-kdpzw38a.js → chunk-yg8ckc3g.js} +95 -7
- package/dist/cli/chunk-yg8ckc3g.js.map +11 -0
- package/dist/cli/{chunk-0pmb4tr4.js → chunk-zxd5jrgx.js} +1205 -222
- package/dist/cli/chunk-zxd5jrgx.js.map +44 -0
- package/dist/cli/index.js +78 -42
- package/dist/cli/index.js.map +7 -6
- package/dist/types/ai/changelog-components.d.ts +18 -0
- package/dist/types/ai/changelog-markdown.d.ts +12 -0
- package/dist/types/ai/openapi-components.d.ts +7 -7
- package/dist/types/ai/operation-details.d.ts +39 -0
- package/dist/types/ai/relative-links.d.ts +3 -1
- package/dist/types/ai/serializers.d.ts +6 -4
- package/dist/types/analytics/head.d.ts +4 -2
- package/dist/types/analytics/script.d.ts +8 -2
- package/dist/types/components/content/youtube.d.ts +20 -0
- package/dist/types/components/layout/nav-utils.d.ts +8 -0
- package/dist/types/components/openapi/example-panels.d.ts +33 -0
- package/dist/types/components/openapi/helpers.d.ts +53 -11
- package/dist/types/components/openapi/snippets.d.ts +7 -1
- package/dist/types/core/alert-diagnostics.d.ts +10 -0
- package/dist/types/core/builtin-tags.d.ts +16 -0
- package/dist/types/core/changelog-list.d.ts +48 -0
- package/dist/types/core/closest-match.d.ts +6 -0
- package/dist/types/core/code-fence-diagnostics.d.ts +18 -0
- package/dist/types/core/code-fences.d.ts +8 -1
- package/dist/types/core/config-input.d.ts +38 -6
- package/dist/types/core/content-assets.d.ts +16 -18
- package/dist/types/core/data.d.ts +6 -2
- package/dist/types/core/diagnostics.d.ts +14 -0
- package/dist/types/core/directive-diagnostics.d.ts +22 -8
- package/dist/types/core/former-routes.d.ts +14 -0
- package/dist/types/core/github.d.ts +5 -4
- package/dist/types/core/heading-markers.d.ts +65 -2
- package/dist/types/core/hidden-pages.d.ts +3 -0
- package/dist/types/core/includes.d.ts +23 -0
- package/dist/types/core/last-modified.d.ts +18 -6
- package/dist/types/core/links.d.ts +42 -2
- package/dist/types/core/load-module.d.ts +19 -4
- package/dist/types/core/manifest.d.ts +14 -1
- package/dist/types/core/markdown-mirrors.d.ts +22 -0
- package/dist/types/core/mcp-clients.d.ts +47 -0
- package/dist/types/core/mdx-elements.d.ts +32 -0
- package/dist/types/core/mdx-syntax.d.ts +100 -0
- package/dist/types/core/meta-diagnostics.d.ts +7 -0
- package/dist/types/core/meta.d.ts +32 -5
- package/dist/types/core/nav-diagnostics.d.ts +16 -2
- package/dist/types/core/navigation.d.ts +13 -0
- package/dist/types/core/ordering-prefix.d.ts +6 -0
- package/dist/types/core/pinned-ids.d.ts +23 -0
- package/dist/types/core/project-graph.d.ts +9 -1
- package/dist/types/core/redirect-patterns.d.ts +18 -0
- package/dist/types/core/relative-files.d.ts +31 -0
- package/dist/types/core/schema.d.ts +322 -11
- package/dist/types/core/sources/normalize.d.ts +101 -9
- package/dist/types/core/sources/types.d.ts +16 -0
- package/dist/types/core/static-files.d.ts +10 -0
- package/dist/types/core/static-host.d.ts +42 -0
- package/dist/types/core/svg-images.d.ts +26 -0
- package/dist/types/core/syntax-diagnostics.d.ts +14 -0
- package/dist/types/core/types.d.ts +42 -1
- package/dist/types/deploy/generated-files.d.ts +41 -0
- package/dist/types/deploy/redirects.d.ts +21 -7
- package/dist/types/markdown/code-title.d.ts +9 -5
- package/dist/types/markdown/directives.d.ts +8 -0
- package/dist/types/markdown/fence-language.d.ts +51 -0
- package/dist/types/markdown/fence-meta.d.ts +5 -0
- package/dist/types/markdown/github-alerts.d.ts +35 -0
- package/dist/types/openapi/asyncapi.d.ts +6 -5
- package/dist/types/openapi/checks.d.ts +10 -5
- package/dist/types/openapi/model.d.ts +55 -8
- package/dist/types/openapi/parse.d.ts +4 -1
- package/dist/types/ratelimit/index.d.ts +2 -0
- package/dist/types/ratelimit/memory.d.ts +1 -1
- package/dist/types/ratelimit/schema.d.ts +40 -0
- package/dist/types/ratelimit/unkey.d.ts +48 -0
- package/dist/types/sources/filesystem.d.ts +14 -4
- package/dist/types/sources/mdx-remote.d.ts +6 -3
- package/dist/types/sources/registry.d.ts +3 -3
- package/dist/types/theme/color.d.ts +33 -0
- package/dist/types/theme/palette.d.ts +122 -0
- package/docs/01-quickstart.mdx +1 -1
- package/docs/02-deployment.mdx +24 -8
- package/docs/04-migrating.mdx +16 -4
- package/docs/advanced/changelog.mdx +27 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +1 -1
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +1 -1
- package/docs/cli/index.mdx +4 -2
- package/docs/cli/validate.mdx +10 -7
- package/docs/configuration/analytics.mdx +2 -0
- package/docs/configuration/customization.mdx +3 -1
- package/docs/configuration/index.mdx +7 -6
- package/docs/configuration/rate-limiting.mdx +20 -1
- package/docs/configuration/theming.mdx +5 -1
- package/docs/content/components.mdx +26 -6
- package/docs/content/frontmatter.mdx +1 -1
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/includes.mdx +6 -2
- package/docs/content/index.mdx +11 -1
- package/docs/content/islands.mdx +2 -0
- package/docs/content/meta.mdx +9 -3
- package/docs/content/navigation.mdx +14 -6
- package/docs/content/sources/obsidian.mdx +1 -1
- package/docs/content/sources/remote-mdx.mdx +3 -1
- package/docs/content/syntax.mdx +76 -8
- package/docs/content/variables.mdx +3 -1
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/json-api.mdx +1 -1
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/mcp.mdx +40 -8
- package/docs/discoverability/open-graph.mdx +1 -1
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/graphql.mdx +2 -0
- package/docs/references/openapi.mdx +45 -7
- package/package.json +4 -4
- package/skills/blume/SKILL.md +2 -2
- package/skills/blume-migrate/SKILL.md +51 -29
- package/skills/blume-migrate/references/docsify.md +262 -0
- package/skills/blume-migrate/references/docus.md +298 -0
- package/skills/blume-migrate/references/docusaurus.md +5 -5
- package/skills/blume-migrate/references/fern.md +327 -0
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/gitbook.md +267 -0
- package/skills/blume-migrate/references/github-wiki.md +259 -0
- package/skills/blume-migrate/references/jekyll.md +253 -0
- package/skills/blume-migrate/references/mdbook.md +256 -0
- package/skills/blume-migrate/references/mintlify.md +5 -5
- package/skills/blume-migrate/references/mkdocs.md +236 -0
- package/skills/blume-migrate/references/monorepo.md +20 -8
- package/skills/blume-migrate/references/nextra.md +5 -5
- package/skills/blume-migrate/references/readme.md +257 -0
- package/skills/blume-migrate/references/redocly.md +198 -0
- package/skills/blume-migrate/references/starlight.md +3 -3
- package/skills/blume-migrate/references/vitepress.md +204 -0
- package/skills/blume-migrate/references/vuepress.md +271 -0
- package/skills/blume-migrate/scripts/docsify-codemod.mjs +2387 -0
- package/skills/blume-migrate/scripts/docus-codemod.mjs +2542 -0
- package/skills/blume-migrate/scripts/fern-codemod.mjs +2633 -0
- package/skills/blume-migrate/scripts/github-wiki-codemod.mjs +2808 -0
- package/skills/blume-migrate/scripts/include-excerpts.mjs +649 -0
- package/skills/blume-migrate/scripts/jekyll-codemod.mjs +3649 -0
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +17 -13
- package/skills/blume-migrate/scripts/mkdocs-codemod.mjs +2526 -0
- package/skills/blume-migrate/scripts/operation-routes.mjs +508 -0
- package/skills/blume-migrate/scripts/pin-heading-ids.mjs +1049 -0
- package/skills/blume-migrate/scripts/readme-codemod.mjs +4139 -0
- package/skills/blume-migrate/scripts/vitepress-codemod.mjs +1511 -0
- package/src/ai/changelog-components.ts +24 -0
- package/src/ai/changelog-markdown.ts +45 -41
- package/src/ai/component-markdown.ts +22 -9
- package/src/ai/llms.ts +36 -5
- package/src/ai/markdown.ts +2 -2
- package/src/ai/openapi-components.ts +25 -9
- package/src/ai/operation-details.ts +208 -0
- package/src/ai/relative-links.ts +48 -8
- package/src/ai/serializers.ts +7 -6
- package/src/ai/site-skill.ts +6 -2
- package/src/analytics/head.ts +11 -5
- package/src/analytics/script.ts +13 -3
- package/src/astro/generate.ts +47 -11
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +27 -1
- package/src/astro/mdx-source-errors.ts +46 -0
- package/src/astro/templates.ts +93 -189
- package/src/audit/checks/redirects.ts +5 -1
- package/src/audit/redirects.ts +36 -19
- package/src/audit/report.ts +22 -9
- package/src/audit/run.ts +12 -28
- package/src/audit/terms.ts +23 -0
- package/src/audit/url.ts +2 -2
- package/src/cli/build-failure.ts +256 -7
- package/src/cli/command-meta.ts +1 -1
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.ts +12 -3
- package/src/cli/commands/check.ts +13 -2
- package/src/cli/commands/dev.ts +1 -1
- package/src/cli/commands/doctor.ts +4 -2
- package/src/cli/commands/init.ts +3 -3
- package/src/cli/commands/preview.ts +17 -1
- package/src/cli/commands/validate.ts +22 -10
- package/src/cli/prepare.ts +1 -1
- package/src/cli/preview-pages.ts +161 -0
- package/src/cli/required-secrets.ts +0 -1
- package/src/cli/unknown-flags.ts +1 -42
- package/src/components/code-copy.ts +51 -0
- package/src/components/code-language.ts +75 -0
- package/src/components/content/AccordionItem.astro +16 -1
- package/src/components/content/Callout.astro +11 -1
- package/src/components/content/Changelog.astro +189 -0
- package/src/components/content/CodeBlock.astro +8 -11
- package/src/components/content/Tabs.astro +16 -2
- package/src/components/content/YouTube.astro +6 -4
- package/src/components/content/code-block.ts +33 -0
- package/src/components/content/content-strings.ts +5 -1
- package/src/components/content/inline-markdown.ts +35 -8
- package/src/components/content/youtube.ts +49 -7
- package/src/components/layout/Analytics.astro +5 -1
- package/src/components/layout/NavTree.astro +8 -3
- package/src/components/layout/PageActions.astro +81 -23
- package/src/components/layout/RootLayout.astro +35 -32
- package/src/components/layout/SiteFooter.astro +31 -8
- package/src/components/layout/nav-utils.ts +14 -0
- package/src/components/layout/search/pagefind.ts +2 -1
- package/src/components/openapi/Operation.astro +4 -0
- package/src/components/openapi/PanelTabs.astro +9 -3
- package/src/components/openapi/RequestBody.astro +42 -8
- package/src/components/openapi/RequestPanel.astro +34 -53
- package/src/components/openapi/example-panels.ts +110 -0
- package/src/components/openapi/helpers.ts +195 -20
- package/src/components/openapi/operation-model.ts +63 -26
- package/src/components/openapi/request.ts +13 -0
- package/src/components/openapi/snippets.ts +14 -2
- package/src/core/alert-diagnostics.ts +89 -0
- package/src/core/builtin-tags.ts +76 -0
- package/src/core/changelog-list.ts +87 -0
- package/src/core/closest-match.ts +41 -0
- package/src/core/code-fence-diagnostics.ts +267 -0
- package/src/core/code-fences.ts +43 -7
- package/src/core/component-diagnostics.ts +65 -12
- package/src/core/config-input.ts +39 -5
- package/src/core/config.ts +46 -1
- package/src/core/content-assets.ts +64 -144
- package/src/core/data.ts +10 -3
- package/src/core/diagnostics.ts +36 -3
- package/src/core/directive-diagnostics.ts +265 -47
- package/src/core/former-routes.ts +46 -0
- package/src/core/git-ignored.ts +53 -0
- package/src/core/github.ts +5 -4
- package/src/core/heading-markers.ts +156 -2
- package/src/core/hidden-pages.ts +64 -0
- package/src/core/includes.ts +181 -41
- package/src/core/last-modified.ts +47 -10
- package/src/core/links.ts +438 -83
- package/src/core/load-module.ts +98 -9
- package/src/core/manifest.ts +12 -9
- package/src/core/markdown-mirrors.ts +52 -0
- package/src/core/mcp-clients.ts +87 -0
- package/src/core/mdx-elements.ts +153 -0
- package/src/core/mdx-syntax.ts +377 -0
- package/src/core/meta-diagnostics.ts +134 -0
- package/src/core/meta.ts +154 -55
- package/src/core/nav-diagnostics.ts +41 -4
- package/src/core/navigation.ts +70 -10
- package/src/core/ordering-prefix.ts +22 -2
- package/src/core/pinned-ids.ts +141 -0
- package/src/core/project-graph.ts +221 -29
- package/src/core/redirect-patterns.ts +41 -0
- package/src/core/relative-files.ts +145 -0
- package/src/core/schema.ts +110 -6
- package/src/core/sources/mdx-remote.ts +75 -14
- package/src/core/sources/normalize.ts +885 -179
- package/src/core/sources/notion.ts +5 -4
- package/src/core/sources/obsidian.ts +2 -5
- package/src/core/sources/types.ts +17 -0
- package/src/core/static-files.ts +40 -0
- package/src/core/static-host.ts +125 -0
- package/src/core/svg-images.ts +98 -0
- package/src/core/syntax-diagnostics.ts +491 -0
- package/src/core/types.ts +43 -1
- package/src/deploy/artifacts.ts +2 -28
- package/src/deploy/generated-files.ts +128 -0
- package/src/deploy/platforms/vercel.ts +25 -1
- package/src/deploy/redirects.ts +43 -16
- package/src/deploy/sitemap.ts +2 -1
- package/src/markdown/base-links.ts +87 -6
- package/src/markdown/code-title.ts +29 -13
- package/src/markdown/content-assets.ts +210 -0
- package/src/markdown/directives.ts +69 -5
- package/src/markdown/fence-language.ts +106 -0
- package/src/markdown/fence-meta.ts +42 -0
- package/src/markdown/github-alerts.ts +172 -0
- package/src/markdown/heading-anchors.ts +265 -56
- package/src/markdown/include.ts +30 -3
- package/src/markdown/index.ts +145 -40
- package/src/markdown/prompt-text.ts +95 -0
- package/src/markdown/relative-links.ts +37 -2
- package/src/markdown/route-snapshot.ts +22 -12
- package/src/markdown/svg-fallback.ts +51 -0
- package/src/markdown/title-heading.ts +134 -0
- package/src/migrate/migrate.ts +127 -2
- package/src/og/card.ts +14 -4
- package/src/openapi/asyncapi.ts +14 -6
- package/src/openapi/checks.ts +160 -15
- package/src/openapi/model.ts +172 -33
- package/src/openapi/parse.ts +13 -4
- package/src/openapi/render-mdx.ts +55 -9
- package/src/openapi/source.ts +87 -6
- package/src/ratelimit/index.ts +2 -0
- package/src/ratelimit/memory.ts +1 -1
- package/src/ratelimit/runtime.ts +81 -0
- package/src/ratelimit/schema.ts +2 -0
- package/src/ratelimit/unkey.ts +61 -0
- package/src/registry/eject.ts +0 -1
- package/src/registry/registry.ts +1 -1
- package/src/search/documents.ts +10 -2
- package/src/sources/filesystem.ts +28 -3
- package/src/sources/mdx-remote.ts +7 -15
- package/src/theme/color.ts +14 -0
- package/src/theme/entry.ts +22 -1
- package/src/theme/palette.ts +74 -1
- package/dist/cli/chunk-0pmb4tr4.js.map +0 -35
- package/dist/cli/chunk-0w6hs479.js.map +0 -10
- package/dist/cli/chunk-150jk7km.js +0 -52
- package/dist/cli/chunk-150jk7km.js.map +0 -10
- package/dist/cli/chunk-36bxs9c7.js.map +0 -10
- package/dist/cli/chunk-53jqw8z0.js +0 -89
- package/dist/cli/chunk-53jqw8z0.js.map +0 -10
- package/dist/cli/chunk-60hz265r.js.map +0 -10
- package/dist/cli/chunk-desvm72z.js.map +0 -14
- package/dist/cli/chunk-dpy8qdjf.js.map +0 -17
- package/dist/cli/chunk-es8h0v3j.js +0 -441
- package/dist/cli/chunk-es8h0v3j.js.map +0 -11
- package/dist/cli/chunk-kdpzw38a.js.map +0 -11
- package/dist/cli/chunk-nbyvgnnm.js.map +0 -36
- package/dist/cli/chunk-s0bdnc7v.js.map +0 -10
- package/dist/cli/chunk-twy7psdz.js.map +0 -10
- package/dist/cli/chunk-ydp3065p.js +0 -64
- package/dist/cli/chunk-ydp3065p.js.map +0 -10
- /package/dist/cli/{chunk-y4msrwm9.js.map → chunk-080mfch6.js.map} +0 -0
- /package/dist/cli/{chunk-9qzgg6mj.js.map → chunk-34wap3ed.js.map} +0 -0
- /package/dist/cli/{chunk-1f882900.js.map → chunk-c5bjxq8v.js.map} +0 -0
- /package/dist/cli/{chunk-bxwhtvw8.js.map → chunk-f260jdrn.js.map} +0 -0
- /package/dist/cli/{chunk-74wfhv79.js.map → chunk-fnxgtjeq.js.map} +0 -0
- /package/dist/cli/{chunk-dhwtqnnd.js.map → chunk-gxhcf2hs.js.map} +0 -0
- /package/dist/cli/{chunk-tfycddbt.js.map → chunk-h0qwdbem.js.map} +0 -0
- /package/dist/cli/{chunk-j1x92mx9.js.map → chunk-j4nfgn2j.js.map} +0 -0
- /package/dist/cli/{chunk-ave1wcbr.js.map → chunk-qcyxkj44.js.map} +0 -0
- /package/dist/cli/{chunk-58bt3hag.js.map → chunk-x7bh6d9j.js.map} +0 -0
- /package/dist/cli/{chunk-hvcxng5f.js.map → chunk-ydqzkhjn.js.map} +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# ReadMe → Blume
|
|
2
|
+
|
|
3
|
+
ReadMe (readme.com developer hubs) is a hosted platform. Only content reaches Git: settings, the landing page, the glossary, variables, redirects, and every metrics and login feature live in its dashboard. Pages are MDX, or ReadMe's looser "MDXish" dialect, saved as `.md`. Published URLs are flat per section (`/docs/<slug>`, `/reference/<slug>`, `/recipes/<slug>`, `/page/<slug>`, `/changelog/<slug>`) however deep a page sits in the sidebar. The plan below keeps every one of them: section folders stay at the top of the content root, categories become `(group)` folders, and nested pages pin their flat URL with `slug`. The API reference is the exception: Blume generates operation pages at new routes, so each old one gets a redirect.
|
|
4
|
+
|
|
5
|
+
Two things go wrong with a green build and no warning: emoji blockquote callouts (plain blockquotes) and `:emoji:` shortcodes (literal text). Two more only warn: `doc:`/`ref:` links (dead links; `blume validate` reports `BLUME_UNSUPPORTED_LINK_SCHEME`) and inline `onClick` handlers (they render and do nothing; `BLUME_MDX_EVENT_HANDLER`). The codemod handles the first three; the handlers are yours.
|
|
6
|
+
|
|
7
|
+
## Detect
|
|
8
|
+
|
|
9
|
+
| Shape | Tells | The sidebar lives in |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| **A. Bi-directional Git sync** (ReadMe Refactored) | `_order.yaml` in `docs/`, `reference/`, `recipes/`, `custom_pages/` and their folders; category folders with spaces (`docs/Getting Started/`); `reference/*.json` specs beside endpoint pages with `api: { file, operationId }` frontmatter; `reference/ReadMeConfig/`; `custom_blocks/`; a `main` branch holding only `changelogs/`; branches named after versions (`v3.0`) | folders and `_order.yaml` |
|
|
12
|
+
| **B. `rdme@10` upload** (one-way) | CI running `readmeio/rdme@v10` or `npx rdme@10` with `docs upload`, `reference upload`, `changelog upload`, `custompages upload`, `openapi upload`; frontmatter `category: { uri }`, `parent: { uri }`, `position`, `privacy: { view }`, `content: { excerpt }` (also `rdme docs export` output) | frontmatter |
|
|
13
|
+
| **C. Legacy `rdme` ≤ 9** | CI running `readmeio/rdme@v9` or older (`rdme docs ./dir`, `rdme openapi`, `rdme changelogs`); frontmatter `category: <24-hex id>` or `categorySlug`, `parentDoc` or `parentDocSlug`, `order`, `hidden`, `type: basic \| link \| error` | frontmatter, keyed by opaque IDs |
|
|
14
|
+
|
|
15
|
+
rdme ignores folder layout, so in shapes B and C the folders say nothing about the sidebar. rdme 10 still accepts `rdme changelogs` as a hidden alias, so tell B from C by the rdme version and the frontmatter. A shape A repo can still run `rdme openapi upload` in CI: it's shape A.
|
|
16
|
+
|
|
17
|
+
**Get everything before you convert.**
|
|
18
|
+
|
|
19
|
+
- **Shape A** is complete per version branch. Find the branch holding the hub's default version (it can be `v3.0`, not `main`). **Changelogs live only on `main`**: `git archive <main-sha> changelogs | tar -x -C <work-dir>`. Ignore `<version>_<name>` branches (ReadMe's editing branches, kept after they merge).
|
|
20
|
+
- **Shapes B and C** hold only what CI uploads, and drift: editor changes never come back, and a failing upload step stops changes going out. Inventory the live hub, export what the repo lacks, and diff pages against their live source.
|
|
21
|
+
- **Exports.** A Refactored project: connect bi-directional sync to a new, empty repository (Settings → Git Connection), which writes shape A with every version as a branch; a ZIP from the Branch menu (no images); or `npx rdme@10 docs export <dir> --branch <version>` and `rdme reference export <dir>` (shape B frontmatter). A legacy project: `rdme@9` can't export; read pages through API v1 (`GET /api/v1/categories/{slug}/docs`, `GET /api/v1/docs/{slug}`) or upgrade the project. Refactored hubs usually serve a page's Markdown at `<url>.md` (docs.readme.com does), and `/llms.txt`, when it's on, lists every public page or links per-section files that do.
|
|
22
|
+
|
|
23
|
+
**Go easy on the live hub.** A ReadMe hub can start answering `429` after as few as eight requests in a few minutes, even spaced seconds apart. Spend them on one page of the hub (save it: it carries the settings JSON below), `sitemap.xml`, `llms.txt`, and a few spot checks. The `files.readme.io` image CDN is separate: one run fetched 84 images there at one every half second without a `429`.
|
|
24
|
+
|
|
25
|
+
## Run the codemod first
|
|
26
|
+
|
|
27
|
+
For shape A, on a branch whose name matches no ReadMe version (see Teardown), with the changelogs copied from `main` into the work tree and one page of the hub saved as `hub.html` (skip the `curl` when the user already saved one at the root):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
curl -s https://docs.example.com/docs/<any-page> -o hub.html # settings JSON + glossary
|
|
31
|
+
node <skill>/scripts/readme-codemod.mjs --site https://docs.example.com --glossary hub.html . # report only
|
|
32
|
+
node <skill>/scripts/readme-codemod.mjs --write --site https://docs.example.com --glossary hub.html . # apply
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--site` (repeatable: add the `*.readme.io` origin too) makes absolute links to the hub root-relative. It's zero-dependency, deterministic, and idempotent (a rerun reports `Nothing to change.`). It:
|
|
36
|
+
|
|
37
|
+
- moves `custom_pages/` → `page/`, `changelogs/` → `changelog/`, categories → `(Category)` group folders, `.md` → `.mdx`;
|
|
38
|
+
- maps frontmatter (Frontmatter, below) and pins `slug` wherever Blume's route would differ from ReadMe's URL;
|
|
39
|
+
- converts callouts, links, magic blocks, ReadMe components, variables, reusable content, icons, shortcodes, code fences, and headings (Content);
|
|
40
|
+
- writes `_order.yaml` → `meta.ts`, deletes endpoint, tag, and empty parent pages, and turns link pages into redirects (Navigation);
|
|
41
|
+
- writes `reference/overlays/<spec>.overlay.json` (API reference), `readme-redirects.json` (the redirects it can compute), and `readme-migration.json` (every old URL, every deleted endpoint, for the second pass).
|
|
42
|
+
|
|
43
|
+
**Its report is the to-do list**: per file, what needs judgment (custom components, inline components, `<style>`, event handlers, dead links, unmapped icons), then "Left for you". Work through it with the sections below. A second pass after the first build handles endpoint redirects and order (API reference).
|
|
44
|
+
|
|
45
|
+
Shapes B and C: rebuild the tree first (Navigation, shapes B and C), then run the codemod. With no `_order.yaml` it converts page content and frontmatter only: no moves, slug pins, URL inventory, endpoint handling, or redirects (it reports link pages instead).
|
|
46
|
+
|
|
47
|
+
## Config: the dashboard → `blume.config.ts`
|
|
48
|
+
|
|
49
|
+
There's no config file in Git. Every page of a Refactored hub embeds the project's settings as JSON: read them from the saved `hub.html` rather than asking. Map what's set:
|
|
50
|
+
|
|
51
|
+
| ReadMe (settings JSON) | Blume | Notes |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `name` | `title` | |
|
|
54
|
+
| `logo`, `logo_white_use` | `logo` | download into `public/`. With `logo_white_use: true` the hub showed a white logo on a colored header, invisible in Blume's light header: recolor the white parts to `currentColor`. A bare mark → the string form (`logo: "/logo.svg"`); a wordmark → `{ image: "/logo.svg", text: "" }` (SKILL.md) |
|
|
55
|
+
| `favicon` | `public/favicon.png` (or `.svg`/`.ico`) | picked up by name |
|
|
56
|
+
| `brand.link_color` (`colors.body_highlight`) | `theme.accent` | `_dark` variants → `{ light, dark }` |
|
|
57
|
+
| `brand.primary_color` (`colors.main`) | `theme.action`, or `theme.accent` when no link color | the colored header has no equivalent: report |
|
|
58
|
+
| `brand.theme` | `theme.mode` | |
|
|
59
|
+
| `typography.headline` / `body` (`Open+Sans:400:sans-serif`) | `theme.fonts.display` / `body` (`{ name: "Open Sans" }`) | Typekit → local `variants`, or drop |
|
|
60
|
+
| `nav_names` + enabled `modules` | `navigation.tabs` | one tab per enabled section with content (`{ label: "Developer hub", path: "/docs" }`) |
|
|
61
|
+
| header links (`link_url` entries) | `navigation.actions` | a sign-up or "Get API keys" button → `navigation.cta`; a login link stays in `actions` |
|
|
62
|
+
| `first_page` | `index.mdx` at the root, or a `/` redirect (status 302) | the landing page doesn't sync |
|
|
63
|
+
| `custom_domain` | `deployment.site` | unless the host is Vercel or Netlify (SKILL.md) |
|
|
64
|
+
| Enterprise group path (`/<project>/docs/…`) | `basePath: "/<project>"` | one Blume site per child project |
|
|
65
|
+
| `integrations.google.analytics`, `segment`, `heap`; custom JS | `googleAnalytics()`, `segment()`, `heap()`, or `script({ src \| content })` in `analytics` | these load only in production builds, and wait for `consent` when it's set |
|
|
66
|
+
| `integrations.intercom`, `zendesk` (a support widget readers click) | a `PageFooter` component (`defineComponents`, SKILL.md "analytics") that loads it | not `analytics`, which can hold it until consent. Check region settings (an AU Intercom workspace needs `api_base`) |
|
|
67
|
+
| `integrations.google.site_verification`, `<meta>` tags in head HTML | `seo.metatags` | other head HTML: report |
|
|
68
|
+
| `stylesheet_hub2` (custom CSS) | a root `theme.css` | rules for ReadMe's classes (`.rm-*`, `.callout_*`, hashed names) match nothing: carry only rules for the site's own markup |
|
|
69
|
+
| Footer HTML | `footer: { copyright, links }` | a copyright line → `copyright`, plain text: strip the tags, decode entities (`©` → `©`). Report the rest |
|
|
70
|
+
| `variables.defaults` | `variables` | Content. **Defaults can be real credentials** (an API key): never copy one into config |
|
|
71
|
+
| `glossaryTerms` | `--glossary hub.html` | the codemod writes `<Tooltip>`s |
|
|
72
|
+
| `redirects` | `redirects` | URLs and redirects |
|
|
73
|
+
| `error404` | `pages/404.astro` or Blume's default | URLs and redirects |
|
|
74
|
+
| Ask AI, MCP server | `ai.assistant`, `agents.mcp` | need a server-output host adapter: report |
|
|
75
|
+
|
|
76
|
+
Then the layout. **Leave the section folders where they are.** Set `content.root: "."` and scope `include` (`references/monorepo.md` §1), import the codemod's redirects, and add the reference:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { defineConfig } from "blume";
|
|
80
|
+
import { openapi } from "blume/reference";
|
|
81
|
+
import redirects from "./readme-redirects.json";
|
|
82
|
+
|
|
83
|
+
export default defineConfig({
|
|
84
|
+
content: {
|
|
85
|
+
root: ".",
|
|
86
|
+
include: [
|
|
87
|
+
"index.mdx",
|
|
88
|
+
"docs/**/*.mdx",
|
|
89
|
+
"reference/**/*.mdx",
|
|
90
|
+
"recipes/**/*.mdx",
|
|
91
|
+
"page/**/*.mdx",
|
|
92
|
+
"changelog/**/*.mdx",
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
redirects: [...redirects /* , your own */],
|
|
96
|
+
reference: [openapi({ sources: [/* API reference */] })],
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`page/` is ReadMe's custom pages at `/page/<slug>`; Blume's own `pages/` folder is for `.astro` pages, a different thing.
|
|
101
|
+
|
|
102
|
+
## Navigation (shape A)
|
|
103
|
+
|
|
104
|
+
What the codemod does, so you can check it:
|
|
105
|
+
|
|
106
|
+
- **Categories → group folders.** `docs/Getting Started/` → `docs/(Getting Started)/`: the group keeps the label and adds no URL segment.
|
|
107
|
+
- **`_order.yaml` → `meta.ts` `pages`**, entries as written (`pages` ignores the parentheses), less duplicates and entries with no file. A category folder's `meta.ts` also sets `title` where Blume would relabel the folder name (`Self-Serve` would show as "Self Serve"). A parent page's folder gets `title` from the parent and `display: "group"`.
|
|
108
|
+
- **`slug` pins.** ReadMe serves every child flat (`/docs/<child>`; the nested path 404s), so every page below a parent folder gets `slug: docs/<stem>`, and a nested parent's own `index.mdx` takes `docs/<folder>`. A parent folder directly in a category needs none: its folder name is the route. Any stem starting with a digit gets one too, since Blume strips `^\d+[-_.]` as an ordering prefix (`1-setup` → `/docs/setup`); dates (`12-05-2022`, `2024-01`, `2022-05-12`) and versions (`1.2`) stay whole, so their pins are harmless.
|
|
109
|
+
- **Hidden pages** (`hidden: true`) were left out of the sidebar and search but served by link: `hidden: true` + `search.exclude: true`, URL kept.
|
|
110
|
+
- **Empty parent pages** (frontmatter, no body) redirected to their first child on ReadMe. The codemod deletes them and adds a 302 to the first child; prefer that to keeping one as a `directory: "card"` landing page. A parent that stays (with a body, or kept as a landing page) whose child has the same title fails `validate --strict` (`BLUME_NAV_DUPLICATE_LABEL`): retitle one, and report it.
|
|
111
|
+
- **Link pages** (`link: { url }`): deleted, with a 302 to the URL. If the link must stay visible, add it to `navigation.featured`.
|
|
112
|
+
- **Section roots.** `/docs` and `/reference` redirect to the section's first page, as on ReadMe; a typed URL would 404 without it. ReadMe answers them with a 301; the codemod writes a 302, since the first page can change.
|
|
113
|
+
- **Custom pages** had no sidebar: `hidden: true` plus `mode: center` (`fullscreen: true` → `mode: custom`).
|
|
114
|
+
|
|
115
|
+
Left for you: an HTML custom page (`custom_pages/<slug>.html`) → `page/<slug>.mdx` with its HTML as JSX, or `pages/page/<slug>.astro` on `PageLayout` for a full document with scripts (`docs/advanced/custom-pages.mdx`); and `/` (see `first_page`).
|
|
116
|
+
|
|
117
|
+
### Versions
|
|
118
|
+
|
|
119
|
+
Version branches hold full copies of guides, recipes, and the reference; ReadMe serves the default version without a prefix and others at `/<version>/docs/<slug>`. **Recommend migrating the default version only**, with `{ from: "/<version>/:path*", to: "/:path*" }` for each other version and the default's own prefix (`/v3.0/docs/x` redirected to `/docs/x` on ReadMe). Pages that only exist in an old version then 404: report it. To keep old versions, run the codemod on each branch's checkout and copy its `docs/`, `recipes/`, and `reference/` into `<version>/` (`v2.1/docs/…` serves `/v2.1/docs/…`), drop that version's prefix redirect (a pattern over pages fails the build), add `"<version>/**/*.mdx"` to `content.include` (a scoped `include` never scans the copy otherwise), and set `versions.archived` (newest first) and `versions.current`. Each id is the URL segment (`v2.1`): ids must start with a letter. References, the changelog, and custom pages stay unversioned, and an archived tree's sidebar isn't scoped by tabs: report both.
|
|
120
|
+
|
|
121
|
+
## Navigation (shapes B and C)
|
|
122
|
+
|
|
123
|
+
Rebuild the tree from frontmatter into shape A's layout, then run the codemod:
|
|
124
|
+
|
|
125
|
+
- **Category** → `docs/(<Category title>)/`. Shape B's `category.uri` ends in the title (`/branches/3.0/categories/guides/Getting%20Started`): decode it. Shape C's `category` is an ID: resolve it with `GET /api/v1/categories`, the hub's sidebar, or the user. `categorySlug` names it.
|
|
126
|
+
- **Parent** (`parent.uri`, `parentDoc`, `parentDocSlug`) → a folder named for the parent's slug, holding the parent as `index.mdx`; pin each child's `slug` as in shape A.
|
|
127
|
+
- **Order** (`position`, `order`) → the folder's `meta.ts` `pages`.
|
|
128
|
+
- **Slug**: frontmatter `slug`, else the file name. Name each file after its slug, and pin any that starts with a digit.
|
|
129
|
+
- **Custom pages and changelog entries** → `page/<slug>.md` and `changelog/<slug>.md`, whatever folder CI uploaded them from: the codemod maps their frontmatter by those folder names (`custom_pages/` and `changelogs/` work too), but outside shape A it moves nothing, so the folder is the URL.
|
|
130
|
+
|
|
131
|
+
The codemod reports these navigation keys and leaves them: delete them once the tree is built.
|
|
132
|
+
|
|
133
|
+
## Content
|
|
134
|
+
|
|
135
|
+
**Every page becomes `.mdx`**: ReadMe's `.md` files are MDX, and in a Blume `.md` page directives stay literal text and components don't render. The codemod converts the mechanical syntax (table below). It also clears what ReadMe's lenient MDXish engine (`"mdxish": true` in the settings JSON) accepts and strict MDX rejects: it deletes `<!-- -->` comments, self-closes void tags, and converts `[block:…]` JSON. **It leaves everything that needs judgment, and reports it per file:**
|
|
136
|
+
|
|
137
|
+
- **Inline components.** A page that defines a component (`export const Name = …`) is left byte for byte. Without hooks it renders as static HTML. With hooks it fails the build: move it to `islands/<Name>.tsx` (`export default`). One defined on several pages goes in `islands/` once.
|
|
138
|
+
- **Custom components** (`custom_blocks/<Name>.mdx`): use a Blume component when it's presentational (a card grid → `CardGroup`), else move it to `islands/<Name>.tsx` and keep `<Name />` in the pages. Blume compiles Tailwind v4 utilities from the project's `.mdx` and `.tsx` files (Tailwind's default theme plus Blume's tokens, `dark:` keyed to Blume's theme), so utility classes keep working; ReadMe's CSS variables (`var(--color-border-default)`) don't exist in Blume: swap them for Blume's (`var(--blume-border)`) or its token utilities (`border-border`, `bg-muted`). Text moved from a prop into children needs `{` and `}` escaped (`\{`), or the build fails (`BLUME_MDX_UNDEFINED_NAME`, at the brace's line).
|
|
139
|
+
- **Event handlers.** `<button onClick={…}>`, `onMouseEnter`, and friends on inline HTML build green and do nothing; `blume check` and `build` warn `BLUME_MDX_EVENT_HANDLER` at each one. Rebuild the widget as an island (`grep -rnE 'on[A-Z][a-zA-Z]*=' --include='*.mdx'` outside code finds them before a build). Hubs often paste the same widget (a "contact support" box) into dozens of pages: one island, and replace every copy. A handler that calls a support widget's global (`Intercom('show')`) also needs that widget loaded (Config, `integrations.intercom`).
|
|
140
|
+
- **`<HTMLBlock>` with `<style>`, `<script>`, or handlers** stays wrapped. **Don't move its `<style>` rules into `theme.css`**: ReadMe authors write global selectors (`p`, `ul`, `h3, h4`), which there restyle the whole site, sidebar included. Rebuild the markup with Blume components (`Tabs`, `Columns`, `CardGroup`, `Panel`, callouts). ReadMe stripped `<script>` unless `runScripts` was on: rebuild what a script did as an island or a `script()` adapter.
|
|
141
|
+
- **Font Awesome `<i>` icons** in raw HTML (`<i className="fa fa-plug" />`): `<Icon icon="<lucide>" />`; Blume loads no Font Awesome, so the `<i>` renders empty. Tailwind classes in raw HTML (`className="mt-4 p-4 bg-gray-50"`) still compile, but fixed colors ignore dark mode: prefer a component (`Panel`, a callout) or Blume's token utilities (`bg-muted`, `border-border`).
|
|
142
|
+
- **Unknown components** (`<PostmanRunButton>`, `<MCPIntro>`, `<TableOfContents>`): drop or replace; each fails the build.
|
|
143
|
+
- **Variables.** `<<name>>`, `{user.name}`, and `<Variable name>` became `{{name}}`; define each in `variables` (from `variables.defaults`). ReadMe filled them per reader; Blume shows one default to everyone (report). The codemod leaves `<<name>>` inside code as written and reports it: change one to `{{name}}` by hand where it should show the default (Blume substitutes in code too).
|
|
144
|
+
- **Glossary terms** with no definition: pass `--glossary`, or write the `<Tooltip>` by hand.
|
|
145
|
+
- **Dead links.** Hubs collect links to slugs from older versions that 404 on the live site too. Check a few live first (ReadMe cross-redirects some, `/reference/x` → `/docs/x`), then point each at the closest current page, or unlink it and keep the text. Report the list.
|
|
146
|
+
- **Images** stay on `files.readme.io`: download them into `public/` and rewrite the URLs (`grep -rhoE 'https://files\.readme\.io/[^)" ]+'`). Some have no extension: add one. Review every alt the codemod derived from a file name.
|
|
147
|
+
- **Tables** with lists or blocks in their cells, or spanning cells (`colSpan`, `rowSpan`), stay `<table>`: check they render.
|
|
148
|
+
- **Recipes**: the codemod deletes the line-highlight comments and demotes the step headings; the walkthrough modal is dropped (report). Repeat a highlighted excerpt under its step with `{1-4}` where it mattered.
|
|
149
|
+
|
|
150
|
+
| ReadMe | Blume (codemod) |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| `> 📘 Title` / `>` / `> Body` (emoji first) | `:::info[Title]` … `:::`; 📘 ℹ️ → `info`, 👍 ✅ → `success`, 🚧 ⚠️ → `warning`, ❗️ 🛑 ‼️ ⁉️ → `danger`, any other emoji → `note`. An emoji alone means no title; `#` marks drop |
|
|
153
|
+
| `<Callout icon theme>` | the directive for `theme` (`okay` → success, `warn` → warning, `error` → danger, `default` → note), else for `icon`; a first-child heading becomes the title |
|
|
154
|
+
| `[block:callout]`, `[block:code]`, `[block:image]`, `[block:table]`/`parameters`, `[block:api-header]`, `[block:embed]`, `[block:html]` | the same conversions as their component forms |
|
|
155
|
+
| adjacent fences (ReadMe's code tabs) | `<CodeGroup>`; untitled tabs labeled with the language, as ReadMe showed them |
|
|
156
|
+
| ` ```javascript Node SDK ` | ` ```javascript title="Node SDK" `; `node` → `js`, `curl` → `bash`, `cplusplus` → `cpp`, `objectivec` → `objc` |
|
|
157
|
+
| `<Image src alt caption>`, `<Image …>caption</Image>`, `` | ``, in `<Frame caption>` when captioned; numeric or missing alts derived from the file name; `align`/`width`/`border` drop |
|
|
158
|
+
| `<Embed>` (YouTube, including `google.com/sorry` interstitials), `[x](url "@embed")` | `<YouTube id>`; anything else → a link |
|
|
159
|
+
| `<HTMLBlock>{`…`}</HTMLBlock>` | its HTML, inline: comments removed, void tags closed, braces as entities |
|
|
160
|
+
| `<Table>` | a Markdown table: a cell's paragraphs joined with `<br />`, all-empty rows dropped |
|
|
161
|
+
| `<Cards columns>` / `<Card iconColor badge target>` | `<CardGroup cols>` / `<Card color>`, `badge` → `<Badge>`, `target` drops; braces from props escaped |
|
|
162
|
+
| `<Columns layout>`, `<Tab icon>` | `<Columns cols>`, Lucide icons |
|
|
163
|
+
| `<Accordion title>` | a run → one `<Accordion>` of `<AccordionItem>`s; one alone → `<Expandable>`, or a one-item `<Accordion>` when it has an icon (`Expandable` takes none) |
|
|
164
|
+
| `<Glossary>`, `<<glossary:x>>` | `<Tooltip tip>` |
|
|
165
|
+
| `<Anchor>`, `<Recipe>`, `[block:recipe]`, `[block:tutorial-tile]` | a link, `<Card href="/recipes/<slug>">` |
|
|
166
|
+
| `custom_blocks/<Name>.md` used as `<Name />` | `_snippets/<name>.mdx` + `<include>/_snippets/<name>.mdx</include>` |
|
|
167
|
+
| `doc:x`, `ref:x`, `page:x`, `changelog:x`, `blog:x`; `https://<site>/docs/x` | `/docs/x`, `/reference/x`, …; root-relative |
|
|
168
|
+
| Font Awesome (`fad fa-hand-wave`) on frontmatter, cards, tabs, accordions | Lucide, or dropped and reported |
|
|
169
|
+
| `:tada:` | 🎉 (unknown names reported) |
|
|
170
|
+
| a body `# H1` repeating the title; any other body H1 | deleted; every body heading demoted one level |
|
|
171
|
+
|
|
172
|
+
Callout titles had anchor ids on ReadMe; Blume's don't. Headings otherwise keep their anchors: both slug with github-slugger, so skip `pin-heading-ids.mjs`, which would also crawl the rate-limited hub. One exception: ReadMe's slugger also counted callout titles and the H1 the codemod deletes, so a later heading with the same text was `<slug>-1` on ReadMe and is `<slug>` in Blume. Another: for a heading that ends in an emoji or symbol after a space, github-slugger keeps a trailing dash (`## Features ✨` → `#features-`), which Blume drops (`#features`). `blume validate --strict` flags links to the old id; retarget them.
|
|
173
|
+
|
|
174
|
+
## Frontmatter
|
|
175
|
+
|
|
176
|
+
Blume's page schema is strict. The codemod maps:
|
|
177
|
+
|
|
178
|
+
| ReadMe | Blume |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `title` | `title` |
|
|
181
|
+
| `excerpt` (A, C), `content.excerpt` (B) | `description` |
|
|
182
|
+
| `hidden: true` (A), `privacy.view: anyone_with_link` (B) | `hidden: true` + `search.exclude: true` |
|
|
183
|
+
| `hidden: true` (C) | the same, reported: rdme maps it to `privacy.view: anyone_with_link`, but check the live URL and use `draft: true` if it 404s |
|
|
184
|
+
| `deprecated`, `state: deprecated` (B) | `deprecated: true` |
|
|
185
|
+
| `icon`, `appearance.icon` (B) | `icon` (Lucide) |
|
|
186
|
+
| `metadata.title` / `description` / `image` | `seo.title` / `description` / `image`; B's `image: { uri }` is an image id, not a URL: reported |
|
|
187
|
+
| `metadata.keywords` | `search.keywords` |
|
|
188
|
+
| `metadata.robots: noindex`, `allow_crawlers: disabled` (B) | `noindex: true` |
|
|
189
|
+
| `next.pages`, `content.next` (B) | `related`, dropping entries that aren't pages in the repo; Blume takes 10 at most (the rest reported) |
|
|
190
|
+
| `link`, `content.link` (B) | a redirect (Navigation) |
|
|
191
|
+
| `table_of_contents: false` | `mode: wide` (an approximation: report) |
|
|
192
|
+
| `fullscreen` (custom pages) | `mode: custom`, else `mode: center` |
|
|
193
|
+
| `recipe`, `x-import`, `name`, `api`, `api_config`, `recipes` | dropped (`recipes` reported) |
|
|
194
|
+
|
|
195
|
+
It keeps keys it doesn't know and reports them: Blume rejects unknown keys, so map or delete each. It drops C's `type` (`basic`, `link`, `error`), since Blume's own `type` sets the content type. Changelog keys are under Changelog.
|
|
196
|
+
|
|
197
|
+
## API reference
|
|
198
|
+
|
|
199
|
+
Every endpoint page is generated from an OpenAPI file. The codemod records each one's old URL, operation, and prose in `readme-migration.json`, and deletes it.
|
|
200
|
+
|
|
201
|
+
1. **Specs → sources.** One `openapi()` source per spec in `reference/`, labeled with the ReadMe category its endpoints sat under, or the spec's `info.title`: `{ label: "Connect", spec: "./reference/connect.json" }` serves `/reference/connect`, with operations at `/reference/connect/<tag>/<operation>`. **A category that held several specs** (the report lists them) can't share a label: they'd share a route and the first would win. Give each its own label, or merge the specs first, and report the split. A single spec → `openapi({ spec })`. Add a `navigation.tabs` entry for `/reference`. A YAML spec: convert it to JSON (`npx @redocly/cli bundle x.yaml --output x.json`) and rerun the codemod, which reads JSON only.
|
|
202
|
+
2. **Overlays.** `reference/overlays/<spec>.overlay.json` sets each operation's `description` to its spec text plus the prose its ReadMe endpoint page showed, and converts the ReadMe Markdown inside spec descriptions (emoji callouts, shortcodes, `doc:` links), which ReadMe rendered and Blume would show plain. Add each to its source: `{ label, spec, overlays: ["./reference/overlays/connect.overlay.json"] }`. JSX doesn't render in descriptions (`<` and `{` are escaped): rewrite any the report names as Markdown.
|
|
203
|
+
3. **Build, then run the second pass.** List the generated routes, then hand them to the codemod with the same `--spec` pairs (the source's route, then its spec):
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
npx blume build
|
|
207
|
+
node <skill>/scripts/operation-routes.mjs dist --spec /reference/connect=reference/connect.json > routes.json
|
|
208
|
+
node <skill>/scripts/readme-codemod.mjs --routes routes.json --spec /reference/connect=reference/connect.json --write .
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
It adds a 301 from each old endpoint URL (`/reference/getaccount`) to its operation page, and a 302 from each tag page (`/reference/accounts-1`) to the tag's first endpoint, as ReadMe answered. It skips an old URL that is now a page (`/reference/enrich`, ReadMe's operation, against an Enrich source's overview): a redirect there would hide the page (`BLUME_REDIRECT_MATCHES_PAGE`). It reports each, so you can pick another `route` instead. It adds a 302 from `/reference` to the first endpoint when nothing else claims it, and drops any pass-one redirect that would now hide a reference page. It also rewrites links to old endpoint and tag URLs outside fenced code, dropping anchors (reported), and writes `<route>/<tag-slug>/meta.ts` (`defineMeta({ title, order, pages })`) with ReadMe's endpoint order, where it can differ from the spec's order, which the generated sidebar follows.
|
|
212
|
+
|
|
213
|
+
4. **Source order, by hand.** Write `<route>/meta.ts` → `defineMeta({ order: <n> })` for each source, with the order the report gives (ReadMe's category order). It merges over the generated group's settings, so the source's `label` stays its title.
|
|
214
|
+
|
|
215
|
+
- **Conceptual pages** (no `api` key) stay in `reference/(<Category>)/` at `/reference/<slug>` and join the reference tab's sidebar; their group folder's `meta.ts` takes an `order` among the sources.
|
|
216
|
+
- **`reference/ReadMeConfig/`** (`api_config` pages: getting started, authentication, my requests) showed the reader's own API key and request log. The codemod keeps any prose as a page and deletes empty ones: redirect each deleted URL to the closest page.
|
|
217
|
+
- **Hidden endpoints**: remove the operation with an overlay action (`remove: true`) if it should stay unpublished. `x-internal: true` likewise: Blume ignores the flag.
|
|
218
|
+
- **`x-readme` extensions** (and flat spellings like `x-samples-languages`, at the root or on an operation): `samples-languages` → `codeSamples`: `shell`, `node`, `javascript`, `python`, `ruby`, `go`, `php`, `java`, `csharp`, `kotlin`, `swift`, `c`, `cplusplus` (read as `cpp`), and `powershell` carry over as written (so does `curl`, which some specs use); `objectivec`, `http`, `json`, `clojure`, `ocaml`, and `r` have no Blume generator and warn `BLUME_OPENAPI_UNKNOWN_CODE_SAMPLE`: leave them out and report them. `code-samples` → `x-codeSamples` by overlay (`language` → `lang`, `code` → `source`, `name` → `label`). `explorer-enabled: false` → `playground: false`; `proxy-enabled` (on by default: Try It went through ReadMe's CORS proxy) → `playground: { proxy: true }` on a server-output host, or the API must allow the docs origin (say which). `codeSamples` and `playground` are per `openapi()` adapter, not per source or operation: when specs or operations disagree, take the setting most of them use and report the rest. `samples-enabled` is no longer supported on ReadMe (it hid nothing): ignore it. `headers`, `x-default`, `oauth-options`, `parameter-ordering`, `metrics-enabled`: no equivalent (report).
|
|
219
|
+
- **Versioned references**: unversioned in Blume; an archived version's spec can be its own source with `route: "/<version>/reference"` (report).
|
|
220
|
+
|
|
221
|
+
## Changelog
|
|
222
|
+
|
|
223
|
+
The codemod moves `changelogs/<slug>.md` → `changelog/<slug>.mdx` (same URL; digit-led stems pinned with `slug`, which date names no longer need) and adds `type: changelog`:
|
|
224
|
+
|
|
225
|
+
| ReadMe | Blume |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| `date`, `published_at` (what synced repos contain), `created_at` (B) | `date` (the day). None (common in C) → reported: take it from the live entry |
|
|
228
|
+
| `author` | `authors`; B's ID object drops |
|
|
229
|
+
| `type` (`added`, `fixed`, `improved`, `deprecated`, `removed`; `none`) | `changelog.category`, capitalized; `none` omitted |
|
|
230
|
+
| `hidden: true`, `privacy.view: anyone_with_link` | `hidden: true`: still built, out of the index and feed |
|
|
231
|
+
|
|
232
|
+
It also adds `/changelog.rss` → `/changelog/rss.xml`; the feed needs `deployment.site` or a detected host. Add a `{ label, path: "/changelog" }` tab. If the project is open source on GitHub and its releases are the product changelog, offer `githubReleases()` (SKILL.md "Changelogs").
|
|
233
|
+
|
|
234
|
+
## URLs and redirects
|
|
235
|
+
|
|
236
|
+
**The old URL list**: `readme-migration.json` lists every URL the repo served (hidden pages included) with its kind; add `sitemap.xml` (it omits hidden pages and empty parents), `llms.txt`, other versions (`/<version>/docs/…`), and Enterprise or translated segments (`/<project>/`, `/lang-de/`). At the end every entry must be a page or a redirect to one.
|
|
237
|
+
|
|
238
|
+
- **Status codes.** Use 302 where ReadMe answered with a 302 (empty parents, tag pages, `/`), for link pages, and for section roots (ReadMe's 301 points at whichever page is first, which can change), and the default 301 for moves (operations). The codemod does, except `/`, which it leaves to you (`first_page`).
|
|
239
|
+
- **ReadMe's own redirects** (`redirects` in the settings JSON, or Settings → Errors & Redirects: `old -> new` per line, full-match regex with `$1`, applied only when no page matches): a literal rule → `{ from, to }`; one-segment or rest-of-path patterns → `:name` / `:name*` (`/old(/\S*)? -> /new$1` → `{ from: "/old/:path*", to: "/new/:path*" }`, which also sends `/old` to `/new`); anything else → host rules (report).
|
|
240
|
+
- **Versions**: `{ from: "/<version>/:path*", to: "/:path*" }` (Versions).
|
|
241
|
+
- **The custom 404** (`error404`): rebuild that custom page as `pages/404.astro`, or keep Blume's default. Keep or redirect its `/page/<slug>` URL.
|
|
242
|
+
- **`blume validate`** accepts a redirect `from` as a link target, so rewrite links before trusting it. It warns about a redirect whose `to` leads nowhere (`BLUME_BROKEN_REDIRECT`), but not about loops or chains: run `blume audit --only redirects` after each build. A link to `/llms.txt` or another file Blume generates passes while the config has that feature on.
|
|
243
|
+
- **Check every old URL** against `dist/` and `dist/blume-redirects.json` (no host adapter), following redirects until each lands on a page, or request each from `blume dev` or `blume preview` with `curl -sL`: both answer every redirect, patterns included.
|
|
244
|
+
|
|
245
|
+
## Teardown
|
|
246
|
+
|
|
247
|
+
**Disconnect the sync first.** With bi-directional sync on, ReadMe's GitHub app reads and writes every branch named after a version, so restructuring one rewrites the live hub. Migrate on a branch that matches no version (`blume-migration`; `<version>_<name>` would sync), and have the user disconnect the repository (Settings → Git Connection) before merging. Remove every `rdme … upload` step from CI in any shape (and an `rdme` dependency); `rdme openapi validate` can stay as a spec linter.
|
|
248
|
+
|
|
249
|
+
Delete `custom_blocks/` once converted, `reference/ReadMeConfig/` leftovers, `frontmatter.schema.json`, `hub.html`, `routes.json`, and `readme-migration.json` once the redirects are final (keep `readme-redirects.json`: the config imports it). Scaffold a `package.json` with `blume` and `dev`/`build`/`preview` scripts. Moving the custom domain's CNAME is the user's step: list it.
|
|
250
|
+
|
|
251
|
+
## Dropped — report these
|
|
252
|
+
|
|
253
|
+
- **Hosted features**: the editor, Branches and Reviews, the AI Linter and Agent, suggested edits (Blume's edit link comes from `github`), discussions and the dev FAQ, API Metrics, My Developers, My Requests and API logs, the Developer Dashboard, health status updates, and the landing page builder (rebuild as `index.mdx` with `mode: custom`, or `pages/index.astro`).
|
|
254
|
+
- **Personalized docs**: per-reader variables, API keys in Try It, `x-default` credentials, and the `ReadMeConfig` widgets. Blume's Try It takes credentials the reader types.
|
|
255
|
+
- **Login-gated docs** (custom login, JWT, site password, hidden versions): Blume has no sign-in. Point at host-level protection (deployment docs, **Private docs**); it covers the whole site, so public and private pages need two sites.
|
|
256
|
+
- **Changelog options** (layouts, relative dates, author toggle, translations), recipe walkthrough modals, Global Reusable Content across projects, translations through Localize or Transifex (offer `i18n` and `blume translate`), and Enterprise cross-project navigation.
|
|
257
|
+
- **Approximations**: `mode: wide` for `table_of_contents: false`, image sizes and alignment, emoji and unmapped icons, unmapped `x-readme` extensions, unversioned references and changelog, custom components restyled as islands, and HTML or scripts dropped from custom blocks.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Redocly → Blume
|
|
2
|
+
|
|
3
|
+
Covers **Redocly Realm** and the products on the same project format (Redoc, Revel, Reef, alone or combined), usually hosted and edited in **Reunite**. A project is a `redocly.yaml`, `.md` pages written in **Markdoc** (`{% tag %}`, not MDX), optional `sidebars.yaml` files, and API description files in the content tree, each rendered as a reference **at its own path**. The work: Markdoc tags become directives and components, each page's body H1 becomes `title`, sidebars become folders and tabs, and every API operation URL changes shape, so the old ones get generated redirects.
|
|
4
|
+
|
|
5
|
+
## Detect
|
|
6
|
+
|
|
7
|
+
A **Realm-family project** has at least one of these (`redocly.yaml` is optional; Realm builds a bare folder of Markdown):
|
|
8
|
+
|
|
9
|
+
- a `sidebars.yaml`, or a prefixed `<name>.sidebars.yaml`, at the root or in a section folder;
|
|
10
|
+
- `.md` pages using Markdoc tags (`{% admonition`, `{% tabs`, `{% partial`);
|
|
11
|
+
- `@theme/`, `_partials/`, `@l10n/`, or `@<version>/` folders, or `*.page.tsx` React pages;
|
|
12
|
+
- a dependency on `@redocly/realm`, `@redocly/redoc`, `@redocly/revel`, `@redocly/reef`, or a combined package (`@redocly/redoc-revel`, `@redocly/redoc-reef`, `@redocly/revel-reef`). Reunite builds projects with no `package.json`, so a missing one proves nothing.
|
|
13
|
+
|
|
14
|
+
Three look-alikes:
|
|
15
|
+
|
|
16
|
+
- **A lint/bundle-only `redocly.yaml`**, with none of the above and only keys Redocly CLI reads (`extends`, `rules`, `decorators`, `preprocessors`, `plugins`, `apis`, `resolve`, `telemetry`), configures `redocly lint`/`bundle`. Leave it untouched and migrate the framework the docs actually use.
|
|
17
|
+
- **The legacy Redocly Developer Portal** (Gatsby; `siteConfig.yaml`, `theme.ts`, a `@redocly/developer-portal` dependency, `.mdx` pages, `*.page.yaml` reference pages, and a `sidebars.yaml` that maps named sidebars to groups of `pages:`). Its content is MDX with `:::` admonitions, so this file's Markdoc mappings don't apply: use SKILL.md's general model, this file's Config, API reference, and URL sections, and tell the user it was the legacy portal.
|
|
18
|
+
- **A standalone Redoc embed** (an HTML page loading `redoc.standalone.js` with `<redoc spec-url>` or `Redoc.init`, or a `redocly build-docs` script): migrate only the spec, with `openapi({ spec })`, and rewrite links to its `#tag/…`/`#operation/…` anchors. A Redoc-product project (`@redocly/redoc` alone) has no Markdown either.
|
|
19
|
+
|
|
20
|
+
**Keep the content where it is**: `content.root: "."`, with `content.include` scoped to the real content folders (`["guides/**/*.{md,mdx}", "apis/**/*.{md,mdx}"]`, per `references/monorepo.md` §1), plus each root-level page by name (`"index.{md,mdx}"`, `"changelog.{md,mdx}"`). A root `*.md` glob would also publish `README.md`, which Realm never did. Routes then keep their paths, `/`-rooted partial paths keep resolving, and the description files stay where `redocly.yaml`'s `apis.*.root` and the lint scripts expect them.
|
|
21
|
+
|
|
22
|
+
**Realm publishes every `.md` in the project** except the root `README.md` and `public/`, partials folders, `static/`, `@theme/`, and the `ignore` globs, so the old sitemap often lists accidental pages: `.github/pull_request_template`, files under `.claude/`, planning notes. Leave those out of `content.include`, add no redirect for them, and list them in the report so the user can add one if they want full URL coverage. Underscore-prefixed files outside a partials folder were pages in Realm but are excluded by Blume's default `**/_*`: rename any that are real pages (`content.exclude: ["!**/_*"]` would publish every partial too).
|
|
23
|
+
|
|
24
|
+
## Config: `redocly.yaml` → `blume.config.ts`
|
|
25
|
+
|
|
26
|
+
Resolve `$ref`s first (`redirects: { $ref: ./redirects.yaml }` is common). Product folders can hold their own `redocly.yaml`, and `env.<environment>` blocks override per environment: map the production values and report the rest.
|
|
27
|
+
|
|
28
|
+
| Redocly | Blume | Notes |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `seo.title` (`seo.projectTitle` when set) | `title` | Blume appends ` - <title>` to every docs page's `<title>` (not to a page titled the same as the site). Realm added a suffix only with `projectTitle`, so on most Realm sites this is a visible change: report it |
|
|
31
|
+
| `seo.description` | `description` | |
|
|
32
|
+
| `seo.siteUrl` | `deployment.site` | unless the new host is Vercel or Netlify (auto-detected). Cloudflare Pages exposes only a per-deploy URL, so keep it there |
|
|
33
|
+
| `seo.meta` (`[{ name, content }]`), `seo.keywords` | `seo.metatags` (`{ [name]: content }`, `keywords: "a, b"`) | minus the tags Blume writes itself; the build names the setting that owns a refused tag |
|
|
34
|
+
| `seo.lang` | nothing for English; else `i18n: { defaultLocale: "<code>", locales: [{ code: "<code>", label: "<language name>" }] }` | `label` is required |
|
|
35
|
+
| `seo.image`, `seo.jsonLd`, `seo.llmstxt` | **drop** (report) | Blume generates per-page cards, JSON-LD, and `llms.txt`; a page in `llmstxt.excludeFiles` gets `ai.exclude: true` |
|
|
36
|
+
| `logo.image` / `logo.srcSet` (`"./l.svg light, ./d.svg dark"`), `altText`, `link` | `logo` / `logo: { image: { light, dark, alt }, href }` | move the files into `public/`; a wordmark also gets `text: ""` |
|
|
37
|
+
| `logo.favicon` | **drop the field**: copy the file to `favicon.<ext>` or `icon.<ext>` in the root or `public/` | detected by filename, for `.svg`, `.png`, and `.ico` only: convert any other format |
|
|
38
|
+
| `navbar.items` | `navigation.tabs` / `actions` / `cta` | see Navigation |
|
|
39
|
+
| `footer.items` (columns, each a `{ group, items }` or a single item) | `footer.links` (one row) + `footer.socials` | flatten every column's items in order (`page` → its route). Links to a platform in Blume's `footer.socials` list (`docs/configuration/index.mdx`) become socials; a podcast (Spotify, Apple Podcasts) is `podcast`; others (TikTok) stay links. `copyrightText` → `footer.copyright`. Column labels drop (report) |
|
|
40
|
+
| `redirects` (`'/from': { to, type }`) | `redirects: [{ from, to, status: type }]` | write `from` without a trailing slash; a trailing `/*` carries over as written (`{ from: "/a/*", to: "/b/*" }`), and also matches the bare `/a`. Blume takes 301/302/307/308 only |
|
|
41
|
+
| `markdown.toc` | `toc: { maxHeadingLevel: <depth> }`, or `toc: false` for `hide` | Realm's default depth 3 is Blume's default |
|
|
42
|
+
| `markdown.lastUpdatedBlock` | `lastModified: "git"`, **only when declared** and not `hide: true` | Realm shows "Last updated" by default; if the source left it at that, offer `lastModified: "git"` in the report. Either way, every page the migration edits (nearly all of them, since each H1 moves) shows the migration commit's date; a rename alone keeps the page's date. Say so |
|
|
43
|
+
| `markdown.editPage.baseUrl` | `github: { owner, repo, branch, dir? }` | the path after the branch → `dir`; a non-`github.com` origin → `host` |
|
|
44
|
+
| `ignore` | `content.exclude: [ … ]` | the globs add to Blume's defaults (`**/_*`, `**/.*`), so `_partials/` stay out of routing |
|
|
45
|
+
| `colorMode` | `theme.mode` | `ignoreDetection` with a first mode of `dark` → `"dark"` |
|
|
46
|
+
| `banner` (a list) | `banner: { content, link: { href, text }, dismissible }` | one banner: keep the first unscheduled, untargeted one. `content` is plain text, so a Markdown link in it becomes `link`; colors, targets, schedules drop |
|
|
47
|
+
| `feedback` | `hide: true` → `feedback: false`; `type: comment` → `{ comments: true }` | other types drop |
|
|
48
|
+
| `search` | omit (built-in Orama); `suggestedPages` → `search: { provider: orama(), popular }` (`orama` from `blume/search`) | `engine` and `filters` (facets) drop |
|
|
49
|
+
| `analytics` | `ga.trackingId` (a `G-` id) → `googleAnalytics({ id })`, `gtm.trackingId` → `googleTagManager({ id })`, `amplitude.apiKey` → `amplitude({ key })`, `segment.writeKey` → `segment({ key })`, `heap.appId` → `heap({ id })`, `adobe.scriptUrl` → `adobe({ url })`, `fullstory`/`rudderstack` → `script()` | from `blume/analytics`. A `UA-` id is Universal Analytics, dead since 2023: drop it and say so |
|
|
50
|
+
| `scripts.head` / `scripts.body` | one `script({ src, strategy, attributes })` each in `analytics` | local `./static/x.js` → `/x.js`; `async`/`defer` → `strategy`. **Adapters in `analytics` load only in production builds and wait for consent when `consent` is set.** A script the page needs to work (a support widget, a form embed that buttons call) goes in a `PageFooter` layout slot component instead (`<script is:inline src="…">`), which runs in `blume dev` too. That slot renders on every content page, API operation pages included, but not on `mode: custom` or `frame` pages or custom `pages/`: report where the script is now missing |
|
|
51
|
+
| `links` | a Google Fonts stylesheet → `theme.fonts` (`{ body, display, mono }`) | each role a curated slug, or `{ name: "Family" }` for anything else; mind renamed families (Source Sans Pro is `source-sans-3`). `preconnect` links drop |
|
|
52
|
+
| `access` (`requiresLogin`, `rbac`, `sso`, `idps`), root `rbac`/`requiresLogin`/`sso`, `ssoDirect`, `userMenu` | **drop** | Blume has no login: point at host-level protection (deployment docs, **Private docs**), which covers the whole site; report every protected path |
|
|
53
|
+
| `l10n` (older: `i18n`) | `i18n` | see i18n |
|
|
54
|
+
| `apis`, `openapi`, `graphql` | `reference` adapters; **keep `apis` in `redocly.yaml`** | see API reference |
|
|
55
|
+
| `products` (`{ id: { name, folder, icon } }`) | `navigation.selectors: [{ kind: "product", label, items: [{ label: name, path: "/<folder>" }] }]` | |
|
|
56
|
+
| `aiAssistant`, `mcp` | nothing | offer `ai.assistant` / `agents.mcp` (server output) as follow-ups |
|
|
57
|
+
| `mockServer`, `catalogClassic`, `entitiesCatalog`, `scorecard*`, `developerOnboarding`, `apiFunctions`, `skills`, `corsProxy`, `responseHeaders`, `reunite`, `removeAttribution`, `palette`, `breadcrumbs`, `codeSnippet`, `navigation`, `navbar.hide`, `footer.hide`, `sidebar.hide` | **drop** (report) | `consent` → a `blume/consent` adapter if the site runs one; `navigation.actions` are Blume's default page actions |
|
|
58
|
+
| `extends`, `rules`, `decorators`, `preprocessors`, `plugins`, `resolve`, `telemetry`, `recheck` | **keep in `redocly.yaml`** | see Teardown |
|
|
59
|
+
| `'{{ process.env.X }}'` | `process.env.X` in `blume.config.ts` | |
|
|
60
|
+
|
|
61
|
+
## Navigation: `sidebars.yaml` and `navbar` → folders and tabs
|
|
62
|
+
|
|
63
|
+
With no sidebar file, Realm generates the sidebar from the file tree (natural sort, `index` first), which Blume's generated sidebar reproduces. Otherwise every file ending in `sidebars.yaml` is a sidebar (one only pulled in through another's `$ref` isn't), `page:` paths resolve from the sidebar file (or the project root with a leading `/`), and **a page no sidebar lists shows no sidebar** (unless its frontmatter `sidebar.path` names one): in Blume's generated tree it would appear. `sidebar.hidden: true` hides it, but also drops it from search, the sitemap, and `llms.txt`, where Realm still listed it: hide only orphans nobody should find, and report which you hid. Realm labels default to the page's `seo.title`, then its first heading, so most `label`s only restate the new `title`.
|
|
64
|
+
|
|
65
|
+
- **`group` + `items`** → a folder with a `meta.ts` (`title`, and `pages` in the declared order). A group whose pages sit flat beside others, or come from several folders, has no on-disk counterpart: move its pages into a subfolder (a page the group opened becomes its `index`, keeping its URL; the others get redirects) or use an explicit `navigation.sidebar`, per SKILL.md "Config-declared nesting".
|
|
66
|
+
- **`label`** → `sidebar.label`, only where it differs from `title`. **`href`** → an explicit sidebar link or `navigation.featured`. **`directory`** → leave the folder to the generated sidebar. **`$ref`** → inline it.
|
|
67
|
+
- **`expanded`**: Realm groups collapse by default, which `navigation.sidebar.display: "group"` reproduces. `expanded: true`/`always` → `collapsed: false` in that folder's `meta.ts`. **`menuStyle: drilldown`** → `display: "page"`.
|
|
68
|
+
- **`separator`** and **`separatorLine`** have no equivalent: a labeled separator heading a run of pages is usually better as a group; report the rest.
|
|
69
|
+
- **`badges`** → `sidebar.badge` (first name). **`icon`** → Lucide (Icons). `rbac`, `disconnect`, `additionalProps`, `external`, `*TranslationKey` drop.
|
|
70
|
+
- **An API description listed as a `page`** places that API's generated tree. Blume can't put generated operation pages into an explicit `navigation.sidebar`; they sit wherever the source's `route` puts them (see API reference).
|
|
71
|
+
|
|
72
|
+
**Several sidebars → header tabs.** Realm gives each page the sidebar that lists it, so one sidebar file per section (`guides/sidebars.yaml`), or top-level `tab:` entries in `sidebars.yaml`, is a tabbed site: one `navigation.tabs` entry per section folder (a `tab` with `menu:` → a tab with `items`). The root sidebar's pages, if they share no folder, get a tab with `path: "/"` and an `href` to their landing page; Blume picks the longest matching tab path, so section routes still select their own tab.
|
|
73
|
+
|
|
74
|
+
**`navbar.items`**: an item that opens a section with its own sidebar is that section's tab. The first item into the root sidebar is the root tab; other items into the same sidebar become `navigation.actions`, or drop if they duplicate a tab's target. A "Sign up" button → `navigation.cta` with an absolute URL; a GitHub link → `github`.
|
|
75
|
+
|
|
76
|
+
## Content: Markdoc → MDX
|
|
77
|
+
|
|
78
|
+
Blume parses `.md` as plain Markdown; directives, components, and ` ```mermaid ` fences need `.mdx`. **Rename only the pages that end up with one of those** (`<include>` works in `.md` too), and leave the rest `.md`, so the diff stays small and their history keeps its file names. Then fix what MDX parses differently, in pages and in every partial an `.mdx` page includes (an included partial parses as MDX):
|
|
79
|
+
|
|
80
|
+
- **Angle-bracket autolinks** (`<https://…>`, `<team@acme.com>`) fail to compile: write `[text](url)` or a bare URL.
|
|
81
|
+
- A literal `{` or `}` in prose: escape it or put it in inline code. **HTML comments** → `{/* */}`.
|
|
82
|
+
- **Raw HTML** must be JSX-valid: string `style="…"` → `style={{ … }}` or a class in `theme.css`; close void tags (`<br />`). `<figure>` + image + `<figcaption>` reads better as `<Frame caption="…">` around the image. A raw `<iframe>` of a YouTube video → `<YouTube id="…" />`.
|
|
83
|
+
- **File links follow the rename**: Blume resolves `./setup.md` by source file, trying the other extension when that file is gone, so a link to a page renamed `setup.mdx` still lands on it, `slug` and numeric prefix included. Update them anyway: a link to the old name breaks wherever the Markdown is read as files, such as on GitHub.
|
|
84
|
+
|
|
85
|
+
**Every Markdoc tag must be converted**: in `.md` an unconverted tag ships as literal text with a green build, and `blume check` and `build` only warn `BLUME_TEMPLATE_TAG` at its line (in `.mdx` the page fails to compile, and `blume check` and `validate` report it as `BLUME_MDX_SYNTAX`). Finish with `grep -rn '{%' <content folders>` returning only samples that document Markdoc itself, in code where the warning skips them.
|
|
86
|
+
|
|
87
|
+
**The body H1 is the title.** Realm renders the page's first `# H1` and uses it for `<title>`, sidebar label, and breadcrumb (unless the page sets `seo.title`; a page with no H1 uses its first heading of any level). Move it to frontmatter `title`, delete it from the body, and demote any later H1 to `##`. Links to the H1's own anchor (`#<h1-slug>`, often the first entry of a hand-written contents list) now break: remove them or point them at the page.
|
|
88
|
+
|
|
89
|
+
| Markdoc | Blume (`.mdx`) |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| `{% admonition type="info" name="Title" %}` … `{% /admonition %}` | `:::info[Title]` … `:::` (`success`, `warning`, `danger` keep their names; `idea` → `tip`). No `name` → no brackets |
|
|
92
|
+
| `{% tabs %}` / `{% tab label="X" %}` | `<Tabs>` / `<Tab title="X">`; `tabs id="k"` → `param="k"`. **A group of tabs that each hold only a code fence** → `<CodeGroup>` with titled fences (` ```ts title="X" `); a bare fence directly inside `tabs` was a tab named by its `label` |
|
|
93
|
+
| `{% code-group %}` | `<CodeGroup>` with titled fences; `mode="dropdown"` → `<CodeGroup dropdown>` |
|
|
94
|
+
| `{% partial file="…" variables={a: "x"} /%}` | `<include a="x">…</include>` on its own line (Partials) |
|
|
95
|
+
| `{% raw-partial file="…" /%}` | inline the file's text |
|
|
96
|
+
| `{% code-snippet file="./x.js" title="x.js" /%}` | `<include lang="js" meta='title="x.js"'>./x.js</include>` (the file inside `content.root`). `from`/`to`/`before`/`after` ranges: paste the lines into a fence instead (report) |
|
|
97
|
+
| `{% cards columns=N %}` / `{% card title to icon image %}` | `<CardGroup cols={N}>` / `<Card title href icon img>`; `layout="horizontal"` → `horizontal` |
|
|
98
|
+
| `{% accordion-group %}` / `{% accordion title expanded %}` | `<Accordion>` / `<AccordionItem title defaultOpen>` |
|
|
99
|
+
| `{% numbered-list %}` / `{% numbered-item %}` | `<Steps>` / `<Step title>` (an item's leading heading becomes `title`) |
|
|
100
|
+
| `{% img src alt caption /%}` | ``, inside `<Frame caption="…">` when it had a caption. `srcSet` light/dark pairs have no equivalent: keep one image (report) |
|
|
101
|
+
| ` ```mermaid ` fence, `{% diagram type="mermaid" %}` | a ` ```mermaid ` fence (inline the file), in an `.mdx` page. PlantUML and Excalidraw have no renderer: export to SVG (report) |
|
|
102
|
+
| `{% icon name="…" /%}`, `{% inline-svg file /%}` | `<Icon icon="<lucide-name>" />`, `` |
|
|
103
|
+
| `{% table %}` | a pipe table (raw HTML for `colspan`/`rowspan`) |
|
|
104
|
+
| `{% if %}` / `{% else /%}` | no conditionals: keep the branch the live site showed; per-reader branches (`$rbac`, `$user`) keep the public one (report) |
|
|
105
|
+
| `{% $frontmatter.x %}` / `{% $env.PUBLIC_X %}` | the literal value / `{{public-x}}` with a `variables` entry (`"public-x": process.env.PUBLIC_X ?? ""`: values must be strings, so an unset variable would fail the config) |
|
|
106
|
+
| `{% json-schema %}`, `{% json-example %}`, `{% openapi-code-sample %}`, `{% openapi-response-sample %}`, `{% replay-openapi %}` | a fenced sample or a `TypeTable`, or a link to the operation page, which renders samples and Try it itself (report) |
|
|
107
|
+
| `{% markdoc-example %}`, `{% login-button %}`, `{% connect-mcp %}`, `{% code-walkthrough %}` | the fence only / drop (report); a walkthrough becomes prose and fences or `<Steps>` |
|
|
108
|
+
| `## Heading {% #id %}` / `{% .class %}` | `## Heading [#id]` / drop |
|
|
109
|
+
| any other tag | a custom tag from `@theme/markdoc/schema.ts`: rewrite its markup, or make its component an island (`islands/<Name>.tsx`, used as `<Name …/>`) |
|
|
110
|
+
|
|
111
|
+
**Code fences**: Realm reads fence meta only from an annotation: ` ```js {% title="app.js" highlight="{2,4-6}" %} ` → ` ```js title="app.js" {2,4-6} `, and `highlight="/word/"` → `// [!code word:word]`. A bare word after the language was ignored by Realm but becomes a title in Blume: delete stray ones. `[!code highlight|++|--|word|focus|error|warning]` comments carry over.
|
|
112
|
+
|
|
113
|
+
**Partials** live in `_partials/` folders at any depth, which Blume also keeps out of routing. `markdown.partialsFolders` replaces that default: add the folders it names to `content.exclude` (which keeps Blume's defaults) or rename them with a leading `_`. A leading `/` in `file` meant the project root, which is `content.root` when that's `"."`. Variables become lowercase attributes (`favFood` → `favfood`), read in the partial as `{{favfood}}`; a partial that read `$frontmatter` needs the value passed in. A partial used only by `.md` pages can stay `.md`.
|
|
114
|
+
|
|
115
|
+
## Frontmatter
|
|
116
|
+
|
|
117
|
+
| Redocly | Blume |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| body `# H1` | `title` |
|
|
120
|
+
| `title` (top level) | **drop.** Realm never rendered it on Markdown pages (`<title>` was the H1), so moving it to `seo.title` would change live titles. Offer it in the report when it looks like a deliberate SEO title |
|
|
121
|
+
| `description` (top level) | `description` (Realm used the site description instead; this improves the meta description) |
|
|
122
|
+
| `seo.title`, `seo.description`, `seo.image` | the same keys (`seo.title` was also Realm's sidebar label: copy it to `sidebar.label` to keep that) |
|
|
123
|
+
| `seo.keywords` | `search.keywords`, as a list (a string splits on commas). Blume uses them as search terms and writes no per-page `<meta name="keywords">` |
|
|
124
|
+
| `excludeFromSearch: true` | `search.exclude: true` + `ai.exclude: true` (+ `noindex: true` to keep it out of the sitemap, as Realm did) |
|
|
125
|
+
| `slug` | `slug` (a full route); a list → the first as `slug`, the others as redirects |
|
|
126
|
+
| `redirects: { '/old/': {} }` | a config `redirects` entry per path, `from` without the trailing slash. Exact entries beat wildcards, as in Realm |
|
|
127
|
+
| `sidebar: { hide: true }` (hides the sidebar on this page; it doesn't take the page out of one) | `mode: center`. Not `sidebar.hidden`, which removes the page from the navigation, search, and the sitemap |
|
|
128
|
+
| `sidebar: { path }` (which sidebar this page shows) | drop: the tab whose `path` holds the page decides its sidebar |
|
|
129
|
+
| `navigation.nextButton` + `previousButton` `hide: true` | `pagination: false` |
|
|
130
|
+
| `navbar`/`footer` hidden | `mode: custom` (the header only: no sidebar, title, or footer). The header always shows: report a hidden navbar |
|
|
131
|
+
| `rbac` | drop; report the page as access-controlled |
|
|
132
|
+
| `markdown.*`, `codeSnippet`, `breadcrumbs`, `colorMode`, `feedback`, `search`, `versionPicker`, `banner`, `template`, `keywords` (Typesense search curation), `seo.meta`/`jsonLd`/`lang`/`priority` | drop (report what was set) |
|
|
133
|
+
| top-level `editPage` (including legacy `editPage: { disable }`) | drop without reporting: Realm reads only `markdown.editPage`, so it never had an effect |
|
|
134
|
+
| custom keys (`metadata`, …) | `frontmatter.extend` if the site needs them, else drop |
|
|
135
|
+
|
|
136
|
+
## API reference
|
|
137
|
+
|
|
138
|
+
Realm renders every description in the content tree (a `.yaml`/`.json` with a top-level `openapi:`, `swagger:`, or `asyncapi:` key, or a `.graphql` schema) **at its path without the extension**: an overview at `/apis/orders/openapi`, a page per tag, and a page per operation below it. `apis` entries match files by `root` and carry lint and display settings; a description needs no entry to render. List every description, and report any `apis.*.root` that points at a missing file.
|
|
139
|
+
|
|
140
|
+
- **Use `openapi()`** from `blume/reference`, one source per description: like Realm, it gives each operation its own page and URL. (`scalar()` would collapse each API onto one page.) AsyncAPI → `asyncapi()`; GraphQL → `graphql()` with `endpoint`. Leave the files where they are.
|
|
141
|
+
- **Choose each `route`.** When the description shares its folder with guides (`apis/orders/openapi.yaml` beside `apis/orders/quick-start.md`), keep the old path (`route: "/apis/orders/openapi"`): its overview URL survives, and the reference sits in that folder's group beside the guides. **When the description is alone in its folder** (`apis/orders/openapi.yaml` and nothing else), the old path nests the reference's group inside a folder group that holds only it: use the folder as the route (`route: "/apis/orders"`), so the reference is that group. That moves one overview URL, which the catch-all below covers. Either way, `label` (the `sidebars.yaml` label, else the spec's `info.title`) names the group. Choosing a route inside a topic folder elsewhere moves the reference to where a `sidebars.yaml` had placed it, at the cost of more redirects; say which you chose. Add a `navigation.tabs` entry if an API was a top-level section.
|
|
142
|
+
- **Spec problems fail `blume validate --strict`** (`BLUME_OPENAPI_*` warnings, e.g. path parameters declared `in: query` or missing). Fix them with an OpenAPI Overlay in the source's `overlays`, leaving a generated spec untouched, and report them for a fix at the source.
|
|
143
|
+
- **Decorators don't run.** Realm applies `decorators` (`remove-x-internal`, `filter-out`, `info-override`), and the `preprocessors` and `plugins` behind them, when it bundles a description; Blume reads the raw file. When any are configured, point `spec` at `redocly bundle <api> --output <file>` output or express the change as an Overlay.
|
|
144
|
+
- **Tag labels and order.** Blume reads `x-displayName` for each tag group's label, and orders tags as the spec's `tags` list does and operations as the spec lists them. `x-tagGroups` isn't read: when the spec has them and their flattened order (how Realm ordered tags) differs from `tags`, write `<route>/<tag-slug>/meta.ts` with `defineMeta({ order })`, the tag's position there (the folder under `content.root`, mirroring the route; it must sit in a folder `content.include` reaches, or `BLUME_META_OUTSIDE_INCLUDE` warns that it's never read). It merges over the generated title and order. Get each tag's folder name from Blume's routes (below), not by slugifying. `x-tagGroups` names drop, and tags left out of every group, which Realm hid, now appear: report both. `x-traitTag`, `x-logo`, and `x-badges` are ignored.
|
|
145
|
+
- **Code samples**: `codeSamples.languages[].lang` (root and per-API `openapi:`) → `codeSamples`; Blume reads Redocly's names (`curl`, `JavaScript`, `Node.js`, `Python`, `Java`, `C#`, `PHP`, `Go`, `Ruby`). `R`, `Payload`, `Java8+Apache`, and `C#+Newtonsoft` have no generator and warn `BLUME_OPENAPI_UNKNOWN_CODE_SAMPLE`: drop them and report. With no languages set, Realm showed its full default list and Blume shows `curl`, `js`, `python`: report the difference. `x-codeSamples` render natively. `codeSamples`, `playground`, and `expandSchemas` are `openapi()` options, shared by all its sources: APIs whose settings differ go in separate `openapi()` entries.
|
|
146
|
+
- **Try it**: `hideReplay: true` → `playground: false`. Realm proxied Try it requests by default; Blume sends them from the browser. Set `playground: { proxy: "<url>" }` only for a proxy the user runs; **never carry over a Redocly-hosted one** (`/_api/cors/`, the default; `https://cors.redocly.com`; `https://cors.redoc.ly`). Probe each API's server for CORS with `curl -si -X OPTIONS -H 'Origin: https://<docs-host>' -H 'Access-Control-Request-Method: GET' <server-url>/<some-path>` and list the ones without a matching `access-control-allow-origin` as a follow-up: `playground: { proxy: true }` fixes them once the user picks a server-output host.
|
|
147
|
+
- **Other display options**: `excludeFromSearch` → the source's `includeInSearch: false`; `schemasExpansionLevel: all` → `expandSchemas: true`; `layout`, download buttons, `showExtensions`, `feedback` (Blume's page rating shows on every overview and operation page, with no per-source switch), `mockServer`, and the rest drop (report).
|
|
148
|
+
|
|
149
|
+
## URLs and redirects
|
|
150
|
+
|
|
151
|
+
**Save the old URL list first**: a Realm site with `seo.siteUrl` serves `<site>/sitemap.xml`, listing every page **and every API overview, tag, `section/`, and operation page**. Every URL on it must end up a Blume page or a redirect to one.
|
|
152
|
+
|
|
153
|
+
- **Page routes.** Realm slugs the file path: lowercased, spaces → `-`, `_` and `.` kept, **numeric prefixes kept**. Blume keeps the filename's case and its spaces, and strips a numeric prefix followed by `-`, `_`, or `.` (`01_setup` → `/setup`; a date like `2024-01` or a version stays whole). Rename mixed-case and spaced files to match; a numbered file needs `slug` (or a redirect) to keep its number; a nested `README.md` (Realm `/…/readme`, Blume `/…/README`) becomes `readme.md` to keep its URL.
|
|
154
|
+
- **Moved pages** (materialized groups, `index` promotions, tabs) and **Realm's own redirects** (config, frontmatter `redirects`, extra `slug`s) all become `redirects`. A long generated list reads best in its own `redirects.ts` module, imported into `blume.config.ts`.
|
|
155
|
+
- **Operation pages change shape.** Realm: `<old route>/<tag-slug>/<operationId lowercased>` (`getMultipleDomains` → `getmultipledomains`, `Domains.getDomain` → `domains.getdomain`), or `<old route>/<tag-slug>/paths/<JSON pointer>/<method>` with no `operationId` (`…/paths/~1pets~1%7Bid%7D/get`). Realm tag slugs keep underscores. Blume's slugs differ, so write **one exact redirect per operation**, generated:
|
|
156
|
+
1. `blume build` once with the references configured.
|
|
157
|
+
2. `node <skill>/scripts/operation-routes.mjs dist > operation-routes.json` prints, per reference route, every endpoint (`GET /pets/{id}`, or `POST petAdopted` for a webhook) mapped to its Blume route, read from the build itself (a Vercel server build's pages are in `.vercel/output/static`: pass that). `--spec <route>=<file.json>` adds operationIds (convert YAML first: `npx @redocly/cli bundle openapi.yaml --output openapi.json`).
|
|
158
|
+
3. For each old operation URL, find its operation in the spec: match the last segment against each `operationId` lowercased, or decode the pointer (`%7B` → `{`, `~1` → `/`, `~0` → `~`) to a path plus method. Look up `METHOD path` under the new route, and emit `{ from: <old URL path>, to: <route> }`.
|
|
159
|
+
- **Tag, `section/`, and tag-description heading pages** (`<old route>/<tag>`, `<old route>/section/<heading>`, `<old route>/<tag>/<heading>`) don't exist in Blume: send them to the overview. When the route moved, one catch-all does it: `{ from: "<old route>/:path*", to: "<new route>" }` (exact operation entries still win). When the route stayed, use `{ from: "<route>/section/:path*", to: "<route>" }` and `{ from: "<route>/:tag", to: "<route>" }`, plus exact entries for tag headings; a pattern that covers a page fails the build (`BLUME_REDIRECT_MATCHES_PAGE`).
|
|
160
|
+
- **Legacy hash links** (`#operation/<id>`, `#tag/<tag>`, `#section/…`) worked on Realm, which resolved them in the browser, and still appear **in content, partials, and the description files' own descriptions**. A server can't redirect a fragment. `blume validate` flags one on a page that still exists as a broken anchor, but accepts any redirect `from` as a link target, so it misses the ones whose path now redirects: `grep -rn '#operation/\|#tag/' <content> <spec files>` and rewrite each to its Blume route. Rewrite absolute links to the site itself (`https://<docs-host>/…`) to root-relative paths too; `blume audit` flags the ones left.
|
|
161
|
+
- **Trailing slashes.** Realm answered `/a/` with a 301 to `/a`, and so do `blume dev` and `blume preview`, for pages and redirect sources alike. In production it depends on the host: static hosts serve a page's `a/index.html` at `/a/`, and server builds (`vercel()`, `node()`) match `/a/` for a redirect `from`, but whether a static host applies a redirect rule to the slashed form varies. When old links used trailing slashes (frontmatter `redirects` often did), check one slashed redirect on a preview deployment and report it.
|
|
162
|
+
- **Versions and locales**: Realm drops the `@` from version folders (`api/@v1/x.md` → `/api/v1/x`) and serves the default version without its segment; non-default locales get the lowercased code (`@l10n/es-ES/` → `/es-es/…`).
|
|
163
|
+
- **Check coverage**: after the build, every old URL should be a page in `dist/` (`<path>/index.html`) or resolve through `dist/blume-redirects.json` (exact entries first, then patterns) to one. That manifest is written for a static build with no host adapter; with one, request each URL from a running `blume dev` (or `blume preview` of a static build) instead: both answer every redirect, patterns included. `blume audit --only redirects` checks the redirects themselves.
|
|
164
|
+
|
|
165
|
+
## Assets, theme, React pages, and the repo
|
|
166
|
+
|
|
167
|
+
- **`static/` → `public/`**: Realm serves `static/` at the root, so root-relative references keep working. Drop a Redocly-hosting `robots.txt` (`/~/`, `/cdn-cgi/` rules); Blume writes its own.
|
|
168
|
+
- **`.gitignore`**: Realm projects often list `public/` (and sometimes `_partials`), which would leave moved files uncommitted: remove those lines. Add `.blume/`, `dist/`, and `.env.local`, as `blume init` does.
|
|
169
|
+
- **Node**: Blume needs Node 22.19 or later, and Realm templates often pin 20 in `.nvmrc`. Update `.nvmrc`/`.node-version`, `engines.node`, and CI `node-version`.
|
|
170
|
+
- **`@theme/styles.css`**: the brand color (`--color-primary-base` or the variable it points at) → `theme.accent`; check it against dark mode, which `blume audit` checks for contrast. Rules for the site's own classes (a landing page, figures) move to a root `theme.css`, with `html.dark` selectors rewritten as `[data-theme="dark"]`. Rules for Realm's components don't apply: report them.
|
|
171
|
+
- **`@theme/components/*`**: a component a page uses → an island (`islands/`, or imported by a custom page with `client:*`); an ejected Realm component → the matching layout slot if one exists, else drop. `@theme/layouts`, `Templates`, `plugin.*`, and `markdoc/` drop once their tags are converted.
|
|
172
|
+
- **`*.page.tsx`**: `index.page.tsx` → `pages/index.astro` on `PageLayout`, with interactive parts as React islands, or an `index.mdx` with `mode: custom` when it's mostly links. Its `export const frontmatter` gives the title. `404.page.tsx` → `pages/404.astro`, or Blume's built-in 404. A React-state light/dark image swap becomes two images with CSS hiding one.
|
|
173
|
+
|
|
174
|
+
## i18n
|
|
175
|
+
|
|
176
|
+
`l10n: { defaultLocale, locales: [{ code, name }] }` → `i18n: { defaultLocale, locales: [{ code, label: name }] }`. Pages under `@l10n/<code>/` move to `<code>/` at the content root. Blume uses `code` as written in URLs, so write it lowercase (`es-es`, folder too) to keep Realm's URLs. `translations.yaml` label keys → per-locale `meta.ts` titles and tab label maps; UI strings → `i18n.ui` where Blume has one; report the rest.
|
|
177
|
+
|
|
178
|
+
## Versions
|
|
179
|
+
|
|
180
|
+
Realm versions a folder through `@<version>/` subfolders and an optional `versions.yaml` (`default`, order; with no `default`, the last listed version is the default); the default version serves without its segment. Blume's versioning is site-wide:
|
|
181
|
+
|
|
182
|
+
- **Version folders at the content root** → Blume versioning: the default version becomes the current tree (`versions.current: { label }`, required), the others top-level folders listed newest first in `versions.archived` as `{ id, label? }` (ids start with a letter: `@1.0` → `v1.0`, redirect `/1.0/:path*`).
|
|
183
|
+
- **A versioned section** (`api/@v1/`) → plain folders reproduce the URLs: the default version's files move up into `api/`, the others into `api/v1/` (a name like `1.0` stays whole). Add a `navigation.selectors` entry `{ kind: "version", … }` and report the missing old-version notice and version-scoped search. Versioned descriptions → one `openapi()` source each.
|
|
184
|
+
|
|
185
|
+
## Icons
|
|
186
|
+
|
|
187
|
+
Realm icons are Font Awesome names (`book`, `solid check-circle`, `brands github`) or image paths. Strip the pack prefix and map to Lucide with the table in `references/mintlify.md`; image paths work as written; brand icons other than the few Lucide ships (listed there, `github` among them) have no Lucide match (report).
|
|
188
|
+
|
|
189
|
+
## Teardown — keep lint and bundle working
|
|
190
|
+
|
|
191
|
+
1. **Trim `redocly.yaml`, don't delete it**: remove the portal keys and keep `extends`, `rules`, `decorators`, `preprocessors`, `plugins`, `resolve`, `telemetry`, and each `apis` entry's `root`, `output`, `overlays`, and lint keys (drop its `openapi`/`graphql`/`theme` display keys). If nothing but `apis` roots remain, keep it anyway when scripts or skills run `redocly lint`; otherwise ask. Run the lint script before and after: the result should match.
|
|
192
|
+
2. Keep `@redocly/cli` and its scripts and CI jobs. Remove the Realm-family packages, `styled-components` and the other template peers nothing else imports (keep `react`/`react-dom` if an island uses them), and the `realm` scripts; add `blume` and the `blume dev`/`build`/`preview` scripts.
|
|
193
|
+
3. Delete `sidebars.yaml` files, `versions.yaml`, `@theme/`, the React pages once rebuilt, `translations.yaml` once mapped, the `tsconfig.json`/`types.d.ts` that only served them, and the redirects file a `$ref` pointed at.
|
|
194
|
+
4. Reunite settings (custom domain, environment variables, teams, hosted analytics) live outside the repo: list what the user must recreate.
|
|
195
|
+
|
|
196
|
+
## Dropped — report these
|
|
197
|
+
|
|
198
|
+
Login, RBAC, and SSO (every protected path); Reunite's editor, reviews, previews, and feedback dashboard; the API explorer's mock server, environments, saved auth, and default CORS proxy (and which APIs now fail CORS); `x-tagGroups` names and the tags they hid; API tag and `section/` pages (redirected); sidebar separators and `expanded: always`; footer column labels; the ` - <title>` suffix now on every `<title>`; dropped frontmatter titles; `seo.image`/`jsonLd` and `llms.txt` sections; extra banners; search facets; resolved `if` branches and per-reader content; `code-snippet` ranges; the Markdoc tags with no equivalent; PlantUML/Excalidraw; light/dark image pairs; unmatched icons; ejected components and Realm CSS; a `UA-` analytics id; scripts that now load only in production; trailing-slash URLs; the accidental pages left out; reset "last updated" dates.
|
|
@@ -12,7 +12,7 @@ Keep content where it is — set `content.root: "src/content/docs"`.
|
|
|
12
12
|
|
|
13
13
|
## Config: `starlight({…})` → `blume.config.ts`
|
|
14
14
|
|
|
15
|
-
**Harvest the surrounding `astro.config.*` too, not just the `starlight()` call:** top-level Astro `redirects` → Blume `redirects`; `site` → `deployment.site`, unless the target host is Vercel
|
|
15
|
+
**Harvest the surrounding `astro.config.*` too, not just the `starlight()` call:** top-level Astro `redirects` → Blume `redirects`; `site` → `deployment.site`, unless the target host is Vercel or Netlify, which Blume auto-detects (see SKILL.md); other integrations → report.
|
|
16
16
|
|
|
17
17
|
| Starlight option | Blume |
|
|
18
18
|
| --- | --- |
|
|
@@ -65,7 +65,7 @@ Starlight's `sidebar` array → prefer letting Blume generate from the filesyste
|
|
|
65
65
|
|
|
66
66
|
## Asides → directives (and the `.md` trap)
|
|
67
67
|
|
|
68
|
-
Starlight's primary callout syntax is the `:::note`/`:::tip`/`:::caution`/`:::danger` directive **in plain `.md` files**. The directive names map perfectly (Blume aliases `caution`→warning; `error`→danger) and `[Title]` syntax carries over — **but Blume only parses directives in `.mdx`**. In a `.md` file, `:::note` renders as literal text and the build stays green. So: **rename every `.md` file that contains asides (or math, or mermaid/package-install fences) to `.mdx`** — for a typical Starlight repo that's most of the content; renaming everything to `.mdx` is usually simpler and safe.
|
|
68
|
+
Starlight's primary callout syntax is the `:::note`/`:::tip`/`:::caution`/`:::danger` directive **in plain `.md` files**. The directive names map perfectly (Blume aliases `caution`→warning; `error`→danger) and `[Title]` syntax carries over — **but Blume only parses directives in `.mdx`**. In a `.md` file, `:::note` renders as literal text and the build stays green, with only a `BLUME_MD_DIRECTIVE` warning at its line. So: **rename every `.md` file that contains asides (or math, or mermaid/package-install fences) to `.mdx`** — for a typical Starlight repo that's most of the content; renaming everything to `.mdx` is usually simpler and safe.
|
|
69
69
|
|
|
70
70
|
- `<Aside type="…" title="…">` (the component form) → the same directives; bare `<Aside>` → `:::note`.
|
|
71
71
|
- An aside custom icon (`:::tip{icon="heart"}`) → drop the attr (report).
|
|
@@ -83,7 +83,7 @@ Starlight content is full of Expressive Code fence meta; Blume understands some
|
|
|
83
83
|
|
|
84
84
|
- `title="file.js"` → works as-is (or use the space-title shorthand). Line ranges `{2-3}` → work as-is.
|
|
85
85
|
- `ins=`/`del=` line marks → `// [!code ++]` / `// [!code --]` comments; `mark=` → `{ranges}` or `// [!code highlight]`.
|
|
86
|
-
- `showLineNumbers` → `lineNumbers
|
|
86
|
+
- `showLineNumbers` → `lineNumbers` (`BLUME_CODE_FENCE_OPTION` flags any left).
|
|
87
87
|
- `wrap` / `wrap=true` → a bare `wrap` (that block's long lines wrap); a site-wide `expressiveCode.defaultProps.wrap: true` → `markdown.code.wrap: true`.
|
|
88
88
|
- **Drop:** `frame="terminal"`, `collapse=`, `wrap=false`, `preserveIndent`/`hangingIndent`, `"string"` and `/regex/` text markers (report if they carried meaning).
|
|
89
89
|
- ` ```diff lang="js" ` → a normal ` ```js ` fence with `[!code ++]`/`[!code --]` markers.
|