@solutiondesk/help 0.0.0-stage → 1.0.0-69d9f69
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 +249 -2
- package/dist/fumadocs.d.ts +614 -0
- package/dist/fumadocs.js +664 -0
- package/dist/index.cjs +344 -0
- package/dist/index.d.cts +427 -0
- package/dist/index.d.ts +427 -0
- package/dist/index.js +334 -0
- package/package.json +84 -3
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import { ComponentType, ReactNode } from 'react';
|
|
2
|
+
import { MetaData, PageData, StaticSource, VirtualFile, DynamicSource } from 'fumadocs-core/source';
|
|
3
|
+
import { TOCItemType } from 'fumadocs-core/toc';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The answers of the public help center API (`GET /v1/help/{workspace}/{site}/…`).
|
|
7
|
+
* Written by hand so the package has no dependencies; a drift test in the
|
|
8
|
+
* SolutionDesk repository keeps them identical to the API's own contracts.
|
|
9
|
+
*
|
|
10
|
+
* Only what is publicly visible ever appears here: a page that is published,
|
|
11
|
+
* public and placed in the site's navigation — except the one page a valid
|
|
12
|
+
* preview token names. Absent values are `null`, never a missing key.
|
|
13
|
+
*
|
|
14
|
+
* Paths: a page's path is its folder slugs plus its slug, without leading or
|
|
15
|
+
* trailing slash (`guides/login`); the site's home page has the path `""`.
|
|
16
|
+
*/
|
|
17
|
+
/** The doc site itself. */
|
|
18
|
+
interface HelpPublicSite {
|
|
19
|
+
/** The site's handle in the URL (`hilfe`). */
|
|
20
|
+
slug: string;
|
|
21
|
+
name: string;
|
|
22
|
+
/** Main language (BCP 47 code, e.g. `de`). */
|
|
23
|
+
language: string;
|
|
24
|
+
/** Every language the site is offered in, main language first. */
|
|
25
|
+
languages: string[];
|
|
26
|
+
/** The docs website's base address (`https://help.acme.com/docs`), if set. */
|
|
27
|
+
websiteUrl: string | null;
|
|
28
|
+
}
|
|
29
|
+
/** A page in the navigation. */
|
|
30
|
+
interface HelpPublicTreePage {
|
|
31
|
+
type: "page";
|
|
32
|
+
/** The page's own slug (the last path segment; `index` for the home page). */
|
|
33
|
+
slug: string;
|
|
34
|
+
path: string;
|
|
35
|
+
title: string;
|
|
36
|
+
description: string | null;
|
|
37
|
+
/** A Lucide icon name (`BookOpen`). */
|
|
38
|
+
icon: string | null;
|
|
39
|
+
}
|
|
40
|
+
/** A folder (Fumadocs: a directory with `meta.json`). Empty folders are left out. */
|
|
41
|
+
interface HelpPublicTreeFolder {
|
|
42
|
+
type: "folder";
|
|
43
|
+
/** Stable node id. */
|
|
44
|
+
id: string;
|
|
45
|
+
slug: string;
|
|
46
|
+
/** The folder's path (its index page, if any, lives here). */
|
|
47
|
+
path: string;
|
|
48
|
+
title: string;
|
|
49
|
+
icon: string | null;
|
|
50
|
+
/** A tab (top level only; Fumadocs `root`). */
|
|
51
|
+
root: boolean;
|
|
52
|
+
defaultOpen: boolean;
|
|
53
|
+
collapsible: boolean;
|
|
54
|
+
/** The folder's own page, shown at the folder's path; null without one. */
|
|
55
|
+
index: HelpPublicTreePage | null;
|
|
56
|
+
children: HelpPublicTreeNode[];
|
|
57
|
+
}
|
|
58
|
+
/** A labelled divider between entries (Fumadocs `---Title---`). */
|
|
59
|
+
interface HelpPublicTreeSeparator {
|
|
60
|
+
type: "separator";
|
|
61
|
+
id: string;
|
|
62
|
+
title: string | null;
|
|
63
|
+
icon: string | null;
|
|
64
|
+
}
|
|
65
|
+
/** A menu entry pointing elsewhere: an https address or a path on the docs website. */
|
|
66
|
+
interface HelpPublicTreeLink {
|
|
67
|
+
type: "link";
|
|
68
|
+
id: string;
|
|
69
|
+
title: string;
|
|
70
|
+
url: string;
|
|
71
|
+
icon: string | null;
|
|
72
|
+
/** Open as an external link (Fumadocs `external:`). */
|
|
73
|
+
external: boolean;
|
|
74
|
+
}
|
|
75
|
+
/** One entry of the navigation tree, discriminated by `type`. */
|
|
76
|
+
type HelpPublicTreeNode = HelpPublicTreePage | HelpPublicTreeFolder | HelpPublicTreeSeparator | HelpPublicTreeLink;
|
|
77
|
+
/** `GET site?lang=` — the site and its navigation in one language. */
|
|
78
|
+
interface HelpPublicSitePayload {
|
|
79
|
+
site: HelpPublicSite;
|
|
80
|
+
/** The language the labels are in (`?lang=`: exact, base language, else the main one). */
|
|
81
|
+
locale: string;
|
|
82
|
+
/** The site's languages, main first (same as `site.languages`). */
|
|
83
|
+
languages: string[];
|
|
84
|
+
tree: HelpPublicTreeNode[];
|
|
85
|
+
}
|
|
86
|
+
/** A visible page without its text (`GET pages`: builds and sitemaps). */
|
|
87
|
+
interface HelpPublicPageSummary {
|
|
88
|
+
path: string;
|
|
89
|
+
slug: string;
|
|
90
|
+
title: string;
|
|
91
|
+
description: string | null;
|
|
92
|
+
icon: string | null;
|
|
93
|
+
/** The language this page's texts are in (falls back to the main language per page). */
|
|
94
|
+
locale: string;
|
|
95
|
+
/** The languages this page is offered in, main language first. */
|
|
96
|
+
languages: string[];
|
|
97
|
+
/** When it was first published (ISO 8601). */
|
|
98
|
+
publishedAt: string | null;
|
|
99
|
+
/** "Updated on", set deliberately by the authors; null when never set. */
|
|
100
|
+
contentUpdatedAt: string | null;
|
|
101
|
+
/** The last change of any kind (ISO 8601) — for sitemaps and caches. */
|
|
102
|
+
updatedAt: string;
|
|
103
|
+
/** The page on the docs website (`websiteUrl` + path), null without a website address. */
|
|
104
|
+
url: string | null;
|
|
105
|
+
}
|
|
106
|
+
/** `GET pages?lang=` — every visible page in reading order. */
|
|
107
|
+
interface HelpPublicPagesPayload {
|
|
108
|
+
locale: string;
|
|
109
|
+
languages: string[];
|
|
110
|
+
pages: HelpPublicPageSummary[];
|
|
111
|
+
}
|
|
112
|
+
/** A heading of the page, with the anchor id the `html` gives it. */
|
|
113
|
+
interface HelpPublicHeading {
|
|
114
|
+
level: number;
|
|
115
|
+
text: string;
|
|
116
|
+
id: string;
|
|
117
|
+
}
|
|
118
|
+
/** The directives a page uses (a website loads tab scripts only when needed). */
|
|
119
|
+
type HelpPublicBlock = "callout" | "steps" | "step" | "tabs" | "tab" | "cards" | "card";
|
|
120
|
+
/** A folder above a page, outermost first; `path` only when the folder has its own page. */
|
|
121
|
+
interface HelpPublicBreadcrumb {
|
|
122
|
+
title: string;
|
|
123
|
+
path: string | null;
|
|
124
|
+
}
|
|
125
|
+
/** The page before or after, in the tree's reading order (never across tabs). */
|
|
126
|
+
interface HelpPublicPageLink {
|
|
127
|
+
path: string;
|
|
128
|
+
title: string;
|
|
129
|
+
}
|
|
130
|
+
/** One page with its text. */
|
|
131
|
+
interface HelpPublicPage extends HelpPublicPageSummary {
|
|
132
|
+
/** The page's Markdown with directives (`:::callout`, `::::steps`, …). */
|
|
133
|
+
markdown: string;
|
|
134
|
+
/** Safe server-rendered HTML of `markdown` (stable `sd-*` classes for the directives). */
|
|
135
|
+
html: string;
|
|
136
|
+
headings: HelpPublicHeading[];
|
|
137
|
+
blocks: HelpPublicBlock[];
|
|
138
|
+
breadcrumbs: HelpPublicBreadcrumb[];
|
|
139
|
+
previous: HelpPublicPageLink | null;
|
|
140
|
+
next: HelpPublicPageLink | null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* `GET page?path=&lang=`. A path the page had before answers `301` with
|
|
144
|
+
* `Location` pointing at the new `page?path=` and the body {@link HelpPublicRedirect}.
|
|
145
|
+
*/
|
|
146
|
+
interface HelpPublicPagePayload {
|
|
147
|
+
page: HelpPublicPage;
|
|
148
|
+
}
|
|
149
|
+
/** The body of a `301` for a moved page. */
|
|
150
|
+
interface HelpPublicRedirect {
|
|
151
|
+
/** The page's current path. */
|
|
152
|
+
redirectTo: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* A page as its preview shows it: any status, any visibility, translations as
|
|
156
|
+
* soon as they have a title. `path` is null while the page isn't placed in the
|
|
157
|
+
* navigation (then without breadcrumbs and neighbours).
|
|
158
|
+
*/
|
|
159
|
+
interface HelpPublicPreviewPage extends Omit<HelpPublicPage, "path"> {
|
|
160
|
+
path: string | null;
|
|
161
|
+
status: "draft" | "published" | "archived";
|
|
162
|
+
visibility: "public" | "internal";
|
|
163
|
+
}
|
|
164
|
+
/** `GET preview?token=&lang=` — never cached. */
|
|
165
|
+
interface HelpPublicPreviewPayload {
|
|
166
|
+
page: HelpPublicPreviewPage;
|
|
167
|
+
}
|
|
168
|
+
/** One search hit. Title hits rank above heading hits above text hits. */
|
|
169
|
+
interface HelpPublicSearchHit {
|
|
170
|
+
path: string;
|
|
171
|
+
title: string;
|
|
172
|
+
description: string | null;
|
|
173
|
+
/** Plain text around the first match (escape it before putting it into HTML). */
|
|
174
|
+
excerpt: string;
|
|
175
|
+
/** The best matching heading, for a `path#id` link. */
|
|
176
|
+
heading: {
|
|
177
|
+
id: string;
|
|
178
|
+
text: string;
|
|
179
|
+
} | null;
|
|
180
|
+
/** The page on the docs website, null without a website address. */
|
|
181
|
+
url: string | null;
|
|
182
|
+
}
|
|
183
|
+
/** `GET search?q=&lang=&limit=` — at most 20 hits, best first. */
|
|
184
|
+
interface HelpPublicSearchPayload {
|
|
185
|
+
query: string;
|
|
186
|
+
locale: string;
|
|
187
|
+
languages: string[];
|
|
188
|
+
hits: HelpPublicSearchHit[];
|
|
189
|
+
}
|
|
190
|
+
/** What a help webhook announces. */
|
|
191
|
+
type HelpWebhookEvent = "page.published" | "page.updated" | "page.unpublished" | "page.deleted" | "navigation.updated" | "ping";
|
|
192
|
+
/** The body of a help webhook call (verify it first — see `verifyHelpWebhook`). */
|
|
193
|
+
interface HelpWebhookBody {
|
|
194
|
+
event: HelpWebhookEvent;
|
|
195
|
+
/** The workspace slug, as in the public API path. */
|
|
196
|
+
workspace: string;
|
|
197
|
+
/** The doc site's slug, as in the public API path. */
|
|
198
|
+
site: string;
|
|
199
|
+
/** The page's path (null for `navigation.updated` and `ping`). */
|
|
200
|
+
path: string | null;
|
|
201
|
+
/** Earlier paths — their pages are stale too (for `navigation.updated`: every path that moved). */
|
|
202
|
+
previousPaths: string[];
|
|
203
|
+
/** The languages the page is offered in after the change (the site's for navigation). */
|
|
204
|
+
locales: string[];
|
|
205
|
+
occurredAt: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Parsing the help center's Markdown the way the API renders it
|
|
210
|
+
* (`packages/db/src/help-markdown.ts`): GFM plus container directives in the
|
|
211
|
+
* generic syntax of `remark-directive`. Only the directive names below mean
|
|
212
|
+
* something; every other directive — and every leaf (`::x`) or text (`:x`)
|
|
213
|
+
* directive — is printed back as the text it was written as.
|
|
214
|
+
*/
|
|
215
|
+
/** The directive names the help center knows. */
|
|
216
|
+
declare const HELP_BLOCKS: readonly ["callout", "steps", "step", "tabs", "tab", "cards", "card"];
|
|
217
|
+
type HelpBlockName = (typeof HELP_BLOCKS)[number];
|
|
218
|
+
/** `callout` types (anything else is shown as `info`). */
|
|
219
|
+
declare const HELP_CALLOUT_TYPES: readonly ["info", "warn", "error", "success", "idea"];
|
|
220
|
+
type HelpCalloutType = (typeof HELP_CALLOUT_TYPES)[number];
|
|
221
|
+
/**
|
|
222
|
+
* The link target if it is one a reader may follow (http(s), mailto, `/path`,
|
|
223
|
+
* `#anchor`), else null. The same rule as the API's `safeMarkdownHref`:
|
|
224
|
+
*
|
|
225
|
+
* 1. Surrounding whitespace is trimmed.
|
|
226
|
+
* 2. Any ASCII control character anywhere → unsafe.
|
|
227
|
+
* 3. A target starting with `//`, `/\`, `\/` or `\\` (protocol-relative) → unsafe.
|
|
228
|
+
* 4. Otherwise allowed: `http://…` / `https://…`, `mailto:…`, `/…` and `#…`,
|
|
229
|
+
* each without whitespace inside.
|
|
230
|
+
*/
|
|
231
|
+
declare function safeHelpHref(raw: string | null | undefined): string | null;
|
|
232
|
+
|
|
233
|
+
interface HelpCalloutProps {
|
|
234
|
+
/** `info`, `warn`, `error`, `success` or `idea` (an unknown type arrives as `info`). */
|
|
235
|
+
type: HelpCalloutType;
|
|
236
|
+
title?: string;
|
|
237
|
+
children: ReactNode;
|
|
238
|
+
}
|
|
239
|
+
interface HelpStepsProps {
|
|
240
|
+
children: ReactNode;
|
|
241
|
+
}
|
|
242
|
+
interface HelpStepProps {
|
|
243
|
+
title?: string;
|
|
244
|
+
children: ReactNode;
|
|
245
|
+
}
|
|
246
|
+
interface HelpTabsProps {
|
|
247
|
+
/** The tab titles, in order (unique). */
|
|
248
|
+
items: string[];
|
|
249
|
+
children: ReactNode;
|
|
250
|
+
}
|
|
251
|
+
interface HelpTabProps {
|
|
252
|
+
/** The tab's entry in `items`. */
|
|
253
|
+
value: string;
|
|
254
|
+
children: ReactNode;
|
|
255
|
+
}
|
|
256
|
+
interface HelpCardsProps {
|
|
257
|
+
children: ReactNode;
|
|
258
|
+
}
|
|
259
|
+
interface HelpCardProps {
|
|
260
|
+
title: string;
|
|
261
|
+
/** A safe link target (http(s), mailto, `/path`, `#anchor`), else absent. */
|
|
262
|
+
href?: string;
|
|
263
|
+
/** The rendered icon (see `HelpBodyProps.icon`). */
|
|
264
|
+
icon?: ReactNode;
|
|
265
|
+
children: ReactNode;
|
|
266
|
+
}
|
|
267
|
+
interface HelpCodeProps {
|
|
268
|
+
code: string;
|
|
269
|
+
/** The fence's language (`ts`), if any. */
|
|
270
|
+
lang?: string;
|
|
271
|
+
/** `title="…"` of the fence, if any. */
|
|
272
|
+
title?: string;
|
|
273
|
+
}
|
|
274
|
+
interface HelpHeadingProps {
|
|
275
|
+
level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
276
|
+
/** The anchor id (the same the API's `headings` name). */
|
|
277
|
+
id: string;
|
|
278
|
+
children: ReactNode;
|
|
279
|
+
}
|
|
280
|
+
interface HelpLinkProps {
|
|
281
|
+
/** Already checked: http(s), mailto, `/path` or `#anchor`. */
|
|
282
|
+
href: string;
|
|
283
|
+
title?: string;
|
|
284
|
+
children: ReactNode;
|
|
285
|
+
}
|
|
286
|
+
interface HelpImageProps {
|
|
287
|
+
src: string;
|
|
288
|
+
alt: string;
|
|
289
|
+
title?: string;
|
|
290
|
+
}
|
|
291
|
+
/** Everything `HelpBody` renders through a component — replace any of them. */
|
|
292
|
+
interface HelpBodyComponents {
|
|
293
|
+
Callout: ComponentType<HelpCalloutProps>;
|
|
294
|
+
Steps: ComponentType<HelpStepsProps>;
|
|
295
|
+
Step: ComponentType<HelpStepProps>;
|
|
296
|
+
Tabs: ComponentType<HelpTabsProps>;
|
|
297
|
+
Tab: ComponentType<HelpTabProps>;
|
|
298
|
+
Cards: ComponentType<HelpCardsProps>;
|
|
299
|
+
Card: ComponentType<HelpCardProps>;
|
|
300
|
+
/** A code fence — e.g. swap in Fumadocs' `DynamicCodeBlock` for syntax highlighting. */
|
|
301
|
+
Code: ComponentType<HelpCodeProps>;
|
|
302
|
+
Heading: ComponentType<HelpHeadingProps>;
|
|
303
|
+
Link: ComponentType<HelpLinkProps>;
|
|
304
|
+
Image: ComponentType<HelpImageProps>;
|
|
305
|
+
}
|
|
306
|
+
/** The Fumadocs UI defaults. */
|
|
307
|
+
declare const helpBodyComponents: HelpBodyComponents;
|
|
308
|
+
interface HelpBodyProps {
|
|
309
|
+
/** The page's Markdown with directives (`page.markdown` from the API). */
|
|
310
|
+
markdown: string;
|
|
311
|
+
/**
|
|
312
|
+
* The page's `headings` from the API: their ids become the headings' anchors,
|
|
313
|
+
* so they always match `getHelpToc(page.headings)`. Without them the ids are
|
|
314
|
+
* computed the API's way.
|
|
315
|
+
*/
|
|
316
|
+
headings?: readonly HelpPublicHeading[];
|
|
317
|
+
/** Replace any of the default Fumadocs UI components. */
|
|
318
|
+
components?: Partial<HelpBodyComponents>;
|
|
319
|
+
/**
|
|
320
|
+
* Turn a card's Lucide icon name (`Rocket`) into an element, e.g. with
|
|
321
|
+
* `lucide-react`: `(name) => { const Icon = icons[name as keyof typeof icons]; return Icon ? <Icon /> : null; }`.
|
|
322
|
+
* Without it cards show no icon.
|
|
323
|
+
*/
|
|
324
|
+
icon?: (name: string) => ReactNode;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* A help page's Markdown with its blocks (callout, steps, tabs, cards, titled
|
|
328
|
+
* code fences) as Fumadocs UI components — a React Server Component, also fine
|
|
329
|
+
* on the client. The API's safety rules apply: raw HTML is shown as text,
|
|
330
|
+
* links only to http(s), mailto, `/paths` and `#anchors`, images only from
|
|
331
|
+
* http(s) or `/paths`; unknown directives stay the text they were written as.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* const page = await source.getPage(slugs)?.data.load();
|
|
335
|
+
* <DocsBody><HelpBody markdown={page.markdown} headings={page.headings} /></DocsBody>
|
|
336
|
+
*/
|
|
337
|
+
declare function HelpBody({ markdown, headings, components, icon }: HelpBodyProps): ReactNode;
|
|
338
|
+
|
|
339
|
+
/** Per-call options. */
|
|
340
|
+
interface RequestOptions {
|
|
341
|
+
/** Cancels the request (an `AbortSignal`). */
|
|
342
|
+
signal?: unknown;
|
|
343
|
+
/** Extra headers for this request. */
|
|
344
|
+
headers?: Record<string, string>;
|
|
345
|
+
/**
|
|
346
|
+
* Extra `fetch` options for this request, passed through unchanged — e.g.
|
|
347
|
+
* Next.js `{ next: { revalidate: 60, tags: ["legal"] } }` or `{ cache: "no-store" }`.
|
|
348
|
+
*/
|
|
349
|
+
fetchOptions?: Record<string, unknown>;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
interface VerifyWebhookOptions {
|
|
353
|
+
/** How old (or how far in the future) the signed time may be. Default 300 (5 minutes). */
|
|
354
|
+
toleranceSeconds?: number;
|
|
355
|
+
/** "Now" in milliseconds (or a `Date`) — for tests. Default `Date.now()`. */
|
|
356
|
+
now?: number | Date;
|
|
357
|
+
/**
|
|
358
|
+
* A Web Crypto implementation. Default `globalThis.crypto`. On Node 18 pass
|
|
359
|
+
* `require("node:crypto").webcrypto` (Node 19+ has it globally).
|
|
360
|
+
*/
|
|
361
|
+
crypto?: {
|
|
362
|
+
subtle: object;
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
interface HelpRevalidateOptions {
|
|
367
|
+
/** The webhook's signing secret (`whsec_…`), shown once in SolutionDesk. */
|
|
368
|
+
secret: string;
|
|
369
|
+
/**
|
|
370
|
+
* Called with every verified change (not for `ping`, the test call) —
|
|
371
|
+
* e.g. `revalidateTag("solutiondesk-help")` in Next.js. Throwing answers
|
|
372
|
+
* `500`, so SolutionDesk retries the call.
|
|
373
|
+
*/
|
|
374
|
+
revalidate: (body: HelpWebhookBody) => unknown;
|
|
375
|
+
/** Also call `revalidate` for `ping` (default false). */
|
|
376
|
+
includePing?: boolean;
|
|
377
|
+
/** For tests: the signature check's options (clock, Web Crypto). */
|
|
378
|
+
verifyOptions?: VerifyWebhookOptions;
|
|
379
|
+
}
|
|
380
|
+
/** The request parts the handler reads — what every `Request` has. */
|
|
381
|
+
interface HelpWebhookRequest {
|
|
382
|
+
headers: {
|
|
383
|
+
get(name: string): string | null;
|
|
384
|
+
};
|
|
385
|
+
text(): Promise<string>;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* A webhook endpoint for any framework with `Request`/`Response` (Next.js
|
|
389
|
+
* route handlers, Remix, Astro, Hono, Bun, Deno …): checks the
|
|
390
|
+
* `X-SolutionDesk-Signature`, then calls `revalidate`. Answers `204` when
|
|
391
|
+
* done, `401` for a wrong, missing or expired signature, `400` for a signed
|
|
392
|
+
* body that isn't a help webhook, `500` while no secret is set.
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* // app/api/solutiondesk/help/route.ts
|
|
396
|
+
* import { revalidateTag } from "next/cache";
|
|
397
|
+
* export const POST = createHelpRevalidateHandler({
|
|
398
|
+
* secret: process.env.SOLUTIONDESK_HELP_WEBHOOK_SECRET!,
|
|
399
|
+
* revalidate: () => revalidateTag("solutiondesk-help", "max"),
|
|
400
|
+
* });
|
|
401
|
+
*/
|
|
402
|
+
declare function createHelpRevalidateHandler(options: HelpRevalidateOptions): (request: HelpWebhookRequest) => Promise<Response>;
|
|
403
|
+
|
|
404
|
+
interface LangParams {
|
|
405
|
+
/** The language to ask for; overrides the client's `lang`. */
|
|
406
|
+
lang?: string;
|
|
407
|
+
}
|
|
408
|
+
interface GetPageParams extends LangParams {
|
|
409
|
+
/**
|
|
410
|
+
* What to do when the path is an earlier address of a page (the API answers
|
|
411
|
+
* `301` with `{ redirectTo }`):
|
|
412
|
+
* - `"follow"` (default): return the page; `movedFrom` holds the path you asked for.
|
|
413
|
+
* - `"manual"`: return `{ redirectTo }` with the current path instead.
|
|
414
|
+
*/
|
|
415
|
+
redirect?: "follow" | "manual";
|
|
416
|
+
}
|
|
417
|
+
interface SearchParams extends LangParams {
|
|
418
|
+
/** At most this many hits, 1–20 (default 20). */
|
|
419
|
+
limit?: number;
|
|
420
|
+
}
|
|
421
|
+
/** A page fetched with `redirect: "follow"`. */
|
|
422
|
+
interface HelpPageResult extends HelpPublicPagePayload {
|
|
423
|
+
/**
|
|
424
|
+
* The path you asked for when the page has moved to `page.path` since
|
|
425
|
+
* (redirect your page there, e.g. with a 301); null when it hasn't.
|
|
426
|
+
*/
|
|
427
|
+
movedFrom: string | null;
|
|
428
|
+
}
|
|
429
|
+
interface HelpClient {
|
|
430
|
+
/** The workspace this client reads. */
|
|
431
|
+
readonly workspace: string;
|
|
432
|
+
/** The doc site this client reads (its slug). */
|
|
433
|
+
readonly siteSlug: string;
|
|
434
|
+
/** The site and its navigation tree in one language (`GET …/site`). */
|
|
435
|
+
site(params?: LangParams, options?: RequestOptions): Promise<HelpPublicSitePayload>;
|
|
436
|
+
/** Every visible page without its text, in reading order (`GET …/pages`) — builds and sitemaps. */
|
|
437
|
+
pages(params?: LangParams, options?: RequestOptions): Promise<HelpPublicPagesPayload>;
|
|
438
|
+
/**
|
|
439
|
+
* One visible page with its Markdown, HTML, headings, breadcrumbs and
|
|
440
|
+
* neighbours (`GET …/page?path=`). The home page has the path `""`.
|
|
441
|
+
* Throws a `SolutionDeskError` with status 404 for an unknown or hidden page.
|
|
442
|
+
*/
|
|
443
|
+
page(path: string, params?: GetPageParams & {
|
|
444
|
+
redirect?: "follow";
|
|
445
|
+
}, options?: RequestOptions): Promise<HelpPageResult>;
|
|
446
|
+
page(path: string, params: GetPageParams & {
|
|
447
|
+
redirect: "manual";
|
|
448
|
+
}, options?: RequestOptions): Promise<HelpPublicPagePayload | HelpPublicRedirect>;
|
|
449
|
+
/** One visible page as plain Markdown (`GET …/page.md?path=`), title and source on top. */
|
|
450
|
+
pageMarkdown(path: string, params?: LangParams, options?: RequestOptions): Promise<string>;
|
|
451
|
+
/** Search the visible pages (`GET …/search?q=`): title hits before heading hits before text hits. */
|
|
452
|
+
search(query: string, params?: SearchParams, options?: RequestOptions): Promise<HelpPublicSearchPayload>;
|
|
453
|
+
/**
|
|
454
|
+
* The current state of a page (also a draft or an internal page) for your
|
|
455
|
+
* preview route — the `token` from your preview address (valid for one hour).
|
|
456
|
+
* The API sends it with `Cache-Control: no-store`; in Next.js also pass
|
|
457
|
+
* `fetchOptions: { cache: "no-store" }`.
|
|
458
|
+
*/
|
|
459
|
+
preview(token: string, params?: LangParams, options?: RequestOptions): Promise<HelpPublicPreviewPayload>;
|
|
460
|
+
/** The site's index in the llms.txt format (`GET …/llms.txt`). */
|
|
461
|
+
llmsTxt(params?: LangParams, options?: RequestOptions): Promise<string>;
|
|
462
|
+
/** Every visible page as Markdown, one after the other (`GET …/llms-full.txt`). */
|
|
463
|
+
llmsFullTxt(params?: LangParams, options?: RequestOptions): Promise<string>;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** Fumadocs' search data of a page (the shape of `remark-structure`). */
|
|
467
|
+
interface HelpStructuredData {
|
|
468
|
+
headings: {
|
|
469
|
+
id: string;
|
|
470
|
+
content: string;
|
|
471
|
+
}[];
|
|
472
|
+
contents: {
|
|
473
|
+
heading: string | undefined;
|
|
474
|
+
content: string;
|
|
475
|
+
}[];
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* A page's search data for Fumadocs (`createFromSource`): every heading with
|
|
479
|
+
* its anchor, and every paragraph, quote and table cell under the heading it
|
|
480
|
+
* belongs to — code is left out, as in Fumadocs' own `remark-structure`.
|
|
481
|
+
*/
|
|
482
|
+
declare function helpStructuredData(markdown: string, headings?: readonly HelpPublicHeading[]): HelpStructuredData;
|
|
483
|
+
|
|
484
|
+
/** What every page of a help source carries in `page.data`. */
|
|
485
|
+
interface HelpPageData extends PageData {
|
|
486
|
+
title: string;
|
|
487
|
+
description?: string;
|
|
488
|
+
/** A Lucide icon name (`BookOpen`) — add `lucideIconsPlugin()` to `loader()` to render it. */
|
|
489
|
+
icon?: string;
|
|
490
|
+
/** The page's path in the help center (`guides/login`, `""` for the home page). */
|
|
491
|
+
path: string;
|
|
492
|
+
/** The language this file was built for (the `lang` asked for; the API falls back per page). */
|
|
493
|
+
lang: string;
|
|
494
|
+
/**
|
|
495
|
+
* The page with its text (`markdown`, `html`, `headings`, `breadcrumbs`,
|
|
496
|
+
* `previous`/`next`). Fetched when called — or right away with
|
|
497
|
+
* `pages: "eager"`, then it resolves to the prefetched page.
|
|
498
|
+
* `null` when the page is gone (taken offline since the source was built,
|
|
499
|
+
* the API answers 404) — render your framework's 404, e.g. `notFound()`.
|
|
500
|
+
*/
|
|
501
|
+
load: () => Promise<HelpPublicPage | null>;
|
|
502
|
+
/**
|
|
503
|
+
* Fumadocs search (`createFromSource`) reads this; built from the page's
|
|
504
|
+
* Markdown. Empty for a page that is gone, so one missing page doesn't
|
|
505
|
+
* break the search index.
|
|
506
|
+
*/
|
|
507
|
+
structuredData: () => Promise<HelpStructuredData>;
|
|
508
|
+
/** The page with its text — only with `pages: "eager"`. */
|
|
509
|
+
page?: HelpPublicPage;
|
|
510
|
+
}
|
|
511
|
+
/** What every folder's `meta.json` of a help source carries. */
|
|
512
|
+
interface HelpMetaData extends MetaData {
|
|
513
|
+
title?: string;
|
|
514
|
+
icon?: string;
|
|
515
|
+
root?: boolean;
|
|
516
|
+
defaultOpen?: boolean;
|
|
517
|
+
collapsible?: boolean;
|
|
518
|
+
pages: string[];
|
|
519
|
+
pagesIndex?: string;
|
|
520
|
+
}
|
|
521
|
+
type HelpSourceConfig = {
|
|
522
|
+
pageData: HelpPageData;
|
|
523
|
+
metaData: HelpMetaData;
|
|
524
|
+
};
|
|
525
|
+
type HelpSource = StaticSource<HelpSourceConfig>;
|
|
526
|
+
type HelpVirtualFile = VirtualFile<HelpSourceConfig>;
|
|
527
|
+
interface HelpSourceOptions {
|
|
528
|
+
/**
|
|
529
|
+
* Build one set of files per language, for a `loader()` with `i18n` (the
|
|
530
|
+
* default `dot` parser: `guides/login.en.mdx`, `guides/meta.en.json`). Use
|
|
531
|
+
* exactly the `languages` of your `defineI18n()` config. Without it the
|
|
532
|
+
* source holds one language — the client's `lang`, else the site's main
|
|
533
|
+
* language — and file names carry no language.
|
|
534
|
+
*/
|
|
535
|
+
languages?: readonly string[];
|
|
536
|
+
/**
|
|
537
|
+
* `"lazy"` (default): only the navigation is fetched (one request per
|
|
538
|
+
* language); a page's text is fetched when `page.data.load()` is called —
|
|
539
|
+
* cheap to build, one request per rendered page (cache it with your
|
|
540
|
+
* framework's fetch cache, see `requestOptions`).
|
|
541
|
+
* `"eager"`: every page is fetched while building (bounded by `concurrency`)
|
|
542
|
+
* and kept in `page.data.page` — slower to build, nothing fetched later;
|
|
543
|
+
* best for fully static exports.
|
|
544
|
+
*/
|
|
545
|
+
pages?: "lazy" | "eager";
|
|
546
|
+
/** With `pages: "eager"`: at most this many page requests at once (default 6). */
|
|
547
|
+
concurrency?: number;
|
|
548
|
+
/**
|
|
549
|
+
* Passed to every request, e.g. Next.js
|
|
550
|
+
* `{ fetchOptions: { next: { tags: ["solutiondesk-help"], revalidate: 300 } } }`.
|
|
551
|
+
*/
|
|
552
|
+
requestOptions?: RequestOptions;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* The entry of a tree node in its folder's `meta.json` `pages` (Fumadocs
|
|
556
|
+
* syntax): a page or folder name, `---[Icon]Title---`, `[Icon][Title](url)`,
|
|
557
|
+
* `external:[Title](url)`.
|
|
558
|
+
*/
|
|
559
|
+
declare function helpMetaEntry(node: HelpPublicTreeNode): string;
|
|
560
|
+
interface HelpFilesOptions {
|
|
561
|
+
/** Append `.<lang>` to every file name (Fumadocs' `dot` i18n parser). */
|
|
562
|
+
suffix?: string;
|
|
563
|
+
/** The language the files are for (`page.data.lang`). */
|
|
564
|
+
lang: string;
|
|
565
|
+
/** Loads a page's text (`page.data.load`); `null` when the page is gone. */
|
|
566
|
+
load: (path: string) => Promise<HelpPublicPage | null>;
|
|
567
|
+
/** Prefetched pages by path (`pages: "eager"`); `null` for a page that was gone. */
|
|
568
|
+
prefetched?: ReadonlyMap<string, HelpPublicPage | null>;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* The Fumadocs virtual files for one language of the site: a `.mdx` page file
|
|
572
|
+
* per page (a folder's own page as `<folder>/index.mdx`, the home page as
|
|
573
|
+
* `index.mdx` at the top, any other page named `index` as `index_.mdx`) and a
|
|
574
|
+
* `meta.json` per folder plus one at the top that fixes the order. Every file
|
|
575
|
+
* path is unique. Exported for custom setups; `createHelpSource` uses it.
|
|
576
|
+
*/
|
|
577
|
+
declare function helpTreeToFiles(payload: HelpPublicSitePayload, options: HelpFilesOptions): HelpVirtualFile[];
|
|
578
|
+
/** Every page path of a tree (index pages included), in reading order. */
|
|
579
|
+
declare function helpTreePaths(tree: readonly HelpPublicTreeNode[]): string[];
|
|
580
|
+
/**
|
|
581
|
+
* A Fumadocs source of a help site, for `loader()`:
|
|
582
|
+
*
|
|
583
|
+
* ```ts
|
|
584
|
+
* const help = createHelpClient({ workspace: "acme", site: "docs" });
|
|
585
|
+
* export const source = loader({ baseUrl: "/docs", source: await createHelpSource(help) });
|
|
586
|
+
* ```
|
|
587
|
+
*
|
|
588
|
+
* One `site` request per language builds the navigation; texts come with
|
|
589
|
+
* `page.data.load()` (or all at once with `pages: "eager"`). The tree is a
|
|
590
|
+
* snapshot — rebuild the loader to pick up changes (see the README).
|
|
591
|
+
*/
|
|
592
|
+
declare function createHelpSource(client: HelpClient, options?: HelpSourceOptions): Promise<HelpSource>;
|
|
593
|
+
/**
|
|
594
|
+
* The same as a Fumadocs dynamic source, for `dynamicLoader()` from
|
|
595
|
+
* `fumadocs-core/source/dynamic`: built on first use, rebuilt after
|
|
596
|
+
* `loader.revalidate()` (e.g. from your webhook route).
|
|
597
|
+
*/
|
|
598
|
+
declare function helpDynamicSource(client: HelpClient, options?: HelpSourceOptions): DynamicSource<HelpSourceConfig>;
|
|
599
|
+
|
|
600
|
+
interface HelpTocOptions {
|
|
601
|
+
/** Leave out headings below this level (default 1 — all). */
|
|
602
|
+
minLevel?: number;
|
|
603
|
+
/** Leave out headings above this level (default 6 — all). */
|
|
604
|
+
maxLevel?: number;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* The page's table of contents for Fumadocs (`<DocsPage toc={…}>`), from the
|
|
608
|
+
* API's `headings` — the same ids `HelpBody` gives the headings.
|
|
609
|
+
*/
|
|
610
|
+
declare function getHelpToc(headings: readonly HelpPublicHeading[] | {
|
|
611
|
+
headings: readonly HelpPublicHeading[];
|
|
612
|
+
}, options?: HelpTocOptions): TOCItemType[];
|
|
613
|
+
|
|
614
|
+
export { HELP_BLOCKS, HELP_CALLOUT_TYPES, type HelpBlockName, HelpBody, type HelpBodyComponents, type HelpBodyProps, type HelpCalloutProps, type HelpCalloutType, type HelpCardProps, type HelpCardsProps, type HelpCodeProps, type HelpFilesOptions, type HelpHeadingProps, type HelpImageProps, type HelpLinkProps, type HelpMetaData, type HelpPageData, type HelpRevalidateOptions, type HelpSource, type HelpSourceConfig, type HelpSourceOptions, type HelpStepProps, type HelpStepsProps, type HelpStructuredData, type HelpTabProps, type HelpTabsProps, type HelpTocOptions, type HelpVirtualFile, type HelpWebhookRequest, createHelpRevalidateHandler, createHelpSource, getHelpToc, helpBodyComponents, helpDynamicSource, helpMetaEntry, helpStructuredData, helpTreePaths, helpTreeToFiles, safeHelpHref };
|