blume 1.6.6 → 1.7.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 +27 -0
- package/dist/cli/{chunk-etsqspj6.js → chunk-12dzsn9b.js} +140 -23
- package/dist/cli/{chunk-etsqspj6.js.map → chunk-12dzsn9b.js.map} +6 -5
- package/dist/cli/{chunk-aerwpe14.js → chunk-4ae4f395.js} +164 -51
- package/dist/cli/chunk-4ae4f395.js.map +15 -0
- package/dist/cli/{chunk-m3p3wahd.js → chunk-52cwcqvp.js} +4 -4
- package/dist/cli/{chunk-j00ezcg5.js → chunk-5gfw0q4j.js} +9 -9
- package/dist/cli/{chunk-bawgnt8x.js → chunk-6mq7qkve.js} +3 -3
- package/dist/cli/{chunk-nyqzjdhj.js → chunk-82atea4k.js} +5 -5
- package/dist/cli/{chunk-tc89yh2r.js → chunk-8p3xe5jv.js} +2 -2
- package/dist/cli/{chunk-s4k1pnvf.js → chunk-90pdhkpm.js} +11 -11
- package/dist/cli/{chunk-n0y172hf.js → chunk-aqjvpd03.js} +4 -4
- package/dist/cli/{chunk-x1vrdjyk.js → chunk-h9ekmtz7.js} +5 -5
- package/dist/cli/{chunk-f75cqye8.js → chunk-he2zfgah.js} +10 -10
- package/dist/cli/{chunk-s4jn7f1q.js → chunk-j5f2wrj5.js} +2 -2
- package/dist/cli/{chunk-wkq5tbtq.js → chunk-k0v1f8bb.js} +3 -3
- package/dist/cli/{chunk-n4qjabmt.js → chunk-ka5k7cz9.js} +6 -19
- package/dist/cli/{chunk-n4qjabmt.js.map → chunk-ka5k7cz9.js.map} +3 -4
- package/dist/cli/{chunk-5yvt556e.js → chunk-kmx2mydj.js} +2 -2
- package/dist/cli/{chunk-ag1zyr5x.js → chunk-mfm4sjwx.js} +11 -11
- package/dist/cli/{chunk-0ewz4trd.js → chunk-np8dmfb0.js} +6 -6
- package/dist/cli/{chunk-cnvm6k3e.js → chunk-pdwg3q9g.js} +11 -11
- package/dist/cli/{chunk-vv237fp3.js → chunk-q56730e0.js} +26 -12
- package/dist/cli/{chunk-vv237fp3.js.map → chunk-q56730e0.js.map} +3 -3
- package/dist/cli/{chunk-3k0kzs6d.js → chunk-qvvpnwaz.js} +2 -2
- package/dist/cli/{chunk-vv3f8mb6.js → chunk-r99hynxh.js} +25 -24
- package/dist/cli/{chunk-vv3f8mb6.js.map → chunk-r99hynxh.js.map} +4 -4
- package/dist/cli/{chunk-wb067mv3.js → chunk-vyqj481z.js} +19 -7
- package/dist/cli/chunk-vyqj481z.js.map +13 -0
- package/dist/cli/{chunk-62qsssnh.js → chunk-x1wvw7a8.js} +411 -145
- package/dist/cli/chunk-x1wvw7a8.js.map +40 -0
- package/dist/cli/{chunk-9sh49q0h.js → chunk-ywn7t0pb.js} +2 -2
- package/dist/cli/index.js +13 -13
- package/dist/types/components/layout/nav-utils.d.ts +46 -1
- package/dist/types/core/config-input.d.ts +7 -0
- package/dist/types/core/schema.d.ts +2 -0
- package/dist/types/theme/fonts.d.ts +22 -22
- package/docs/02-deployment.mdx +21 -0
- package/docs/08-faq.mdx +21 -0
- package/docs/configuration/ask-ai.mdx +16 -0
- package/docs/content/navigation.mdx +2 -0
- package/docs/content/sources.mdx +2 -2
- package/docs/content/syntax.mdx +1 -1
- package/docs/discoverability/open-graph.mdx +4 -0
- package/package.json +1 -1
- package/src/ai/ask.ts +31 -4
- package/src/astro/generate.ts +142 -5
- package/src/astro/integration.ts +12 -1
- package/src/astro/module-types.ts +9 -0
- package/src/astro/templates.ts +260 -56
- package/src/cli/commands/build.ts +28 -0
- package/src/components/Icon.astro +24 -0
- package/src/components/content/YouTube.astro +1 -1
- package/src/components/icon-sprite-middleware.ts +41 -0
- package/src/components/icon-sprite.ts +93 -0
- package/src/components/layout/Header.astro +1 -1
- package/src/components/layout/IconSprite.astro +11 -0
- package/src/components/layout/NavTree.astro +156 -188
- package/src/components/layout/NavTreeCache.astro +45 -0
- package/src/components/layout/NavTreeScript.astro +256 -0
- package/src/components/layout/PageActions.astro +11 -5
- package/src/components/layout/PageLayout.astro +7 -0
- package/src/components/layout/ReferenceLayout.astro +7 -0
- package/src/components/layout/RootLayout.astro +30 -2
- package/src/components/layout/Search.astro +11 -0
- package/src/components/layout/nav-cache.ts +49 -0
- package/src/components/layout/nav-utils.ts +87 -1
- package/src/core/config-input.ts +7 -0
- package/src/core/schema.ts +5 -0
- package/src/core/sources/assets.ts +162 -26
- package/src/core/sources/notion.ts +60 -1
- package/src/markdown/language-icon.ts +64 -20
- package/src/markdown/mermaid.ts +11 -0
- package/src/og/cache.ts +236 -0
- package/src/og/card.ts +12 -4
- package/src/og/index.ts +8 -1
- package/src/registry/eject.ts +24 -8
- package/src/theme/entry.ts +50 -7
- package/src/theme/fonts.ts +30 -23
- package/dist/cli/chunk-62qsssnh.js.map +0 -36
- package/dist/cli/chunk-aerwpe14.js.map +0 -15
- package/dist/cli/chunk-wb067mv3.js.map +0 -13
- /package/dist/cli/{chunk-m3p3wahd.js.map → chunk-52cwcqvp.js.map} +0 -0
- /package/dist/cli/{chunk-j00ezcg5.js.map → chunk-5gfw0q4j.js.map} +0 -0
- /package/dist/cli/{chunk-bawgnt8x.js.map → chunk-6mq7qkve.js.map} +0 -0
- /package/dist/cli/{chunk-nyqzjdhj.js.map → chunk-82atea4k.js.map} +0 -0
- /package/dist/cli/{chunk-tc89yh2r.js.map → chunk-8p3xe5jv.js.map} +0 -0
- /package/dist/cli/{chunk-s4k1pnvf.js.map → chunk-90pdhkpm.js.map} +0 -0
- /package/dist/cli/{chunk-n0y172hf.js.map → chunk-aqjvpd03.js.map} +0 -0
- /package/dist/cli/{chunk-x1vrdjyk.js.map → chunk-h9ekmtz7.js.map} +0 -0
- /package/dist/cli/{chunk-f75cqye8.js.map → chunk-he2zfgah.js.map} +0 -0
- /package/dist/cli/{chunk-s4jn7f1q.js.map → chunk-j5f2wrj5.js.map} +0 -0
- /package/dist/cli/{chunk-wkq5tbtq.js.map → chunk-k0v1f8bb.js.map} +0 -0
- /package/dist/cli/{chunk-5yvt556e.js.map → chunk-kmx2mydj.js.map} +0 -0
- /package/dist/cli/{chunk-ag1zyr5x.js.map → chunk-mfm4sjwx.js.map} +0 -0
- /package/dist/cli/{chunk-0ewz4trd.js.map → chunk-np8dmfb0.js.map} +0 -0
- /package/dist/cli/{chunk-cnvm6k3e.js.map → chunk-pdwg3q9g.js.map} +0 -0
- /package/dist/cli/{chunk-3k0kzs6d.js.map → chunk-qvvpnwaz.js.map} +0 -0
- /package/dist/cli/{chunk-9sh49q0h.js.map → chunk-ywn7t0pb.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# blume
|
|
2
2
|
|
|
3
|
+
## 1.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f52d4b7: Add `ai.ask.headers` to send static request headers to the Ask AI provider on every backend (gateway, OpenRouter, and the OpenAI-compatible providers), so a shared LLM backend can identify the caller without an external endpoint or an eject.
|
|
8
|
+
- b9645bf: Render callouts, steps, and every other Blume component inside changelog entries on the `/changelog` index. The index rendered each entry's MDX body without the component map the docs pages use, so a `:::info` directive or `<Steps>` in a release note failed the build (and the dev route) with "Expected component `Callout` to be defined".
|
|
9
|
+
- c25c859: Prevent the page behind the search dialog from scrolling while Command K search is open, and restore any existing page scroll lock when search closes.
|
|
10
|
+
- 39f683c: Fix the grouped sidebar 404ing its deferred section fragments in `blume dev` on sites whose default locale is unprefixed (`i18n.hideDefaultLocalePrefix`, the default). Astro's i18n routing rejects any page URL that carries the default locale's code as a segment, so `/blume-nav/current/de/…` never resolved for a site with `defaultLocale: "de"`; those fragments now live under `default`, the same way the locale's pages drop the prefix.
|
|
11
|
+
- 2575166: Import video blocks from Notion pages. A video block previously rendered as an `unsupported Notion block` comment, so neither uploaded videos nor pasted YouTube links appeared in the output. A YouTube link now becomes a `<YouTube>` embed, and any other video becomes a `<video>` player whose source is downloaded at build time — Notion's uploaded-file URLs are signed and expire, so they would otherwise rot the build. Downloads stream to disk through a shared concurrency gate with a timeout, a file already on disk is reused instead of fetched again, an extension-less asset is named by the response's media type, and a video link that answers with a web page (a Vimeo or Loom URL) is reported as a warning rather than written out as a broken player. String props the adapter writes (captions, toggle titles) use JSX expression form, so a double quote in a Notion caption no longer breaks the page.
|
|
12
|
+
|
|
13
|
+
## 1.7.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 78aadc8: Bundle Mermaid and the EPUB generator only for sites that use them. Both were dynamic imports, so they never loaded on a page that didn't need them, but they were still built on every `blume build` — over 3 MB of client chunks (ELK, Cytoscape, KaTeX, every diagram type) that most sites never serve, and most of the client build's memory. The generated runtime now decides at generation time whether any page has a mermaid fence and whether `export.epub` is on, and leaves the libraries out of the module graph otherwise; the dev server also stops pre-bundling them for sites that don't need them.
|
|
18
|
+
- 51eb2ac: Leave collapsed sidebar sections out of the page. In `group` and `page` display modes, a section that isn't open on the current page no longer ships its rows in that page's HTML; the empty disclosure or panel fetches a prerendered fragment on first open (prefetched on hover or focus, and kept for the visit), so a large site's pages carry only the open section instead of every section on every page. Group ids are now stable across tab-scoped views of the sidebar.
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- ede3c94: Cache rendered OG cards between builds. Each card is stored under `node_modules/.cache/blume/og`, keyed by everything that decides its pixels (title, description, branding, palette, fonts, and the Blume version), so a rebuild renders only the cards whose inputs changed and reads the rest back from disk. The build log reports how many cards were reused, and cards no page asks for any more are pruned after each build.
|
|
23
|
+
- a43c1d9: Paint code-block language icons from the theme instead of inlining an SVG in every block. A block now carries `data-icon="<slug>"` and the theme masks the brand path onto it, with one rule per language the site's Markdown uses, so a page with twenty TypeScript blocks no longer repeats the same 1 kB logo twenty times. Set icons rendered by the Icon component are deduplicated the same way, through a per-page sprite.
|
|
24
|
+
- 7b7d585: Prerender pages concurrently. The build now renders up to eight pages at once (one per available CPU below that), so the main thread renders the next page while a page's OG card renders on a native thread and its HTML is written to disk, instead of idling behind each page's off-thread work. A 1,400-page site's route generation phase runs in roughly half the time.
|
|
25
|
+
- 903eec0: Render the sidebar's group rows (collapsible summaries, flat headings, drill-in buttons, and the links inside them) through theme utility classes, as page rows already are, so a sidebar with many groups adds a few dozen bytes per group to every page instead of several hundred.
|
|
26
|
+
- 7b7d585: Shrink the sidebar's per-page cost. Every page's HTML carries the whole sidebar, so on a large site the sidebar was most of every page: each row now renders as a single theme utility class (`blume-nav-link`) instead of a dozen Tailwind classes, a bare row drops its inner spans, and groups that don't contain the current page are rendered once per build and reused across pages. A 1,400-page site's pages go from about 570 kB to under 190 kB each, and the build's HTML output shrinks and renders accordingly.
|
|
27
|
+
- 4005c27: Load the curated Google fonts that ship as variable fonts (every preset except IBM Plex Mono, IBM Plex Serif, and Space Mono) as one weight range, so each page declares one `@font-face` per style instead of one per weight — the same font files, a quarter of the inline font CSS. A configured `"100..900"` range now reaches Astro in the form it understands; it previously loaded nothing for that weight.
|
|
28
|
+
- 071e35d: Fix `blume dev` and `blume build` failing on Windows with `Cannot find module '@astrojs/mdx'` under Bun's isolated linker. The hidden runtime's `node_modules` link is now a directory symlink (falling back to a junction where symlinks need elevated privileges), because Windows can't follow the relative symlinks Bun writes into Blume's dependency directory when they're reached through a junction.
|
|
29
|
+
|
|
3
30
|
## 1.6.6
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
pageMetaSchema,
|
|
11
11
|
resolveProjectContext,
|
|
12
12
|
slugify
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-r99hynxh.js";
|
|
14
14
|
import {
|
|
15
15
|
isInternalPath,
|
|
16
16
|
stripBasePath,
|
|
@@ -3803,21 +3803,81 @@ import { setTimeout as sleep2 } from "node:timers/promises";
|
|
|
3803
3803
|
import pLimit from "p-limit";
|
|
3804
3804
|
import { join as join6 } from "pathe";
|
|
3805
3805
|
|
|
3806
|
+
// src/components/content/youtube.ts
|
|
3807
|
+
var BARE_ID = /^[\w-]{11}$/u;
|
|
3808
|
+
var URL_ID = /(?:youtu\.be\/|\/embed\/|\/shorts\/|\/live\/|[?&]v=)(?<id>[\w-]{11})/u;
|
|
3809
|
+
var parseYouTubeId = (input) => {
|
|
3810
|
+
const value = input.trim();
|
|
3811
|
+
if (!value) {
|
|
3812
|
+
return null;
|
|
3813
|
+
}
|
|
3814
|
+
if (BARE_ID.test(value)) {
|
|
3815
|
+
return value;
|
|
3816
|
+
}
|
|
3817
|
+
return URL_ID.exec(value)?.groups?.id ?? null;
|
|
3818
|
+
};
|
|
3819
|
+
|
|
3806
3820
|
// src/core/sources/assets.ts
|
|
3807
|
-
import {
|
|
3821
|
+
import { randomUUID } from "node:crypto";
|
|
3822
|
+
import {
|
|
3823
|
+
access,
|
|
3824
|
+
mkdir as mkdir3,
|
|
3825
|
+
readdir,
|
|
3826
|
+
rename,
|
|
3827
|
+
rm,
|
|
3828
|
+
writeFile as writeFile3
|
|
3829
|
+
} from "node:fs/promises";
|
|
3808
3830
|
import { extname as extname5, join as join5 } from "pathe";
|
|
3809
3831
|
var MD_IMAGE2 = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
|
|
3832
|
+
var HTML_VIDEO_SRC = /(?<open><video\b[^>]*?\ssrc=")(?<url>[^"]+)(?<close>")/gu;
|
|
3810
3833
|
var REMOTE = /^https?:\/\//u;
|
|
3811
3834
|
var SAFE_EXT = /^\.[a-z0-9]+$/iu;
|
|
3812
3835
|
var CODE_FENCE_BLOCK = /^(?<fence>`{3,}|~{3,})[^\n]*\n[\s\S]*?^\k<fence>[^\n]*(?=\n|$)/gmu;
|
|
3813
3836
|
var FENCE_TOKEN = /\u0000blume-fence-(?<index>\d+)\u0000/gu;
|
|
3814
|
-
var
|
|
3837
|
+
var EXT_BY_MIME = new Map([
|
|
3838
|
+
["image/avif", ".avif"],
|
|
3839
|
+
["image/gif", ".gif"],
|
|
3840
|
+
["image/jpeg", ".jpg"],
|
|
3841
|
+
["image/png", ".png"],
|
|
3842
|
+
["image/svg+xml", ".svg"],
|
|
3843
|
+
["image/webp", ".webp"],
|
|
3844
|
+
["video/mp4", ".mp4"],
|
|
3845
|
+
["video/ogg", ".ogv"],
|
|
3846
|
+
["video/quicktime", ".mov"],
|
|
3847
|
+
["video/webm", ".webm"]
|
|
3848
|
+
]);
|
|
3849
|
+
var UNKNOWN_EXT = ".bin";
|
|
3850
|
+
var NON_MEDIA_TYPE = /^(?:text\/|application\/(?:[\w.-]+\+)?(?:json|xml|javascript))/u;
|
|
3851
|
+
var PART_SUFFIX = ".part";
|
|
3852
|
+
var DEFAULT_TIMEOUT_MS = 120000;
|
|
3853
|
+
var extFromUrl = (url) => {
|
|
3815
3854
|
const clean = url.split("?")[0] ?? url;
|
|
3816
3855
|
const ext = extname5(clean);
|
|
3817
|
-
return SAFE_EXT.test(ext) ? ext.toLowerCase() :
|
|
3856
|
+
return SAFE_EXT.test(ext) ? ext.toLowerCase() : null;
|
|
3857
|
+
};
|
|
3858
|
+
var mediaType = (res) => res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
3859
|
+
var exists = async (path) => {
|
|
3860
|
+
try {
|
|
3861
|
+
await access(path);
|
|
3862
|
+
return true;
|
|
3863
|
+
} catch {
|
|
3864
|
+
return false;
|
|
3865
|
+
}
|
|
3866
|
+
};
|
|
3867
|
+
var completedFor = async (dir, stem) => {
|
|
3868
|
+
let names;
|
|
3869
|
+
try {
|
|
3870
|
+
names = await readdir(dir);
|
|
3871
|
+
} catch {
|
|
3872
|
+
return null;
|
|
3873
|
+
}
|
|
3874
|
+
const candidates = names.filter((name) => name.startsWith(`${stem}.`) && !name.endsWith(PART_SUFFIX));
|
|
3875
|
+
return candidates.length === 1 ? candidates[0] ?? null : null;
|
|
3818
3876
|
};
|
|
3819
3877
|
var materializeAssets = async (markdown, ctx) => {
|
|
3820
3878
|
const doFetch = ctx.fetchImpl ?? globalThis.fetch;
|
|
3879
|
+
const limit = ctx.limit ?? ((task) => task());
|
|
3880
|
+
const timeoutMs = ctx.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
3821
3881
|
const diagnostics = [];
|
|
3822
3882
|
const fences = [];
|
|
3823
3883
|
const masked = markdown.replace(CODE_FENCE_BLOCK, (block) => {
|
|
@@ -3825,23 +3885,52 @@ var materializeAssets = async (markdown, ctx) => {
|
|
|
3825
3885
|
return `\x00blume-fence-${fences.length - 1}\x00`;
|
|
3826
3886
|
});
|
|
3827
3887
|
const urls = new Set;
|
|
3828
|
-
for (const
|
|
3829
|
-
const
|
|
3830
|
-
|
|
3831
|
-
|
|
3888
|
+
for (const pattern of [MD_IMAGE2, HTML_VIDEO_SRC]) {
|
|
3889
|
+
for (const match of masked.matchAll(pattern)) {
|
|
3890
|
+
const url = match.groups?.url;
|
|
3891
|
+
if (url && REMOTE.test(url)) {
|
|
3892
|
+
urls.add(url);
|
|
3893
|
+
}
|
|
3832
3894
|
}
|
|
3833
3895
|
}
|
|
3896
|
+
const download = async (url) => {
|
|
3897
|
+
const stem = hashText(url.split("?")[0] ?? url);
|
|
3898
|
+
const urlExt = extFromUrl(url);
|
|
3899
|
+
if (urlExt && await exists(join5(ctx.assetsDir, `${stem}${urlExt}`))) {
|
|
3900
|
+
return `${stem}${urlExt}`;
|
|
3901
|
+
}
|
|
3902
|
+
const completed = urlExt ? null : await completedFor(ctx.assetsDir, stem);
|
|
3903
|
+
if (completed) {
|
|
3904
|
+
return completed;
|
|
3905
|
+
}
|
|
3906
|
+
const res = await doFetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
3907
|
+
if (!res.ok) {
|
|
3908
|
+
throw new Error(`${res.status}`);
|
|
3909
|
+
}
|
|
3910
|
+
const type = mediaType(res);
|
|
3911
|
+
if (NON_MEDIA_TYPE.test(type)) {
|
|
3912
|
+
throw new Error(`responded with ${type}, not a media file`);
|
|
3913
|
+
}
|
|
3914
|
+
if (!res.body) {
|
|
3915
|
+
throw new Error("empty response body");
|
|
3916
|
+
}
|
|
3917
|
+
const file = `${stem}${urlExt ?? EXT_BY_MIME.get(type) ?? UNKNOWN_EXT}`;
|
|
3918
|
+
const target = join5(ctx.assetsDir, file);
|
|
3919
|
+
await mkdir3(ctx.assetsDir, { recursive: true });
|
|
3920
|
+
const part = `${target}.${randomUUID()}${PART_SUFFIX}`;
|
|
3921
|
+
try {
|
|
3922
|
+
await writeFile3(part, res.body);
|
|
3923
|
+
} catch (error) {
|
|
3924
|
+
await rm(part, { force: true });
|
|
3925
|
+
throw error;
|
|
3926
|
+
}
|
|
3927
|
+
await rename(part, target);
|
|
3928
|
+
return file;
|
|
3929
|
+
};
|
|
3834
3930
|
const rewrites = new Map;
|
|
3835
3931
|
await Promise.all([...urls].map(async (url) => {
|
|
3836
3932
|
try {
|
|
3837
|
-
const
|
|
3838
|
-
if (!res.ok) {
|
|
3839
|
-
throw new Error(`${res.status}`);
|
|
3840
|
-
}
|
|
3841
|
-
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
3842
|
-
const file = `${hashText(url.split("?")[0] ?? url)}${extFor(url)}`;
|
|
3843
|
-
await mkdir3(ctx.assetsDir, { recursive: true });
|
|
3844
|
-
await writeFile3(join5(ctx.assetsDir, file), bytes);
|
|
3933
|
+
const file = await limit(() => download(url));
|
|
3845
3934
|
rewrites.set(url, `${ctx.assetsBaseUrl}/${file}`);
|
|
3846
3935
|
} catch (error) {
|
|
3847
3936
|
diagnostics.push({
|
|
@@ -3854,6 +3943,9 @@ var materializeAssets = async (markdown, ctx) => {
|
|
|
3854
3943
|
const rewritten = masked.replaceAll(MD_IMAGE2, (match, alt, url) => {
|
|
3855
3944
|
const local = rewrites.get(url);
|
|
3856
3945
|
return local ? `` : match;
|
|
3946
|
+
}).replaceAll(HTML_VIDEO_SRC, (match, open, url, close) => {
|
|
3947
|
+
const local = rewrites.get(url);
|
|
3948
|
+
return local ? `${open}${local}${close}` : match;
|
|
3857
3949
|
}).replaceAll(FENCE_TOKEN, (token, index) => fences[Number(index)] ?? token);
|
|
3858
3950
|
return { diagnostics, markdown: rewritten };
|
|
3859
3951
|
};
|
|
@@ -3886,6 +3978,7 @@ var MAX_RETRIES = 4;
|
|
|
3886
3978
|
var BASE_DELAY_MS = 500;
|
|
3887
3979
|
var SECOND_MS2 = 1000;
|
|
3888
3980
|
var DEFAULT_CONCURRENCY = 3;
|
|
3981
|
+
var ASSET_DOWNLOAD_CONCURRENCY = 4;
|
|
3889
3982
|
var withNotionRetry = async (call, attempt = 0) => {
|
|
3890
3983
|
try {
|
|
3891
3984
|
return await call();
|
|
@@ -3911,6 +4004,25 @@ var LIST_BLOCKS = new Set([
|
|
|
3911
4004
|
"to_do"
|
|
3912
4005
|
]);
|
|
3913
4006
|
var isListItem = (block) => block !== undefined && LIST_BLOCKS.has(block.type);
|
|
4007
|
+
var richToPlain = (rich = []) => rich.map((node) => node.plain_text).join("");
|
|
4008
|
+
var jsxString = (value) => `{${JSON.stringify(value)}}`;
|
|
4009
|
+
var YOUTUBE_HOST = /(?:^|\.)(?:youtube(?:-nocookie)?\.com|youtu\.be)$/u;
|
|
4010
|
+
var isYouTubeUrl = (url) => {
|
|
4011
|
+
const host = URL.parse(url)?.hostname ?? "";
|
|
4012
|
+
return YOUTUBE_HOST.test(host) && parseYouTubeId(url) !== null;
|
|
4013
|
+
};
|
|
4014
|
+
var renderVideo = (data) => {
|
|
4015
|
+
const url = data.external?.url ?? data.file?.url;
|
|
4016
|
+
if (!url) {
|
|
4017
|
+
return "";
|
|
4018
|
+
}
|
|
4019
|
+
const caption = richToMarkdown(data.caption);
|
|
4020
|
+
const title = caption ? ` title=${jsxString(richToPlain(data.caption))}` : "";
|
|
4021
|
+
const media = isYouTubeUrl(url) ? `<YouTube${title} url=${JSON.stringify(url)} />` : `<video controls src=${JSON.stringify(url)} />`;
|
|
4022
|
+
return caption ? `<Frame caption=${jsxString(caption)}>
|
|
4023
|
+
${media}
|
|
4024
|
+
</Frame>` : media;
|
|
4025
|
+
};
|
|
3914
4026
|
var renderLeaf = (block) => {
|
|
3915
4027
|
const data = payloadOf(block) ?? {};
|
|
3916
4028
|
const text = richToMarkdown(blockField(block));
|
|
@@ -3951,6 +4063,9 @@ ${text}
|
|
|
3951
4063
|
const url = data.external?.url ?? data.file?.url;
|
|
3952
4064
|
return url ? `` : "";
|
|
3953
4065
|
}
|
|
4066
|
+
case "video": {
|
|
4067
|
+
return renderVideo(data);
|
|
4068
|
+
}
|
|
3954
4069
|
default: {
|
|
3955
4070
|
return null;
|
|
3956
4071
|
}
|
|
@@ -3959,6 +4074,7 @@ ${text}
|
|
|
3959
4074
|
var notionSource = (options, ctx) => {
|
|
3960
4075
|
const props = options.properties ?? {};
|
|
3961
4076
|
const limit = pLimit(Math.max(1, options.concurrency ?? DEFAULT_CONCURRENCY));
|
|
4077
|
+
const downloads = pLimit(ASSET_DOWNLOAD_CONCURRENCY);
|
|
3962
4078
|
const notionCall = (call) => withNotionRetry(() => limit(call));
|
|
3963
4079
|
const cache = snapshotCache(ctx?.cacheDir ?? join6(".blume", "cache", options.name));
|
|
3964
4080
|
const assetsDir = ctx?.assetsDir ?? join6(".blume", "public", "blume-assets", options.name);
|
|
@@ -3998,7 +4114,7 @@ ${body}
|
|
|
3998
4114
|
</Callout>`;
|
|
3999
4115
|
}
|
|
4000
4116
|
if (block.type === "toggle") {
|
|
4001
|
-
const title =
|
|
4117
|
+
const title = jsxString(richToMarkdown(blockField(block)));
|
|
4002
4118
|
return `<Accordion>
|
|
4003
4119
|
<AccordionItem title=${title}>
|
|
4004
4120
|
${await children(block)}
|
|
@@ -4099,7 +4215,8 @@ ${nested}`;
|
|
|
4099
4215
|
const assets = await materializeAssets(mdx, {
|
|
4100
4216
|
assetsBaseUrl,
|
|
4101
4217
|
assetsDir,
|
|
4102
|
-
fetchImpl: options.fetchImpl
|
|
4218
|
+
fetchImpl: options.fetchImpl,
|
|
4219
|
+
limit: downloads
|
|
4103
4220
|
});
|
|
4104
4221
|
const raw = frontmatter_default.stringify(assets.markdown, data);
|
|
4105
4222
|
return {
|
|
@@ -4168,7 +4285,7 @@ ${nested}`;
|
|
|
4168
4285
|
|
|
4169
4286
|
// src/core/sources/obsidian.ts
|
|
4170
4287
|
import { existsSync as existsSync3, watch as fsWatch2, statSync } from "node:fs";
|
|
4171
|
-
import { readdir, readFile as readFile5, stat } from "node:fs/promises";
|
|
4288
|
+
import { readdir as readdir2, readFile as readFile5, stat } from "node:fs/promises";
|
|
4172
4289
|
import { basename as basename2, isAbsolute as isAbsolute3, join as join7, relative as relative5, resolve as resolve3 } from "pathe";
|
|
4173
4290
|
var MARKDOWN_FILE = /\.md$/iu;
|
|
4174
4291
|
var OBSIDIAN_COMMENT = /%%.*?%%/gu;
|
|
@@ -4528,7 +4645,7 @@ var classify = async (dir, entry) => {
|
|
|
4528
4645
|
var byVaultOrder = (a, b) => Number(b.directory) - Number(a.directory) || a.name.localeCompare(b.name, "en", { numeric: true, sensitivity: "base" }) || (a.name < b.name ? -1 : 1);
|
|
4529
4646
|
var walkVault = async (dir, root, exclude) => {
|
|
4530
4647
|
const found = [];
|
|
4531
|
-
const listed = await
|
|
4648
|
+
const listed = await readdir2(dir, { withFileTypes: true });
|
|
4532
4649
|
const entries = await Promise.all(listed.filter((entry) => !(isHidden(entry.name) || exclude.has(entry.name))).map((entry) => classify(dir, entry)));
|
|
4533
4650
|
for (const entry of entries.toSorted(byVaultOrder)) {
|
|
4534
4651
|
const full = join7(dir, entry.name);
|
|
@@ -5164,7 +5281,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
5164
5281
|
};
|
|
5165
5282
|
};
|
|
5166
5283
|
|
|
5167
|
-
export { YAML_SCHEMA, frontmatter_default, TOC_HIDDEN_KEY, parseHeadingMarkers, BLUME_IGNORE_DIRS, i18nEnabled, localeCodes, resolveFallbackLocale, localePrefix, localizeRoute, localeTargetPath, validateSearchPopularIcons, validateNavTargets, VERSION_LIKE, versionizeRoute, nextFenceState, HTML_COMMENT, INLINE_CODE, scanBody, MD_IMAGE, targetOffsetIn, hasIncludeStatements, expandIncludes, buildIncludeGraph, contentIndexable, buildManifest, hashText, specOf, operationOf, specAddresses, apiNamePhrase, operationSignature, isOpenApiSource, resolveDocsCollection, isWithin, scanProject };
|
|
5284
|
+
export { YAML_SCHEMA, frontmatter_default, TOC_HIDDEN_KEY, parseHeadingMarkers, BLUME_IGNORE_DIRS, i18nEnabled, localeCodes, resolveFallbackLocale, localePrefix, localizeRoute, localeTargetPath, validateSearchPopularIcons, validateNavTargets, VERSION_LIKE, versionizeRoute, nextFenceState, HTML_COMMENT, INLINE_CODE, scanBody, MD_IMAGE, targetOffsetIn, hasIncludeStatements, expandIncludes, buildIncludeGraph, contentIndexable, buildManifest, hashText, specOf, operationOf, specAddresses, apiNamePhrase, operationSignature, isOpenApiSource, parseYouTubeId, resolveDocsCollection, isWithin, scanProject };
|
|
5168
5285
|
|
|
5169
|
-
//# debugId=
|
|
5170
|
-
//# sourceMappingURL=chunk-
|
|
5286
|
+
//# debugId=A3A6EEB99D149F0C64756E2164756E21
|
|
5287
|
+
//# sourceMappingURL=chunk-12dzsn9b.js.map
|