@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.
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/dist/chunk-3ZX4WIE3.js +2984 -0
- package/dist/chunk-3ZX4WIE3.js.map +1 -0
- package/dist/chunk-JCYR6RPE.js +31 -0
- package/dist/chunk-JCYR6RPE.js.map +1 -0
- package/dist/chunk-ZKOOKLZ3.js +124 -0
- package/dist/chunk-ZKOOKLZ3.js.map +1 -0
- package/dist/cli.js +534 -0
- package/dist/cli.js.map +1 -0
- package/dist/generator.cjs +508 -0
- package/dist/generator.cjs.map +1 -0
- package/dist/generator.d.cts +122 -0
- package/dist/generator.d.ts +122 -0
- package/dist/generator.js +177 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.cjs +3024 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1182 -0
- package/dist/index.d.ts +1182 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation-CGqFIPlP.d.cts +498 -0
- package/dist/navigation-CGqFIPlP.d.ts +498 -0
- package/dist/openapi-types-CJ6p5Cux.d.cts +78 -0
- package/dist/openapi-types-CJ6p5Cux.d.ts +78 -0
- package/dist/ui/api-try-it.cjs +654 -0
- package/dist/ui/api-try-it.cjs.map +1 -0
- package/dist/ui/api-try-it.d.cts +78 -0
- package/dist/ui/api-try-it.d.ts +78 -0
- package/dist/ui/api-try-it.js +509 -0
- package/dist/ui/api-try-it.js.map +1 -0
- package/dist/ui/ask-ai.cjs +810 -0
- package/dist/ui/ask-ai.cjs.map +1 -0
- package/dist/ui/ask-ai.d.cts +57 -0
- package/dist/ui/ask-ai.d.ts +57 -0
- package/dist/ui/ask-ai.js +808 -0
- package/dist/ui/ask-ai.js.map +1 -0
- package/dist/ui/copy-page.cjs +312 -0
- package/dist/ui/copy-page.cjs.map +1 -0
- package/dist/ui/copy-page.d.cts +33 -0
- package/dist/ui/copy-page.d.ts +33 -0
- package/dist/ui/copy-page.js +183 -0
- package/dist/ui/copy-page.js.map +1 -0
- package/dist/ui/mermaid.cjs +363 -0
- package/dist/ui/mermaid.cjs.map +1 -0
- package/dist/ui/mermaid.d.cts +13 -0
- package/dist/ui/mermaid.d.ts +13 -0
- package/dist/ui/mermaid.js +361 -0
- package/dist/ui/mermaid.js.map +1 -0
- package/dist/ui.cjs +661 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.d.cts +428 -0
- package/dist/ui.d.ts +428 -0
- package/dist/ui.js +537 -0
- package/dist/ui.js.map +1 -0
- package/package.json +145 -0
- package/patches/fumadocs-openapi.patch +173 -0
- package/skills/AGENTS-section.md +36 -0
- package/skills/SKILL.md +363 -0
- package/styles/api-reference.css +1417 -0
- package/styles/ask-ai.css +563 -0
- package/styles/auth.css +462 -0
- package/styles/docs.css +247 -0
- package/styles/home.css +376 -0
- package/templates/init/content/docs/index.mdx.tmpl +52 -0
- package/templates/init/content/docs/meta.json.tmpl +3 -0
- package/templates/init/content/docs.json.tmpl +12 -0
- package/templates/init/content/nav.json.tmpl +7 -0
- package/templates/init/docs.config.ts.tmpl +36 -0
- package/templates/init/env.example.tmpl +15 -0
package/dist/index.d.cts
ADDED
|
@@ -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 };
|