blume 1.4.3 → 1.5.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/CHANGELOG.md +32 -0
- package/README.md +16 -12
- package/dist/cli/index.js +1784 -633
- package/dist/cli/index.js.map +111 -106
- package/dist/types/ai/component-markdown.d.ts +14 -4
- package/dist/types/core/config-input.d.ts +80 -28
- package/dist/types/core/config.d.ts +2 -1
- package/dist/types/core/data.d.ts +19 -3
- package/dist/types/core/diagnostics.d.ts +5 -1
- package/dist/types/core/i18n-ui.d.ts +12 -0
- package/dist/types/core/schema.d.ts +112 -15
- package/dist/types/core/sources/types.d.ts +3 -1
- package/dist/types/core/standard-schema.d.ts +7 -3
- package/dist/types/core/types.d.ts +43 -2
- package/dist/types/core/ui-packs/index.d.ts +9 -1
- package/dist/types/openapi/references.d.ts +6 -5
- package/dist/types/seo/x-handle.d.ts +3 -2
- package/dist/types/theme/fonts.d.ts +11 -2
- package/docs/advanced/api-reference.mdx +8 -6
- package/docs/advanced/custom-pages.mdx +5 -1
- package/docs/configuration/index.mdx +1 -1
- package/docs/configuration/search.mdx +2 -0
- package/docs/configuration/seo.mdx +1 -1
- package/docs/configuration/theming.mdx +4 -2
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/meta.mdx +2 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +35 -1
- package/docs/content/versioning.mdx +106 -0
- package/docs/reference/cli.mdx +2 -1
- package/docs/reference/frontmatter.mdx +3 -0
- package/package.json +3 -1
- package/skills/blume-migrate/SKILL.md +2 -2
- package/skills/blume-migrate/references/docusaurus.md +1 -1
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +1 -1
- package/src/ai/agent-readability.ts +37 -10
- package/src/ai/ask-context.ts +5 -1
- package/src/ai/ask.ts +10 -1
- package/src/ai/component-markdown.ts +80 -43
- package/src/ai/llms.ts +40 -16
- package/src/ai/mcp/data.ts +48 -12
- package/src/ai/mcp/discovery.ts +28 -11
- package/src/ai/mcp/server.ts +183 -38
- package/src/ai/mcp/tools.ts +3 -3
- package/src/ai/skills.ts +32 -9
- package/src/ai/visibility.ts +2 -2
- package/src/astro/component-slots.ts +2 -0
- package/src/astro/examples.ts +6 -2
- package/src/astro/generate.ts +64 -34
- package/src/astro/integration.ts +13 -2
- package/src/astro/islands.ts +16 -9
- package/src/astro/templates.ts +181 -40
- package/src/audit/agent.ts +2 -2
- package/src/audit/checks/content.ts +26 -11
- package/src/audit/checks/dns-aid.ts +3 -0
- package/src/audit/checks/indexability.ts +24 -6
- package/src/audit/checks/llms.ts +9 -4
- package/src/audit/checks/network.ts +2 -0
- package/src/audit/checks/social.ts +18 -10
- package/src/audit/crawl.ts +37 -9
- package/src/audit/report.ts +20 -19
- package/src/audit/run.ts +5 -2
- package/src/audit/snapshot.ts +2 -4
- package/src/audit/types.ts +25 -3
- package/src/blume-modules.d.ts +5 -1
- package/src/cli/commands/audit.ts +9 -4
- package/src/cli/commands/build.ts +15 -9
- package/src/cli/commands/dev.ts +2 -0
- package/src/cli/commands/doctor.ts +2 -0
- package/src/cli/commands/eval.ts +7 -3
- package/src/cli/commands/init.ts +9 -9
- package/src/cli/commands/mcp-stdio.ts +3 -0
- package/src/cli/commands/translate.ts +14 -3
- package/src/cli/commands/version.ts +85 -0
- package/src/cli/dev-lock.ts +31 -10
- package/src/cli/eject-scripts.ts +17 -2
- package/src/cli/index.ts +2 -0
- package/src/cli/init/questions.ts +1 -1
- package/src/cli/init/scaffold.ts +22 -15
- package/src/cli/internal-error.ts +1 -0
- package/src/components/content/auto-type-table.ts +3 -0
- package/src/components/content/diff.ts +9 -5
- package/src/components/content/github-info.ts +2 -0
- package/src/components/islands/ask-ai.tsx +33 -25
- package/src/components/islands/hooks.ts +5 -1
- package/src/components/islands/webmcp.ts +49 -12
- package/src/components/layout/Fonts.astro +23 -3
- package/src/components/layout/Header.astro +25 -1
- package/src/components/layout/NavSelector.astro +11 -2
- package/src/components/layout/NavTree.astro +4 -2
- package/src/components/layout/PageLayout.astro +72 -3
- package/src/components/layout/ReferenceLayout.astro +2 -1
- package/src/components/layout/RootLayout.astro +20 -1
- package/src/components/layout/Search.astro +77 -13
- package/src/components/layout/VersionBanner.astro +39 -0
- package/src/components/layout/analytics-client.ts +8 -5
- package/src/components/layout/hydration-hint.ts +1 -1
- package/src/components/layout/nav-utils.ts +1 -4
- package/src/components/layout/overrides.ts +25 -12
- package/src/components/layout/search/algolia.ts +18 -5
- package/src/components/layout/search/endpoint.ts +3 -0
- package/src/components/layout/search/flexsearch.ts +23 -7
- package/src/components/layout/search/orama-cloud.ts +1 -1
- package/src/components/layout/search/orama.ts +4 -1
- package/src/components/layout/search/pagefind.ts +2 -0
- package/src/components/layout/search/types.ts +13 -1
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/ApiOverview.astro +32 -6
- package/src/components/openapi/AsyncApiOperation.astro +237 -0
- package/src/components/openapi/Bindings.astro +89 -0
- package/src/components/openapi/MethodBadge.astro +3 -0
- package/src/components/openapi/Operation.astro +7 -2
- package/src/components/openapi/PanelTabs.astro +131 -0
- package/src/components/openapi/ParametersTable.astro +2 -0
- package/src/components/openapi/RequestPanel.astro +12 -119
- package/src/components/openapi/async-snippets.ts +174 -0
- package/src/components/openapi/async.ts +348 -0
- package/src/components/openapi/helpers.ts +52 -20
- package/src/components/openapi/security.ts +102 -29
- package/src/components/openapi/snippets.ts +11 -11
- package/src/core/component-overrides.ts +28 -23
- package/src/core/config-input.ts +89 -28
- package/src/core/config.ts +20 -7
- package/src/core/content.ts +3 -1
- package/src/core/data.ts +19 -3
- package/src/core/define-components.ts +5 -0
- package/src/core/diagnostics.ts +46 -38
- package/src/core/frontmatter.ts +33 -7
- package/src/core/graph.ts +137 -53
- package/src/core/i18n-ui.ts +15 -0
- package/src/core/i18n.ts +16 -8
- package/src/core/last-modified.ts +49 -0
- package/src/core/load-module.ts +1 -0
- package/src/core/manifest.ts +92 -3
- package/src/core/meta.ts +44 -14
- package/src/core/nav-diagnostics.ts +3 -3
- package/src/core/navigation.ts +247 -67
- package/src/core/project-graph.ts +26 -3
- package/src/core/schema.ts +214 -68
- package/src/core/sources/assets.ts +2 -0
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/github-releases.ts +39 -31
- package/src/core/sources/mdx-remote.ts +4 -0
- package/src/core/sources/normalize.ts +67 -20
- package/src/core/sources/notion.ts +49 -17
- package/src/core/sources/portable-text.ts +32 -11
- package/src/core/sources/sanity.ts +68 -14
- package/src/core/sources/types.ts +4 -0
- package/src/core/sources/watch.ts +1 -1
- package/src/core/standard-schema.ts +9 -3
- package/src/core/text-width.ts +26 -0
- package/src/core/tsconfig-aliases.ts +9 -5
- package/src/core/types.ts +45 -2
- package/src/core/ui-packs/index.ts +9 -1
- package/src/core/version-cut.ts +301 -0
- package/src/core/version.ts +2 -0
- package/src/core/versions.ts +170 -0
- package/src/deploy/adapter-output.ts +5 -2
- package/src/deploy/cloudflare-negotiation.ts +25 -10
- package/src/deploy/sitemap.ts +33 -1
- package/src/deploy/vercel-negotiation.ts +45 -18
- package/src/eval/report.ts +4 -4
- package/src/eval/run.ts +2 -2
- package/src/eval/schema.ts +1 -1
- package/src/markdown/base-links.ts +6 -6
- package/src/markdown/directives.ts +7 -1
- package/src/markdown/heading-anchors.ts +17 -6
- package/src/markdown/index.ts +73 -24
- package/src/markdown/inline-code.ts +14 -2
- package/src/markdown/language-icon.ts +6 -2
- package/src/markdown/mdast.ts +18 -4
- package/src/markdown/package-commands.ts +6 -8
- package/src/markdown/table-wrap.ts +4 -1
- package/src/markdown/twoslash.ts +2 -0
- package/src/og/card.ts +33 -12
- package/src/og/derive.ts +43 -27
- package/src/openapi/asyncapi.ts +366 -0
- package/src/openapi/model.ts +126 -57
- package/src/openapi/parse.ts +97 -5
- package/src/openapi/references.ts +12 -10
- package/src/openapi/render-mdx.ts +73 -34
- package/src/openapi/scalar.ts +6 -8
- package/src/openapi/source.ts +98 -28
- package/src/registry/eject.ts +7 -2
- package/src/search/documents.ts +25 -5
- package/src/search/facets.ts +7 -5
- package/src/search/orama-index.ts +66 -20
- package/src/search/popular.ts +10 -5
- package/src/search/providers.ts +2 -2
- package/src/search/sync/index.ts +2 -0
- package/src/search/sync/typesense.ts +4 -2
- package/src/seo/jsonld.ts +24 -6
- package/src/seo/x-handle.ts +8 -3
- package/src/theme/chrome-icons.ts +7 -2
- package/src/theme/entry.ts +24 -2
- package/src/theme/fonts.ts +83 -7
- package/src/theme/icons.ts +4 -2
- package/src/theme/palette.ts +22 -14
- package/src/translate/meta.ts +15 -6
- package/src/translate/report.ts +9 -5
- package/src/translate/run.ts +10 -4
- package/src/translate/validate.ts +52 -17
- package/src/translate/work-list.ts +0 -0
package/src/astro/generate.ts
CHANGED
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
examplesEntryTemplate,
|
|
62
62
|
tailwindEntryTemplate,
|
|
63
63
|
} from "../theme/entry.ts";
|
|
64
|
-
import { buildFontsCss,
|
|
64
|
+
import { buildFontsCss, configuredFonts } from "../theme/fonts.ts";
|
|
65
65
|
import { buildThemeCss } from "../theme/palette.ts";
|
|
66
66
|
import { twoslashCss } from "../theme/twoslash.ts";
|
|
67
67
|
import { planComponentSlots } from "./component-slots.ts";
|
|
@@ -489,12 +489,14 @@ export const ensureDepsLink = async (
|
|
|
489
489
|
* (`<build.server>/.prerender/`) output — so it fires for exactly that build.
|
|
490
490
|
* Inert in dev, where there is no build and `writeBundle` never runs.
|
|
491
491
|
*/
|
|
492
|
-
export
|
|
493
|
-
pkgDir: string = packageRoot()
|
|
494
|
-
): {
|
|
492
|
+
export interface PrerenderDepsPlugin {
|
|
495
493
|
name: string;
|
|
496
494
|
writeBundle: (options: { dir?: string }) => Promise<void>;
|
|
497
|
-
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export const prerenderDepsPlugin = (
|
|
498
|
+
pkgDir: string = packageRoot()
|
|
499
|
+
): PrerenderDepsPlugin => ({
|
|
498
500
|
name: "blume:prerender-deps",
|
|
499
501
|
writeBundle: async (options) => {
|
|
500
502
|
if (!options.dir || basename(options.dir) !== ".prerender") {
|
|
@@ -528,14 +530,16 @@ interface ServerAppResolveContext {
|
|
|
528
530
|
* Stripping the spurious `.js` and delegating back to Astro's resolver lets the
|
|
529
531
|
* reload complete cleanly, so the renamed route resolves without a restart.
|
|
530
532
|
*/
|
|
531
|
-
export
|
|
533
|
+
export interface ServerAppResolvePlugin {
|
|
532
534
|
enforce: "pre";
|
|
533
535
|
name: string;
|
|
534
536
|
resolveId: (
|
|
535
537
|
this: ServerAppResolveContext,
|
|
536
538
|
id: string
|
|
537
539
|
) => Promise<string | null>;
|
|
538
|
-
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export const serverAppResolvePlugin = (): ServerAppResolvePlugin => ({
|
|
539
543
|
enforce: "pre",
|
|
540
544
|
name: "blume:server-app-resolve",
|
|
541
545
|
async resolveId(id) {
|
|
@@ -548,20 +552,20 @@ export const serverAppResolvePlugin = (): {
|
|
|
548
552
|
});
|
|
549
553
|
|
|
550
554
|
/** Astro integration package each non-React island framework needs installed. */
|
|
551
|
-
const ISLAND_FRAMEWORK_DEPS
|
|
552
|
-
svelte
|
|
553
|
-
vue
|
|
554
|
-
|
|
555
|
+
const ISLAND_FRAMEWORK_DEPS = new Map([
|
|
556
|
+
["svelte", "@astrojs/svelte"],
|
|
557
|
+
["vue", "@astrojs/vue"],
|
|
558
|
+
]);
|
|
555
559
|
|
|
556
560
|
/**
|
|
557
561
|
* Adapter package the project must install itself for each deployment
|
|
558
562
|
* platform whose adapter Blume doesn't ship. Node and Vercel ship with Blume,
|
|
559
563
|
* so they never need this.
|
|
560
564
|
*/
|
|
561
|
-
const DEPLOYMENT_ADAPTER_DEPS
|
|
562
|
-
cloudflare
|
|
563
|
-
netlify
|
|
564
|
-
|
|
565
|
+
const DEPLOYMENT_ADAPTER_DEPS = new Map([
|
|
566
|
+
["cloudflare", "@astrojs/cloudflare"],
|
|
567
|
+
["netlify", "@astrojs/netlify"],
|
|
568
|
+
]);
|
|
565
569
|
|
|
566
570
|
/**
|
|
567
571
|
* Warn when a Vue/Svelte island is present but its Astro integration isn't
|
|
@@ -574,7 +578,7 @@ const islandFrameworkWarnings = (
|
|
|
574
578
|
): string[] => {
|
|
575
579
|
const warnings: string[] = [];
|
|
576
580
|
for (const framework of frameworks) {
|
|
577
|
-
const dep = ISLAND_FRAMEWORK_DEPS
|
|
581
|
+
const dep = ISLAND_FRAMEWORK_DEPS.get(framework);
|
|
578
582
|
if (dep && !canResolveFrom(root, dep)) {
|
|
579
583
|
warnings.push(
|
|
580
584
|
`Islands use ${framework}, which needs "${dep}". Install it (e.g. \`npm install ${dep} ${framework}\`).`
|
|
@@ -599,7 +603,7 @@ const deploymentAdapterWarnings = (
|
|
|
599
603
|
): string[] => {
|
|
600
604
|
const dep =
|
|
601
605
|
deployment.output === "server" && deployment.adapter
|
|
602
|
-
? DEPLOYMENT_ADAPTER_DEPS
|
|
606
|
+
? DEPLOYMENT_ADAPTER_DEPS.get(deployment.adapter)
|
|
603
607
|
: undefined;
|
|
604
608
|
if (
|
|
605
609
|
dep &&
|
|
@@ -906,6 +910,10 @@ const readLogoSvg = (
|
|
|
906
910
|
return file ? readFileSync(file, "utf-8") : undefined;
|
|
907
911
|
};
|
|
908
912
|
|
|
913
|
+
/** Narrows a config union's string shorthand from its object form. */
|
|
914
|
+
const isStringShorthand = <T>(value: T | string): value is string =>
|
|
915
|
+
typeof value === "string";
|
|
916
|
+
|
|
909
917
|
/**
|
|
910
918
|
* Resolve the configured logo. A single SVG is read and inlined so a
|
|
911
919
|
* `currentColor` logo follows the theme; other images keep their URL for an
|
|
@@ -916,12 +924,12 @@ const resolveLogo = (project: BlumeProject): BlumeLogo | null => {
|
|
|
916
924
|
if (!logo) {
|
|
917
925
|
return null;
|
|
918
926
|
}
|
|
919
|
-
const config =
|
|
927
|
+
const config = isStringShorthand(logo) ? { image: logo } : logo;
|
|
920
928
|
// `text` is passed through verbatim: `undefined` lets the brand fall back to
|
|
921
929
|
// the site title, `""` renders the mark alone (a logo with the wordmark baked
|
|
922
930
|
// in).
|
|
923
931
|
const { href, image: source, text } = config;
|
|
924
|
-
const image =
|
|
932
|
+
const image = isStringShorthand(source) ? { light: source } : source;
|
|
925
933
|
const light = image?.light ?? image?.dark;
|
|
926
934
|
const dark = image?.dark ?? image?.light;
|
|
927
935
|
const alt = image?.alt ?? "";
|
|
@@ -957,18 +965,18 @@ const FAVICON_CANDIDATES = [
|
|
|
957
965
|
];
|
|
958
966
|
|
|
959
967
|
/** `<link type>` MIME for the favicon extensions we recognize. */
|
|
960
|
-
const FAVICON_TYPES
|
|
961
|
-
ico
|
|
962
|
-
jpeg
|
|
963
|
-
jpg
|
|
964
|
-
png
|
|
965
|
-
svg
|
|
966
|
-
|
|
968
|
+
const FAVICON_TYPES = new Map([
|
|
969
|
+
["ico", "image/x-icon"],
|
|
970
|
+
["jpeg", "image/jpeg"],
|
|
971
|
+
["jpg", "image/jpeg"],
|
|
972
|
+
["png", "image/png"],
|
|
973
|
+
["svg", "image/svg+xml"],
|
|
974
|
+
]);
|
|
967
975
|
|
|
968
976
|
/** Infer the `<link type>` MIME from a filename, when we recognize the extension. */
|
|
969
977
|
const faviconType = (name: string): string | undefined => {
|
|
970
978
|
const ext = name.split(".").pop()?.toLowerCase();
|
|
971
|
-
return ext ? FAVICON_TYPES
|
|
979
|
+
return ext ? FAVICON_TYPES.get(ext) : undefined;
|
|
972
980
|
};
|
|
973
981
|
|
|
974
982
|
/** Read a file and encode it as a `data:` URI of the given MIME type. */
|
|
@@ -1041,7 +1049,7 @@ const resolveBanner = (config: ResolvedConfig): BlumeBanner | null => {
|
|
|
1041
1049
|
if (!banner) {
|
|
1042
1050
|
return null;
|
|
1043
1051
|
}
|
|
1044
|
-
if (
|
|
1052
|
+
if (isStringShorthand(banner)) {
|
|
1045
1053
|
return { content: banner, dismissible: false, key: banner };
|
|
1046
1054
|
}
|
|
1047
1055
|
return {
|
|
@@ -1234,6 +1242,7 @@ export const buildRuntimeData = (project: BlumeProject): string => {
|
|
|
1234
1242
|
theme: config.theme,
|
|
1235
1243
|
title: config.title,
|
|
1236
1244
|
toc: config.toc,
|
|
1245
|
+
versions: config.versions ?? null,
|
|
1237
1246
|
webmcp: {
|
|
1238
1247
|
enabled: config.ai.webmcp,
|
|
1239
1248
|
llms: config.ai.llmsTxt.enabled,
|
|
@@ -1246,10 +1255,23 @@ export const buildRuntimeData = (project: BlumeProject): string => {
|
|
|
1246
1255
|
})),
|
|
1247
1256
|
// CSS variables for Astro's <Font> component; matches the astro.config
|
|
1248
1257
|
// `fonts:` entries derived from the same theme.fonts config.
|
|
1249
|
-
fontCssVars:
|
|
1258
|
+
fontCssVars: configuredFonts(config.theme.fonts),
|
|
1250
1259
|
navigation: withRepoUrl(graph.navigation),
|
|
1251
1260
|
// Per-locale navigation; the catch-all selects the active locale's tree.
|
|
1252
1261
|
navigationByLocale,
|
|
1262
|
+
// Per-archived-version navigation; the catch-all selects by the route's
|
|
1263
|
+
// version, then locale.
|
|
1264
|
+
navigationByVersion: Object.fromEntries(
|
|
1265
|
+
Object.entries(graph.navigationByVersion).map(([id, byLocale]) => [
|
|
1266
|
+
id,
|
|
1267
|
+
Object.fromEntries(
|
|
1268
|
+
Object.entries(byLocale).map(([code, nav]) => [
|
|
1269
|
+
code,
|
|
1270
|
+
withRepoUrl(nav),
|
|
1271
|
+
])
|
|
1272
|
+
),
|
|
1273
|
+
])
|
|
1274
|
+
),
|
|
1253
1275
|
routes: manifest.routes.map((route) => ({
|
|
1254
1276
|
alternates: route.alternates,
|
|
1255
1277
|
collection: route.collection,
|
|
@@ -1264,6 +1286,8 @@ export const buildRuntimeData = (project: BlumeProject): string => {
|
|
|
1264
1286
|
locale: route.locale,
|
|
1265
1287
|
path: route.path,
|
|
1266
1288
|
title: route.title,
|
|
1289
|
+
version: route.version,
|
|
1290
|
+
versionAlternates: route.versionAlternates,
|
|
1267
1291
|
})),
|
|
1268
1292
|
// Default-locale chrome strings (English baseline when not under i18n).
|
|
1269
1293
|
ui: defaultUi,
|
|
@@ -1600,6 +1624,11 @@ export const generateRuntime = async (
|
|
|
1600
1624
|
// private and filtered out anyway, but the intent is the user's pages.
|
|
1601
1625
|
const ogRoutes = customOgRoutes(pages, config.title, config.seo.og.titles);
|
|
1602
1626
|
|
|
1627
|
+
// Whether the generated `/changelog` index exists — shared by the OG endpoint
|
|
1628
|
+
// (which adds the index's own card) and the page write below. Computed here,
|
|
1629
|
+
// before the MCP discovery pages are appended, on the user's own pages.
|
|
1630
|
+
const changelogIndex = hasGeneratedChangelog(project, pages);
|
|
1631
|
+
|
|
1603
1632
|
// The hosted MCP server. The `.well-known` discovery docs are injected as
|
|
1604
1633
|
// prerendered routes alongside user pages; the server endpoint itself is a
|
|
1605
1634
|
// normal (server-rendered) page written by `writeMcpFiles`.
|
|
@@ -1756,12 +1785,12 @@ export const generateRuntime = async (
|
|
|
1756
1785
|
if (config.seo.og.enabled) {
|
|
1757
1786
|
await write(
|
|
1758
1787
|
join(srcDir, "pages", "og", "[...slug].png.ts"),
|
|
1759
|
-
ogEndpointTemplate(ogRoutes, projectOgFonts(project))
|
|
1788
|
+
ogEndpointTemplate(ogRoutes, projectOgFonts(project), changelogIndex)
|
|
1760
1789
|
);
|
|
1761
1790
|
}
|
|
1762
1791
|
|
|
1763
1792
|
// Changelog index (`/changelog`), rendered through the Update timeline layout.
|
|
1764
|
-
if (
|
|
1793
|
+
if (changelogIndex) {
|
|
1765
1794
|
await write(
|
|
1766
1795
|
join(srcDir, "pages", "changelog.astro"),
|
|
1767
1796
|
changelogIndexTemplate({
|
|
@@ -1861,8 +1890,9 @@ export const generateRuntime = async (
|
|
|
1861
1890
|
]);
|
|
1862
1891
|
}
|
|
1863
1892
|
|
|
1864
|
-
// API/AsyncAPI reference pages (
|
|
1865
|
-
// mounted on its configured route and
|
|
1893
|
+
// Scalar-rendered API/AsyncAPI reference pages (`renderer: "scalar"`). One
|
|
1894
|
+
// self-contained page per source, mounted on its configured route and
|
|
1895
|
+
// regenerated each run.
|
|
1866
1896
|
const warnings: string[] = [
|
|
1867
1897
|
...(depsLinkWarning ? [depsLinkWarning] : []),
|
|
1868
1898
|
...reactCompilerWarnings(config, needsReact, reactCompilerPath),
|
|
@@ -1881,7 +1911,7 @@ export const generateRuntime = async (
|
|
|
1881
1911
|
...pages.map((page) => page.pattern),
|
|
1882
1912
|
...referenceRoutes(config),
|
|
1883
1913
|
]);
|
|
1884
|
-
if (
|
|
1914
|
+
if (changelogIndex) {
|
|
1885
1915
|
navTargetRoutes.add("/changelog");
|
|
1886
1916
|
}
|
|
1887
1917
|
// Curated `search.popular` icons live outside the navigation model, so they
|
package/src/astro/integration.ts
CHANGED
|
@@ -6,9 +6,20 @@ import { enrichDiagnostic } from "../core/diagnostics.ts";
|
|
|
6
6
|
import type { Diagnostic } from "../core/types.ts";
|
|
7
7
|
import { markdownVariantUrl, prefersMarkdown } from "./markdown-negotiation.ts";
|
|
8
8
|
|
|
9
|
+
/** The `{ type: "error" }` payload Vite's browser overlay renders. */
|
|
10
|
+
interface OverlayErrorPayload {
|
|
11
|
+
err: {
|
|
12
|
+
id?: string;
|
|
13
|
+
message: string;
|
|
14
|
+
plugin: string;
|
|
15
|
+
stack: string;
|
|
16
|
+
};
|
|
17
|
+
type: "error";
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
/** The dev server's HMR channel — either `.ws` (Vite ≤5) or `.hot` (Vite 6+). */
|
|
10
21
|
interface OverlayChannel {
|
|
11
|
-
send: (payload:
|
|
22
|
+
send: (payload: OverlayErrorPayload) => void;
|
|
12
23
|
}
|
|
13
24
|
interface OverlayServer {
|
|
14
25
|
hot?: OverlayChannel;
|
|
@@ -164,7 +175,7 @@ export const blumeIntegration = (
|
|
|
164
175
|
"astro:server:setup": ({ server }) => {
|
|
165
176
|
// Keep a handle on the dev server so Blume diagnostics can be pushed to
|
|
166
177
|
// its browser error overlay (see `showBlumeErrorOverlay`).
|
|
167
|
-
overlayServer = server
|
|
178
|
+
overlayServer = server;
|
|
168
179
|
// Prepend so the rewrite happens before Astro's own request handler,
|
|
169
180
|
// letting the rewritten URL resolve to the `.md` endpoint.
|
|
170
181
|
server.middlewares.stack.unshift({
|
package/src/astro/islands.ts
CHANGED
|
@@ -40,13 +40,20 @@ const VALID_MODES = new Set<IslandClientMode>([
|
|
|
40
40
|
"visible",
|
|
41
41
|
]);
|
|
42
42
|
|
|
43
|
+
/** Whether a declared client mode is one Astro's directives support. */
|
|
44
|
+
const isClientMode = (mode: string): mode is IslandClientMode =>
|
|
45
|
+
// SAFETY: `Set.has` only compares identity at runtime; the assertion widens
|
|
46
|
+
// the lookup key so the narrower-typed set accepts it, and the `has` result
|
|
47
|
+
// is exactly the predicate being claimed.
|
|
48
|
+
VALID_MODES.has(mode as IslandClientMode);
|
|
49
|
+
|
|
43
50
|
/** Island extensions mapped to the Astro renderer that handles them. */
|
|
44
|
-
const FRAMEWORK_BY_EXT
|
|
45
|
-
jsx
|
|
46
|
-
svelte
|
|
47
|
-
tsx
|
|
48
|
-
vue
|
|
49
|
-
|
|
51
|
+
const FRAMEWORK_BY_EXT = new Map<string, IslandFramework>([
|
|
52
|
+
["jsx", "react"],
|
|
53
|
+
["svelte", "svelte"],
|
|
54
|
+
["tsx", "react"],
|
|
55
|
+
["vue", "vue"],
|
|
56
|
+
]);
|
|
50
57
|
|
|
51
58
|
// Captures the extension so we can both strip it from the name and pick the
|
|
52
59
|
// framework. Kept in sync with the glob below.
|
|
@@ -66,13 +73,13 @@ export const readClientMode = (
|
|
|
66
73
|
if (!mode) {
|
|
67
74
|
return DEFAULT_CLIENT;
|
|
68
75
|
}
|
|
69
|
-
if (!
|
|
76
|
+
if (!isClientMode(mode)) {
|
|
70
77
|
warnings.push(
|
|
71
78
|
`Island "${file}" declares an unknown client mode "${mode}"; defaulting to "${DEFAULT_CLIENT}". Use "load", "idle", "visible", or "only".`
|
|
72
79
|
);
|
|
73
80
|
return DEFAULT_CLIENT;
|
|
74
81
|
}
|
|
75
|
-
return mode
|
|
82
|
+
return mode;
|
|
76
83
|
};
|
|
77
84
|
|
|
78
85
|
/**
|
|
@@ -109,7 +116,7 @@ export const discoverIslands = async (
|
|
|
109
116
|
const collectIsland = (file: string, source: string): void => {
|
|
110
117
|
const base = basename(file);
|
|
111
118
|
const ext = base.match(ISLAND_FILE)?.groups?.ext;
|
|
112
|
-
const framework = ext ? FRAMEWORK_BY_EXT
|
|
119
|
+
const framework = ext ? FRAMEWORK_BY_EXT.get(ext) : undefined;
|
|
113
120
|
if (!framework) {
|
|
114
121
|
return;
|
|
115
122
|
}
|