@stainless-api/docs 0.1.0-beta.99 → 1.0.0-beta.141
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/CHANGELOG.md +401 -0
- package/ambient.d.ts +6 -0
- package/eslint-suppressions.json +22 -6
- package/{eslint.config.js → eslint.config.ts} +1 -7
- package/package.json +62 -40
- package/plugin/buildAlgoliaIndex.ts +6 -12
- package/plugin/components/SDKSelect.astro +0 -6
- package/plugin/components/SnippetCode.tsx +6 -37
- package/plugin/components/search/SearchAlgolia.astro +1 -1
- package/plugin/components/search/SearchIsland.tsx +19 -13
- package/plugin/generateAPIReferenceLink.ts +0 -40
- package/plugin/globalJs/ai-dropdown-options.ts +22 -9
- package/plugin/globalJs/code-snippets.ts +5 -5
- package/plugin/globalJs/copy.ts +20 -91
- package/plugin/globalJs/navigation.ts +13 -13
- package/plugin/globalJs/summary-selection-tweak.ts +29 -0
- package/plugin/index.ts +107 -163
- package/plugin/loadPluginConfig.ts +49 -151
- package/plugin/markdown/highlighter.ts +100 -0
- package/plugin/markdown/index.ts +39 -0
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +2 -0
- package/plugin/react/Routing.tsx +10 -244
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +1 -1
- package/plugin/routes/Docs.astro +3 -1
- package/plugin/routes/Overview.astro +14 -7
- package/plugin/routes/llms.ts +186 -0
- package/plugin/routes/markdown.ts +62 -13
- package/plugin/sidebar-utils/sidebar-builder.ts +38 -12
- package/plugin/specs/defaultSpecLoader.ts +192 -0
- package/plugin/specs/fetchSpecSSR.ts +1 -1
- package/plugin/specs/utils.ts +86 -0
- package/shared/conditionalIntegration.ts +28 -0
- package/shared/getProsePages.ts +6 -7
- package/shared/virtualModule.ts +1 -26
- package/stl-docs/aiChatExamples.ts +31 -0
- package/stl-docs/chat/docs-chat-handler.ts +17 -0
- package/stl-docs/chat/hook.ts +225 -0
- package/stl-docs/chat/schemas.ts +27 -0
- package/stl-docs/chat/ui/AiChat.module.css +591 -0
- package/stl-docs/chat/ui/AiChat.tsx +175 -0
- package/stl-docs/chat/ui/Trigger.tsx +154 -0
- package/stl-docs/chat/ui/components/ChatControls.tsx +51 -0
- package/stl-docs/chat/ui/components/ChatEmpty.tsx +42 -0
- package/stl-docs/chat/ui/components/ChatLog.tsx +93 -0
- package/stl-docs/chat/ui/components/ChatMessage.tsx +47 -0
- package/stl-docs/chat/ui/components/CodeBlock.tsx +33 -0
- package/stl-docs/chat/ui/components/MessageFeedback.tsx +106 -0
- package/stl-docs/chat/ui/components/Table.tsx +15 -0
- package/stl-docs/chat/ui/components/ToolCall.tsx +34 -0
- package/stl-docs/chat/ui/components/hljs-github.css +81 -0
- package/stl-docs/chat/ui/scroll-manager.ts +86 -0
- package/stl-docs/chat/ui/types.ts +45 -0
- package/stl-docs/components/AiChatIsland.tsx +10 -12
- package/stl-docs/components/ContentPanel.astro +9 -0
- package/stl-docs/components/Footer.astro +89 -0
- package/stl-docs/components/Header.astro +0 -5
- package/stl-docs/components/PageFrame.astro +23 -8
- package/stl-docs/components/PageSidebar.astro +11 -0
- package/stl-docs/components/StainlessLogo.svg +4 -0
- package/stl-docs/components/TwoColumnContent.astro +2 -0
- package/stl-docs/components/headers/DefaultHeader.astro +6 -8
- package/stl-docs/components/headers/StackedHeader.astro +5 -53
- package/stl-docs/components/mintlify-compat/Accordion.astro +2 -2
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +0 -4
- package/stl-docs/components/mintlify-compat/Columns.astro +2 -2
- package/stl-docs/components/mintlify-compat/Frame.astro +2 -2
- package/stl-docs/components/mintlify-compat/Tab.astro +2 -2
- package/stl-docs/components/mintlify-compat/callouts/Callout.astro +2 -2
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +0 -4
- package/stl-docs/components/nav-tabs/NavDropdown.astro +12 -7
- package/stl-docs/components/nav-tabs/NavTabs.astro +5 -3
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +2 -0
- package/stl-docs/components/pagination/Pagination.astro +4 -2
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +2 -2
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +2 -2
- package/stl-docs/components/pagination/util.ts +3 -3
- package/stl-docs/components/sidebars/BaseSidebar.astro +72 -1
- package/stl-docs/disableCalloutSyntax.ts +1 -1
- package/stl-docs/fonts.ts +5 -5
- package/stl-docs/index.ts +76 -53
- package/stl-docs/loadStlDocsConfig.ts +38 -8
- package/stl-docs/og-image/components/OpenGraphFunctionSignature.tsx +64 -0
- package/stl-docs/og-image/components/OpenGraphImage.tsx +126 -0
- package/stl-docs/og-image/config.ts +56 -0
- package/stl-docs/og-image/image-gen/generate-api-reference-og-image.tsx +188 -0
- package/stl-docs/og-image/image-gen/generate-og-image.tsx +119 -0
- package/stl-docs/og-image/image-gen/get-logo-url.ts +47 -0
- package/stl-docs/og-image/index.ts +135 -0
- package/stl-docs/og-image/routes/add-og-image.ts +45 -0
- package/stl-docs/og-image/routes/get-api-reference-og-image.ts +36 -0
- package/stl-docs/og-image/routes/get-og-image.ts +28 -0
- package/stl-docs/og-image/theme.ts +43 -0
- package/stl-docs/og-image/utils.ts +14 -0
- package/stl-docs/proseDocSync.test.ts +74 -0
- package/stl-docs/proseDocSync.ts +344 -0
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +4 -12
- package/stl-docs/schema-extension.ts +12 -0
- package/stl-docs/tabsMiddleware.ts +1 -1
- package/styles/overrides.css +2 -14
- package/styles/page.css +210 -71
- package/styles/sidebar.css +30 -17
- package/styles/sl-variables.css +3 -8
- package/styles/stldocs-variables.css +2 -2
- package/styles/toc.css +8 -0
- package/tsconfig.json +1 -1
- package/virtual-module.d.ts +35 -11
- package/playground-virtual-modules.d.ts +0 -96
- package/plugin/globalJs/create-playground.shim.ts +0 -3
- package/plugin/globalJs/playground-data.shim.ts +0 -1
- package/plugin/globalJs/playground-data.ts +0 -14
- package/plugin/specs/FileCache.ts +0 -99
- package/plugin/specs/generateSpec.ts +0 -112
- package/plugin/specs/index.ts +0 -132
- package/plugin/specs/inputResolver.ts +0 -146
- package/plugin/specs/worker.ts +0 -199
- package/plugin/vendor/preview.worker.docs.js +0 -26108
- package/plugin/vendor/templates/cli.md +0 -1
- package/plugin/vendor/templates/go.md +0 -316
- package/plugin/vendor/templates/java.md +0 -89
- package/plugin/vendor/templates/kotlin.md +0 -89
- package/plugin/vendor/templates/node.md +0 -235
- package/plugin/vendor/templates/python.md +0 -251
- package/plugin/vendor/templates/ruby.md +0 -147
- package/plugin/vendor/templates/terraform.md +0 -60
- package/plugin/vendor/templates/typescript.md +0 -319
- package/scripts/vendor_deps.ts +0 -50
- package/stl-docs/components/ClientRouterHead.astro +0 -41
- package/stl-docs/components/content-panel/ContentPanel.astro +0 -42
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +0 -65
- package/stl-docs/proseSearchIndexing.ts +0 -606
package/plugin/react/Routing.tsx
CHANGED
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { marked, Tokens } from 'marked';
|
|
3
2
|
import { getDocsLanguages } from '../helpers/multiSpec';
|
|
4
3
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
CreateShikiHighlighterOptions,
|
|
8
|
-
type MarkdownProcessor,
|
|
9
|
-
} from '@astrojs/markdown-remark';
|
|
10
|
-
import remarkGfmAlerts from 'remark-github-alerts';
|
|
4
|
+
import { astroMarkdownRenderText } from '../markdown';
|
|
5
|
+
import { highlight } from '../markdown/highlighter';
|
|
11
6
|
|
|
12
7
|
import type { MarkdownHeading } from 'astro';
|
|
13
|
-
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
14
8
|
import type * as SDKJSON from '@stainless/sdk-json';
|
|
15
|
-
import { LanguageNames,
|
|
9
|
+
import { LanguageNames, type DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
16
10
|
|
|
17
|
-
import {
|
|
18
|
-
generateRoute,
|
|
19
|
-
parseStainlessPath,
|
|
20
|
-
walkTree,
|
|
21
|
-
getLanguageSnippet,
|
|
22
|
-
} from '@stainless-api/docs-ui/routing';
|
|
11
|
+
import { parseStainlessPath, getLanguageSnippet } from '@stainless-api/docs-ui/routing';
|
|
23
12
|
|
|
24
13
|
import {
|
|
25
14
|
DocsProvider,
|
|
26
15
|
MarkdownProvider,
|
|
27
16
|
NavigationProvider,
|
|
28
|
-
useSpec,
|
|
29
17
|
type ContentPanelLayout,
|
|
30
18
|
} from '@stainless-api/docs-ui/contexts';
|
|
31
19
|
|
|
@@ -45,15 +33,13 @@ import { Dropdown } from '@stainless-api/docs/components';
|
|
|
45
33
|
|
|
46
34
|
import {
|
|
47
35
|
RESOLVED_API_REFERENCE_PATH,
|
|
48
|
-
EXPAND_RESOURCES,
|
|
49
|
-
HIGHLIGHT_THEMES,
|
|
50
36
|
BREADCRUMB_CONFIG,
|
|
51
37
|
PROPERTY_SETTINGS,
|
|
52
38
|
ENABLE_CONTEXT_MENU,
|
|
53
39
|
EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS,
|
|
40
|
+
MIDDLEWARE,
|
|
54
41
|
} from 'virtual:stl-starlight-virtual-module';
|
|
55
42
|
import style from '@stainless-api/docs-ui/style';
|
|
56
|
-
import { BundledTheme, createHighlighter, HighlighterGeneric, type BundledLanguage } from 'shiki';
|
|
57
43
|
import {
|
|
58
44
|
SnippetCode,
|
|
59
45
|
SnippetContainer,
|
|
@@ -67,66 +53,6 @@ import { AIDropdown } from '../../stl-docs/components/AIDropdown';
|
|
|
67
53
|
import { ChevronsUpDownIcon } from 'lucide-react';
|
|
68
54
|
import { MethodDescription } from '../components/MethodDescription';
|
|
69
55
|
|
|
70
|
-
function isResourceNonEmpty(resource: SDKJSON.Resource) {
|
|
71
|
-
return (
|
|
72
|
-
Object.keys(resource.methods ?? {}).length > 0 ||
|
|
73
|
-
Object.keys(resource.subresources ?? {}).length > 0 ||
|
|
74
|
-
Object.keys(resource.models ?? {}).length > 0
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
type SidebarEntry = StarlightRouteData['sidebar'][number];
|
|
79
|
-
|
|
80
|
-
export function buildSidebar(
|
|
81
|
-
basePath: string,
|
|
82
|
-
language: DocsLanguage,
|
|
83
|
-
current: string,
|
|
84
|
-
spec: SDKJSON.Spec,
|
|
85
|
-
resources?: Record<string, SDKJSON.Resource>,
|
|
86
|
-
nested?: boolean,
|
|
87
|
-
): StarlightRouteData['sidebar'] {
|
|
88
|
-
const totalRoutes = Array.from(walkTree(spec, false)).filter(
|
|
89
|
-
(item) => item.data.kind === 'http_method',
|
|
90
|
-
).length;
|
|
91
|
-
|
|
92
|
-
return Object.values(resources ?? spec.resources ?? [])
|
|
93
|
-
.filter((resource) => isResourceNonEmpty(resource))
|
|
94
|
-
.sort((a, b) => (a.name.startsWith('$') === b.name.startsWith('$') ? 0 : a.name.startsWith('$') ? 1 : -1))
|
|
95
|
-
.map((resource) => {
|
|
96
|
-
const subs = buildSidebar(basePath, language, current, spec, resource.subresources, true);
|
|
97
|
-
|
|
98
|
-
const overview: SidebarEntry = {
|
|
99
|
-
type: 'link',
|
|
100
|
-
isCurrent: current === resource.stainlessPath,
|
|
101
|
-
attrs: { 'data-stldocs-overview': resource.name },
|
|
102
|
-
label: 'Overview',
|
|
103
|
-
href: generateRoute(basePath, language, resource.stainlessPath) ?? basePath,
|
|
104
|
-
badge: undefined,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const meths: SidebarEntry[] = Object.values(resource.methods ?? [])
|
|
108
|
-
.filter((method) => spec.decls?.[language]?.[method.stainlessPath])
|
|
109
|
-
.map((method) => ({
|
|
110
|
-
type: 'link',
|
|
111
|
-
isCurrent: current === method.stainlessPath,
|
|
112
|
-
attrs: { 'data-stldocs-method': method.httpMethod },
|
|
113
|
-
label: method.summary ?? method.name,
|
|
114
|
-
href: generateRoute(basePath, language, method.stainlessPath) ?? basePath,
|
|
115
|
-
badge: undefined,
|
|
116
|
-
}));
|
|
117
|
-
|
|
118
|
-
const shouldExpand = EXPAND_RESOURCES ?? totalRoutes < 20;
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
type: 'group',
|
|
122
|
-
label: resource.title,
|
|
123
|
-
badge: undefined,
|
|
124
|
-
collapsed: !shouldExpand || nested === true,
|
|
125
|
-
entries: [...(resources ? [] : [overview]), ...meths, ...subs],
|
|
126
|
-
};
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
56
|
export function buildPageNavigation(resource: SDKJSON.Resource, depth: number = 2): MarkdownHeading[] {
|
|
131
57
|
const output: MarkdownHeading[] = [{ depth, slug: resource.stainlessPath, text: resource.title }];
|
|
132
58
|
|
|
@@ -137,58 +63,6 @@ export function buildPageNavigation(resource: SDKJSON.Resource, depth: number =
|
|
|
137
63
|
return [...output, ...subs];
|
|
138
64
|
}
|
|
139
65
|
|
|
140
|
-
async function renderMarkdown(content: string) {
|
|
141
|
-
const highlighter = await astroHighlight();
|
|
142
|
-
|
|
143
|
-
const renderer = {
|
|
144
|
-
code({ text, lang }: Tokens.Code) {
|
|
145
|
-
return shikiHighlight({
|
|
146
|
-
highlighter,
|
|
147
|
-
content: text,
|
|
148
|
-
language: lang,
|
|
149
|
-
});
|
|
150
|
-
},
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
marked.use({ renderer });
|
|
154
|
-
return marked.parse(content, {
|
|
155
|
-
gfm: true,
|
|
156
|
-
}) as string;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function shikiHighlight({
|
|
160
|
-
highlighter,
|
|
161
|
-
content,
|
|
162
|
-
language,
|
|
163
|
-
themes,
|
|
164
|
-
}: {
|
|
165
|
-
highlighter: HighlighterGeneric<BundledLanguage, BundledTheme>;
|
|
166
|
-
content: string;
|
|
167
|
-
language?: string;
|
|
168
|
-
themes?: CreateShikiHighlighterOptions['themes'] | Record<string, 'stainless-docs-json'>;
|
|
169
|
-
}) {
|
|
170
|
-
let _themes = themes;
|
|
171
|
-
if (!themes && language === 'json') {
|
|
172
|
-
_themes = {
|
|
173
|
-
light: 'stainless-docs-json',
|
|
174
|
-
dark: 'stainless-docs-json',
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!_themes) {
|
|
179
|
-
_themes = HIGHLIGHT_THEMES;
|
|
180
|
-
}
|
|
181
|
-
return highlighter.codeToHtml(content, {
|
|
182
|
-
lang: language ?? 'javascript',
|
|
183
|
-
themes: _themes || {},
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async function highlight(content: string, language?: string) {
|
|
188
|
-
const highlighter = await astroHighlight();
|
|
189
|
-
return shikiHighlight({ highlighter, content, language });
|
|
190
|
-
}
|
|
191
|
-
|
|
192
66
|
export function SDKSelectReactComponent({
|
|
193
67
|
selected,
|
|
194
68
|
languages,
|
|
@@ -268,6 +142,7 @@ const componentOverrides = {
|
|
|
268
142
|
SnippetFooter,
|
|
269
143
|
SnippetResponse,
|
|
270
144
|
...(EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS ? { MethodDescription } : {}),
|
|
145
|
+
...MIDDLEWARE.componentOverrides,
|
|
271
146
|
} satisfies React.ComponentProps<typeof ComponentProvider>['components'];
|
|
272
147
|
|
|
273
148
|
export function RenderLibraries({ metadata }: { metadata: SpecMetadata }) {
|
|
@@ -293,7 +168,7 @@ export function RenderSpecOverview({ spec, language }: { spec: SDKJSON.Spec; lan
|
|
|
293
168
|
<DocsProvider spec={spec} language={language ?? 'node'}>
|
|
294
169
|
<ComponentProvider components={componentOverrides}>
|
|
295
170
|
<NavigationProvider basePath={RESOLVED_API_REFERENCE_PATH}>
|
|
296
|
-
<MarkdownProvider render={
|
|
171
|
+
<MarkdownProvider render={astroMarkdownRenderText} highlight={highlight}>
|
|
297
172
|
<div className={style.Overview}>
|
|
298
173
|
{resources
|
|
299
174
|
.filter(({ resource }) => !resource.name.startsWith('$'))
|
|
@@ -340,7 +215,7 @@ export function RenderSpec({
|
|
|
340
215
|
|
|
341
216
|
return (
|
|
342
217
|
<DocsProvider
|
|
343
|
-
spec={spec
|
|
218
|
+
spec={spec}
|
|
344
219
|
language={language ?? 'node'}
|
|
345
220
|
settings={{
|
|
346
221
|
contentPanelLayout,
|
|
@@ -349,12 +224,12 @@ export function RenderSpec({
|
|
|
349
224
|
>
|
|
350
225
|
<ComponentProvider components={componentOverrides}>
|
|
351
226
|
<NavigationProvider basePath={RESOLVED_API_REFERENCE_PATH} selectedPath={path}>
|
|
352
|
-
<MarkdownProvider render={
|
|
227
|
+
<MarkdownProvider render={astroMarkdownRenderText} highlight={highlight}>
|
|
353
228
|
{
|
|
354
229
|
<div className="stldocs-root stl-ui-not-prose">
|
|
355
230
|
<div className="stl-page-nav-container">
|
|
356
231
|
<SDKBreadcrumbs
|
|
357
|
-
spec={spec
|
|
232
|
+
spec={spec}
|
|
358
233
|
currentPath={currentPath}
|
|
359
234
|
basePath={RESOLVED_API_REFERENCE_PATH}
|
|
360
235
|
config={BREADCRUMB_CONFIG}
|
|
@@ -378,22 +253,6 @@ export function RenderSpec({
|
|
|
378
253
|
);
|
|
379
254
|
}
|
|
380
255
|
|
|
381
|
-
export function RenderMethod({ path }: { path: string }) {
|
|
382
|
-
const spec = useSpec();
|
|
383
|
-
if (!spec) return null;
|
|
384
|
-
|
|
385
|
-
const parsed = parseStainlessPath(path);
|
|
386
|
-
const resource = getResourceFromSpec(path, spec);
|
|
387
|
-
|
|
388
|
-
if (!resource || !parsed) {
|
|
389
|
-
console.warn(`Could not find resource or parsed path for '${path}'`);
|
|
390
|
-
return null;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const method = resource.methods[parsed.method!]!;
|
|
394
|
-
return <SDKMethod method={method} />;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
256
|
export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguage) {
|
|
398
257
|
const repoUrl = spec.metadata?.[language]?.repo_url;
|
|
399
258
|
|
|
@@ -410,96 +269,3 @@ export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguag
|
|
|
410
269
|
|
|
411
270
|
return spec.readme[language];
|
|
412
271
|
}
|
|
413
|
-
|
|
414
|
-
let astroShikiHighlighter:
|
|
415
|
-
| HighlighterGeneric<BundledLanguage, BundledTheme>
|
|
416
|
-
| Promise<HighlighterGeneric<BundledLanguage, BundledTheme>>
|
|
417
|
-
| null = null;
|
|
418
|
-
|
|
419
|
-
async function astroHighlight() {
|
|
420
|
-
if (astroShikiHighlighter) {
|
|
421
|
-
return astroShikiHighlighter;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
astroShikiHighlighter = createHighlighter({
|
|
425
|
-
themes: [
|
|
426
|
-
'github-light',
|
|
427
|
-
'github-dark',
|
|
428
|
-
{
|
|
429
|
-
name: 'stainless-docs-json',
|
|
430
|
-
colors: {
|
|
431
|
-
'editor.background': 'var(--stl-color-background)',
|
|
432
|
-
'editor.foreground': 'var(--stl-color-foreground)',
|
|
433
|
-
},
|
|
434
|
-
|
|
435
|
-
tokenColors: [
|
|
436
|
-
{
|
|
437
|
-
scope: ['comment', 'punctuation.definition.comment'],
|
|
438
|
-
settings: { foreground: 'var(--stl-color-foreground-muted)' },
|
|
439
|
-
},
|
|
440
|
-
// numbers, booleans, null
|
|
441
|
-
{
|
|
442
|
-
scope: ['constant.numeric', 'constant.language'],
|
|
443
|
-
settings: { foreground: 'var(--stl-color-orange-foreground)' },
|
|
444
|
-
},
|
|
445
|
-
// strings
|
|
446
|
-
{
|
|
447
|
-
scope: ['string', 'string.quoted', 'string.template'],
|
|
448
|
-
settings: { foreground: 'var(--stl-color-green-foreground)' },
|
|
449
|
-
},
|
|
450
|
-
// Keys, brackets
|
|
451
|
-
{
|
|
452
|
-
scope: ['support.type', 'meta'],
|
|
453
|
-
settings: { foreground: 'var(--stl-color-foreground)' },
|
|
454
|
-
},
|
|
455
|
-
// brackets
|
|
456
|
-
{
|
|
457
|
-
scope: ['meta'],
|
|
458
|
-
settings: { foreground: 'var(--stl-color-foreground-muted)' },
|
|
459
|
-
},
|
|
460
|
-
// built-in types
|
|
461
|
-
{
|
|
462
|
-
scope: ['support.type.builtin'],
|
|
463
|
-
settings: { foreground: 'var(--stl-color-purple-foreground)' },
|
|
464
|
-
},
|
|
465
|
-
],
|
|
466
|
-
},
|
|
467
|
-
],
|
|
468
|
-
langs: SupportedLanguageSyntaxes,
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
return astroShikiHighlighter;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Astro's markdown processor is a singleton
|
|
475
|
-
// Need to cache it instead of instantiating per request
|
|
476
|
-
let astroMarkdownProcessor: MarkdownProcessor;
|
|
477
|
-
async function astroMarkdown() {
|
|
478
|
-
if (!astroMarkdownProcessor) {
|
|
479
|
-
astroMarkdownProcessor = await createMarkdownProcessor({
|
|
480
|
-
gfm: true,
|
|
481
|
-
remarkPlugins: [remarkGfmAlerts],
|
|
482
|
-
shikiConfig: {
|
|
483
|
-
themes: HIGHLIGHT_THEMES,
|
|
484
|
-
},
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
return astroMarkdownProcessor;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
export async function astroMarkdownRender(content: string) {
|
|
492
|
-
const md = await astroMarkdown();
|
|
493
|
-
const output = await md.render(content);
|
|
494
|
-
|
|
495
|
-
// Map GFM callouts to the closest Starlight equivalent
|
|
496
|
-
output.code = output.code
|
|
497
|
-
.replaceAll('markdown-alert-caution', 'markdown-alert-danger')
|
|
498
|
-
.replaceAll('markdown-alert-warning', 'markdown-alert-caution')
|
|
499
|
-
.replaceAll('markdown-alert-important', 'markdown-alert-caution')
|
|
500
|
-
.replaceAll('markdown-alert-title', 'starlight-aside__title')
|
|
501
|
-
.replaceAll('markdown-alert-', 'starlight-aside--')
|
|
502
|
-
.replaceAll('markdown-alert', 'starlight-aside');
|
|
503
|
-
|
|
504
|
-
return output;
|
|
505
|
-
}
|
|
@@ -21,7 +21,7 @@ export function makePlaceholderItems(id: number) {
|
|
|
21
21
|
|
|
22
22
|
type StarlightConfig = Parameters<typeof starlight>[0];
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
type SidebarConfigEntry = Exclude<StarlightConfig['sidebar'], undefined>[number];
|
|
25
25
|
|
|
26
26
|
export function getAPIReferencePlaceholderItemFromSidebarConfig(
|
|
27
27
|
sidebar: SidebarConfigEntry[],
|
|
@@ -32,7 +32,7 @@ function markCurrentItems(sidebar: SidebarEntry[], currentSlug: string) {
|
|
|
32
32
|
return mutableSidebarInstance;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export const onRequest = defineRouteMiddleware(
|
|
35
|
+
export const onRequest = defineRouteMiddleware((context) => {
|
|
36
36
|
// if using content collection schema, use: context.locals.starlightRoute.entry.data.stainlessStarlight
|
|
37
37
|
// this worked without collections but relied on hijacking starlightRoute: context.props.frontmatter.stainlessStarlight
|
|
38
38
|
const slug = path.posix.join(import.meta.env.BASE_URL ?? '', `/${context.locals.starlightRoute.id}`); // same as .slug but not deprecated
|
package/plugin/routes/Docs.astro
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
|
|
3
|
-
import { getReadmeContent, buildPageNavigation, RenderSpec
|
|
3
|
+
import { getReadmeContent, buildPageNavigation, RenderSpec } from '../react/Routing';
|
|
4
|
+
import { astroMarkdownRender } from '../markdown';
|
|
4
5
|
import { getResourceFromSpec } from '@stainless-api/docs-ui/utils';
|
|
5
6
|
import { parseRoute, parseStainlessPath } from '@stainless-api/docs-ui/routing';
|
|
6
7
|
import {
|
|
@@ -120,3 +121,4 @@ if (props.kind === 'http_method' && props.stainlessPath) {
|
|
|
120
121
|
<script src="../globalJs/tooltip.ts"></script>
|
|
121
122
|
<script src="../globalJs/code-snippets.ts"></script>
|
|
122
123
|
<script src="../globalJs/method-descriptions.ts"></script>
|
|
124
|
+
<script src="../globalJs/summary-selection-tweak.ts"></script>
|
|
@@ -29,7 +29,7 @@ const metadata: SpecMetadata = langsWithSpecs.map(({ language, spec }) => [
|
|
|
29
29
|
|
|
30
30
|
// PageTitle override will skip rendering the default Starlight title
|
|
31
31
|
Astro.locals._stlStarlightPage = {
|
|
32
|
-
hasMarkdownRoute:
|
|
32
|
+
hasMarkdownRoute: true,
|
|
33
33
|
};
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -41,11 +41,17 @@ Astro.locals._stlStarlightPage = {
|
|
|
41
41
|
}}
|
|
42
42
|
>
|
|
43
43
|
<div class="stl-overview">
|
|
44
|
-
|
|
44
|
+
{
|
|
45
|
+
metadata.length > 0 && (
|
|
46
|
+
<>
|
|
47
|
+
<h3>Libraries</h3>
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
<div class="stldocs-root language-blocks stl-ui-not-prose not-content">
|
|
50
|
+
<RenderLibraries metadata={metadata} />
|
|
51
|
+
</div>
|
|
52
|
+
</>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
49
55
|
|
|
50
56
|
<h3>API Overview</h3>
|
|
51
57
|
|
|
@@ -62,8 +68,9 @@ Astro.locals._stlStarlightPage = {
|
|
|
62
68
|
gap: 1rem;
|
|
63
69
|
margin-top: 2rem;
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
width:
|
|
71
|
+
> * {
|
|
72
|
+
width: 0;
|
|
73
|
+
flex: 1 1 350px;
|
|
67
74
|
}
|
|
68
75
|
}
|
|
69
76
|
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import { base as ASTRO_BASE } from 'astro:config/server';
|
|
4
|
+
import { SITE_TITLE, API_REFERENCE_BASE_PATH } from 'virtual:stl-docs-virtual-module';
|
|
5
|
+
import { LLMS_TXT_DESCRIPTION, LLMS_TXT_DETAIL_THRESHOLD } from 'virtual:stl-starlight-virtual-module';
|
|
6
|
+
import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
|
|
7
|
+
import Markdoc from '@markdoc/markdoc';
|
|
8
|
+
import type { Node } from '@markdoc/markdoc';
|
|
9
|
+
import * as md from '@stainless-api/docs-ui/markdown/md';
|
|
10
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
11
|
+
import { generateRoute, walkTree } from '@stainless-api/docs-ui/routing';
|
|
12
|
+
|
|
13
|
+
export const prerender = true;
|
|
14
|
+
|
|
15
|
+
function joinUrlParts(...parts: (string | boolean | null | undefined)[]) {
|
|
16
|
+
return (
|
|
17
|
+
'/' +
|
|
18
|
+
parts
|
|
19
|
+
.map((p) => {
|
|
20
|
+
if (typeof p === 'string') {
|
|
21
|
+
return p.split('/');
|
|
22
|
+
}
|
|
23
|
+
return p;
|
|
24
|
+
})
|
|
25
|
+
.flat()
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join('/')
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ProsePageEntry = {
|
|
32
|
+
id: string;
|
|
33
|
+
title: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function isResourceEmpty(resource: SDKJSON.Resource) {
|
|
38
|
+
return Object.values(resource.methods).length < 1 && Object.values(resource.subresources ?? {}).length < 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function trimPath(path: string) {
|
|
42
|
+
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function apiHref(basePath: string, language: string, stainlessPath: string) {
|
|
46
|
+
const href = generateRoute(basePath, language, stainlessPath);
|
|
47
|
+
if (!href) return null;
|
|
48
|
+
return joinUrlParts(ASTRO_BASE, href, 'index.md');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function linkListItem(title: string, url: string, description?: string): Node {
|
|
52
|
+
const children = [md.link(url, title)];
|
|
53
|
+
if (description) children.push(md.text(`: ${description}`));
|
|
54
|
+
return md.item(md.inline(...children));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function generateProseIndex(routes: ProsePageEntry[], detailed: boolean) {
|
|
58
|
+
const pageEntryLink = (page: ProsePageEntry) =>
|
|
59
|
+
linkListItem(
|
|
60
|
+
page.title,
|
|
61
|
+
joinUrlParts(ASTRO_BASE, page.id === 'index' ? null : page.id, 'index.md'),
|
|
62
|
+
detailed ? page.description : undefined,
|
|
63
|
+
);
|
|
64
|
+
return [md.heading(2, 'Docs'), md.list(...routes.map(pageEntryLink))];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function renderMethods(basePath: string, language: string, methods: Record<string, SDKJSON.Method>) {
|
|
68
|
+
const output: Node[] = [];
|
|
69
|
+
|
|
70
|
+
for (const method of Object.values(methods)) {
|
|
71
|
+
const href = apiHref(basePath, language, method.stainlessPath);
|
|
72
|
+
if (href) output.push(linkListItem(method.title, href, method.summary));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return md.list(...output);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function renderResource(
|
|
79
|
+
basePath: string,
|
|
80
|
+
language: string,
|
|
81
|
+
detailed: boolean,
|
|
82
|
+
resource: SDKJSON.Resource,
|
|
83
|
+
): Node {
|
|
84
|
+
const href = apiHref(basePath, language, resource.stainlessPath);
|
|
85
|
+
const output = [md.paragraph(href ? md.link(href, resource.title) : md.text(resource.title))];
|
|
86
|
+
if (resource.methods && detailed) output.push(renderMethods(basePath, language, resource.methods));
|
|
87
|
+
if (resource.subresources) output.push(renderSubs(basePath, language, detailed, resource.subresources));
|
|
88
|
+
return md.item(...output);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function renderSubs(
|
|
92
|
+
basePath: string,
|
|
93
|
+
language: string,
|
|
94
|
+
detailed: boolean,
|
|
95
|
+
resources: Record<string, SDKJSON.Resource>,
|
|
96
|
+
): Node {
|
|
97
|
+
return md.list(
|
|
98
|
+
...Object.values(resources)
|
|
99
|
+
.filter((res) => !isResourceEmpty(res))
|
|
100
|
+
.map((sub) => renderResource(basePath, language, detailed, sub)),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function renderLanguageNote(basePath: string, languages: string[]) {
|
|
105
|
+
return [
|
|
106
|
+
md.paragraph(
|
|
107
|
+
md.text('Links below point to language-neutral HTTP documentation. '),
|
|
108
|
+
md.text(
|
|
109
|
+
'SDK-specific docs follow the same URL structure with the language inserted after the base path: ',
|
|
110
|
+
),
|
|
111
|
+
md.code(`${trimPath(basePath)}/{language}/resources/...`),
|
|
112
|
+
md.text('.'),
|
|
113
|
+
),
|
|
114
|
+
md.paragraph(md.text(`Available languages: ${languages.join(', ')}`)),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function generateRefIndex(
|
|
119
|
+
basePath: string,
|
|
120
|
+
languages: string[],
|
|
121
|
+
language: string,
|
|
122
|
+
detailed: boolean,
|
|
123
|
+
spec: SDKJSON.Spec,
|
|
124
|
+
) {
|
|
125
|
+
const output = [md.heading(2, 'API Reference'), ...renderLanguageNote(basePath, languages)];
|
|
126
|
+
|
|
127
|
+
for (const resource of Object.values(spec.resources)) {
|
|
128
|
+
if (isResourceEmpty(resource)) continue;
|
|
129
|
+
const href = apiHref(basePath, language, resource.stainlessPath);
|
|
130
|
+
output.push(md.heading(3, [href ? md.link(href, resource.title) : md.text(resource.title)]));
|
|
131
|
+
if (resource.methods && detailed) output.push(renderMethods(basePath, language, resource.methods));
|
|
132
|
+
if (resource.subresources) output.push(renderSubs(basePath, language, detailed, resource.subresources));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return output;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function generateMarkdownIndex({
|
|
139
|
+
siteTitle,
|
|
140
|
+
description,
|
|
141
|
+
basePath,
|
|
142
|
+
languages,
|
|
143
|
+
spec,
|
|
144
|
+
detailed,
|
|
145
|
+
proseRoutes,
|
|
146
|
+
}: {
|
|
147
|
+
siteTitle: string;
|
|
148
|
+
description: string | null;
|
|
149
|
+
basePath: string;
|
|
150
|
+
languages: string[];
|
|
151
|
+
spec: SDKJSON.Spec;
|
|
152
|
+
detailed: boolean;
|
|
153
|
+
proseRoutes: ProsePageEntry[];
|
|
154
|
+
}) {
|
|
155
|
+
const output: Node[] = [md.heading(1, siteTitle)];
|
|
156
|
+
if (description) output.push(md.paragraph(md.text(description)));
|
|
157
|
+
if (proseRoutes.length > 0) output.push(...generateProseIndex(proseRoutes, detailed));
|
|
158
|
+
if (languages.length > 0) output.push(...generateRefIndex(basePath, languages, 'http', detailed, spec));
|
|
159
|
+
|
|
160
|
+
const doc = new Markdoc.Ast.Node('document', {}, output);
|
|
161
|
+
return Markdoc.format(doc);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const GET: APIRoute = async () => {
|
|
165
|
+
const [docsCollection, spec] = await Promise.all([getCollection('docs'), getSDKJSONInSSR('http')]);
|
|
166
|
+
const apiEntries = [...walkTree(spec)].filter((n) => n.data.kind !== 'model');
|
|
167
|
+
const proseRoutes = docsCollection.map((entry) => ({
|
|
168
|
+
id: entry.id,
|
|
169
|
+
title: entry.data.title,
|
|
170
|
+
description: entry.data.description,
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
const content = generateMarkdownIndex({
|
|
174
|
+
siteTitle: SITE_TITLE,
|
|
175
|
+
description: LLMS_TXT_DESCRIPTION,
|
|
176
|
+
basePath: API_REFERENCE_BASE_PATH,
|
|
177
|
+
languages: spec.docs?.languages ?? [],
|
|
178
|
+
detailed: apiEntries.length + proseRoutes.length < LLMS_TXT_DETAIL_THRESHOLD,
|
|
179
|
+
spec,
|
|
180
|
+
proseRoutes,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return new Response(content, {
|
|
184
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
185
|
+
});
|
|
186
|
+
};
|