@blaaiz/docs-core 0.1.0

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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/dist/chunk-3ZX4WIE3.js +2984 -0
  4. package/dist/chunk-3ZX4WIE3.js.map +1 -0
  5. package/dist/chunk-JCYR6RPE.js +31 -0
  6. package/dist/chunk-JCYR6RPE.js.map +1 -0
  7. package/dist/chunk-ZKOOKLZ3.js +124 -0
  8. package/dist/chunk-ZKOOKLZ3.js.map +1 -0
  9. package/dist/cli.js +534 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/generator.cjs +508 -0
  12. package/dist/generator.cjs.map +1 -0
  13. package/dist/generator.d.cts +122 -0
  14. package/dist/generator.d.ts +122 -0
  15. package/dist/generator.js +177 -0
  16. package/dist/generator.js.map +1 -0
  17. package/dist/index.cjs +3024 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.cts +1182 -0
  20. package/dist/index.d.ts +1182 -0
  21. package/dist/index.js +3 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/navigation-CGqFIPlP.d.cts +498 -0
  24. package/dist/navigation-CGqFIPlP.d.ts +498 -0
  25. package/dist/openapi-types-CJ6p5Cux.d.cts +78 -0
  26. package/dist/openapi-types-CJ6p5Cux.d.ts +78 -0
  27. package/dist/ui/api-try-it.cjs +654 -0
  28. package/dist/ui/api-try-it.cjs.map +1 -0
  29. package/dist/ui/api-try-it.d.cts +78 -0
  30. package/dist/ui/api-try-it.d.ts +78 -0
  31. package/dist/ui/api-try-it.js +509 -0
  32. package/dist/ui/api-try-it.js.map +1 -0
  33. package/dist/ui/ask-ai.cjs +810 -0
  34. package/dist/ui/ask-ai.cjs.map +1 -0
  35. package/dist/ui/ask-ai.d.cts +57 -0
  36. package/dist/ui/ask-ai.d.ts +57 -0
  37. package/dist/ui/ask-ai.js +808 -0
  38. package/dist/ui/ask-ai.js.map +1 -0
  39. package/dist/ui/copy-page.cjs +312 -0
  40. package/dist/ui/copy-page.cjs.map +1 -0
  41. package/dist/ui/copy-page.d.cts +33 -0
  42. package/dist/ui/copy-page.d.ts +33 -0
  43. package/dist/ui/copy-page.js +183 -0
  44. package/dist/ui/copy-page.js.map +1 -0
  45. package/dist/ui/mermaid.cjs +363 -0
  46. package/dist/ui/mermaid.cjs.map +1 -0
  47. package/dist/ui/mermaid.d.cts +13 -0
  48. package/dist/ui/mermaid.d.ts +13 -0
  49. package/dist/ui/mermaid.js +361 -0
  50. package/dist/ui/mermaid.js.map +1 -0
  51. package/dist/ui.cjs +661 -0
  52. package/dist/ui.cjs.map +1 -0
  53. package/dist/ui.d.cts +428 -0
  54. package/dist/ui.d.ts +428 -0
  55. package/dist/ui.js +537 -0
  56. package/dist/ui.js.map +1 -0
  57. package/package.json +145 -0
  58. package/patches/fumadocs-openapi.patch +173 -0
  59. package/skills/AGENTS-section.md +36 -0
  60. package/skills/SKILL.md +363 -0
  61. package/styles/api-reference.css +1417 -0
  62. package/styles/ask-ai.css +563 -0
  63. package/styles/auth.css +462 -0
  64. package/styles/docs.css +247 -0
  65. package/styles/home.css +376 -0
  66. package/templates/init/content/docs/index.mdx.tmpl +52 -0
  67. package/templates/init/content/docs/meta.json.tmpl +3 -0
  68. package/templates/init/content/docs.json.tmpl +12 -0
  69. package/templates/init/content/nav.json.tmpl +7 -0
  70. package/templates/init/docs.config.ts.tmpl +36 -0
  71. package/templates/init/env.example.tmpl +15 -0
