@docubook/flame 1.3.2 → 1.3.3

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.
@@ -28,7 +28,8 @@ function createHtmlResponse(
28
28
  description: string,
29
29
  body: string,
30
30
  status: number,
31
- state: ServerState
31
+ state: ServerState,
32
+ depth = 0
32
33
  ): Response {
33
34
  const nonce = generateNonce();
34
35
  const favicon = state.docuConfig.meta?.favicon || "/favicon.ico";
@@ -42,6 +43,7 @@ function createHtmlResponse(
42
43
  nonce,
43
44
  extraScripts: hmrScript(nonce),
44
45
  themeCss: state.inlineThemeCss,
46
+ depth,
45
47
  });
46
48
  return htmlResponse(html, nonce, status, process.env.NODE_ENV !== "production");
47
49
  }
@@ -140,6 +142,9 @@ async function renderDocsServerPage(
140
142
 
141
143
  const body = renderToString(page);
142
144
 
145
+ // Match build.ts depth calculation: slug.split("/").length, fallback to 1 for empty
146
+ const depth = slug.length || 1;
147
+
143
148
  if (state.builder) {
144
149
  const ctx: PageContext = {
145
150
  slug: slug.join("/") || "/",
@@ -164,12 +169,13 @@ async function renderDocsServerPage(
164
169
  themeCss: state.inlineThemeCss,
165
170
  headExtra,
166
171
  bodyExtra,
172
+ depth,
167
173
  });
168
174
  html = await state.builder.runTransformHtmlChain(html, ctx);
169
175
  return htmlResponse(html, nonce, 200, process.env.NODE_ENV !== "production");
170
176
  }
171
177
 
172
- return createHtmlResponse(title, description, body, 200, state);
178
+ return createHtmlResponse(title, description, body, 200, state, depth);
173
179
  }
174
180
 
175
181
  function renderPage(
@@ -178,7 +184,8 @@ function renderPage(
178
184
  description: string,
179
185
  status: number,
180
186
  state: ServerState,
181
- props: Record<string, unknown> = {}
187
+ props: Record<string, unknown> = {},
188
+ depth = 0
182
189
  ): Response {
183
190
  const page = React.createElement(
184
191
  DocsLayout,
@@ -186,19 +193,20 @@ function renderPage(
186
193
  React.createElement(Component, props)
187
194
  );
188
195
  const body = renderToString(page);
189
- return createHtmlResponse(title, description, body, status, state);
196
+ return createHtmlResponse(title, description, body, status, state, depth);
190
197
  }
191
198
 
192
199
  export async function handleDocsIndex(state: ServerState): Promise<Response> {
193
200
  const doc = await getDocsForSlug("", state);
194
- if (!doc) return renderPage(NotFoundPage, "404 - Not Found", "", 404, state);
201
+ if (!doc) return renderPage(NotFoundPage, "404 - Not Found", "", 404, state, {}, 1);
195
202
  return renderDocsServerPage(doc, [], "/docs", state);
196
203
  }
197
204
 
198
205
  export async function handleDocsRoute(slug: string[], state: ServerState): Promise<Response> {
199
206
  const path = slug.join("/");
200
207
  const doc = await getDocsForSlug(path, state);
201
- if (!doc) return renderPage(NotFoundPage, "404 - Not Found", "", 404, state);
208
+ if (!doc)
209
+ return renderPage(NotFoundPage, "404 - Not Found", "", 404, state, {}, slug.length || 1);
202
210
  return renderDocsServerPage(doc, slug, `/docs/${path}`, state);
203
211
  }
204
212
 
@@ -214,8 +222,8 @@ export function handleIndex(state: ServerState): Response {
214
222
  );
215
223
  }
216
224
 
217
- export function handleNotFound(state: ServerState): Response {
218
- return renderPage(NotFoundPage, "404 - Not Found", "", 404, state);
225
+ export function handleNotFound(state: ServerState, depth = 0): Response {
226
+ return renderPage(NotFoundPage, "404 - Not Found", "", 404, state, {}, depth);
219
227
  }
220
228
 
221
229
  export function serveStatic(pathname: string): Response | null {
@@ -15,6 +15,7 @@ import {
15
15
  serverErrorResponse,
16
16
  type ServerState,
17
17
  } from "./server-routes";
18
+ import { SECURITY_HEADERS, cspHeader, generateNonce } from "./security";
18
19
 
19
20
  const docuConfig = loadDocuConfig();
20
21
 
@@ -107,13 +108,30 @@ const server = Bun.serve({
107
108
  hostname: server.hostname!,
108
109
  });
109
110
  if (pluginResponse) {
111
+ // Wrap plugin response with security headers.
112
+ // Plugin's own headers take precedence over defaults.
113
+ const securedHeaders = new Headers(pluginResponse.headers);
114
+ for (const [key, value] of Object.entries(SECURITY_HEADERS)) {
115
+ if (!securedHeaders.has(key)) {
116
+ securedHeaders.set(key, value);
117
+ }
118
+ }
119
+ const contentType = securedHeaders.get("Content-Type") || "";
120
+ if (contentType.includes("text/html") && !securedHeaders.has("Content-Security-Policy")) {
121
+ securedHeaders.set("Content-Security-Policy", cspHeader(generateNonce(), true));
122
+ }
123
+ const securedResponse = new Response(pluginResponse.body, {
124
+ status: pluginResponse.status,
125
+ statusText: pluginResponse.statusText,
126
+ headers: securedHeaders,
127
+ });
110
128
  logger.request(
111
129
  req.method,
112
130
  pathname,
113
- pluginResponse.status,
131
+ securedResponse.status,
114
132
  Math.round(performance.now() - startTime)
115
133
  );
116
- return pluginResponse;
134
+ return securedResponse;
117
135
  }
118
136
  }
119
137
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docubook/flame",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54,8 +54,8 @@
54
54
  "unified": "^11.0.0",
55
55
  "@docubook/core": "^1.7.2",
56
56
  "@docubook/mdx-content": "^3.2.2",
57
- "@docubook/ui-react": "^0.1.4",
58
- "@docubook/themes-colors": "^0.10.2"
57
+ "@docubook/themes-colors": "^0.10.2",
58
+ "@docubook/ui-react": "^0.1.4"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@sentry/bun": "^10.0.0"
@@ -17,7 +17,7 @@
17
17
  "actions": [
18
18
  {
19
19
  "text": "Get Started",
20
- "link": "/docs/getting-started/introduction",
20
+ "link": "/docs",
21
21
  "theme": "primary"
22
22
  },
23
23
  {