@krak-stack/registry 0.1.23 → 0.1.25

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/README.md CHANGED
@@ -20,7 +20,8 @@ import {
20
20
  } from "@krak-stack/registry/httpapi-toolkit";
21
21
  import { ApiClient } from "@krak-stack/registry/httpapi/client";
22
22
  import { HttpApiSpec } from "@krak-stack/registry/httpapi/helpers";
23
- import { createMdxDocsSource, makeDocs } from "@krak-stack/registry/docs";
23
+ import { createDocsSource, makeDocs } from "@krak-stack/registry/docs";
24
+ import { loadMdxDocsDirectory } from "@krak-stack/registry/docs/server";
24
25
  import {
25
26
  DocumentationToolkit,
26
27
  DocumentationToolkitLayer,
@@ -68,8 +69,18 @@ HTTP API client, schema, AI tool, CLI, and MCP utilities are available under
68
69
  the `@krak-stack/registry/httpapi/*` subpaths. Keep application-specific API
69
70
  layers, handlers, authentication, and client bindings in the application.
70
71
 
71
- Documentation consumers create their content source in the application so Vite
72
- can resolve the local `import.meta.glob`, then pass it to `makeDocs`.
72
+ Documentation consumers load and compile their application-owned MDX on the
73
+ server, then pass the validated page records to `createDocsSource` and
74
+ `makeDocs`:
75
+
76
+ ```ts
77
+ const pages = await loadMdxDocsDirectory("src/content/docs");
78
+ const source = createDocsSource({ pages, locales: ["en", "fr"] });
79
+ ```
80
+
81
+ The `@krak-stack/registry/docs/server` export requires the Bun runtime. Keep it
82
+ behind a server-only module or server function so it is not included in browser
83
+ bundles.
73
84
 
74
85
  Add the package's Tailwind source to the application stylesheet:
75
86
 
@@ -0,0 +1,41 @@
1
+ import { type DocsPage } from "./docs.js";
2
+ export declare const compileDocsMarkdown: (source: string) => {
3
+ codeBlocks: import("./markdown/server.js").MarkdownCodeBlock[];
4
+ html: string;
5
+ source: string;
6
+ headings: {
7
+ readonly depth: 2 | 3;
8
+ readonly id: string;
9
+ readonly title: string;
10
+ }[];
11
+ searchText: string;
12
+ };
13
+ export declare const compileMdxDocsPage: (sourceFile: string, source: string) => DocsPage;
14
+ export declare const loadMdxDocsDirectory: (root: string) => Promise<{
15
+ readonly slug: string;
16
+ readonly path: string;
17
+ readonly title: string;
18
+ readonly description: string;
19
+ readonly icon?: string | undefined;
20
+ readonly order: number;
21
+ readonly locale: string;
22
+ readonly section: string;
23
+ readonly type: "concept" | "how-to" | "reference" | "runbook" | "tutorial";
24
+ readonly createdAt?: string | undefined;
25
+ readonly updatedAt?: string | undefined;
26
+ readonly legacySlugs?: readonly string[] | undefined;
27
+ readonly tags?: readonly string[] | undefined;
28
+ readonly codeBlocks: readonly {
29
+ readonly code: string;
30
+ readonly language: string;
31
+ }[];
32
+ readonly headings: readonly {
33
+ readonly depth: 2 | 3;
34
+ readonly id: string;
35
+ readonly title: string;
36
+ }[];
37
+ readonly html: string;
38
+ readonly searchText: string;
39
+ readonly sourceFile: string;
40
+ readonly source: string;
41
+ }[]>;
@@ -0,0 +1,473 @@
1
+ // @bun
2
+ // ../../src/lib/docs.server.ts
3
+ import { Schema as Schema4 } from "effect";
4
+
5
+ // ../../src/lib/docs.tsx
6
+ import { Schema as Schema3 } from "effect";
7
+ import {
8
+ forwardRef,
9
+ useDeferredValue,
10
+ useEffect as useEffect5,
11
+ useState as useState5
12
+ } from "react";
13
+
14
+ // ../../src/components/ui/app-brand.tsx
15
+ import { Link } from "@tanstack/react-router";
16
+
17
+ // ../../src/components/ui/badge.tsx
18
+ import { mergeProps } from "@base-ui/react/merge-props";
19
+ import { useRender } from "@base-ui/react/use-render";
20
+ import { cva } from "class-variance-authority";
21
+
22
+ // ../../src/lib/utils.ts
23
+ import { clsx } from "clsx";
24
+ import { twMerge } from "tailwind-merge";
25
+
26
+ // ../../src/components/ui/badge.tsx
27
+ var badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
28
+ variants: {
29
+ variant: {
30
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
31
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
32
+ destructive: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
33
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
34
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
35
+ link: "text-primary underline-offset-4 hover:underline"
36
+ }
37
+ },
38
+ defaultVariants: {
39
+ variant: "default"
40
+ }
41
+ });
42
+
43
+ // ../../src/components/ui/button.tsx
44
+ import { Button as ButtonPrimitive } from "@base-ui/react/button";
45
+ import { cva as cva2 } from "class-variance-authority";
46
+ var buttonVariants = cva2("group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
47
+ variants: {
48
+ variant: {
49
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
50
+ outline: "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
51
+ secondary: "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
52
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
53
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
54
+ link: "text-primary underline-offset-4 hover:underline"
55
+ },
56
+ size: {
57
+ default: "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
58
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
59
+ sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
60
+ lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
61
+ icon: "size-9",
62
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
63
+ "icon-sm": "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
64
+ "icon-lg": "size-10"
65
+ }
66
+ },
67
+ defaultVariants: {
68
+ variant: "default",
69
+ size: "default"
70
+ }
71
+ });
72
+
73
+ // ../../src/components/ui/copy-button.tsx
74
+ import { Check, Copy, TriangleAlert } from "lucide-react";
75
+ import { useEffect, useRef, useState } from "react";
76
+
77
+ // ../../src/components/ui/code-block.tsx
78
+ import { highlight } from "@tanstack/highlight";
79
+ import { createThemeCss } from "@tanstack/highlight/theme";
80
+ import { githubDarkTheme } from "@tanstack/highlight/themes/github-dark";
81
+ import { githubLightTheme } from "@tanstack/highlight/themes/github-light";
82
+ var themeCss = `${createThemeCss({
83
+ light: githubLightTheme,
84
+ dark: githubDarkTheme,
85
+ lightSelector: "[data-code-theme]",
86
+ darkSelector: ".dark [data-code-theme]",
87
+ codeBlockSelector: "[data-code-theme] pre.th-code",
88
+ lineNumbersSelector: "[data-code-theme] .th-code--line-numbers"
89
+ })}
90
+ [data-code-theme] pre.th-code {
91
+ margin: 0;
92
+ overflow: visible;
93
+ background: transparent;
94
+ font: inherit;
95
+ color: inherit;
96
+ }
97
+ [data-code-theme] pre.th-code code { font: inherit; }`;
98
+
99
+ // ../../src/components/ui/collapsible.tsx
100
+ import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
101
+
102
+ // ../../src/components/ui/search-menu.tsx
103
+ import { SearchIcon as SearchIcon2 } from "lucide-react";
104
+ import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
105
+
106
+ // ../../src/components/ui/command.tsx
107
+ import { Command as CommandPrimitive } from "cmdk";
108
+ import { SearchIcon } from "lucide-react";
109
+
110
+ // ../../src/components/ui/dialog.tsx
111
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
112
+ import { XIcon } from "lucide-react";
113
+
114
+ // ../../src/paraglide/runtime.js
115
+ import"@inlang/paraglide-js/urlpattern-polyfill";
116
+ var isServer = import.meta.env?.SSR ?? typeof window === "undefined";
117
+ globalThis.__paraglide = globalThis.__paraglide ?? {};
118
+ globalThis.__paraglide.ssr = globalThis.__paraglide.ssr ?? {};
119
+ var rtlLanguages = new Set([
120
+ "ar",
121
+ "dv",
122
+ "fa",
123
+ "he",
124
+ "ks",
125
+ "ku",
126
+ "ps",
127
+ "sd",
128
+ "ug",
129
+ "ur",
130
+ "yi"
131
+ ]);
132
+ var customServerStrategies = new Map;
133
+ var customClientStrategies = new Map;
134
+
135
+ // ../../src/components/ui/sidebar-layout.tsx
136
+ import { useAtom } from "@effect/atom-react";
137
+ import { BrowserKeyValueStore } from "@effect/platform-browser";
138
+ import { Link as Link2, Outlet, useRouterState } from "@tanstack/react-router";
139
+ import { Schema as Schema2 } from "effect";
140
+ import { Atom } from "effect/unstable/reactivity";
141
+
142
+ // ../../src/components/ui/sidebar.tsx
143
+ import * as React2 from "react";
144
+ import { mergeProps as mergeProps2 } from "@base-ui/react/merge-props";
145
+ import { useRender as useRender2 } from "@base-ui/react/use-render";
146
+ import { cva as cva3 } from "class-variance-authority";
147
+
148
+ // ../../src/hooks/use-mobile.ts
149
+ import * as React from "react";
150
+
151
+ // ../../src/components/ui/input.tsx
152
+ import { Input as InputPrimitive } from "@base-ui/react/input";
153
+
154
+ // ../../src/components/ui/separator.tsx
155
+ import { Separator as SeparatorPrimitive } from "@base-ui/react/separator";
156
+
157
+ // ../../src/components/ui/sheet.tsx
158
+ import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
159
+ import { XIcon as XIcon2 } from "lucide-react";
160
+ "use client";
161
+
162
+ // ../../src/components/ui/tooltip.tsx
163
+ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
164
+ "use client";
165
+
166
+ // ../../src/components/ui/sidebar.tsx
167
+ import { PanelLeftIcon } from "lucide-react";
168
+ import { Schema } from "effect";
169
+ var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
170
+ var SidebarContext = React2.createContext(null);
171
+ var sidebarMenuButtonVariants = cva3("peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate", {
172
+ variants: {
173
+ variant: {
174
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
175
+ outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
176
+ },
177
+ size: {
178
+ default: "h-8 text-sm",
179
+ sm: "h-7 text-xs",
180
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
181
+ }
182
+ },
183
+ defaultVariants: {
184
+ variant: "default",
185
+ size: "default"
186
+ }
187
+ });
188
+
189
+ // ../../src/components/ui/sidebar-layout.tsx
190
+ var sidebarStorageRuntime = Atom.runtime(BrowserKeyValueStore.layerLocalStorage);
191
+ var sidebarOpenAtom = Atom.kvs({
192
+ runtime: sidebarStorageRuntime,
193
+ key: "sidebar:open",
194
+ schema: Schema2.Boolean,
195
+ defaultValue: () => true
196
+ });
197
+
198
+ // ../../src/lib/docs.tsx
199
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
200
+ var makeIcon = (name, paths) => {
201
+ const Icon = forwardRef(({ absoluteStrokeWidth: _absoluteStrokeWidth, size = 24, ...props }, ref) => /* @__PURE__ */ jsx("svg", {
202
+ "aria-hidden": "true",
203
+ fill: "none",
204
+ height: size,
205
+ ref,
206
+ stroke: "currentColor",
207
+ strokeLinecap: "round",
208
+ strokeLinejoin: "round",
209
+ strokeWidth: "2",
210
+ viewBox: "0 0 24 24",
211
+ width: size,
212
+ ...props,
213
+ children: paths
214
+ }));
215
+ Icon.displayName = name;
216
+ return Icon;
217
+ };
218
+ var ArrowLeft = makeIcon("ArrowLeft", /* @__PURE__ */ jsxs(Fragment, {
219
+ children: [
220
+ /* @__PURE__ */ jsx("path", {
221
+ d: "m12 19-7-7 7-7"
222
+ }),
223
+ /* @__PURE__ */ jsx("path", {
224
+ d: "M19 12H5"
225
+ })
226
+ ]
227
+ }));
228
+ var ArrowRight = makeIcon("ArrowRight", /* @__PURE__ */ jsxs(Fragment, {
229
+ children: [
230
+ /* @__PURE__ */ jsx("path", {
231
+ d: "M5 12h14"
232
+ }),
233
+ /* @__PURE__ */ jsx("path", {
234
+ d: "m12 5 7 7-7 7"
235
+ })
236
+ ]
237
+ }));
238
+ var BookOpen = makeIcon("BookOpen", /* @__PURE__ */ jsxs(Fragment, {
239
+ children: [
240
+ /* @__PURE__ */ jsx("path", {
241
+ d: "M12 7v14"
242
+ }),
243
+ /* @__PURE__ */ jsx("path", {
244
+ d: "M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-5a4 4 0 0 0-4 4 4 4 0 0 0-4-4Z"
245
+ })
246
+ ]
247
+ }));
248
+ var ChevronDown = makeIcon("ChevronDown", /* @__PURE__ */ jsx("path", {
249
+ d: "m6 9 6 6 6-6"
250
+ }));
251
+ var ExternalLink = makeIcon("ExternalLink", /* @__PURE__ */ jsxs(Fragment, {
252
+ children: [
253
+ /* @__PURE__ */ jsx("path", {
254
+ d: "M15 3h6v6"
255
+ }),
256
+ /* @__PURE__ */ jsx("path", {
257
+ d: "M10 14 21 3"
258
+ }),
259
+ /* @__PURE__ */ jsx("path", {
260
+ d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"
261
+ })
262
+ ]
263
+ }));
264
+ var Hash = makeIcon("Hash", /* @__PURE__ */ jsxs(Fragment, {
265
+ children: [
266
+ /* @__PURE__ */ jsx("line", {
267
+ x1: "4",
268
+ x2: "20",
269
+ y1: "9",
270
+ y2: "9"
271
+ }),
272
+ /* @__PURE__ */ jsx("line", {
273
+ x1: "4",
274
+ x2: "20",
275
+ y1: "15",
276
+ y2: "15"
277
+ }),
278
+ /* @__PURE__ */ jsx("line", {
279
+ x1: "10",
280
+ x2: "8",
281
+ y1: "3",
282
+ y2: "21"
283
+ }),
284
+ /* @__PURE__ */ jsx("line", {
285
+ x1: "16",
286
+ x2: "14",
287
+ y1: "3",
288
+ y2: "21"
289
+ })
290
+ ]
291
+ }));
292
+ var DocsSection = Schema3.String.annotate({
293
+ identifier: "DocsSection"
294
+ });
295
+ var DocsPageType = Schema3.Literals([
296
+ "concept",
297
+ "tutorial",
298
+ "how-to",
299
+ "reference",
300
+ "runbook"
301
+ ]).annotate({ identifier: "DocsPageType" });
302
+ var DocsDate = Schema3.String.pipe(Schema3.check(Schema3.makeFilter((date) => Number.isNaN(new Date(date).getTime()) ? "Expected a valid date" : undefined)));
303
+ var DocsFrontmatter = Schema3.Struct({
304
+ slug: Schema3.String,
305
+ path: Schema3.String,
306
+ title: Schema3.String,
307
+ description: Schema3.String,
308
+ icon: Schema3.optional(Schema3.String),
309
+ order: Schema3.Number,
310
+ locale: Schema3.String,
311
+ section: DocsSection,
312
+ type: DocsPageType,
313
+ createdAt: Schema3.optional(DocsDate),
314
+ updatedAt: Schema3.optional(DocsDate),
315
+ legacySlugs: Schema3.optional(Schema3.Array(Schema3.String)),
316
+ tags: Schema3.optional(Schema3.Array(Schema3.NonEmptyString))
317
+ }).annotate({ identifier: "DocsFrontmatter" });
318
+ var DocsHeadingSchema = Schema3.Struct({
319
+ depth: Schema3.Literals([2, 3]),
320
+ id: Schema3.String,
321
+ title: Schema3.String
322
+ }).annotate({ identifier: "DocsHeading" });
323
+ var DocsCodeBlockSchema = Schema3.Struct({
324
+ code: Schema3.String,
325
+ language: Schema3.String
326
+ }).annotate({ identifier: "DocsCodeBlock" });
327
+ var DocsPageSchema = Schema3.Struct({
328
+ ...DocsFrontmatter.fields,
329
+ codeBlocks: Schema3.Array(DocsCodeBlockSchema),
330
+ headings: Schema3.Array(DocsHeadingSchema),
331
+ html: Schema3.String,
332
+ searchText: Schema3.String,
333
+ sourceFile: Schema3.String,
334
+ source: Schema3.String
335
+ }).annotate({ identifier: "DocsPage" });
336
+ var EmptyIcon = forwardRef(() => null);
337
+
338
+ // ../../src/lib/markdown/server.ts
339
+ var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
340
+ var decodeMarkdownCode = (value) => value.replaceAll("&quot;", '"').replaceAll("&#39;", "'").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&amp;", "&");
341
+ var safeUrl = (value, image = false) => {
342
+ if (value.startsWith("/") || value.startsWith("#") || value.startsWith("https://") || value.startsWith("http://") || !image && value.startsWith("mailto:")) {
343
+ return value;
344
+ }
345
+ return image ? "" : "#";
346
+ };
347
+ var markdownOptions = {
348
+ autolinks: true,
349
+ headings: { ids: true },
350
+ noHtmlBlocks: true,
351
+ noHtmlSpans: true,
352
+ tagFilter: true
353
+ };
354
+ var markdownPlainText = (source, includeCode = false) => Bun.markdown.render(source, {
355
+ blockquote: (children) => `${children} `,
356
+ code: (children) => includeCode ? `${children} ` : " ",
357
+ codespan: (children) => `${children} `,
358
+ heading: (children) => `${children} `,
359
+ html: () => " ",
360
+ image: (children) => `${children} `,
361
+ list: (children) => `${children} `,
362
+ listItem: (children) => `${children} `,
363
+ paragraph: (children) => `${children} `,
364
+ table: (children) => `${children} `,
365
+ td: (children) => `${children} `,
366
+ th: (children) => `${children} `,
367
+ tr: (children) => `${children} `
368
+ }, markdownOptions).replace(/\s+/g, " ").trim();
369
+ var compileMarkdown = (source) => {
370
+ const codeBlocks = [];
371
+ const html = Bun.markdown.render(source, {
372
+ blockquote: (children) => `<blockquote>${children}</blockquote>`,
373
+ code: (children, meta) => {
374
+ const index = codeBlocks.length;
375
+ const code = decodeMarkdownCode(children.replace(/\n$/, ""));
376
+ const language = meta?.language ?? "text";
377
+ codeBlocks.push({ code, language });
378
+ return `<markdown-code-block data-index="${index}"></markdown-code-block>`;
379
+ },
380
+ codespan: (children) => `<code data-inline-code>${escapeHtml(children)}</code>`,
381
+ emphasis: (children) => `<em>${children}</em>`,
382
+ heading: (children, { id, level }) => {
383
+ const headingId = escapeHtml(id ?? "");
384
+ const anchor = level === 2 || level === 3 ? `<a href="#${headingId}" aria-hidden="true">#</a>` : "";
385
+ return `<h${level} id="${headingId}">${children}${anchor}</h${level}>`;
386
+ },
387
+ hr: () => "<hr>",
388
+ html: (children) => escapeHtml(children),
389
+ image: (children, { src, title }) => {
390
+ const resolvedSrc = safeUrl(src, true);
391
+ if (!resolvedSrc)
392
+ return children;
393
+ const titleAttribute = title ? ` title="${escapeHtml(title)}"` : "";
394
+ return `<img src="${escapeHtml(resolvedSrc)}" alt="${escapeHtml(children)}"${titleAttribute}>`;
395
+ },
396
+ link: (children, { href, title }) => {
397
+ const resolvedHref = safeUrl(href);
398
+ const external = /^https?:\/\//.test(resolvedHref);
399
+ const titleAttribute = title ? ` title="${escapeHtml(title)}"` : "";
400
+ const externalAttributes = external ? ' target="_blank" rel="noreferrer"' : "";
401
+ return `<a href="${escapeHtml(resolvedHref)}"${titleAttribute}${externalAttributes}>${children}</a>`;
402
+ },
403
+ list: (children, { ordered, start }) => ordered ? `<ol${start && start !== 1 ? ` start="${start}"` : ""}>${children}</ol>` : `<ul>${children}</ul>`,
404
+ listItem: (children, { checked }) => {
405
+ const checkbox = checked === undefined ? "" : `<input type="checkbox" disabled${checked ? " checked" : ""}>`;
406
+ return `<li>${checkbox}${children}</li>`;
407
+ },
408
+ paragraph: (children) => `<p>${children}</p>`,
409
+ strikethrough: (children) => `<del>${children}</del>`,
410
+ strong: (children) => `<strong>${children}</strong>`,
411
+ table: (children) => `<div data-markdown-table><table>${children}</table></div>`,
412
+ tbody: (children) => `<tbody>${children}</tbody>`,
413
+ td: (children, meta) => `<td${meta?.align ? ` align="${meta.align}"` : ""}>${children}</td>`,
414
+ text: escapeHtml,
415
+ th: (children, meta) => `<th${meta?.align ? ` align="${meta.align}"` : ""}>${children}</th>`,
416
+ thead: (children) => `<thead>${children}</thead>`,
417
+ tr: (children) => `<tr>${children}</tr>`
418
+ }, markdownOptions);
419
+ return { codeBlocks, html, source };
420
+ };
421
+
422
+ // ../../src/lib/docs.server.ts
423
+ var compileDocsMarkdown = (source) => {
424
+ const headings = [];
425
+ const seen = new Set;
426
+ Bun.markdown.render(source, {
427
+ heading: (children, { id, level }) => {
428
+ if ((level === 2 || level === 3) && id) {
429
+ if (seen.has(id))
430
+ throw new Error(`Duplicate heading ${id}`);
431
+ seen.add(id);
432
+ headings.push({ depth: level, id, title: children });
433
+ }
434
+ return "";
435
+ }
436
+ }, markdownOptions);
437
+ const compiled = compileMarkdown(source);
438
+ return {
439
+ ...compiled,
440
+ headings,
441
+ searchText: markdownPlainText(source)
442
+ };
443
+ };
444
+ var compileMdxDocsPage = (sourceFile, source) => {
445
+ const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/.exec(source);
446
+ if (!match)
447
+ throw new Error(`Missing frontmatter in ${sourceFile}`);
448
+ const frontmatter = Schema4.decodeUnknownSync(DocsFrontmatter)(Bun.YAML.parse(match[1] ?? ""));
449
+ const bodySource = match[2] ?? "";
450
+ const title = /^#\s+(.+?)\s*$/m.exec(bodySource)?.[1];
451
+ if (!title || markdownPlainText(title, true) !== markdownPlainText(frontmatter.title, true)) {
452
+ throw new Error(`Body title does not match frontmatter in ${sourceFile}`);
453
+ }
454
+ const body = bodySource.replace(/^\s*#\s+.+?\r?\n+/, "");
455
+ return Schema4.decodeUnknownSync(DocsPageSchema)({
456
+ ...frontmatter,
457
+ ...compileDocsMarkdown(body),
458
+ sourceFile
459
+ });
460
+ };
461
+ var loadMdxDocsDirectory = async (root) => {
462
+ const glob = new Bun.Glob("**/*.mdx");
463
+ const pages = [];
464
+ for await (const file of glob.scan({ cwd: root, onlyFiles: true })) {
465
+ pages.push(compileMdxDocsPage(`${root}/${file}`, await Bun.file(`${root}/${file}`).text()));
466
+ }
467
+ return pages;
468
+ };
469
+ export {
470
+ compileDocsMarkdown,
471
+ compileMdxDocsPage,
472
+ loadMdxDocsDirectory
473
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krak-stack/registry",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Tree-shakable KrakStack components and Effect services.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -52,6 +52,10 @@
52
52
  "types": "./dist/lib/docs.d.ts",
53
53
  "import": "./dist/lib/docs.js"
54
54
  },
55
+ "./docs/server": {
56
+ "types": "./dist/lib/docs.server.d.ts",
57
+ "import": "./dist/lib/docs.server.js"
58
+ },
55
59
  "./documentation-toolkit": {
56
60
  "types": "./dist/lib/documentation-toolkit.d.ts",
57
61
  "import": "./dist/lib/documentation-toolkit.js"
@@ -219,8 +223,8 @@
219
223
  "peerDependencies": {
220
224
  "@aws-sdk/client-sesv2": "^3.1068.0",
221
225
  "@base-ui/react": "^1.5.0",
222
- "@effect/atom-react": "4.0.0-rc.111",
223
- "@effect/platform-browser": "4.0.0-rc.111",
226
+ "@effect/atom-react": "4.0.0-rc.112",
227
+ "@effect/platform-browser": "4.0.0-rc.112",
224
228
  "@iconify/react": "^6.0.2",
225
229
  "@inlang/paraglide-js": "^2.19.0",
226
230
  "@lucas-barake/effect-form": "0.25.0-beta.6",
@@ -234,7 +238,7 @@
234
238
  "clsx": "^2.1.1",
235
239
  "cmdk": "^1.1.1",
236
240
  "drizzle-orm": "^1.0.0-rc.4-5d5b77c",
237
- "effect": "4.0.0-rc.111",
241
+ "effect": "4.0.0-rc.112",
238
242
  "lucide-react": "^1.18.0",
239
243
  "react": "^19.2.0",
240
244
  "react-dom": "^19.2.0",