@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
@@ -0,0 +1,1182 @@
1
+ import { A as AiConfig, T as ThemeConfig, D as DocsConfig, N as Navigation } from './navigation-CGqFIPlP.cjs';
2
+ export { a as AI_PROVIDER_MODELS, b as AI_PROVIDER_NAMES, c as AiConfigError, d as AiProviderModels, e as AiProviderName, f as AuthConfig, g as DocPage, h as DocsConfigError, F as FeaturesConfig, G as GoogleProviderConfig, i as NavGroup, j as NavItem, k as NavMethod, l as NavPage, m as NavTab, O as OpenApiPage, P as ProxyConfig, R as ResolvedAiConfig, S as SecretProviderConfig, n as SeoConfig, o as ThemeLogo, p as ThemePalette, W as WorkspaceAuthConfig, q as WorkspaceProviders, r as defineDocsConfig, s as resolveAiConfig, v as validateDocsConfig } from './navigation-CGqFIPlP.cjs';
3
+ import { b as OpenApiDocument, O as OpenApiInfo, a as OpenApiServer } from './openapi-types-CJ6p5Cux.cjs';
4
+ export { c as OpenApiComponents, d as OpenApiOperation, e as OpenApiPathItem, f as OpenApiTag } from './openapi-types-CJ6p5Cux.cjs';
5
+
6
+ /**
7
+ * The try-it proxy.
8
+ *
9
+ * The interactive playground cannot call an API directly from the browser
10
+ * (cross-origin). Instead it posts an envelope to a same-origin route, which
11
+ * forwards the request server-side. This module builds that forwarder in a
12
+ * framework-agnostic way, using the Web `Request`/`Response` types so it drops
13
+ * into a Next.js route handler, an edge function, or any Fetch-based runtime.
14
+ *
15
+ * Security model: the proxy forwards the caller's own credentials and injects
16
+ * none of its own. It only reaches an origin the site has allow-listed, and it
17
+ * refuses private, loopback, and link-local hosts so it cannot be turned into
18
+ * an SSRF relay. Every forward is rate-limited per client IP, so a public
19
+ * playground cannot be used to hammer the site's own API.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ /**
24
+ * A minimal fetch signature, so a test can inject a fake upstream.
25
+ *
26
+ * @public
27
+ */
28
+ type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
29
+ /**
30
+ * Options for {@link createTryItProxy}.
31
+ *
32
+ * @public
33
+ */
34
+ interface CreateTryItProxyOptions {
35
+ /** Exhaustive list of upstream origins the proxy may forward to. */
36
+ readonly allowedOrigins: readonly string[];
37
+ /**
38
+ * Forwards per minute per client IP. Default 60 — pass
39
+ * `config.proxy.rateLimitPerMinute` to let the site set it.
40
+ */
41
+ readonly rateLimitPerMinute?: number;
42
+ /** Fetch implementation. Defaults to the global `fetch`. */
43
+ readonly fetch?: FetchLike;
44
+ /** Clock for the rate limiter, for tests. Defaults to `Date.now`. */
45
+ readonly now?: () => number;
46
+ }
47
+ /**
48
+ * Thrown when a forward target is missing, malformed, blocked, or not allow-listed.
49
+ *
50
+ * @public
51
+ */
52
+ declare class ProxyTargetError extends Error {
53
+ constructor(message: string);
54
+ }
55
+ /**
56
+ * Validate a forward target against the allow-list and the host block rules.
57
+ *
58
+ * @param target - the requested upstream URL
59
+ * @param allowedOrigins - allow-listed origins
60
+ * @returns the parsed, approved URL
61
+ * @throws {@link ProxyTargetError} when the target is invalid, blocked, or not allow-listed
62
+ * @public
63
+ */
64
+ declare function assertAllowedTarget(target: string, allowedOrigins: readonly string[]): URL;
65
+ /**
66
+ * The request envelope the playground posts to the proxy route.
67
+ *
68
+ * @public
69
+ */
70
+ interface TryItEnvelope {
71
+ readonly url: string;
72
+ readonly method?: string;
73
+ readonly headers?: Record<string, string>;
74
+ readonly body?: string | null;
75
+ }
76
+ /**
77
+ * Build a same-origin try-it proxy handler.
78
+ *
79
+ * Every request is rate-limited per client IP before anything is forwarded. A
80
+ * caller over the limit gets `429` with a `Retry-After` header and the same JSON
81
+ * body the Ask AI route returns.
82
+ *
83
+ * @param options - the allow-list, the rate limit, and an optional fetch implementation
84
+ * @returns a handler mapping an incoming `Request` to a forwarded `Response`
85
+ * @public
86
+ */
87
+ declare function createTryItProxy(options: CreateTryItProxyOptions): (request: Request) => Promise<Response>;
88
+ /**
89
+ * A set of HTTP method handlers for a try-it proxy route, ready to re-export
90
+ * from a framework route file (e.g. a Next.js `route.ts`).
91
+ *
92
+ * @public
93
+ */
94
+ interface TryItProxyRoute {
95
+ readonly GET: (request: Request) => Promise<Response>;
96
+ readonly POST: (request: Request) => Promise<Response>;
97
+ readonly PUT: (request: Request) => Promise<Response>;
98
+ readonly PATCH: (request: Request) => Promise<Response>;
99
+ readonly DELETE: (request: Request) => Promise<Response>;
100
+ readonly OPTIONS: () => Response;
101
+ }
102
+ /**
103
+ * Build a drop-in try-it proxy route that speaks the query-parameter protocol
104
+ * API playgrounds use: the target URL arrives in a query parameter, with the
105
+ * caller's own method, headers, and body.
106
+ *
107
+ * Two parameter names are accepted, because two playgrounds disagree. `url` is
108
+ * preferred and is the name {@link unwrapProxyTarget} decodes for display;
109
+ * `scalar_url` is what the Scalar playground sends. Passing both uses `url`.
110
+ *
111
+ * The route validates the target with {@link assertAllowedTarget} (allow-list +
112
+ * SSRF guard), rate-limits per client IP, strips inbound infra headers, and
113
+ * forwards server-side. Export its handlers directly from a route file:
114
+ *
115
+ * @example
116
+ * ```ts
117
+ * export const { GET, POST, PUT, PATCH, DELETE, OPTIONS } = createTryItProxyRoute({
118
+ * allowedOrigins: config.proxy.allowedOrigins,
119
+ * rateLimitPerMinute: config.proxy.rateLimitPerMinute,
120
+ * });
121
+ * ```
122
+ *
123
+ * @param options - the allow-list, the rate limit, and an optional fetch implementation
124
+ * @returns the method handlers for the route
125
+ * @public
126
+ */
127
+ declare function createTryItProxyRoute(options: CreateTryItProxyOptions): TryItProxyRoute;
128
+ /**
129
+ * Recover the real target URL from a try-it proxy URL, for display.
130
+ *
131
+ * The playground fetches through the same-origin proxy, so a response's URL is
132
+ * the proxy URL (`.../api/proxy?url=<encoded target>&...`). This returns the
133
+ * decoded target so the response panel shows the real endpoint, not the proxy.
134
+ * Any URL that is not a proxy URL is returned unchanged.
135
+ *
136
+ * It reads the same two parameter names {@link createTryItProxyRoute} accepts,
137
+ * `url` first and `scalar_url` second, so a Scalar-shaped proxy URL is decoded
138
+ * too.
139
+ *
140
+ * @param url - a proxy URL, or any URL
141
+ * @returns the decoded target URL, or the input unchanged
142
+ * @public
143
+ */
144
+ declare function unwrapProxyTarget(url: string): string;
145
+
146
+ /**
147
+ * The provider seam.
148
+ *
149
+ * Every provider is reduced to one shape: an async generator of three event
150
+ * kinds — text, done, error. Nothing above this layer knows whether Anthropic
151
+ * or OpenAI answered, which is what lets the route treat them as equals and
152
+ * lets a test script a stream without a network.
153
+ *
154
+ * @packageDocumentation
155
+ */
156
+
157
+ /**
158
+ * One turn of the conversation. Only the two roles a reader can produce: the
159
+ * system prompt is built by the framework and travels outside `messages`.
160
+ */
161
+ interface AiMessage {
162
+ readonly role: 'user' | 'assistant';
163
+ readonly content: string;
164
+ }
165
+
166
+ /**
167
+ * Lightweight client-shippable search.
168
+ *
169
+ * The framework builds a compact term index from a site's pages and scores
170
+ * queries against it with BM25: term frequency, inverse document frequency,
171
+ * and document-length normalization. IDF is what keeps ranking honest — a
172
+ * word that appears in every page ("how", "the", "a") carries almost no
173
+ * weight, so a query like "how do I deploy" is decided by "deploy", not by
174
+ * its stopwords. A light, symmetric stemmer is applied to both the index and
175
+ * the query, so "wallets" finds "wallet" and "authentication" finds
176
+ * "authenticate".
177
+ *
178
+ * It is intentionally simple — good for the hundreds-to-low-thousands of
179
+ * pages a docs site has — and ships to the browser as plain JSON, so search
180
+ * needs no server round-trip. A site provides the input UI.
181
+ *
182
+ * @packageDocumentation
183
+ */
184
+ /**
185
+ * A page to index.
186
+ *
187
+ * @public
188
+ */
189
+ interface SearchDocument {
190
+ readonly id: string;
191
+ readonly title: string;
192
+ readonly path: string;
193
+ /** Optional grouping label, e.g. the section or tab name. */
194
+ readonly section?: string;
195
+ /** Free text to index (body, description). Not retained in the index. */
196
+ readonly body?: string;
197
+ }
198
+ /**
199
+ * One indexed page. Part of the serialized {@link SearchIndex} wire format.
200
+ *
201
+ * @public
202
+ */
203
+ interface IndexedDocument {
204
+ readonly id: string;
205
+ readonly title: string;
206
+ readonly path: string;
207
+ readonly section?: string;
208
+ /** Stemmed term → occurrence count across title, section, and body. */
209
+ readonly terms: Readonly<Record<string, number>>;
210
+ /** Total token count, for length normalization. */
211
+ readonly length: number;
212
+ /** The title's stemmed terms, precomputed for the per-query title bonus. */
213
+ readonly titleTerms: readonly string[];
214
+ /** The section label's stemmed terms, when a section is set. */
215
+ readonly sectionTerms?: readonly string[];
216
+ }
217
+ /**
218
+ * A built, serializable search index.
219
+ *
220
+ * @public
221
+ */
222
+ interface SearchIndex {
223
+ readonly documents: readonly IndexedDocument[];
224
+ /** Stemmed term → number of documents containing it. */
225
+ readonly documentFrequency: Readonly<Record<string, number>>;
226
+ /** Every indexed term, sorted, for binary-searched prefix matching. */
227
+ readonly vocabulary: readonly string[];
228
+ /** Mean token count per document, for length normalization. */
229
+ readonly averageLength: number;
230
+ }
231
+ /**
232
+ * A ranked search hit.
233
+ *
234
+ * @public
235
+ */
236
+ interface SearchResult {
237
+ readonly id: string;
238
+ readonly title: string;
239
+ readonly path: string;
240
+ readonly section?: string;
241
+ readonly score: number;
242
+ }
243
+ /**
244
+ * Build a search index from a list of documents.
245
+ *
246
+ * @public
247
+ */
248
+ declare function buildSearchIndex(documents: readonly SearchDocument[]): SearchIndex;
249
+ /**
250
+ * Search an index with BM25 scoring. Rare words dominate common ones, term
251
+ * repetition saturates, long pages get no volume advantage, and a term that
252
+ * also appears in the title (as a whole token, never a substring) or the
253
+ * section label earns a bonus. A stemmed term that matches nothing exactly
254
+ * falls back to prefix matching at reduced weight — including the title and
255
+ * section bonuses, so a half-typed word still ranks the page it names first.
256
+ * Ties break deterministically by title, then path, independent of locale.
257
+ *
258
+ * Returns up to `limit` results, best first.
259
+ *
260
+ * @public
261
+ */
262
+ declare function searchIndex(index: SearchIndex, query: string, limit?: number): SearchResult[];
263
+
264
+ /**
265
+ * The Ask AI route.
266
+ *
267
+ * One handler, framework-agnostic, built on the Web `Request`/`Response` types
268
+ * so it drops into a Next.js route file, an edge function, or any Fetch-based
269
+ * runtime. It runs the whole question pipeline: validate the body, rate-limit
270
+ * the caller, retrieve the grounding pages, build the prompt, stream the
271
+ * provider, and re-emit a provider-agnostic SSE stream to the browser.
272
+ *
273
+ * Two deliberate choices:
274
+ *
275
+ * - **Configuration is resolved eagerly.** {@link createAskAiRoute} validates
276
+ * the `ai` block when the route is built, so a typo in `docs.config.ts` fails
277
+ * the build. Deferring it to the first request would turn a site's typo into a
278
+ * reader's error message.
279
+ * - **The API key is read lazily, per request.** An edge runtime binds its
280
+ * environment per invocation, not at module load, so the key is looked up when
281
+ * it is needed. It is never logged; a missing key is reported by env var name.
282
+ *
283
+ * The browser protocol is three event names — `sources`, `text`, `done` — with
284
+ * `error` replacing the tail of the stream on failure. See
285
+ * {@link createAskAiRoute} for the exact payloads.
286
+ *
287
+ * @packageDocumentation
288
+ */
289
+
290
+ /**
291
+ * Where the route gets the site's pages: the array itself, or a loader for a
292
+ * site that builds it at runtime. Either way it is read once and treated as
293
+ * immutable build-time content.
294
+ *
295
+ * @public
296
+ */
297
+ type AskAiDocumentsSource = readonly SearchDocument[] | (() => Promise<readonly SearchDocument[]>);
298
+ /**
299
+ * Options for {@link createAskAiRoute}.
300
+ *
301
+ * @public
302
+ */
303
+ interface AskAiRouteOptions {
304
+ /** The site's raw `ai` block. Validated when the route is built. */
305
+ readonly config: AiConfig;
306
+ /** Display name used in the system prompt, normally `theme.name`. */
307
+ readonly siteName: string;
308
+ /**
309
+ * The API key value. Supply it only when the server resolves the key itself;
310
+ * otherwise leave it out and the route reads `ai.apiKeyEnv` per request.
311
+ */
312
+ readonly apiKey?: string;
313
+ /** Reads an environment variable. Defaults to `process.env`, looked up per request. */
314
+ readonly env?: (name: string) => string | undefined;
315
+ /** The site's pages, for retrieval. */
316
+ readonly documents: AskAiDocumentsSource;
317
+ /** Loads a page's Markdown by its URL. Returns `null` when there is none. */
318
+ readonly loadPageMarkdown: (url: string) => Promise<string | null>;
319
+ /** Fetch implementation passed to the provider. Defaults to the global `fetch`. */
320
+ readonly fetch?: FetchLike;
321
+ /** Clock for the rate limiter, for tests. Defaults to `Date.now`. */
322
+ readonly now?: () => number;
323
+ /** Upper bound on one answer, in tokens. Default 2048. */
324
+ readonly maxOutputTokens?: number;
325
+ }
326
+ /**
327
+ * A citation sent to the browser before the answer streams.
328
+ *
329
+ * @public
330
+ */
331
+ interface AskAiSource {
332
+ readonly url: string;
333
+ readonly title: string;
334
+ }
335
+ /**
336
+ * The Ask AI route's handlers, ready to re-export from a framework route file.
337
+ *
338
+ * @public
339
+ */
340
+ interface AskAiRoute {
341
+ readonly POST: (request: Request) => Promise<Response>;
342
+ }
343
+ /**
344
+ * Build the Ask AI route.
345
+ *
346
+ * The route answers `POST` with `{ "messages": [{ "role": "user", "content": "…" }] }`
347
+ * and streams `text/event-stream`:
348
+ *
349
+ * | Event | Payload | When |
350
+ * | --------- | -------------------------- | ------------------------------------- |
351
+ * | `sources` | `[{ url, title }]` | Once, first — the retrieved pages. |
352
+ * | `text` | `{ text }` | Per delta, appended in order. |
353
+ * | `done` | `{}` | Last event of a successful answer. |
354
+ * | `error` | `{ message }` | Replaces the tail; one readable line. |
355
+ *
356
+ * Failures before the stream starts are plain JSON, not SSE: `400` for a bad
357
+ * body (the message names the offending field), `429` with `Retry-After` when
358
+ * the caller is over the limit, and `500` when the API key is not set on the
359
+ * server.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * // app/api/ask-ai/route.ts
364
+ * export const { POST } = createAskAiRoute({
365
+ * config: docsConfig.ai!,
366
+ * siteName: docsConfig.theme.name,
367
+ * documents: searchDocuments,
368
+ * loadPageMarkdown: readPageMarkdown,
369
+ * });
370
+ * ```
371
+ *
372
+ * @param options - the site's `ai` block, its pages, and the Markdown loader
373
+ * @returns the route's `POST` handler
374
+ * @throws {@link AiConfigError} when the `ai` block or the wiring is invalid
375
+ * @public
376
+ */
377
+ declare function createAskAiRoute(options: AskAiRouteOptions): AskAiRoute;
378
+
379
+ /**
380
+ * Theme → CSS.
381
+ *
382
+ * A site declares its palette in config; the framework turns it into CSS custom
383
+ * properties. This is the seam that lets each organization brand its docs
384
+ * without touching the framework: the values live in the site, the mapping
385
+ * lives here.
386
+ *
387
+ * @packageDocumentation
388
+ */
389
+
390
+ /**
391
+ * Build the CSS that applies a site's theme colours. Inject the returned string
392
+ * into a `<style>` tag so it overrides the framework defaults.
393
+ *
394
+ * @param theme - the site's theme configuration
395
+ * @returns a CSS string (empty when no colours are declared)
396
+ * @public
397
+ */
398
+ declare function buildThemeCss(theme: ThemeConfig): string;
399
+
400
+ /**
401
+ * SEO metadata, derived from {@link DocsConfig}.
402
+ *
403
+ * The framework owns *how* metadata is shaped — the title template, the
404
+ * canonical URL, the Open Graph and Twitter cards, the robots policy — so every
405
+ * site gets correct, consistent tags from its config alone. A site owns only
406
+ * the facts: its public origin, its sharing image, its description.
407
+ *
408
+ * These functions return plain objects that are structurally assignable to
409
+ * Next's `Metadata` and `MetadataRoute.*` types, so the framework needs no
410
+ * dependency on `next`. A site uses them directly:
411
+ *
412
+ * ```ts
413
+ * export const metadata: Metadata = buildMetadata(config);
414
+ * ```
415
+ *
416
+ * @packageDocumentation
417
+ */
418
+
419
+ /**
420
+ * The subset of Next's `Metadata` the framework produces. Literal types are
421
+ * used where Next expects them (`openGraph.type`, `twitter.card`) so the result
422
+ * assigns to `Metadata` without a cast.
423
+ *
424
+ * @public
425
+ */
426
+ interface DocsMetadata {
427
+ readonly metadataBase?: URL;
428
+ readonly title: string | {
429
+ readonly default: string;
430
+ readonly template: string;
431
+ };
432
+ readonly description?: string;
433
+ readonly keywords?: string[];
434
+ readonly alternates?: {
435
+ readonly canonical?: string;
436
+ };
437
+ /**
438
+ * The site icon, from {@link ThemeConfig.favicon}. Shaped as Next's `Icons`
439
+ * object so the result assigns to `Metadata` without a cast.
440
+ */
441
+ readonly icons?: {
442
+ readonly icon: string;
443
+ };
444
+ readonly robots?: {
445
+ readonly index: boolean;
446
+ readonly follow: boolean;
447
+ };
448
+ readonly openGraph?: {
449
+ readonly type: 'website';
450
+ readonly siteName: string;
451
+ readonly title: string;
452
+ readonly description?: string;
453
+ readonly url?: string;
454
+ readonly images?: {
455
+ readonly url: string;
456
+ }[];
457
+ };
458
+ readonly twitter?: {
459
+ readonly card: 'summary' | 'summary_large_image';
460
+ readonly title: string;
461
+ readonly description?: string;
462
+ readonly site?: string;
463
+ readonly images?: string[];
464
+ };
465
+ }
466
+ /**
467
+ * Per-page metadata inputs. Omit everything for the site-wide default (the home
468
+ * document): the title is then {@link ThemeConfig.name} verbatim and the
469
+ * template is exposed for inner pages.
470
+ *
471
+ * @public
472
+ */
473
+ interface PageSeo {
474
+ /** The page title, before the template is applied. */
475
+ readonly title?: string;
476
+ /** The page description; falls back to {@link SeoConfig.description}. */
477
+ readonly description?: string;
478
+ /** The page path for the canonical URL, e.g. `/docs/guides/refunds`. */
479
+ readonly path?: string;
480
+ /** Override the sharing image for this page. */
481
+ readonly ogImage?: string;
482
+ /** Extra keywords for this page, merged with the site-wide set. */
483
+ readonly keywords?: readonly string[];
484
+ /** Keep this page out of the index while the rest stays indexable. */
485
+ readonly noindex?: boolean;
486
+ }
487
+ /**
488
+ * Build a page's (or the site's) metadata from config.
489
+ *
490
+ * Call it with no page for the root layout — you get the default title plus the
491
+ * template inner pages inherit. Call it with a {@link PageSeo} in a page's
492
+ * `generateMetadata` for that page's title, canonical URL, and cards.
493
+ *
494
+ * {@link ThemeConfig.favicon} becomes the `icons` field, so declaring the
495
+ * favicon in config is all a site does — no `<link rel="icon">` by hand.
496
+ *
497
+ * @param config - the site configuration
498
+ * @param page - the page's metadata inputs; omit for the site default
499
+ * @returns metadata assignable to Next's `Metadata`
500
+ * @public
501
+ */
502
+ declare function buildMetadata(config: DocsConfig, page?: PageSeo): DocsMetadata;
503
+ /**
504
+ * A robots policy, assignable to Next's `MetadataRoute.Robots`.
505
+ *
506
+ * @public
507
+ */
508
+ interface DocsRobots {
509
+ readonly rules: {
510
+ readonly userAgent: string;
511
+ readonly allow?: string;
512
+ readonly disallow?: string | string[];
513
+ };
514
+ readonly sitemap?: string;
515
+ readonly host?: string;
516
+ }
517
+ /**
518
+ * Build the robots policy. A `noindex` (or auth-gated) site disallows crawling
519
+ * entirely; a public site allows everything except the sign-in and API routes,
520
+ * which carry no indexable content. Points crawlers at the sitemap when a
521
+ * `siteUrl` is set.
522
+ *
523
+ * @param config - the site configuration
524
+ * @returns robots rules for `app/robots.ts`
525
+ * @public
526
+ */
527
+ declare function buildRobots(config: DocsConfig): DocsRobots;
528
+ /**
529
+ * One sitemap entry a site supplies (typically from the page tree).
530
+ *
531
+ * @public
532
+ */
533
+ interface SitemapEntry {
534
+ /** Site-relative path, e.g. `/docs/guides/refunds`. */
535
+ readonly path: string;
536
+ /** Last-modified date, if known. */
537
+ readonly lastModified?: Date | string;
538
+ }
539
+ /**
540
+ * How often a crawler should revisit a page. The values Google documents for
541
+ * `<changefreq>`.
542
+ *
543
+ * @public
544
+ */
545
+ type SitemapChangeFrequency = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
546
+ /**
547
+ * A resolved sitemap row, assignable to Next's `MetadataRoute.Sitemap[number]`.
548
+ *
549
+ * @public
550
+ */
551
+ interface DocsSitemapEntry {
552
+ readonly url: string;
553
+ readonly lastModified?: Date | string;
554
+ readonly changeFrequency: SitemapChangeFrequency;
555
+ readonly priority: number;
556
+ }
557
+ /**
558
+ * Overrides for {@link buildSitemap}. Every field is optional, and the defaults
559
+ * suit a documentation site that publishes continuously.
560
+ *
561
+ * @public
562
+ */
563
+ interface BuildSitemapOptions {
564
+ /** Revisit hint for every row. Default `'weekly'`. */
565
+ readonly changeFrequency?: SitemapChangeFrequency;
566
+ /** Priority for every page except the home path. Default `0.7`. */
567
+ readonly priority?: number;
568
+ /** Priority for the home path (`/`). Default `1`. */
569
+ readonly homePriority?: number;
570
+ }
571
+ /**
572
+ * Build sitemap rows from the site's pages. The home path gets top priority;
573
+ * everything else a shade lower. Absolute URLs need a `siteUrl` in config;
574
+ * without one the paths are emitted relative, which most crawlers still accept.
575
+ *
576
+ * A site that publishes on a slower cycle, or that wants its guides to outrank
577
+ * its generated reference pages, overrides the defaults:
578
+ *
579
+ * @example
580
+ * ```ts
581
+ * buildSitemap(entries, config, { changeFrequency: 'monthly', priority: 0.5 });
582
+ * ```
583
+ *
584
+ * @param entries - the site's page paths (and optional modified dates)
585
+ * @param config - the site configuration, for the origin
586
+ * @param options - override the revisit hint and the priorities
587
+ * @returns sitemap rows for `app/sitemap.ts`
588
+ * @public
589
+ */
590
+ declare function buildSitemap(entries: readonly SitemapEntry[], config: DocsConfig, options?: BuildSitemapOptions): DocsSitemapEntry[];
591
+
592
+ /**
593
+ * Turns the normalized navigation into a content-tree plan: which folders and
594
+ * `meta.json` files encode the navigation, and where each API page belongs.
595
+ * The site's `docs.json` stays the single source of truth — authors reorganize
596
+ * routes and groups by editing one file, never by moving generated files.
597
+ *
598
+ * The planner is pure; `@blaaiz/docs-core/generator` executes the plan.
599
+ *
600
+ * @packageDocumentation
601
+ */
602
+
603
+ /**
604
+ * A planned API reference page: one operation and the folder it belongs to.
605
+ *
606
+ * @public
607
+ */
608
+ interface PlannedApiPage {
609
+ /** Spec file reference from `docs.json`, relative to the content directory. */
610
+ readonly file: string;
611
+ /** The operation's HTTP method. */
612
+ readonly method: string;
613
+ /** The operation's API route. */
614
+ readonly apiPath: string;
615
+ /** Output folder, relative to the docs output directory (e.g. `api/authentication`). */
616
+ readonly dir: string;
617
+ /** Position within the group. */
618
+ readonly order: number;
619
+ }
620
+ /**
621
+ * A planned API group folder. The generator fills its page order once the
622
+ * operation slugs are known.
623
+ *
624
+ * @public
625
+ */
626
+ interface PlannedApiGroup {
627
+ readonly dir: string;
628
+ readonly title: string;
629
+ }
630
+ /**
631
+ * A `meta.json` file the plan wants written.
632
+ *
633
+ * @public
634
+ */
635
+ interface PlannedMeta {
636
+ /** Path relative to the docs output directory, e.g. `guides/meta.json`. */
637
+ readonly path: string;
638
+ readonly content: Record<string, unknown>;
639
+ }
640
+ /**
641
+ * The complete content-tree plan for one navigation.
642
+ *
643
+ * @public
644
+ */
645
+ interface DocsTreePlan {
646
+ /** Unique spec files referenced by the navigation, in order of appearance. */
647
+ readonly specs: readonly string[];
648
+ readonly apiPages: readonly PlannedApiPage[];
649
+ readonly apiGroups: readonly PlannedApiGroup[];
650
+ /** Fully-known meta files: the root, tab folders, and doc groups. */
651
+ readonly metas: readonly PlannedMeta[];
652
+ }
653
+ /**
654
+ * Options for {@link planDocsTree}.
655
+ *
656
+ * @public
657
+ */
658
+ interface PlanDocsTreeOptions {
659
+ /** Folder for generated API pages. Default `api`. */
660
+ readonly apiDir?: string;
661
+ }
662
+ /**
663
+ * Plan the content tree for a navigation.
664
+ *
665
+ * Conventions (Mintlify-shaped):
666
+ * - A tab whose items reference OpenAPI files becomes the API tab; its groups
667
+ * become folders under `apiDir`, named by slugified group title.
668
+ * - A tab of doc pages becomes the folder its pages share (their first path
669
+ * segment); a doc group's pages must share one directory.
670
+ * - Root-level doc pages (no `/` in the path) are listed in the root meta.
671
+ * - Tab folders get `root: true`, so the sidebar scopes to the active tab.
672
+ *
673
+ * @param navigation - the parsed navigation
674
+ * @param options - the API folder name
675
+ * @returns the plan the generator executes
676
+ * @public
677
+ */
678
+ declare function planDocsTree(navigation: Navigation, options?: PlanDocsTreeOptions): DocsTreePlan;
679
+
680
+ /**
681
+ * Page-to-Markdown conversion for the "Copy page / View as Markdown" feature.
682
+ *
683
+ * A docs page is authored in MDX: frontmatter, prose, and JSX components. An
684
+ * LLM wants none of that machinery — it wants clean Markdown. This module turns
685
+ * a raw MDX source into readable Markdown, and builds a runtime-agnostic route
686
+ * that serves it as `text/plain`.
687
+ *
688
+ * The transform is pure (string in, string out) and the route takes the content
689
+ * reader as an injected function, so `core` never touches a filesystem or a
690
+ * framework: the consuming site decides where its MDX lives.
691
+ *
692
+ * @packageDocumentation
693
+ */
694
+
695
+ /**
696
+ * Reads the raw MDX source for a page, addressed by its route slug segments
697
+ * (`undefined` or `[]` for the index). Returns `null` when no such page exists.
698
+ *
699
+ * The site owns this: it knows where its content directory is.
700
+ *
701
+ * @public
702
+ */
703
+ type MdxReader = (slug: readonly string[] | undefined) => Promise<string | null>;
704
+ /**
705
+ * Options for {@link mdxToMarkdown}.
706
+ *
707
+ * @public
708
+ */
709
+ interface MdxToMarkdownOptions {
710
+ /** Heading used when the source declares no `title` in frontmatter. */
711
+ readonly fallbackTitle?: string;
712
+ /**
713
+ * Named OpenAPI documents, keyed by the document name the generated page
714
+ * references (`document="…"`). When the page's document is present, its
715
+ * operations are rendered in full — auth, parameters, request-body fields,
716
+ * and responses — instead of the bare `METHOD /path` line. When a page
717
+ * names no document and exactly one is supplied, that one is used.
718
+ */
719
+ readonly openApiDocuments?: Readonly<Record<string, OpenApiDocument>>;
720
+ }
721
+ /**
722
+ * Convert a raw MDX source into clean, LLM-friendly Markdown.
723
+ *
724
+ * Guide pages return their prose (frontmatter title + description prepended,
725
+ * JSX stripped, code fences intact). Generated OpenAPI pages return a compact
726
+ * summary of the endpoint. Returns `null` for empty input.
727
+ *
728
+ * @param raw - the MDX file source
729
+ * @param options - optional fallback title
730
+ * @returns the Markdown rendering, or `null` when `raw` is empty
731
+ * @public
732
+ */
733
+ declare function mdxToMarkdown(raw: string, options?: MdxToMarkdownOptions): string | null;
734
+ /**
735
+ * A Markdown route ready to re-export from a framework route file.
736
+ *
737
+ * @public
738
+ */
739
+ interface MarkdownRoute {
740
+ readonly GET: (request: Request, context: {
741
+ params: Promise<{
742
+ slug?: string[];
743
+ }>;
744
+ }) => Promise<Response>;
745
+ }
746
+ /**
747
+ * Options for {@link createMarkdownRoute}.
748
+ *
749
+ * @public
750
+ */
751
+ interface CreateMarkdownRouteOptions {
752
+ /** Reads the raw MDX for a page slug. Supplied by the site. */
753
+ readonly read: MdxReader;
754
+ /**
755
+ * Loads the site's named OpenAPI documents so generated API pages render
756
+ * their operations in full. Called per request — cache inside the loader
757
+ * when the document is expensive to build.
758
+ */
759
+ readonly loadOpenApiDocuments?: () => Readonly<Record<string, OpenApiDocument>> | Promise<Readonly<Record<string, OpenApiDocument>>>;
760
+ }
761
+ /**
762
+ * Build a drop-in route that serves a page as plain Markdown. It reads the raw
763
+ * MDX for the requested slug, converts it with {@link mdxToMarkdown}, and
764
+ * returns `text/plain` (or `404` when the page does not exist).
765
+ *
766
+ * @example
767
+ * ```ts
768
+ * // app/md/[[...slug]]/route.ts
769
+ * export const { GET } = createMarkdownRoute({ read: readDocMdx });
770
+ * ```
771
+ *
772
+ * @param options - the content reader
773
+ * @returns the route's `GET` handler
774
+ * @public
775
+ */
776
+ declare function createMarkdownRoute(options: CreateMarkdownRouteOptions): MarkdownRoute;
777
+
778
+ /**
779
+ * Allowed-domain checks.
780
+ *
781
+ * @packageDocumentation
782
+ */
783
+ /**
784
+ * Return whether an email address belongs to one of the allowed domains.
785
+ * Matching is case-insensitive and exact on the domain part.
786
+ *
787
+ * @param email - the email address to test
788
+ * @param allowedDomains - permitted domains, e.g. `['blaaiz.com']`
789
+ * @public
790
+ */
791
+ declare function isAllowedEmail(email: string, allowedDomains: readonly string[]): boolean;
792
+
793
+ /**
794
+ * The email identity provider.
795
+ *
796
+ * The simplest provider: a form posts an email; if it belongs to an allowed
797
+ * domain, a session is issued. It needs no external credentials, so it is ideal
798
+ * for local development and for organizations that gate by email domain alone.
799
+ *
800
+ * @packageDocumentation
801
+ */
802
+ /**
803
+ * Options for {@link createEmailSignIn}.
804
+ *
805
+ * @public
806
+ */
807
+ interface EmailSignInOptions {
808
+ readonly secret: string;
809
+ readonly allowedDomains: readonly string[];
810
+ /** Session lifetime in seconds. Default 8 hours. */
811
+ readonly ttlSeconds?: number;
812
+ /** Set the `Secure` cookie flag. Default `true`. */
813
+ readonly secureCookies?: boolean;
814
+ /** Fallback redirect after sign-in when no `from` is supplied. Default `/`. */
815
+ readonly defaultRedirect?: string;
816
+ /**
817
+ * Where a browser (form) submission with a disallowed domain is sent back to,
818
+ * carrying `?error=forbidden`. Default `/signin`. JSON clients still get a
819
+ * `403` instead of a redirect.
820
+ */
821
+ readonly signInPath?: string;
822
+ }
823
+ /**
824
+ * Build the email sign-in POST handler.
825
+ *
826
+ * @param options - secret, allowed domains, and session settings
827
+ * @returns a request handler that issues a session; a browser submission with a
828
+ * disallowed domain is redirected back to the sign-in page with
829
+ * `?error=forbidden`, while a JSON request gets a `403`
830
+ * @public
831
+ */
832
+ declare function createEmailSignIn(options: EmailSignInOptions): (request: Request) => Promise<Response>;
833
+
834
+ /**
835
+ * The Google OAuth identity provider.
836
+ *
837
+ * Implements the OAuth 2.0 authorization-code flow against Google, restricted
838
+ * to the allowed email domains. Credentials are passed in by the caller (which
839
+ * reads them from environment variables named in config), never hard-coded.
840
+ *
841
+ * @packageDocumentation
842
+ */
843
+
844
+ /**
845
+ * Options for {@link createGoogleAuth}. `clientId` and `clientSecret` come from
846
+ * the environment; the config only names the variables.
847
+ *
848
+ * @public
849
+ */
850
+ interface GoogleAuthOptions {
851
+ readonly clientId: string;
852
+ readonly clientSecret: string;
853
+ /** The full callback URL registered with Google. */
854
+ readonly redirectUri: string;
855
+ /** The session-signing secret. */
856
+ readonly secret: string;
857
+ readonly allowedDomains: readonly string[];
858
+ readonly ttlSeconds?: number;
859
+ readonly secureCookies?: boolean;
860
+ readonly defaultRedirect?: string;
861
+ /**
862
+ * Where a failed callback (bad state, token error, disallowed account) is
863
+ * sent, carrying an `?error=` code. Default `/signin`.
864
+ */
865
+ readonly signInPath?: string;
866
+ /** Fetch implementation for the token exchange (injectable for tests). */
867
+ readonly fetch?: FetchLike;
868
+ }
869
+ /**
870
+ * The two Google OAuth route handlers.
871
+ *
872
+ * @public
873
+ */
874
+ interface GoogleAuthHandlers {
875
+ /** Redirects the browser to Google's consent screen. */
876
+ readonly start: (request: Request) => Response;
877
+ /** Handles Google's redirect back, issues a session, and redirects on. */
878
+ readonly callback: (request: Request) => Promise<Response>;
879
+ }
880
+ /**
881
+ * Build the Google OAuth handlers.
882
+ *
883
+ * @param options - client credentials, callback URL, and session settings
884
+ * @returns the `start` and `callback` route handlers
885
+ * @public
886
+ */
887
+ declare function createGoogleAuth(options: GoogleAuthOptions): GoogleAuthHandlers;
888
+
889
+ /**
890
+ * The auth gate — the enforcement half of authentication.
891
+ *
892
+ * Given a request, it decides: is there a valid session for an allowed email?
893
+ * If so the request passes (`null`); otherwise it returns a redirect to the
894
+ * sign-in page. The gate is identity-provider-agnostic — it does not care how
895
+ * the session was established, only that it is valid.
896
+ *
897
+ * @packageDocumentation
898
+ */
899
+ /**
900
+ * Options for {@link createAuthGate}.
901
+ *
902
+ * @public
903
+ */
904
+ interface AuthGateOptions {
905
+ /** The session-signing secret. */
906
+ readonly secret: string;
907
+ /** Email domains permitted access. */
908
+ readonly allowedDomains: readonly string[];
909
+ /** Where to send unauthenticated requests. Default `/signin`. */
910
+ readonly signInPath?: string;
911
+ /** Extra path prefixes that never require a session. */
912
+ readonly publicPaths?: readonly string[];
913
+ }
914
+ /**
915
+ * Build an auth gate for a Next.js middleware (or any Fetch runtime).
916
+ *
917
+ * @param options - secret, allowed domains, and sign-in path
918
+ * @returns a function returning `null` to allow, or a redirect `Response` to block
919
+ * @public
920
+ */
921
+ declare function createAuthGate(options: AuthGateOptions): (request: Request) => Promise<Response | null>;
922
+
923
+ /**
924
+ * The shared-secret identity provider.
925
+ *
926
+ * A two-step gate: an allowed-domain email, then one site-wide secret. Security
927
+ * lives entirely in the second step — the domain is re-checked and the secret
928
+ * compared in constant time — so the first step is only progressive disclosure
929
+ * and cannot be used to bypass anything. No client JavaScript: each step is a
930
+ * native form POST, the way an email → password flow works.
931
+ *
932
+ * @packageDocumentation
933
+ */
934
+ /**
935
+ * Options for {@link createSecretSignIn}.
936
+ *
937
+ * @public
938
+ */
939
+ interface SecretSignInOptions {
940
+ /** The session-signing secret (HMAC key), as for the other providers. */
941
+ readonly secret: string;
942
+ /** The shared access secret a reader must supply. Resolved from the env. */
943
+ readonly accessSecret: string;
944
+ readonly allowedDomains: readonly string[];
945
+ /** Session lifetime in seconds. Default 8 hours. */
946
+ readonly ttlSeconds?: number;
947
+ /** Set the `Secure` cookie flag. Default `true`. */
948
+ readonly secureCookies?: boolean;
949
+ /** Fallback redirect after sign-in when no `from` is supplied. Default `/`. */
950
+ readonly defaultRedirect?: string;
951
+ /** The sign-in page path, where each step and any error is shown. Default `/signin`. */
952
+ readonly signInPath?: string;
953
+ /** How long the between-steps email cookie lives. Default 15 minutes. */
954
+ readonly pendingTtlSeconds?: number;
955
+ }
956
+ /**
957
+ * Build the shared-secret sign-in POST handler. It serves both steps of the
958
+ * flow, told apart by whether the request carries a `secret` field:
959
+ *
960
+ * - **Email step** (no `secret`): validate the domain. On success, remember the
961
+ * email in a short-lived cookie and advance to the secret step; on failure,
962
+ * bounce back with `?error=forbidden`.
963
+ * - **Secret step** (`secret` present): read the remembered email, re-check its
964
+ * domain, and compare the secret in constant time. On success, issue the
965
+ * session; on failure, stay on the secret step with `?error=badsecret`.
966
+ *
967
+ * @param options - the two secrets, allowed domains, and session settings
968
+ * @returns a request handler for `/api/auth/secret`
969
+ * @public
970
+ */
971
+ declare function createSecretSignIn(options: SecretSignInOptions): (request: Request) => Promise<Response>;
972
+
973
+ /**
974
+ * Signed session tokens.
975
+ *
976
+ * A session is a small JSON payload (the verified email and an expiry) encoded
977
+ * and signed with HMAC-SHA256 via the Web Crypto API — so it works in Node, in
978
+ * an edge runtime, and in a Next.js middleware without any Node-only imports.
979
+ * The secret never leaves the server; the browser only holds the signed token.
980
+ *
981
+ * @packageDocumentation
982
+ */
983
+ /** The name of the session cookie. @public */
984
+ declare const SESSION_COOKIE = "docs_session";
985
+ /**
986
+ * The decoded session payload.
987
+ *
988
+ * @public
989
+ */
990
+ interface SessionPayload {
991
+ /** The verified email address. */
992
+ readonly email: string;
993
+ /** Expiry, as a Unix time in seconds. */
994
+ readonly exp: number;
995
+ }
996
+ /**
997
+ * Sign a session payload into a `data.signature` token.
998
+ *
999
+ * @public
1000
+ */
1001
+ declare function signSession(payload: SessionPayload, secret: string): Promise<string>;
1002
+ /**
1003
+ * Verify a session token and return its payload, or `null` when the signature
1004
+ * is invalid or the session has expired.
1005
+ *
1006
+ * @param token - the signed token
1007
+ * @param secret - the signing secret
1008
+ * @param nowSeconds - current Unix time; defaults to the real clock
1009
+ * @public
1010
+ */
1011
+ declare function verifySession(token: string, secret: string, nowSeconds?: number): Promise<SessionPayload | null>;
1012
+ /**
1013
+ * Read a cookie value from a `Cookie` header string.
1014
+ *
1015
+ * @public
1016
+ */
1017
+ declare function readCookie(cookieHeader: string | null, name: string): string | null;
1018
+ /**
1019
+ * Build a `Set-Cookie` header value carrying the session token.
1020
+ *
1021
+ * @public
1022
+ */
1023
+ declare function buildSessionCookie(token: string, options: {
1024
+ maxAgeSeconds: number;
1025
+ secure?: boolean;
1026
+ }): string;
1027
+ /**
1028
+ * Build a `Set-Cookie` header value that clears the session.
1029
+ *
1030
+ * @public
1031
+ */
1032
+ declare function clearSessionCookie(options?: {
1033
+ secure?: boolean;
1034
+ }): string;
1035
+
1036
+ /**
1037
+ * Sign-out handler.
1038
+ *
1039
+ * @packageDocumentation
1040
+ */
1041
+ /**
1042
+ * Options for {@link createSignOut}.
1043
+ *
1044
+ * @public
1045
+ */
1046
+ interface SignOutOptions {
1047
+ readonly secureCookies?: boolean;
1048
+ /** Where to send the browser after signing out. Default `/signin`. */
1049
+ readonly redirectTo?: string;
1050
+ }
1051
+ /**
1052
+ * Build a sign-out handler that clears the session cookie and redirects.
1053
+ *
1054
+ * @public
1055
+ */
1056
+ declare function createSignOut(options?: SignOutOptions): () => Response;
1057
+
1058
+ /**
1059
+ * OpenAPI-to-Markdown rendering for LLM corpora.
1060
+ *
1061
+ * A generated API reference page renders its parameters, schemas, and
1062
+ * responses at runtime from the OpenAPI document — none of that text exists in
1063
+ * the page's MDX. Ask AI and the `/md` route need it as text, so this module
1064
+ * renders one operation from the document into compact, deterministic
1065
+ * Markdown: auth requirements, parameters, request-body fields with types,
1066
+ * required markers, enums and defaults, and response shapes.
1067
+ *
1068
+ * The input document is site content and is never trusted: every lookup is
1069
+ * type-checked and malformed fragments are skipped rather than thrown on.
1070
+ * Recursion is bounded twice — a `seen` set of open `$ref` targets stops
1071
+ * self-referencing schemas, and a depth cap bounds legitimately deep nesting
1072
+ * with an explicit elision marker.
1073
+ *
1074
+ * @packageDocumentation
1075
+ */
1076
+
1077
+ /**
1078
+ * Addresses one operation inside an OpenAPI document.
1079
+ *
1080
+ * @public
1081
+ */
1082
+ interface OpenApiOperationRef {
1083
+ /** The path key, exactly as it appears under `paths`. */
1084
+ readonly path: string;
1085
+ /** The HTTP method, case-insensitive. */
1086
+ readonly method: string;
1087
+ }
1088
+ /**
1089
+ * Render one operation from an OpenAPI document as compact Markdown: auth,
1090
+ * parameters, request-body fields, and response shapes. The page-level title
1091
+ * and description are deliberately not rendered — the caller already has them
1092
+ * from the page frontmatter.
1093
+ *
1094
+ * Returns `null` when the document has no such operation.
1095
+ *
1096
+ * @param document - the (merged) OpenAPI document
1097
+ * @param ref - the operation's path and method
1098
+ * @returns Markdown for the operation, or `null` when it is not found
1099
+ * @public
1100
+ */
1101
+ declare function openApiOperationToMarkdown(document: OpenApiDocument, ref: OpenApiOperationRef): string | null;
1102
+
1103
+ /**
1104
+ * `docs.json` navigation adapter.
1105
+ *
1106
+ * Translates a Mintlify `docs.json` navigation block into the framework's
1107
+ * normalized {@link Navigation} tree. It understands the two page-string forms
1108
+ * Mintlify uses — a plain content path, and an OpenAPI entry of the form
1109
+ * `"<file> <METHOD> <route>"` — and it recurses through arbitrarily nested
1110
+ * groups.
1111
+ *
1112
+ * @packageDocumentation
1113
+ */
1114
+
1115
+ /**
1116
+ * Thrown when a `docs.json` navigation block does not match the expected shape.
1117
+ *
1118
+ * @public
1119
+ */
1120
+ declare class InvalidNavigationError extends Error {
1121
+ constructor(message: string);
1122
+ }
1123
+ /**
1124
+ * Parse a Mintlify `docs.json` object into the normalized {@link Navigation} tree.
1125
+ *
1126
+ * @param docsJson - the parsed contents of a `docs.json` file
1127
+ * @returns the normalized, ordered list of tabs
1128
+ * @throws {@link InvalidNavigationError} when the navigation shape is invalid
1129
+ * @public
1130
+ */
1131
+ declare function parseNavigation(docsJson: unknown): Navigation;
1132
+
1133
+ /**
1134
+ * OpenAPI merge adapter.
1135
+ *
1136
+ * A Mintlify-style API reference stores one OpenAPI file per endpoint. Renderers
1137
+ * (Scalar, fumadocs-openapi) want a single document. `mergeOpenApiDocuments`
1138
+ * combines many single-operation OpenAPI files into one document: it unions
1139
+ * servers, tags, and components, and assembles the paths. A genuine conflict —
1140
+ * the same method on the same route defined twice — is an error, not a
1141
+ * silent overwrite.
1142
+ *
1143
+ * @packageDocumentation
1144
+ */
1145
+
1146
+ /**
1147
+ * Options controlling the merge.
1148
+ *
1149
+ * @public
1150
+ */
1151
+ interface MergeOpenApiOptions {
1152
+ /** The `info` block of the merged document. */
1153
+ readonly info: OpenApiInfo;
1154
+ /**
1155
+ * Servers for the merged document. When omitted, servers are unioned from
1156
+ * the input documents (deduplicated by `url`).
1157
+ */
1158
+ readonly servers?: readonly OpenApiServer[];
1159
+ /** The OpenAPI version string of the merged document. Defaults to `3.1.0`. */
1160
+ readonly openapi?: string;
1161
+ }
1162
+ /**
1163
+ * Thrown when an input is not a usable OpenAPI document, or when two inputs
1164
+ * define the same operation (method + route).
1165
+ *
1166
+ * @public
1167
+ */
1168
+ declare class OpenApiMergeError extends Error {
1169
+ constructor(message: string);
1170
+ }
1171
+ /**
1172
+ * Merge many single-operation OpenAPI documents into one document.
1173
+ *
1174
+ * @param inputs - parsed OpenAPI documents, each typically holding one operation
1175
+ * @param options - the merged document's `info`, and optional server/version overrides
1176
+ * @returns the merged {@link OpenApiDocument}
1177
+ * @throws {@link OpenApiMergeError} on an invalid input or a duplicate operation
1178
+ * @public
1179
+ */
1180
+ declare function mergeOpenApiDocuments(inputs: readonly unknown[], options: MergeOpenApiOptions): OpenApiDocument;
1181
+
1182
+ export { AiConfig, type AiMessage, type AskAiDocumentsSource, type AskAiRoute, type AskAiRouteOptions, type AskAiSource, type AuthGateOptions, type BuildSitemapOptions, type CreateMarkdownRouteOptions, type CreateTryItProxyOptions, DocsConfig, type DocsMetadata, type DocsRobots, type DocsSitemapEntry, type DocsTreePlan, type EmailSignInOptions, type FetchLike, type GoogleAuthHandlers, type GoogleAuthOptions, type IndexedDocument, InvalidNavigationError, type MarkdownRoute, type MdxReader, type MdxToMarkdownOptions, type MergeOpenApiOptions, Navigation, OpenApiDocument, OpenApiInfo, OpenApiMergeError, type OpenApiOperationRef, OpenApiServer, type PageSeo, type PlanDocsTreeOptions, type PlannedApiGroup, type PlannedApiPage, type PlannedMeta, ProxyTargetError, SESSION_COOKIE, type SearchDocument, type SearchIndex, type SearchResult, type SecretSignInOptions, type SessionPayload, type SignOutOptions, type SitemapChangeFrequency, type SitemapEntry, ThemeConfig, type TryItEnvelope, type TryItProxyRoute, assertAllowedTarget, buildMetadata, buildRobots, buildSearchIndex, buildSessionCookie, buildSitemap, buildThemeCss, clearSessionCookie, createAskAiRoute, createAuthGate, createEmailSignIn, createGoogleAuth, createMarkdownRoute, createSecretSignIn, createSignOut, createTryItProxy, createTryItProxyRoute, isAllowedEmail, mdxToMarkdown, mergeOpenApiDocuments, openApiOperationToMarkdown, parseNavigation, planDocsTree, readCookie, searchIndex, signSession, unwrapProxyTarget, verifySession };