blume 2.1.0 → 2.1.2
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/CHANGELOG.md +110 -0
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/{chunk-43zcf4gz.js → chunk-0pmb4tr4.js} +541 -368
- package/dist/cli/chunk-0pmb4tr4.js.map +35 -0
- package/dist/cli/{chunk-9geymqns.js → chunk-0w6hs479.js} +15 -15
- package/dist/cli/{chunk-xkz5xbtv.js → chunk-124fvmzq.js} +2802 -1422
- package/dist/cli/chunk-124fvmzq.js.map +220 -0
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-y4ykbark.js → chunk-1f882900.js} +2 -2
- package/dist/cli/{chunk-5ffywsmb.js → chunk-297ajdcv.js} +8 -6
- package/dist/cli/{chunk-5ffywsmb.js.map → chunk-297ajdcv.js.map} +3 -3
- package/dist/cli/{chunk-h2a48yhd.js → chunk-32khwcb6.js} +120 -16
- package/dist/cli/{chunk-h2a48yhd.js.map → chunk-32khwcb6.js.map} +10 -10
- package/dist/cli/{chunk-5cg2rzgf.js → chunk-36bxs9c7.js} +20 -49
- package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-36bxs9c7.js.map} +4 -5
- package/dist/cli/{chunk-py62fewh.js → chunk-53jqw8z0.js} +3 -3
- package/dist/cli/{chunk-5wj2qwn2.js → chunk-58bt3hag.js} +4 -4
- package/dist/cli/{chunk-e7vvk5ya.js → chunk-5cmts6dv.js} +3 -3
- package/dist/cli/{chunk-y5h4r2y0.js → chunk-60hz265r.js} +15 -5
- package/dist/cli/chunk-60hz265r.js.map +10 -0
- package/dist/cli/chunk-74wfhv79.js +65 -0
- package/dist/cli/chunk-74wfhv79.js.map +10 -0
- package/dist/cli/{chunk-g2z9x01v.js → chunk-9qzgg6mj.js} +3 -3
- package/dist/cli/{chunk-q3wxxq39.js → chunk-a57yh0h9.js} +5 -5
- package/dist/cli/{chunk-713mngdq.js → chunk-ave1wcbr.js} +76 -10
- package/dist/cli/chunk-ave1wcbr.js.map +14 -0
- package/dist/cli/{chunk-2n4ps1b3.js → chunk-bqxaqn5p.js} +40 -22
- package/dist/cli/chunk-bqxaqn5p.js.map +15 -0
- package/dist/cli/{chunk-jnwj5kjj.js → chunk-bxwhtvw8.js} +20 -7
- package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-bxwhtvw8.js.map} +3 -3
- package/dist/cli/chunk-ckrcm08h.js +324 -0
- package/dist/cli/chunk-ckrcm08h.js.map +14 -0
- package/dist/cli/{chunk-2f3ndkpw.js → chunk-desvm72z.js} +3 -3
- package/dist/cli/{chunk-gp84za0h.js → chunk-dhwtqnnd.js} +2 -2
- package/dist/cli/{chunk-4h8z9vv5.js → chunk-dpy8qdjf.js} +93 -47
- package/dist/cli/chunk-dpy8qdjf.js.map +17 -0
- package/dist/cli/{chunk-2f7n4qzt.js → chunk-dqhg54mr.js} +1 -1
- package/dist/cli/{chunk-0gz36akr.js → chunk-dv2z0rzf.js} +21 -5
- package/dist/cli/chunk-dv2z0rzf.js.map +12 -0
- package/dist/cli/{chunk-cm89scdv.js → chunk-es8h0v3j.js} +9 -11
- package/dist/cli/{chunk-cm89scdv.js.map → chunk-es8h0v3j.js.map} +3 -3
- package/dist/cli/{chunk-zhvd6adm.js → chunk-gfc5fqvf.js} +14 -14
- package/dist/cli/{chunk-nd1821sk.js → chunk-gxtg6ed2.js} +33 -19
- package/dist/cli/chunk-gxtg6ed2.js.map +10 -0
- package/dist/cli/{chunk-p804f3pe.js → chunk-hvcxng5f.js} +6 -6
- package/dist/cli/{chunk-ta27feev.js → chunk-j1x92mx9.js} +21 -2
- package/dist/cli/chunk-j1x92mx9.js.map +10 -0
- package/dist/cli/{chunk-rekqz4qg.js → chunk-k3gr1nm9.js} +19 -16
- package/dist/cli/chunk-k3gr1nm9.js.map +10 -0
- package/dist/cli/{chunk-1n228xqb.js → chunk-kdpzw38a.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js → chunk-ms9z66nz.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-ms9z66nz.js.map} +2 -2
- package/dist/cli/{chunk-zf748avv.js → chunk-nbyvgnnm.js} +193 -286
- package/dist/cli/chunk-nbyvgnnm.js.map +36 -0
- package/dist/cli/{chunk-6bm0xpgd.js → chunk-s0bdnc7v.js} +2 -2
- package/dist/cli/{chunk-yxmk4pec.js → chunk-sc93apfs.js} +17 -16
- package/dist/cli/{chunk-yxmk4pec.js.map → chunk-sc93apfs.js.map} +3 -3
- package/dist/cli/{chunk-cmtcnh9f.js → chunk-tfycddbt.js} +2 -2
- package/dist/cli/{chunk-9xr4dgee.js → chunk-twy7psdz.js} +29 -16
- package/dist/cli/chunk-twy7psdz.js.map +10 -0
- package/dist/cli/{chunk-ntv4qrt7.js → chunk-y4msrwm9.js} +15 -15
- package/dist/cli/{chunk-yj17vs39.js → chunk-ydp3065p.js} +5 -5
- package/dist/cli/index.js +24 -19
- package/dist/cli/index.js.map +3 -3
- package/dist/types/ai/ask-context.d.ts +6 -2
- package/dist/types/ai/ask.d.ts +24 -5
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/analytics/clics.d.ts +37 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +18 -0
- package/dist/types/astro/integration.d.ts +11 -4
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +4 -1
- package/dist/types/components/content/api-page.d.ts +6 -1
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +22 -1
- package/dist/types/components/openapi/security.d.ts +10 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +37 -6
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +2 -0
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/powered-by.d.ts +12 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +11 -3
- package/dist/types/core/schema.d.ts +228 -3
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +10 -2
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/notion.d.ts +8 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +17 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/cloudflare-negotiation.d.ts +5 -2
- package/dist/types/deploy/node-headers.d.ts +12 -4
- package/dist/types/deploy/platforms/cloudflare.d.ts +10 -7
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +21 -2
- package/dist/types/deploy/redirects.d.ts +17 -1
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +44 -21
- package/dist/types/narration/build.d.ts +34 -12
- package/dist/types/narration/provider.d.ts +96 -8
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +15 -4
- package/dist/types/openapi/parse.d.ts +3 -0
- package/dist/types/openapi/references.d.ts +16 -0
- package/dist/types/openapi/sentence.d.ts +11 -1
- package/dist/types/ratelimit/index.d.ts +1 -1
- package/dist/types/ratelimit/schema.d.ts +8 -0
- package/dist/types/ratelimit/upstash.d.ts +39 -14
- package/dist/types/reference/graphql.d.ts +76 -1
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +2 -2
- package/dist/types/reference/options.d.ts +37 -1
- package/dist/types/reference/schema.d.ts +84 -0
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/orama-index.d.ts +9 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/jsonld.d.ts +11 -6
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/notion.d.ts +8 -0
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +63 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +59 -13
- package/docs/03-upgrading.mdx +2 -1
- package/docs/04-migrating.mdx +9 -9
- package/docs/08-faq.mdx +12 -12
- package/docs/advanced/changelog.mdx +30 -2
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +30 -7
- package/docs/cli/doctor.mdx +6 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +19 -1
- package/docs/configuration/assistant.mdx +6 -2
- package/docs/configuration/customization.mdx +4 -2
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +4 -2
- package/docs/configuration/narration.mdx +43 -6
- package/docs/configuration/rate-limiting.mdx +23 -2
- package/docs/configuration/search.mdx +37 -14
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -3
- package/docs/content/i18n.mdx +2 -2
- package/docs/content/includes.mdx +1 -1
- package/docs/content/navigation.mdx +8 -6
- package/docs/content/sources/contentful.mdx +9 -4
- package/docs/content/sources/custom.mdx +7 -3
- package/docs/content/sources/github-releases.mdx +12 -2
- package/docs/content/sources/index.mdx +3 -3
- package/docs/content/sources/notion.mdx +17 -2
- package/docs/content/sources/obsidian.mdx +3 -1
- package/docs/content/sources/payload.mdx +5 -2
- package/docs/content/sources/remote-mdx.mdx +6 -0
- package/docs/content/sources/sanity.mdx +4 -2
- package/docs/content/sources/strapi.mdx +5 -2
- package/docs/content/syntax.mdx +2 -2
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/index.mdx +1 -1
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +6 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/discoverability/structured-data.mdx +8 -6
- package/docs/references/api-pages.mdx +1 -1
- package/docs/references/asyncapi.mdx +5 -1
- package/docs/references/graphql.mdx +15 -1
- package/docs/references/openapi.mdx +64 -8
- package/package.json +9 -9
- package/skills/blume/SKILL.md +1 -1
- package/skills/blume-migrate/SKILL.md +2 -2
- package/skills/blume-migrate/assets/{oxfmt@0.67.0.patch → oxfmt@0.71.0.patch} +7 -7
- package/skills/blume-migrate/references/docusaurus.md +4 -4
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/monorepo.md +5 -5
- package/skills/blume-migrate/references/nextra.md +8 -5
- package/skills/blume-migrate/references/starlight.md +9 -7
- package/src/ai/ask-context.ts +33 -3
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask.ts +24 -6
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +1 -1
- package/src/ai/cors.ts +12 -3
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +28 -4
- package/src/ai/relative-links.ts +4 -38
- package/src/analytics/clics.ts +58 -0
- package/src/analytics/head.ts +5 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +91 -56
- package/src/astro/integration.ts +72 -22
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +3 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/render-deps.ts +10 -5
- package/src/astro/runtime-deps.ts +23 -2
- package/src/astro/templates.ts +129 -81
- package/src/audit/catalog.ts +19 -3
- package/src/audit/checks/links.ts +14 -1
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/run.ts +3 -0
- package/src/audit/types.ts +2 -0
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +5 -1
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +45 -12
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/init/scaffold.ts +9 -6
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +3 -2
- package/src/components/content/ApiPlayground.astro +6 -2
- package/src/components/content/api-field.ts +4 -1
- package/src/components/content/api-page.ts +31 -7
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +7 -4
- package/src/components/islands/hooks.ts +27 -1
- package/src/components/layout/NavTree.astro +49 -5
- package/src/components/layout/NavTreeScript.astro +18 -0
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageLayout.astro +13 -3
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +17 -3
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/analytics-client.ts +8 -8
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +42 -14
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +12 -0
- package/src/components/layout/search/typesense.ts +18 -6
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +24 -1
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +19 -2
- package/src/components/openapi/Responses.astro +1 -0
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +61 -5
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +77 -58
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +10 -0
- package/src/components/openapi/snippets.ts +5 -3
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/powered-by-middleware.ts +33 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +42 -6
- package/src/core/data.ts +2 -0
- package/src/core/diagnostics.ts +5 -0
- package/src/core/i18n-ui.ts +2 -0
- package/src/core/includes.ts +1 -1
- package/src/core/links.ts +47 -17
- package/src/core/powered-by.ts +12 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +59 -18
- package/src/core/redirect-patterns.ts +36 -7
- package/src/core/schema.ts +26 -6
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/lower.ts +19 -3
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +227 -41
- package/src/core/sources/notion.ts +34 -10
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +18 -0
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +1 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +1 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +1 -0
- package/src/core/ui-packs/el.ts +1 -0
- package/src/core/ui-packs/es.ts +1 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +1 -0
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +1 -0
- package/src/core/ui-packs/hu.ts +1 -0
- package/src/core/ui-packs/id.ts +1 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +1 -0
- package/src/core/ui-packs/ko.ts +1 -0
- package/src/core/ui-packs/nl.ts +1 -0
- package/src/core/ui-packs/no.ts +1 -0
- package/src/core/ui-packs/pl.ts +1 -0
- package/src/core/ui-packs/pt-br.ts +1 -0
- package/src/core/ui-packs/pt.ts +1 -0
- package/src/core/ui-packs/ro.ts +1 -0
- package/src/core/ui-packs/ru.ts +1 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +1 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +1 -0
- package/src/core/ui-packs/uk.ts +1 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +2 -1
- package/src/deploy/cloudflare-negotiation.ts +36 -7
- package/src/deploy/headers.ts +15 -1
- package/src/deploy/node-headers.ts +32 -20
- package/src/deploy/platforms/cloudflare.ts +14 -9
- package/src/deploy/platforms/netlify.ts +2 -1
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +115 -17
- package/src/deploy/redirects.ts +66 -6
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +325 -103
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/base-links.ts +15 -14
- package/src/markdown/package-commands.ts +9 -8
- package/src/markdown/relative-links.ts +3 -2
- package/src/narration/build.ts +218 -40
- package/src/narration/provider.ts +89 -9
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +15 -3
- package/src/openapi/parse.ts +127 -2
- package/src/openapi/references.ts +43 -3
- package/src/openapi/render-mdx.ts +68 -8
- package/src/openapi/sentence.ts +29 -2
- package/src/openapi/source.ts +39 -14
- package/src/ratelimit/index.ts +1 -1
- package/src/ratelimit/runtime.ts +37 -19
- package/src/ratelimit/upstash.ts +40 -10
- package/src/reference/graphql.ts +15 -1
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +2 -2
- package/src/reference/options.ts +29 -1
- package/src/registry/eject.ts +8 -2
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/orama-index.ts +163 -31
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +99 -9
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/typesense.ts +72 -27
- package/src/seo/jsonld.ts +38 -20
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/notion.ts +7 -0
- package/src/sources/shared.ts +3 -0
- package/src/theme/color.ts +9 -10
- package/src/theme/entry.ts +43 -6
- package/src/translate/validate.ts +23 -1
- package/dist/cli/chunk-0gz36akr.js.map +0 -12
- package/dist/cli/chunk-2n4ps1b3.js.map +0 -15
- package/dist/cli/chunk-43zcf4gz.js.map +0 -36
- package/dist/cli/chunk-4ejxbzee.js +0 -39
- package/dist/cli/chunk-4ejxbzee.js.map +0 -10
- package/dist/cli/chunk-4h8z9vv5.js.map +0 -16
- package/dist/cli/chunk-713mngdq.js.map +0 -14
- package/dist/cli/chunk-9xr4dgee.js.map +0 -10
- package/dist/cli/chunk-amrb6hgh.js +0 -145
- package/dist/cli/chunk-amrb6hgh.js.map +0 -11
- package/dist/cli/chunk-nd1821sk.js.map +0 -10
- package/dist/cli/chunk-rekqz4qg.js.map +0 -10
- package/dist/cli/chunk-ta27feev.js.map +0 -10
- package/dist/cli/chunk-xkz5xbtv.js.map +0 -213
- package/dist/cli/chunk-y5h4r2y0.js.map +0 -10
- package/dist/cli/chunk-zf748avv.js.map +0 -37
- /package/dist/cli/{chunk-9geymqns.js.map → chunk-0w6hs479.js.map} +0 -0
- /package/dist/cli/{chunk-y4ykbark.js.map → chunk-1f882900.js.map} +0 -0
- /package/dist/cli/{chunk-py62fewh.js.map → chunk-53jqw8z0.js.map} +0 -0
- /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-58bt3hag.js.map} +0 -0
- /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-5cmts6dv.js.map} +0 -0
- /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-9qzgg6mj.js.map} +0 -0
- /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-a57yh0h9.js.map} +0 -0
- /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-desvm72z.js.map} +0 -0
- /package/dist/cli/{chunk-gp84za0h.js.map → chunk-dhwtqnnd.js.map} +0 -0
- /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-dqhg54mr.js.map} +0 -0
- /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-gfc5fqvf.js.map} +0 -0
- /package/dist/cli/{chunk-p804f3pe.js.map → chunk-hvcxng5f.js.map} +0 -0
- /package/dist/cli/{chunk-1n228xqb.js.map → chunk-kdpzw38a.js.map} +0 -0
- /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-s0bdnc7v.js.map} +0 -0
- /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-tfycddbt.js.map} +0 -0
- /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-y4msrwm9.js.map} +0 -0
- /package/dist/cli/{chunk-yj17vs39.js.map → chunk-ydp3065p.js.map} +0 -0
package/src/core/ui-packs/uk.ts
CHANGED
package/src/core/ui-packs/vi.ts
CHANGED
package/src/core/ui-packs/zh.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { cp, mkdir, rm } from "node:fs/promises";
|
|
|
3
3
|
|
|
4
4
|
import { dirname, join } from "pathe";
|
|
5
5
|
|
|
6
|
+
import { normalizeBasePath } from "../core/base-path.ts";
|
|
6
7
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
7
8
|
import type { ProjectContext } from "../core/types.ts";
|
|
8
9
|
import type { ResolvedDeployment } from "./adapters/registry.ts";
|
|
@@ -30,7 +31,8 @@ export const deployOutputDir = (
|
|
|
30
31
|
* served. A static build serves `dist/` wherever it lands; a server build
|
|
31
32
|
* serves what its platform declares — the Build Output tree's `static/` half
|
|
32
33
|
* on Vercel, Astro's `build.client` dir (`dist/client/`) on Node and
|
|
33
|
-
* Cloudflare, `dist/` on Netlify.
|
|
34
|
+
* Cloudflare, `dist/` on Netlify. On Vercel and Cloudflare that's its
|
|
35
|
+
* `<base>/` directory under `deployment.base`, where the files land.
|
|
34
36
|
*/
|
|
35
37
|
export const deployStaticDir = (
|
|
36
38
|
config: ResolvedConfig,
|
|
@@ -38,7 +40,10 @@ export const deployStaticDir = (
|
|
|
38
40
|
): string => {
|
|
39
41
|
const { deployment } = config;
|
|
40
42
|
return deployment.options.output === "server"
|
|
41
|
-
? deployPlatform(deployment).serverStaticDir(
|
|
43
|
+
? deployPlatform(deployment).serverStaticDir(
|
|
44
|
+
context,
|
|
45
|
+
normalizeBasePath(deployment.options.base)
|
|
46
|
+
)
|
|
42
47
|
: distDir(context);
|
|
43
48
|
};
|
|
44
49
|
|
|
@@ -23,11 +23,13 @@ export const cloudflareAdapterSchema = adapterDescriptorSchema(
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Cloudflare
|
|
27
|
-
* `dist/server` (with a
|
|
28
|
-
* text/markdown`) and serves
|
|
29
|
-
*
|
|
30
|
-
* (`
|
|
26
|
+
* Cloudflare. A server build targets Workers only (`@astrojs/cloudflare`
|
|
27
|
+
* dropped Pages in v13): it emits a Worker into `dist/server` (with a
|
|
28
|
+
* generated wrapper that answers `Accept: text/markdown`) and serves
|
|
29
|
+
* `dist/client` through the ASSETS binding. A static build
|
|
30
|
+
* (`output: "static"`) never loads the adapter, and its `dist/` deploys to
|
|
31
|
+
* Pages or to Workers static assets. `@astrojs/cloudflare` is an optional
|
|
32
|
+
* peer: install it in the project (`npm install @astrojs/cloudflare`).
|
|
31
33
|
*/
|
|
32
34
|
export const cloudflare = (
|
|
33
35
|
options: CloudflareOptions = {}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
1
3
|
import { adapterDescriptorSchema } from "../../core/adapter.ts";
|
|
2
4
|
import type { DeployAdapter, DeployOptions } from "./types.ts";
|
|
3
5
|
import { deployOptionsSchema, serverRuntimeDeps } from "./types.ts";
|
|
@@ -6,18 +8,54 @@ import { deployOptionsSchema, serverRuntimeDeps } from "./types.ts";
|
|
|
6
8
|
export const NODE_ADAPTER_PACKAGE = "@astrojs/node";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* defaults `mode` to `"standalone"`; an option you pass wins. `host` and
|
|
12
|
-
* `port` are forwarded too, but `@astrojs/node` replaces both with Astro's
|
|
13
|
-
* own server settings, so the standalone server listens on `localhost:4321`
|
|
14
|
-
* unless the `HOST` and `PORT` environment variables are set when it starts.
|
|
11
|
+
* A host the server trusts forwarded headers for, in Astro's
|
|
12
|
+
* `security.allowedDomains` shape: each field set must match.
|
|
15
13
|
*/
|
|
16
|
-
|
|
14
|
+
// oxlint-disable-next-line typescript/consistent-type-definitions -- interface loses the implicit index signature a deploy option's JsonValue needs
|
|
15
|
+
export type NodeAllowedDomain = {
|
|
16
|
+
/** The host, like `docs.example.com`; `*.example.com` matches subdomains. */
|
|
17
|
+
hostname?: string;
|
|
18
|
+
/** The port, as a string. */
|
|
19
|
+
port?: string;
|
|
20
|
+
/** The scheme, like `https`. */
|
|
21
|
+
protocol?: string;
|
|
22
|
+
};
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Options for {@link node}: `output`, `site`, `base`, and `allowedDomains`,
|
|
26
|
+
* plus any option of `@astrojs/node` forwarded verbatim (`mode`,
|
|
27
|
+
* `staticHeaders`, …). Blume defaults `mode` to `"standalone"`; an option you
|
|
28
|
+
* pass wins. `host` and `port` are forwarded too, but `@astrojs/node`
|
|
29
|
+
* replaces both with Astro's own server settings, so the standalone server
|
|
30
|
+
* listens on `localhost:4321` unless the `HOST` and `PORT` environment
|
|
31
|
+
* variables are set when it starts.
|
|
32
|
+
*/
|
|
33
|
+
export type NodeOptions = DeployOptions & {
|
|
34
|
+
/**
|
|
35
|
+
* The hosts a reverse proxy in front of the server answers for, set as
|
|
36
|
+
* Astro's `security.allowedDomains`. A request whose `Host` (or
|
|
37
|
+
* `X-Forwarded-Host`) matches one is trusted to name the reader in
|
|
38
|
+
* `X-Forwarded-For`, which the rate limit counts by; otherwise every
|
|
39
|
+
* reader counts as the proxy's address. Only list them when a proxy sets
|
|
40
|
+
* that header on every request, since a reader could otherwise send their
|
|
41
|
+
* own.
|
|
42
|
+
*/
|
|
43
|
+
allowedDomains?: NodeAllowedDomain[];
|
|
44
|
+
};
|
|
19
45
|
|
|
20
|
-
export
|
|
46
|
+
export type NodeAdapter = DeployAdapter<"node", NodeOptions>;
|
|
47
|
+
|
|
48
|
+
export const nodeOptionsSchema = deployOptionsSchema.extend({
|
|
49
|
+
allowedDomains: z
|
|
50
|
+
.array(
|
|
51
|
+
z.strictObject({
|
|
52
|
+
hostname: z.string().min(1).optional(),
|
|
53
|
+
port: z.string().min(1).optional(),
|
|
54
|
+
protocol: z.string().min(1).optional(),
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
.optional(),
|
|
58
|
+
});
|
|
21
59
|
|
|
22
60
|
export const nodeAdapterSchema = adapterDescriptorSchema(
|
|
23
61
|
"node",
|
|
@@ -84,13 +84,17 @@ const NAMED_OPTIONS = new Set(["base", "output", "site"]);
|
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
86
|
* The options Blume does not name — what reaches the `@astrojs/*` adapter's
|
|
87
|
-
* constructor verbatim.
|
|
87
|
+
* constructor verbatim. `configOptions` are the ones a host adapter names
|
|
88
|
+
* itself, for the Astro config rather than the constructor.
|
|
88
89
|
*/
|
|
89
90
|
export const deployPassthrough = (
|
|
90
|
-
options: DeployOptions
|
|
91
|
+
options: DeployOptions,
|
|
92
|
+
configOptions: readonly string[] = []
|
|
91
93
|
): Record<string, JsonValue> =>
|
|
92
94
|
Object.fromEntries(
|
|
93
|
-
Object.entries(options).filter(
|
|
95
|
+
Object.entries(options).filter(
|
|
96
|
+
([key]) => !(NAMED_OPTIONS.has(key) || configOptions.includes(key))
|
|
97
|
+
)
|
|
94
98
|
);
|
|
95
99
|
|
|
96
100
|
/**
|
package/src/deploy/artifacts.ts
CHANGED
|
@@ -445,7 +445,8 @@ export const publishBuildArtifacts = async (
|
|
|
445
445
|
await buildNarration(project, distDir, logger);
|
|
446
446
|
|
|
447
447
|
// Upload the index to a hosted provider (Algolia, Orama Cloud, Typesense).
|
|
448
|
-
// Skipped with a warning when its admin key isn't configured
|
|
448
|
+
// Skipped with a warning when its admin key isn't configured; with the key
|
|
449
|
+
// set, a failed sync fails the build.
|
|
449
450
|
await syncSearchProvider(project, {
|
|
450
451
|
start: logger.info.bind(logger),
|
|
451
452
|
success: logger.info.bind(logger),
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
* Cloudflare does not apply `_headers` to worker-first routes, so the wrapper
|
|
41
41
|
* also re-stamps what the static layer would otherwise add on the routes it
|
|
42
42
|
* takes over: the homepage agent-discovery `Link` header, the Markdown
|
|
43
|
-
* `charset=utf-8`,
|
|
44
|
-
*
|
|
43
|
+
* `charset=utf-8`, the sandbox on the SVGs a content source downloaded (see
|
|
44
|
+
* `deploy/headers.ts`), and `X-Powered-By` unless `poweredBy` is `false`. The
|
|
45
|
+
* raw `.md`/`.mdx` URLs are
|
|
45
46
|
* exempted from worker-first routing with negative rules, keeping their
|
|
46
47
|
* `_headers` treatment and their zero-Worker serving path.
|
|
47
48
|
*
|
|
@@ -85,6 +86,7 @@ import {
|
|
|
85
86
|
OPENAPI_PATH,
|
|
86
87
|
} from "../ai/api/paths.ts";
|
|
87
88
|
import { normalizeBasePath, normalizePath } from "../core/base-path.ts";
|
|
89
|
+
import { POWERED_BY_HEADERS } from "../core/powered-by.ts";
|
|
88
90
|
import { compileRedirects, isPatternPath } from "../core/redirect-patterns.ts";
|
|
89
91
|
import { CONTENT_ASSETS_ROOT, SVG_ASSET_HEADERS } from "./headers.ts";
|
|
90
92
|
import type { NotFoundVariants } from "./vercel-negotiation.ts";
|
|
@@ -244,6 +246,8 @@ export interface NegotiationWorkerOptions {
|
|
|
244
246
|
base?: string;
|
|
245
247
|
/** Homepage agent-discovery `Link` header (see `ai/link-headers.ts`). */
|
|
246
248
|
homeLinkHeader?: string | null;
|
|
249
|
+
/** Whether responses identify Blume with `X-Powered-By`. Defaults to `true`. */
|
|
250
|
+
poweredBy?: boolean;
|
|
247
251
|
/** Estimated token count of the homepage Markdown mirror. */
|
|
248
252
|
homeTokens?: number;
|
|
249
253
|
/** Configured redirects the wrapper answers with their exact status. */
|
|
@@ -277,6 +281,9 @@ export const buildNegotiationWorker = (
|
|
|
277
281
|
const binding = JSON.stringify(options.assetsBinding);
|
|
278
282
|
const prefix = JSON.stringify(encodeURI(normalizeBasePath(options.base)));
|
|
279
283
|
const homeLinkHeader = JSON.stringify(options.homeLinkHeader ?? null);
|
|
284
|
+
const poweredBy = JSON.stringify(
|
|
285
|
+
options.poweredBy === false ? {} : POWERED_BY_HEADERS
|
|
286
|
+
);
|
|
280
287
|
const homeTokens = JSON.stringify(
|
|
281
288
|
options.homeTokens === undefined ? null : String(options.homeTokens)
|
|
282
289
|
);
|
|
@@ -331,6 +338,7 @@ const PATTERN_REDIRECTS = ${patternRedirects}.map(
|
|
|
331
338
|
);
|
|
332
339
|
const NOT_FOUND = ${notFound};
|
|
333
340
|
const SVG_ASSET_HEADERS = ${JSON.stringify(SVG_ASSET_HEADERS)};
|
|
341
|
+
const POWERED_BY = ${poweredBy};
|
|
334
342
|
|
|
335
343
|
// An SVG a content source downloaded: a document that could run script as the
|
|
336
344
|
// docs site if opened directly, so it goes out sandboxed. Matched on the
|
|
@@ -542,12 +550,30 @@ const isHomePath = (pathname) => {
|
|
|
542
550
|
return rest === "" || rest === "/";
|
|
543
551
|
};
|
|
544
552
|
|
|
553
|
+
// Blume's X-Powered-By, on every answer the wrapper gives unless the
|
|
554
|
+
// response already names its own (the project's middleware, say).
|
|
555
|
+
const identify = (headers) => {
|
|
556
|
+
for (const [name, value] of Object.entries(POWERED_BY)) {
|
|
557
|
+
if (!headers.has(name)) {
|
|
558
|
+
headers.set(name, value);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
|
|
545
563
|
const withHeaders = (response, apply) => {
|
|
546
564
|
const patched = new Response(response.body, response);
|
|
547
565
|
apply(patched.headers);
|
|
566
|
+
identify(patched.headers);
|
|
548
567
|
return patched;
|
|
549
568
|
};
|
|
550
569
|
|
|
570
|
+
// A response that already carries the header (Blume's runtime middleware sets
|
|
571
|
+
// it on every page Astro renders) goes out as it is.
|
|
572
|
+
const withPoweredBy = (response) =>
|
|
573
|
+
Object.keys(POWERED_BY).every((name) => response.headers.has(name))
|
|
574
|
+
? response
|
|
575
|
+
: withHeaders(response, () => {});
|
|
576
|
+
|
|
551
577
|
export default {
|
|
552
578
|
async fetch(request, env, context) {
|
|
553
579
|
const url = new URL(request.url);
|
|
@@ -556,7 +582,10 @@ export default {
|
|
|
556
582
|
const redirect = redirectFor(url.pathname);
|
|
557
583
|
if (redirect !== null) {
|
|
558
584
|
return new Response(null, {
|
|
559
|
-
headers: {
|
|
585
|
+
headers: {
|
|
586
|
+
...POWERED_BY,
|
|
587
|
+
location: redirectLocation(redirect[0], url.search),
|
|
588
|
+
},
|
|
560
589
|
status: redirect[1],
|
|
561
590
|
});
|
|
562
591
|
}
|
|
@@ -568,7 +597,7 @@ export default {
|
|
|
568
597
|
});
|
|
569
598
|
}
|
|
570
599
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
571
|
-
return server.fetch(request, env, context);
|
|
600
|
+
return withPoweredBy(await server.fetch(request, env, context));
|
|
572
601
|
}
|
|
573
602
|
const assets = env[ASSETS_BINDING];
|
|
574
603
|
// The request goes through untouched, so a conditional revalidation
|
|
@@ -577,7 +606,7 @@ export default {
|
|
|
577
606
|
if (assets !== undefined && isPageJson(url.pathname)) {
|
|
578
607
|
const asset = await assets.fetch(request);
|
|
579
608
|
if (asset.status !== 404) {
|
|
580
|
-
return asset;
|
|
609
|
+
return withPoweredBy(asset);
|
|
581
610
|
}
|
|
582
611
|
}
|
|
583
612
|
const variant = markdownVariantUrl(url.pathname + url.search);
|
|
@@ -608,10 +637,10 @@ export default {
|
|
|
608
637
|
const response = await server.fetch(request, env, context);
|
|
609
638
|
const twin = await notFoundTwin(request, url, response, assets);
|
|
610
639
|
if (twin !== null) {
|
|
611
|
-
return twin;
|
|
640
|
+
return withPoweredBy(twin);
|
|
612
641
|
}
|
|
613
642
|
if (variant === null && !(home && HOME_LINK_HEADER !== null)) {
|
|
614
|
-
return response;
|
|
643
|
+
return withPoweredBy(response);
|
|
615
644
|
}
|
|
616
645
|
return withHeaders(response, (headers) => {
|
|
617
646
|
if (variant !== null) {
|
package/src/deploy/headers.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
SIGNATURES_DIRECTORY_TYPE,
|
|
11
11
|
} from "../ai/web-bot-auth.ts";
|
|
12
12
|
import { normalizeBasePath } from "../core/base-path.ts";
|
|
13
|
+
import { POWERED_BY_HEADERS } from "../core/powered-by.ts";
|
|
13
14
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -98,6 +99,13 @@ export const headerRules = (
|
|
|
98
99
|
path: `${deployBase}/*.${rule.ext}`,
|
|
99
100
|
value: rule.contentType,
|
|
100
101
|
}));
|
|
102
|
+
// One rule for the whole site: `/*` matches the homepage too, and a host
|
|
103
|
+
// that joins the values of overlapping rules would send a second one twice.
|
|
104
|
+
if (config.poweredBy) {
|
|
105
|
+
for (const [name, value] of Object.entries(POWERED_BY_HEADERS)) {
|
|
106
|
+
rules.push({ name, path: `${deployBase}/*`, value });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
101
109
|
if (homeLinkHeader) {
|
|
102
110
|
rules.push({ name: "Link", path: `${deployBase}/`, value: homeLinkHeader });
|
|
103
111
|
}
|
|
@@ -212,9 +220,15 @@ export const escapeVercelSource = (path: string): string =>
|
|
|
212
220
|
* A `_headers` path as a `vercel.json` `source`, which `path-to-regexp` reads:
|
|
213
221
|
* the literal parts are escaped, and a `*` glob becomes the `(.*)` group that
|
|
214
222
|
* spans path segments as the glob does. An exact directory path (the homepage
|
|
215
|
-
* rule's `/docs/`) drops its trailing slash, the URL Vercel serves it at.
|
|
223
|
+
* rule's `/docs/`) drops its trailing slash, the URL Vercel serves it at. A
|
|
224
|
+
* whole-directory glob (`/docs/*`) becomes an optional group,
|
|
225
|
+
* `/docs/:path(.*)?`, so it matches that bare URL as well as every path
|
|
226
|
+
* beneath it.
|
|
216
227
|
*/
|
|
217
228
|
const vercelSource = (path: string): string => {
|
|
229
|
+
if (path.endsWith("/*")) {
|
|
230
|
+
return `${escapeVercelSource(path.slice(0, -2))}/:path(.*)?`;
|
|
231
|
+
}
|
|
218
232
|
const trimmed =
|
|
219
233
|
path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
220
234
|
return trimmed.split("*").map(escapeVercelSource).join("(.*)");
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
SIGNATURES_DIRECTORY_TYPE,
|
|
15
15
|
} from "../ai/web-bot-auth.ts";
|
|
16
16
|
import { normalizeBasePath, normalizePath } from "../core/base-path.ts";
|
|
17
|
+
import { POWERED_BY_HEADERS } from "../core/powered-by.ts";
|
|
17
18
|
import type { BlumeProject } from "../core/project-graph.ts";
|
|
18
19
|
import { compileRedirects, isPatternPath } from "../core/redirect-patterns.ts";
|
|
19
20
|
import type { CompiledRedirect } from "../core/redirect-patterns.ts";
|
|
@@ -159,6 +160,8 @@ export const nodePatternRedirects = (
|
|
|
159
160
|
export interface NodeEntryOptions {
|
|
160
161
|
/** `deployment.base`, normalized (`""` at the root). */
|
|
161
162
|
base?: string;
|
|
163
|
+
/** Whether responses identify Blume with `X-Powered-By`. Defaults to `true`. */
|
|
164
|
+
poweredBy?: boolean;
|
|
162
165
|
/** The configured redirects, from {@link nodeRedirects}. */
|
|
163
166
|
redirects?: NodeRedirects;
|
|
164
167
|
/** The configured pattern redirects, from {@link nodePatternRedirects}. */
|
|
@@ -169,7 +172,12 @@ export interface NodeEntryOptions {
|
|
|
169
172
|
* The entry that replaces Astro's: it answers a configured redirect with its
|
|
170
173
|
* exact status, and otherwise stamps the rules' headers on the response and
|
|
171
174
|
* hands the request to Astro's handler. `send` leaves a Content-Type that is
|
|
172
|
-
* already set alone, so the registered media type wins.
|
|
175
|
+
* already set alone, so the registered media type wins. Unless `poweredBy` is
|
|
176
|
+
* `false`, every answer also names Blume in `X-Powered-By` — the redirects,
|
|
177
|
+
* and the prerendered pages and files the static handler serves, which
|
|
178
|
+
* Blume's runtime middleware never sees. A middleware-mode entry leaves that
|
|
179
|
+
* header to the middleware: Astro hands a request it has no route for back to
|
|
180
|
+
* the host app through `next()`, and that response is the host's own.
|
|
173
181
|
*
|
|
174
182
|
* A rule matches the file the static handler will serve, not the raw URL:
|
|
175
183
|
* Astro strips the base when it leads the path and serves the rest from the
|
|
@@ -194,10 +202,11 @@ export const nodeEntryWrapper = (
|
|
|
194
202
|
// This wrapper answers the configured redirects with their exact status and
|
|
195
203
|
// sets the headers the standalone server's static handler can't (the media
|
|
196
204
|
// types and CORS headers of the .well-known discovery files, the sandbox on
|
|
197
|
-
// downloaded SVGs), then hands every other request to Astro.
|
|
205
|
+
// downloaded SVGs, X-Powered-By), then hands every other request to Astro.
|
|
198
206
|
import { posix } from "node:path";
|
|
199
207
|
|
|
200
208
|
const BASE = ${JSON.stringify(options.base ?? "")};
|
|
209
|
+
const POWERED_BY = ${JSON.stringify(options.poweredBy === false ? {} : POWERED_BY_HEADERS)};
|
|
201
210
|
const RULES = new Map(${JSON.stringify(exactRules(rules))});
|
|
202
211
|
const PATTERNS = ${JSON.stringify(patternRules(rules))};
|
|
203
212
|
const REDIRECTS = ${JSON.stringify(options.redirects ?? {})};
|
|
@@ -221,20 +230,20 @@ const servedPath = (req) => {
|
|
|
221
230
|
: path;
|
|
222
231
|
return BASE + (rest || "/");
|
|
223
232
|
};
|
|
224
|
-
const applyHeaders = (req, res) => {
|
|
233
|
+
const applyHeaders = (req, res, identify) => {
|
|
225
234
|
const path = servedPath(req);
|
|
226
235
|
const lower = path.toLowerCase();
|
|
227
|
-
const headers =
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
const headers = {
|
|
237
|
+
...(identify ? POWERED_BY : {}),
|
|
238
|
+
...(RULES.get(path) ??
|
|
239
|
+
PATTERNS.find(
|
|
240
|
+
([prefix, suffix]) =>
|
|
241
|
+
lower.startsWith(prefix.toLowerCase()) &&
|
|
242
|
+
lower.endsWith(suffix.toLowerCase())
|
|
243
|
+
)?.[2]),
|
|
244
|
+
};
|
|
245
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
246
|
+
res.setHeader(name, value);
|
|
238
247
|
}
|
|
239
248
|
};
|
|
240
249
|
// A pattern redirect's Location: its template, each $n filled with that
|
|
@@ -268,7 +277,7 @@ const answerRedirect = (req, res) => {
|
|
|
268
277
|
return false;
|
|
269
278
|
}
|
|
270
279
|
const [location, status] = redirect;
|
|
271
|
-
res.writeHead(status, { location });
|
|
280
|
+
res.writeHead(status, { ...POWERED_BY, location });
|
|
272
281
|
res.end();
|
|
273
282
|
return true;
|
|
274
283
|
};
|
|
@@ -285,7 +294,7 @@ export const handler = (req, res, ...rest) => {
|
|
|
285
294
|
if (answerRedirect(req, res)) {
|
|
286
295
|
return;
|
|
287
296
|
}
|
|
288
|
-
applyHeaders(req, res);
|
|
297
|
+
applyHeaders(req, res, options.mode !== "middleware");
|
|
289
298
|
return astro.handler(req, res, ...rest);
|
|
290
299
|
};
|
|
291
300
|
export const startServer = () => {
|
|
@@ -301,7 +310,7 @@ export const startServer = () => {
|
|
|
301
310
|
if (answerRedirect(req, res)) {
|
|
302
311
|
return;
|
|
303
312
|
}
|
|
304
|
-
applyHeaders(req, res);
|
|
313
|
+
applyHeaders(req, res, true);
|
|
305
314
|
for (const listener of astroListeners) {
|
|
306
315
|
listener.call(httpServer, req, res);
|
|
307
316
|
}
|
|
@@ -315,9 +324,10 @@ if (options.mode === "standalone" && previous !== "disabled") {
|
|
|
315
324
|
`;
|
|
316
325
|
|
|
317
326
|
/**
|
|
318
|
-
* Put the wrapper in front of a Node server build's entry. A build with
|
|
319
|
-
* rule (no API catalog, AI catalog, MCP server,
|
|
320
|
-
* downloaded content assets) and no redirect leaves
|
|
327
|
+
* Put the wrapper in front of a Node server build's entry. A build with
|
|
328
|
+
* `poweredBy` off, no rule (no API catalog, AI catalog, MCP server,
|
|
329
|
+
* signatures directory, or downloaded content assets), and no redirect leaves
|
|
330
|
+
* Astro's entry alone.
|
|
321
331
|
*/
|
|
322
332
|
export const wrapNodeEntry = async (
|
|
323
333
|
project: BlumeProject,
|
|
@@ -341,6 +351,7 @@ export const wrapNodeEntry = async (
|
|
|
341
351
|
const redirects = nodeRedirects(project);
|
|
342
352
|
const patternRedirects = nodePatternRedirects(project);
|
|
343
353
|
if (
|
|
354
|
+
!project.config.poweredBy &&
|
|
344
355
|
rules.length === 0 &&
|
|
345
356
|
Object.keys(redirects).length === 0 &&
|
|
346
357
|
patternRedirects.length === 0
|
|
@@ -365,6 +376,7 @@ export const wrapNodeEntry = async (
|
|
|
365
376
|
nodeEntryWrapper(rules, {
|
|
366
377
|
base: normalizeBasePath(project.config.deployment.options.base),
|
|
367
378
|
patternRedirects,
|
|
379
|
+
poweredBy: project.config.poweredBy,
|
|
368
380
|
redirects,
|
|
369
381
|
}),
|
|
370
382
|
"utf-8"
|
|
@@ -122,6 +122,7 @@ export const emitCloudflareNegotiation = async (
|
|
|
122
122
|
)
|
|
123
123
|
.map((route) => pageJsonPath(route.path))
|
|
124
124
|
: [],
|
|
125
|
+
poweredBy: config.poweredBy,
|
|
125
126
|
// The wrapper Worker matches full served URLs, so the redirects are
|
|
126
127
|
// based the same way the platform files are — it answers any the
|
|
127
128
|
// worker-first rules claim, where `_redirects` is never consulted and
|
|
@@ -305,17 +306,21 @@ export const bindCloudflareRateLimit = async (
|
|
|
305
306
|
};
|
|
306
307
|
|
|
307
308
|
/**
|
|
308
|
-
* Cloudflare
|
|
309
|
-
* `dist/server` and serves
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
309
|
+
* Cloudflare. A server build targets Workers only (`@astrojs/cloudflare`
|
|
310
|
+
* dropped Pages in v13): it emits the Worker into `dist/server` and serves
|
|
311
|
+
* `dist/client` through the ASSETS binding, which honors `_headers` from that
|
|
312
|
+
* directory exactly as Pages does — so the file applies to both output modes
|
|
313
|
+
* here. A static build never loads the adapter; its `dist/` deploys to Pages,
|
|
314
|
+
* whose build environment `env` detects, or to Workers static assets (Workers
|
|
315
|
+
* Builds exposes no site URL to detect). Without a configured driver the
|
|
316
|
+
* adapter force-enables KV-backed sessions and declares a `SESSION` binding
|
|
317
|
+
* that `wrangler deploy` then demands a namespace for, even though Blume
|
|
318
|
+
* never reads `Astro.session`; `session: false` opts the project out.
|
|
315
319
|
*/
|
|
316
320
|
export const cloudflarePlatform: DeployPlatform = {
|
|
317
321
|
astro: {
|
|
318
|
-
config: { session: false },
|
|
322
|
+
config: () => ({ session: false }),
|
|
323
|
+
configOptions: [],
|
|
319
324
|
options: adapterOptions,
|
|
320
325
|
package: CLOUDFLARE_ADAPTER_PACKAGE,
|
|
321
326
|
},
|
|
@@ -350,5 +355,5 @@ export const cloudflarePlatform: DeployPlatform = {
|
|
|
350
355
|
// build, and hoists its own `_headers`/`_redirects` back up to `dist/client`.
|
|
351
356
|
serverClientUnderBase: true,
|
|
352
357
|
serverOutputDir: distDir,
|
|
353
|
-
serverStaticDir: clientDir,
|
|
358
|
+
serverStaticDir: (context, base) => join(clientDir(context), base),
|
|
354
359
|
};
|
|
@@ -118,7 +118,8 @@ export const emitNetlifyPatternRedirects = async (
|
|
|
118
118
|
*/
|
|
119
119
|
export const netlifyPlatform: DeployPlatform = {
|
|
120
120
|
astro: {
|
|
121
|
-
config: {},
|
|
121
|
+
config: () => ({}),
|
|
122
|
+
configOptions: [],
|
|
122
123
|
options: () => ({}),
|
|
123
124
|
package: NETLIFY_ADAPTER_PACKAGE,
|
|
124
125
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JsonValue } from "../../core/adapter.ts";
|
|
1
2
|
import { NODE_ADAPTER_PACKAGE } from "../adapters/node.ts";
|
|
2
3
|
import { wrapNodeEntry } from "../node-headers.ts";
|
|
3
4
|
import { clientDir, distDir } from "./paths.ts";
|
|
@@ -11,11 +12,20 @@ import type { DeployPlatform } from "./types.ts";
|
|
|
11
12
|
* discovery files and downloaded SVGs need instead, and answers the
|
|
12
13
|
* configured redirects with their exact status, which Astro's own handler
|
|
13
14
|
* would default to 301 or 308. No platform env to detect: the site URL has to
|
|
14
|
-
* be configured.
|
|
15
|
+
* be configured. `allowedDomains` becomes Astro's `security.allowedDomains`,
|
|
16
|
+
* which a server behind a reverse proxy needs before Astro reads the reader's
|
|
17
|
+
* address from `X-Forwarded-For`.
|
|
15
18
|
*/
|
|
16
19
|
export const nodePlatform: DeployPlatform = {
|
|
17
20
|
astro: {
|
|
18
|
-
config: {}
|
|
21
|
+
config: ({ allowedDomains }) => {
|
|
22
|
+
const config: Record<string, JsonValue> = {};
|
|
23
|
+
if (allowedDomains) {
|
|
24
|
+
config.security = { allowedDomains };
|
|
25
|
+
}
|
|
26
|
+
return config;
|
|
27
|
+
},
|
|
28
|
+
configOptions: ["allowedDomains"],
|
|
19
29
|
options: () => ({ mode: "standalone" }),
|
|
20
30
|
package: NODE_ADAPTER_PACKAGE,
|
|
21
31
|
},
|
|
@@ -2,7 +2,10 @@ import type { JsonValue } from "../../core/adapter.ts";
|
|
|
2
2
|
import type { BlumeProject } from "../../core/project-graph.ts";
|
|
3
3
|
import type { ResolvedConfig } from "../../core/schema.ts";
|
|
4
4
|
import type { ProjectContext } from "../../core/types.ts";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
DeployAdapterKind,
|
|
7
|
+
ResolvedDeployOptions,
|
|
8
|
+
} from "../adapters/registry.ts";
|
|
6
9
|
import type { DeployOutput } from "../adapters/types.ts";
|
|
7
10
|
|
|
8
11
|
/**
|
|
@@ -15,8 +18,16 @@ import type { DeployOutput } from "../adapters/types.ts";
|
|
|
15
18
|
|
|
16
19
|
/** How the generated `astro.config.mjs` constructs the `@astrojs/*` adapter. */
|
|
17
20
|
export interface AstroAdapterSpec {
|
|
18
|
-
/**
|
|
19
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Top-level `defineConfig` entries the adapter needs beside itself, some
|
|
23
|
+
* of them set from the deployment's own options.
|
|
24
|
+
*/
|
|
25
|
+
config: (options: ResolvedDeployOptions) => Record<string, JsonValue>;
|
|
26
|
+
/**
|
|
27
|
+
* The deployment options `config` reads, which therefore stay out of the
|
|
28
|
+
* passthrough to the `@astrojs/*` constructor.
|
|
29
|
+
*/
|
|
30
|
+
configOptions: string[];
|
|
20
31
|
/** Blume's own constructor options; the user's passthrough is spread over them. */
|
|
21
32
|
options: (context: ProjectContext) => Record<string, JsonValue>;
|
|
22
33
|
/** The package the config imports the adapter from. */
|
|
@@ -115,13 +126,16 @@ export interface DeployPlatform {
|
|
|
115
126
|
/**
|
|
116
127
|
* Whether the adapter moves a server build's client output under
|
|
117
128
|
* `deployment.base` (`dist/client/<base>/`, the directory Astro then hands
|
|
118
|
-
* `astro:build:done`) while the platform keeps serving `
|
|
119
|
-
*
|
|
129
|
+
* `astro:build:done`) while the platform keeps serving `dist/client` as
|
|
130
|
+
* the assets root. The files the platform reads there, like `_headers`,
|
|
120
131
|
* belong above the directory Astro reports.
|
|
121
132
|
*/
|
|
122
133
|
serverClientUnderBase: boolean;
|
|
123
134
|
/** Where a server build's deploy bundle lands. */
|
|
124
135
|
serverOutputDir: (context: ProjectContext) => string;
|
|
125
|
-
/**
|
|
126
|
-
|
|
136
|
+
/**
|
|
137
|
+
* The directory a server build serves as static files, given the normalized
|
|
138
|
+
* `deployment.base` for a platform that serves them from `<dir>/<base>/`.
|
|
139
|
+
*/
|
|
140
|
+
serverStaticDir: (context: ProjectContext, base: string) => string;
|
|
127
141
|
}
|