package/package.json ADDED
@@ -0,0 +1,145 @@
1
+ {
2
+ "name": "@blaaiz/docs-core",
3
+ "version": "0.1.0",
4
+ "description": "Neutral, self-hostable documentation framework core — navigation parsing, OpenAPI merging, MDX doc components, and a hardened try-it proxy. Config and content live in each consuming site.",
5
+ "keywords": [
6
+ "documentation",
7
+ "docs",
8
+ "openapi",
9
+ "api-playground",
10
+ "mdx",
11
+ "react",
12
+ "framework"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "Blaaiz",
16
+ "homepage": "https://github.com/blaaiz/docs-core#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/blaaiz/docs-core.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/blaaiz/docs-core/issues"
23
+ },
24
+ "type": "module",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js",
29
+ "require": "./dist/index.cjs"
30
+ },
31
+ "./ui": {
32
+ "types": "./dist/ui.d.ts",
33
+ "import": "./dist/ui.js",
34
+ "require": "./dist/ui.cjs"
35
+ },
36
+ "./ui/copy-page": {
37
+ "types": "./dist/ui/copy-page.d.ts",
38
+ "import": "./dist/ui/copy-page.js",
39
+ "require": "./dist/ui/copy-page.cjs"
40
+ },
41
+ "./ui/mermaid": {
42
+ "types": "./dist/ui/mermaid.d.ts",
43
+ "import": "./dist/ui/mermaid.js",
44
+ "require": "./dist/ui/mermaid.cjs"
45
+ },
46
+ "./ui/api-try-it": {
47
+ "types": "./dist/ui/api-try-it.d.ts",
48
+ "import": "./dist/ui/api-try-it.js",
49
+ "require": "./dist/ui/api-try-it.cjs"
50
+ },
51
+ "./ui/ask-ai": {
52
+ "types": "./dist/ui/ask-ai.d.ts",
53
+ "import": "./dist/ui/ask-ai.js",
54
+ "require": "./dist/ui/ask-ai.cjs"
55
+ },
56
+ "./generator": {
57
+ "types": "./dist/generator.d.ts",
58
+ "import": "./dist/generator.js",
59
+ "require": "./dist/generator.cjs"
60
+ },
61
+ "./styles/*": {
62
+ "style": "./styles/*",
63
+ "default": "./styles/*"
64
+ },
65
+ "./package.json": "./package.json"
66
+ },
67
+ "main": "./dist/index.cjs",
68
+ "module": "./dist/index.js",
69
+ "types": "./dist/index.d.ts",
70
+ "bin": {
71
+ "docs-core": "./dist/cli.js"
72
+ },
73
+ "files": [
74
+ "dist",
75
+ "styles",
76
+ "patches",
77
+ "templates",
78
+ "skills"
79
+ ],
80
+ "sideEffects": false,
81
+ "engines": {
82
+ "node": ">=20.11.0"
83
+ },
84
+ "publishConfig": {
85
+ "access": "public"
86
+ },
87
+ "peerDependencies": {
88
+ "mermaid": "^11.0.0",
89
+ "react": "^18.2.0 || ^19.0.0",
90
+ "react-dom": "^18.2.0 || ^19.0.0"
91
+ },
92
+ "peerDependenciesMeta": {
93
+ "mermaid": {
94
+ "optional": true
95
+ },
96
+ "react": {
97
+ "optional": true
98
+ },
99
+ "react-dom": {
100
+ "optional": true
101
+ }
102
+ },
103
+ "devDependencies": {
104
+ "@changesets/cli": "^2.27.11",
105
+ "@commitlint/cli": "^19.6.1",
106
+ "@commitlint/config-conventional": "^19.6.0",
107
+ "@eslint/js": "^9.17.0",
108
+ "@microsoft/api-extractor": "^7.48.1",
109
+ "@types/node": "^22.10.5",
110
+ "@types/react": "^19.0.7",
111
+ "@types/react-dom": "^19.0.3",
112
+ "@vitest/coverage-v8": "^2.1.8",
113
+ "dependency-cruiser": "^16.9.0",
114
+ "eslint": "^9.17.0",
115
+ "eslint-config-prettier": "^9.1.0",
116
+ "lefthook": "^1.10.1",
117
+ "mermaid": "^11.17.2",
118
+ "plop": "^4.0.1",
119
+ "prettier": "^3.4.2",
120
+ "react": "^19.0.0",
121
+ "react-dom": "^19.0.0",
122
+ "tsup": "^8.3.5",
123
+ "typescript": "^5.7.2",
124
+ "typescript-eslint": "^8.19.0",
125
+ "vitest": "^2.1.8"
126
+ },
127
+ "scripts": {
128
+ "build": "tsup",
129
+ "dev": "tsup --watch",
130
+ "typecheck": "tsc --noEmit",
131
+ "lint": "eslint .",
132
+ "lint:fix": "eslint . --fix",
133
+ "format": "prettier --write .",
134
+ "format:check": "prettier --check .",
135
+ "arch": "depcruise src",
136
+ "test": "vitest run",
137
+ "test:watch": "vitest",
138
+ "test:coverage": "vitest run --coverage",
139
+ "api:check": "api-extractor run --verbose && api-extractor run --verbose --config api-extractor.ui.json && api-extractor run --verbose --config api-extractor.generator.json",
140
+ "api:update": "api-extractor run --local --verbose && api-extractor run --local --verbose --config api-extractor.ui.json && api-extractor run --local --verbose --config api-extractor.generator.json",
141
+ "gen": "plop",
142
+ "verify": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run arch && pnpm run test:coverage && pnpm run build && pnpm run api:check",
143
+ "release": "changeset publish"
144
+ }
145
+ }
@@ -0,0 +1,173 @@
1
+ diff --git a/dist/playground/components/oauth-dialog.js b/dist/playground/components/oauth-dialog.js
2
+ index 38925fd7df86dd837fca419161772a5b41070b2d..cf453defa42b08b9ca76fc0b73c8d325165f9817 100644
3
+ --- a/dist/playground/components/oauth-dialog.js
4
+ +++ b/dist/playground/components/oauth-dialog.js
5
+ @@ -1,4 +1,5 @@
6
+ -import { useRenderContext } from "../../ui/contexts/api.js";
7
+ +import { useRenderContext, useServerContext } from "../../ui/contexts/api.js";
8
+ +import { joinURL, resolveServerUrl } from "@fumadocs/api-docs/utils/url";
9
+ import { cn } from "../../utils/cn.js";
10
+ import { useQuery } from "../../utils/use-query.js";
11
+ import { useAuth } from "../auth.js";
12
+ @@ -10,6 +11,28 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
13
+ import { Input, labelVariants } from "@fumadocs/api-docs/components/input";
14
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@fumadocs/api-docs/components/dialog";
15
+ //#region src/playground/components/oauth-dialog.tsx
16
+ +
17
+ +// Blaaiz: OpenAPI allows a relative `tokenUrl` (resolved against the server),
18
+ +// but the dialog fetched it verbatim, so it hit the docs origin instead of the
19
+ +// API. Resolve it the same way the playground resolves a request URL.
20
+ +function blaaizResolveTokenUrl(tokenUrl, server) {
21
+ + if (/^[a-z][a-z0-9+.-]*:\/\//i.test(tokenUrl)) return tokenUrl;
22
+ + const base = new URL(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin).href;
23
+ + return joinURL(base, tokenUrl);
24
+ +}
25
+ +// Blaaiz: a failed exchange threw the raw response body, so an HTML error page
26
+ +// flooded the dialog. Prefer the OAuth error fields, else a short summary.
27
+ +async function blaaizTokenError(res) {
28
+ + const raw = (await res.text()).trim();
29
+ + let message;
30
+ + try {
31
+ + const parsed = JSON.parse(raw);
32
+ + message = parsed.error_description ?? parsed.error ?? parsed.message;
33
+ + } catch {}
34
+ + if (!message) message = raw.startsWith("<") || raw.length > 300 ? `${res.status} ${res.statusText || "error"} from the token endpoint.` : raw;
35
+ + return new Error(`Token request failed: ${message}`);
36
+ +}
37
+ +
38
+ const OAuthDialog = Dialog;
39
+ function OAuthDialogContent(props) {
40
+ const t = useTranslations({ note: "OAuth dialog" });
41
+ @@ -17,6 +40,9 @@ function OAuthDialogContent(props) {
42
+ }
43
+ function Content({ schemeId, scopes, setToken, setOpen }) {
44
+ const { dereferenced, resolve } = useRenderContext().schema;
45
+ + // Blaaiz: the selected server, so a relative tokenUrl resolves against the
46
+ + // API rather than the docs origin.
47
+ + const { server: blaaizServer } = useServerContext();
48
+ const schemes = dereferenced.components?.securitySchemes;
49
+ const tokenInfo = useAuth().store[schemeId];
50
+ const scheme = resolve(schemes?.[schemeId]);
51
+ @@ -118,7 +144,7 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
52
+ if (values.clientId) body.set("client_id", values.clientId);
53
+ if (values.clientSecret) body.set("client_secret", values.clientSecret);
54
+ }
55
+ - res = await fetch(value.tokenUrl, {
56
+ + res = await fetch(blaaizResolveTokenUrl(value.tokenUrl, blaaizServer), {
57
+ method: "POST",
58
+ headers,
59
+ body
60
+ @@ -126,7 +152,7 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
61
+ }
62
+ if (type === "clientCredentials") {
63
+ const value = scheme.flows[type];
64
+ - res = await fetch(value.tokenUrl, {
65
+ + res = await fetch(blaaizResolveTokenUrl(value.tokenUrl, blaaizServer), {
66
+ method: "POST",
67
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
68
+ body: new URLSearchParams({
69
+ @@ -138,7 +164,7 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
70
+ });
71
+ }
72
+ if (res) {
73
+ - if (!res.ok) throw new Error(await res.text());
74
+ + if (!res.ok) throw await blaaizTokenError(res);
75
+ const { access_token, token_type = "Bearer" } = await res.json();
76
+ setToken(`${token_type} ${access_token}`);
77
+ setOpen(false);
78
+ diff --git a/dist/ui/index.d.ts b/dist/ui/index.d.ts
79
+ index d9d78c8e161189b998c56441787f243e5f3bdc4d..ac3230e5574c12afc0864a57591c529653328b32 100644
80
+ --- a/dist/ui/index.d.ts
81
+ +++ b/dist/ui/index.d.ts
82
+ @@ -204,3 +204,10 @@ declare function createOpenAPIPage(options?: CreateOpenAPIPageOptions): FC<OpenA
83
+ type ApiPageProps = OpenAPIPageProps;
84
+ //#endregion
85
+ export { APIPlaygroundProps, ApiPageProps, CreateOpenAPIPageOptions, GenerateTypeScriptDefinitionsContext, OpenAPIPageProps, OpenAPIPageProps_Preloaded, OpenAPIPageProps_Spec, type OperationItem, type WebhookItem, createOpenAPIPage };
86
+ +// Blaaiz: server context, for a site-owned server switcher.
87
+ +export declare function useServerContext(): {
88
+ + servers?: { url: string; description?: string; name?: string }[];
89
+ + server?: { url: string; name?: string; variables: Record<string, string> } | null;
90
+ + setServer(url: string): void;
91
+ + setServerVariables(variables: Record<string, string>): void;
92
+ +};
93
+ diff --git a/dist/ui/index.js b/dist/ui/index.js
94
+ index 79678f643989b2ec048c18cc9a6dc83bf701154a..17cd7595ea2c79b2b3119b0abb43cb7e679ada1c 100644
95
+ --- a/dist/ui/index.js
96
+ +++ b/dist/ui/index.js
97
+ @@ -12,4 +12,7 @@ function createOpenAPIPage(options = {}) {
98
+ });
99
+ }
100
+ //#endregion
101
+ +// Blaaiz: expose the server context so a site can build its own server
102
+ +// switcher (the built-in one is a full dialog).
103
+ +export { useServerContext } from "./contexts/api.js";
104
+ export { createOpenAPIPage };
105
+ diff --git a/dist/ui/operation/usage-tabs.js b/dist/ui/operation/usage-tabs.js
106
+ index c26343b90b81499835392af83df7600373cea057..edb31d8efcb74c5ed90ad64cc71a97f43cc391d0 100644
107
+ --- a/dist/ui/operation/usage-tabs.js
108
+ +++ b/dist/ui/operation/usage-tabs.js
109
+ @@ -10,6 +10,42 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
110
+ import { joinURL, resolveServerUrl } from "@fumadocs/api-docs/utils/url";
111
+ import { CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger } from "fumadocs-ui/components/codeblock";
112
+ //#region src/ui/operation/usage-tabs.tsx
113
+ +// Blaaiz: render the code-sample languages as a Select dropdown floated to the
114
+ +// right, with the endpoint name as the panel title — matching Mintlify.
115
+ +function BlaaizUsageDropdown({ map, title }) {
116
+ + const [id, setId] = useState(map[0][0]);
117
+ + const active = map.find(([key]) => key === id) ?? map[0];
118
+ + const items = map.map(([key, item]) => ({ value: key, label: item.label ?? item.lang }));
119
+ + return /* @__PURE__ */ jsxs("div", {
120
+ + className: "not-prose openapi-usage",
121
+ + children: [
122
+ + /* @__PURE__ */ jsxs("div", {
123
+ + className: "openapi-usage-header",
124
+ + children: [
125
+ + /* @__PURE__ */ jsx("span", { className: "openapi-usage-title", children: title ?? "" }),
126
+ + /* @__PURE__ */ jsxs(Select, {
127
+ + items,
128
+ + value: id,
129
+ + onValueChange: (v) => v !== null && setId(v),
130
+ + children: [
131
+ + /* @__PURE__ */ jsx(SelectTrigger, {
132
+ + className: "openapi-usage-lang",
133
+ + children: /* @__PURE__ */ jsx(SelectValue, {})
134
+ + }),
135
+ + /* @__PURE__ */ jsx(SelectContent, {
136
+ + children: items.map((it) => /* @__PURE__ */ jsx(SelectItem, {
137
+ + value: it.value,
138
+ + children: it.label
139
+ + }, it.value))
140
+ + })
141
+ + ]
142
+ + })
143
+ + ]
144
+ + }),
145
+ + /* @__PURE__ */ jsx(UsageTab, { id, lang: active[1].lang })
146
+ + ]
147
+ + });
148
+ +}
149
+ function UsageTabs({ method, operation, pathItem }) {
150
+ const ctx = useRenderContext();
151
+ let { renderAPIExampleUsageTabs, renderAPIExampleLayout } = ctx.content ?? {};
152
+ @@ -26,20 +62,7 @@ function UsageTabs({ method, operation, pathItem }) {
153
+ renderAPIExampleUsageTabs ??= (registry) => {
154
+ const map = Array.from(registry.map().entries());
155
+ if (map.length === 0) return null;
156
+ - return /* @__PURE__ */ jsxs(CodeBlockTabs, {
157
+ - groupId: "fumadocs_openapi_requests",
158
+ - defaultValue: map[0][0],
159
+ - children: [/* @__PURE__ */ jsx(CodeBlockTabsList, { children: map.map(([id, item]) => /* @__PURE__ */ jsx(CodeBlockTabsTrigger, {
160
+ - value: id,
161
+ - children: item.label ?? item.lang
162
+ - }, id)) }), map.map(([id, item]) => /* @__PURE__ */ jsx(CodeBlockTab, {
163
+ - value: id,
164
+ - children: /* @__PURE__ */ jsx(UsageTab, {
165
+ - id,
166
+ - lang: item.lang
167
+ - })
168
+ - }, id))]
169
+ - });
170
+ + return /* @__PURE__ */ jsx(BlaaizUsageDropdown, { map, title: operation.summary });
171
+ };
172
+ const registry = useMemo(() => {
173
+ const registry = createCodeUsageGeneratorRegistry(ctx.codeUsages);
@@ -0,0 +1,36 @@
1
+ ## Documentation site — @blaaiz/docs-core
2
+
3
+ This project's documentation site is built with `@blaaiz/docs-core`. The package
4
+ owns the logic; this repository owns config and content. Rules that always apply:
5
+
6
+ - **Never edit `node_modules/@blaaiz/docs-core`.** Every behaviour change comes
7
+ from `docs.config.ts`, `content/docs.json`, or a content file. If a change
8
+ seems to need a package edit, it belongs in the `docs-core` repository — say so
9
+ instead of patching the install.
10
+ - **`docs.config.ts` is the only place for site-specific values**: the brand, the
11
+ access mode, the try-it proxy allow-list, the opt-in features, SEO, and Ask AI.
12
+ A secret never goes in it. Config names an environment variable; the server
13
+ reads the value at runtime.
14
+ - **`content/docs.json` is the single source of truth for navigation.** Tabs,
15
+ groups, page order, and which API endpoints are published all live there.
16
+ Never reorganize the sidebar by moving files.
17
+ - **Generated files are outputs, not sources.** On a site that runs
18
+ `@blaaiz/docs-core/generator`, `content/docs/api/**`, `content/nav.json`,
19
+ `content/api-methods.json`, and every `meta.json` are rewritten from
20
+ `docs.json` on each run. Hand edits are lost. Change `docs.json` and re-run the
21
+ generator.
22
+ - **`proxy.allowedOrigins` is security-critical.** It is the exhaustive list of
23
+ upstream origins the try-it playground may reach. Add an origin only when the
24
+ site really must call it.
25
+ - **Verify before you finish**: run the project's `typecheck` and `build`, and
26
+ check the affected pages at `/docs` in the browser.
27
+
28
+ The full skill — the complete config schema, the `docs.json` shape, task recipes,
29
+ and every error the framework raises with its fix — is installed for both agents:
30
+
31
+ - Claude Code: `.claude/skills/docs-core/SKILL.md`
32
+ - Codex: `.agents/skills/docs-core/SKILL.md`
33
+
34
+ Refresh them after a `docs-core` upgrade with `npx docs-core agents --force`.
35
+ That command rewrites only the block between its own two markers in this file,
36
+ so anything you add outside them is safe.