@stainless-api/docs 0.1.0-beta.10 → 0.1.0-beta.100
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 +846 -0
- package/eslint-suppressions.json +27 -0
- package/locals.d.ts +17 -0
- package/package.json +49 -40
- package/playground-virtual-modules.d.ts +96 -0
- package/plugin/assets/languages/cli.svg +14 -0
- package/plugin/assets/languages/csharp.svg +1 -0
- package/plugin/assets/languages/php.svg +4 -0
- package/plugin/buildAlgoliaIndex.ts +40 -39
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
- package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
- package/plugin/components/RequestBuilder/index.tsx +37 -0
- package/plugin/components/RequestBuilder/props.ts +9 -0
- package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
- package/plugin/components/RequestBuilder/styles.css +67 -0
- package/plugin/components/SDKSelect.astro +18 -105
- package/plugin/components/SnippetCode.tsx +111 -66
- package/plugin/components/StainlessIslands.tsx +126 -0
- package/plugin/components/search/SearchAlgolia.astro +45 -28
- package/plugin/components/search/SearchIsland.tsx +47 -29
- package/plugin/generateAPIReferenceLink.ts +2 -2
- package/plugin/globalJs/ai-dropdown-options.ts +243 -0
- package/plugin/globalJs/code-snippets.ts +40 -11
- package/plugin/globalJs/copy.ts +95 -17
- package/plugin/globalJs/create-playground.shim.ts +3 -0
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +12 -32
- package/plugin/globalJs/playground-data.shim.ts +1 -0
- package/plugin/globalJs/playground-data.ts +14 -0
- package/plugin/helpers/generateDocsRoutes.ts +59 -0
- package/plugin/helpers/multiSpec.ts +8 -0
- package/plugin/index.ts +299 -118
- package/plugin/languages.ts +8 -2
- package/plugin/loadPluginConfig.ts +251 -107
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
- package/plugin/react/Routing.tsx +210 -141
- package/plugin/referencePlaceholderUtils.ts +18 -15
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +38 -34
- package/plugin/routes/Docs.astro +70 -119
- package/plugin/routes/DocsStatic.astro +6 -5
- package/plugin/routes/Overview.astro +37 -27
- package/plugin/routes/markdown.ts +13 -12
- package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +49 -60
- package/plugin/specs/FileCache.ts +99 -0
- package/plugin/specs/fetchSpecSSR.ts +27 -0
- package/plugin/specs/generateSpec.ts +112 -0
- package/plugin/specs/index.ts +132 -0
- package/plugin/specs/inputResolver.ts +146 -0
- package/plugin/{cms → specs}/worker.ts +82 -5
- package/plugin/vendor/preview.worker.docs.js +22406 -17955
- package/plugin/vendor/templates/cli.md +1 -0
- package/plugin/vendor/templates/go.md +4 -2
- package/plugin/vendor/templates/java.md +3 -1
- package/plugin/vendor/templates/kotlin.md +3 -1
- package/plugin/vendor/templates/node.md +4 -2
- package/plugin/vendor/templates/python.md +4 -2
- package/plugin/vendor/templates/ruby.md +4 -2
- package/plugin/vendor/templates/terraform.md +1 -1
- package/plugin/vendor/templates/typescript.md +3 -1
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +5 -5
- package/shared/getProsePages.ts +42 -0
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/shared/virtualModule.ts +54 -1
- package/src/content.config.ts +9 -0
- package/stl-docs/components/AIDropdown.tsx +63 -0
- package/stl-docs/components/AiChatIsland.tsx +14 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
- package/stl-docs/components/Head.astro +20 -0
- package/stl-docs/components/Header.astro +6 -8
- package/stl-docs/components/PageFrame.astro +18 -0
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeProvider.astro +36 -0
- package/stl-docs/components/ThemeSelect.astro +84 -139
- package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
- package/stl-docs/components/headers/StackedHeader.astro +29 -24
- package/stl-docs/components/icons/chat-gpt.tsx +2 -2
- package/stl-docs/components/icons/cursor.tsx +10 -0
- package/stl-docs/components/icons/gemini.tsx +19 -0
- package/stl-docs/components/icons/markdown.tsx +1 -1
- package/stl-docs/components/index.ts +1 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +5 -3
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +3 -3
- package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
- package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
- package/stl-docs/components/mintlify-compat/card.css +33 -35
- package/stl-docs/components/mintlify-compat/index.ts +2 -4
- package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -70
- package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +175 -0
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
- package/stl-docs/components/pagination/util.ts +71 -0
- package/stl-docs/components/scripts.ts +1 -0
- package/stl-docs/components/sidebars/BaseSidebar.astro +79 -2
- package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
- package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/fonts.ts +186 -0
- package/stl-docs/index.ts +154 -51
- package/stl-docs/loadStlDocsConfig.ts +58 -8
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/proseSearchIndexing.ts +606 -0
- package/stl-docs/tabsMiddleware.ts +13 -4
- package/styles/code.css +133 -136
- package/styles/links.css +11 -48
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +49 -57
- package/styles/page.css +100 -59
- package/styles/sdk_select.css +9 -7
- package/styles/search.css +57 -69
- package/styles/sidebar.css +26 -156
- package/styles/{variables.css → sl-variables.css} +3 -2
- package/styles/stldocs-variables.css +6 -0
- package/styles/toc.css +41 -34
- package/theme.css +11 -11
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +64 -8
- package/components/variables.css +0 -135
- package/plugin/cms/client.ts +0 -62
- package/plugin/cms/server.ts +0 -268
- package/plugin/globalJs/ai-dropdown.ts +0 -57
- package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
- package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
- package/stl-docs/components/mintlify-compat/Step.astro +0 -58
- package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
- package/styles/fonts.css +0 -68
- /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
package/stl-docs/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import starlight from '@astrojs/starlight';
|
|
2
2
|
import react from '@astrojs/react';
|
|
3
|
-
import {
|
|
3
|
+
import type { StarlightPlugin } from '@astrojs/starlight/types';
|
|
4
|
+
import { disableCalloutSyntaxStarlightPlugin } from './disableCalloutSyntax';
|
|
4
5
|
|
|
5
6
|
import type { AstroIntegration } from 'astro';
|
|
6
7
|
|
|
@@ -16,11 +17,18 @@ import {
|
|
|
16
17
|
type StarlightSidebarConfig,
|
|
17
18
|
} from './loadStlDocsConfig';
|
|
18
19
|
import { buildVirtualModuleString } from '../shared/virtualModule';
|
|
19
|
-
|
|
20
|
-
import
|
|
20
|
+
import type * as StlDocsVirtualModule from 'virtual:stl-docs-virtual-module';
|
|
21
|
+
import { resolveSrcFile } from '../resolveSrcFile';
|
|
22
|
+
import { stainlessDocsMarkdownRenderer } from './proseMarkdown/proseMarkdownIntegration';
|
|
23
|
+
import { setSharedLogger } from '../shared/getSharedLogger';
|
|
24
|
+
import { stainlessDocsAlgoliaProseIndexing, stainlessDocsVectorProseIndexing } from './proseSearchIndexing';
|
|
25
|
+
import { stainlessStarlight } from '../plugin';
|
|
26
|
+
import { getFontRoles, flattenFonts } from './fonts';
|
|
21
27
|
|
|
22
28
|
export * from '../plugin';
|
|
23
29
|
|
|
30
|
+
const COMPONENTS_FOLDER = '/stl-docs/components';
|
|
31
|
+
|
|
24
32
|
function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig) {
|
|
25
33
|
// We transform our tabs into a Starlight sidebar
|
|
26
34
|
// This gives them all the built-in features of Starlight (eg. auto-generated entries by directory)
|
|
@@ -40,21 +48,44 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
|
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
type ComponentOverrides = StarlightConfigDefined['components'];
|
|
43
|
-
const plugins = [...config.starlightCompat.plugins];
|
|
44
|
-
|
|
45
51
|
const componentOverrides: ComponentOverrides = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
PageFrame: resolveSrcFile(COMPONENTS_FOLDER, './PageFrame.astro'),
|
|
53
|
+
|
|
54
|
+
Head: resolveSrcFile(COMPONENTS_FOLDER, './Head.astro'),
|
|
55
|
+
Header: resolveSrcFile(COMPONENTS_FOLDER, './Header.astro'),
|
|
56
|
+
ThemeProvider: resolveSrcFile(COMPONENTS_FOLDER, './ThemeProvider.astro'),
|
|
57
|
+
ThemeSelect: resolveSrcFile(COMPONENTS_FOLDER, './ThemeSelect.astro'),
|
|
58
|
+
|
|
59
|
+
Sidebar: resolveSrcFile(COMPONENTS_FOLDER, './sidebars/BaseSidebar.astro'),
|
|
60
|
+
ContentPanel: resolveSrcFile(COMPONENTS_FOLDER, './content-panel/ContentPanel.astro'),
|
|
61
|
+
TableOfContents: resolveSrcFile(COMPONENTS_FOLDER, './TableOfContents.astro'),
|
|
62
|
+
|
|
63
|
+
PageTitle: resolveSrcFile(COMPONENTS_FOLDER, './PageTitle.astro'),
|
|
64
|
+
Pagination: resolveSrcFile(COMPONENTS_FOLDER, './pagination/Pagination.astro'),
|
|
50
65
|
};
|
|
51
66
|
|
|
67
|
+
const plugins: StarlightPlugin[] = [
|
|
68
|
+
// Disable starlight callout syntax in favor of our own component
|
|
69
|
+
disableCalloutSyntaxStarlightPlugin,
|
|
70
|
+
];
|
|
71
|
+
|
|
52
72
|
if (config.apiReference !== null) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
plugins.push(
|
|
74
|
+
stainlessStarlight({
|
|
75
|
+
...config.apiReference,
|
|
76
|
+
contextMenu: config.contextMenu,
|
|
77
|
+
experimentalPrerender:
|
|
78
|
+
config.apiReference.experimentalPrerender === undefined
|
|
79
|
+
? config.starlightPassThrough.prerender
|
|
80
|
+
: config.apiReference.experimentalPrerender,
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
componentOverrides.Sidebar = resolveSrcFile(COMPONENTS_FOLDER, './sidebars/SDKSelectSidebar.astro');
|
|
84
|
+
componentOverrides.Search = resolveSrcFile('/plugin/components/search/Search.astro');
|
|
56
85
|
}
|
|
57
86
|
|
|
87
|
+
plugins.push(...config.starlightCompat.plugins, ...config.plugins.map((p) => p(config)));
|
|
88
|
+
|
|
58
89
|
// TODO: re-add once we figure out what to do with the client router
|
|
59
90
|
// if (config.enableClientRouter) {
|
|
60
91
|
// // logger.info(`Client router is enabled`);
|
|
@@ -63,6 +94,8 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
|
|
|
63
94
|
// // logger.info(`Client router is disabled`);
|
|
64
95
|
// }
|
|
65
96
|
|
|
97
|
+
const userExpressiveCode = typeof config.expressiveCode === 'object' ? config.expressiveCode : {};
|
|
98
|
+
|
|
66
99
|
return starlight({
|
|
67
100
|
...config.starlightPassThrough,
|
|
68
101
|
sidebar,
|
|
@@ -86,69 +119,112 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
|
|
|
86
119
|
setupNavLinksInitial();
|
|
87
120
|
`,
|
|
88
121
|
},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
122
|
+
],
|
|
123
|
+
routeMiddleware: [
|
|
124
|
+
...config.starlightCompat.routeMiddleware,
|
|
125
|
+
resolveSrcFile('/stl-docs/tabsMiddleware.ts'),
|
|
126
|
+
],
|
|
127
|
+
customCss: [resolveSrcFile('/theme.css'), ...config.customCss],
|
|
128
|
+
|
|
129
|
+
expressiveCode: {
|
|
130
|
+
...userExpressiveCode,
|
|
131
|
+
themes: userExpressiveCode.themes ?? ['github-light', 'github-dark'],
|
|
132
|
+
styleOverrides: {
|
|
133
|
+
...userExpressiveCode.styleOverrides,
|
|
134
|
+
textMarkers: {
|
|
135
|
+
insBackground: 'var(--stl-color-green-muted-background)',
|
|
136
|
+
insBorderColor: 'var(--stl-color-green-border)',
|
|
137
|
+
insDiffIndicatorColor: 'var(--stl-color-green-foreground-reduced)',
|
|
138
|
+
|
|
139
|
+
delBackground: 'var(--stl-color-red-muted-background)',
|
|
140
|
+
delBorderColor: 'var(--stl-color-red-border)',
|
|
141
|
+
delDiffIndicatorColor: 'var(--stl-color-red-foreground-reduced)',
|
|
142
|
+
|
|
143
|
+
markBackground: 'var(--stl-color-blue-muted-background)',
|
|
144
|
+
markBorderColor: 'var(--stl-color-blue-border)',
|
|
145
|
+
...userExpressiveCode.styleOverrides?.textMarkers,
|
|
99
146
|
},
|
|
100
147
|
},
|
|
101
|
-
|
|
102
|
-
routeMiddleware: [...config.starlightCompat.routeMiddleware, '@stainless-api/docs/tabsMiddleware'],
|
|
103
|
-
customCss: ['@stainless-api/docs/theme', ...config.customCss],
|
|
148
|
+
},
|
|
104
149
|
plugins,
|
|
105
150
|
});
|
|
106
151
|
}
|
|
107
152
|
|
|
108
|
-
function stainlessDocsIntegration(
|
|
109
|
-
|
|
153
|
+
function stainlessDocsIntegration(
|
|
154
|
+
config: NormalizedStainlessDocsConfig,
|
|
155
|
+
apiReferenceBasePath: string | null,
|
|
156
|
+
): AstroIntegration {
|
|
110
157
|
// The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
|
|
111
|
-
const
|
|
158
|
+
const resolveVirtualModuleId = (id: string) => `\0${id}`;
|
|
112
159
|
let redirects: NormalizedRedirectConfig | null = null;
|
|
113
160
|
|
|
114
161
|
return {
|
|
115
|
-
name: 'stl-docs-
|
|
162
|
+
name: 'stl-docs-astro',
|
|
116
163
|
hooks: {
|
|
117
164
|
'astro:config:setup': ({ updateConfig, command, config: astroConfig }) => {
|
|
118
|
-
//
|
|
119
|
-
//
|
|
165
|
+
// we only handle redirects for builds
|
|
166
|
+
// in dev, Astro handles them for us
|
|
120
167
|
if (command === 'build' && astroConfig.redirects) {
|
|
121
168
|
redirects = normalizeRedirects(astroConfig.redirects);
|
|
122
169
|
}
|
|
123
170
|
|
|
171
|
+
const virtualModules = new Map(
|
|
172
|
+
Object.entries({
|
|
173
|
+
'virtual:stl-docs-virtual-module': buildVirtualModuleString({
|
|
174
|
+
TABS: config.tabs,
|
|
175
|
+
SPLIT_TABS_ENABLED: config.splitTabsEnabled,
|
|
176
|
+
HEADER_LINKS: config.header.links,
|
|
177
|
+
HEADER_LAYOUT: config.header.layout,
|
|
178
|
+
ENABLE_CLIENT_ROUTER: config.enableClientRouter,
|
|
179
|
+
API_REFERENCE_BASE_PATH: apiReferenceBasePath ?? '/api',
|
|
180
|
+
ENABLE_PROSE_MARKDOWN_RENDERING: config.enableProseMarkdownRendering,
|
|
181
|
+
ENABLE_CONTEXT_MENU: config.contextMenu, // TODO: do not duplicate this between both virtual modules
|
|
182
|
+
RENDER_PAGE_DESCRIPTIONS: config.renderPageDescriptions,
|
|
183
|
+
FONTS: getFontRoles(config.fonts),
|
|
184
|
+
LINK_GROUP_TITLES_TO_OVERVIEW_PAGES: config.linkGroupTitlesToOverviewPages,
|
|
185
|
+
} satisfies typeof StlDocsVirtualModule),
|
|
186
|
+
|
|
187
|
+
'virtual:stl-docs/components/AiChat.tsx': `
|
|
188
|
+
${
|
|
189
|
+
config.aiChat
|
|
190
|
+
? `export { default } from ${JSON.stringify(config.aiChat.chatComponentPath)};`
|
|
191
|
+
: // export null when no AI chat component is provided
|
|
192
|
+
`export default null;`
|
|
193
|
+
}
|
|
194
|
+
export const STAINLESS_PROJECT = ${config.apiReference ? JSON.stringify(config.apiReference.stainlessProject) : 'undefined'};
|
|
195
|
+
`,
|
|
196
|
+
}),
|
|
197
|
+
);
|
|
198
|
+
|
|
124
199
|
updateConfig({
|
|
200
|
+
experimental: {
|
|
201
|
+
fonts: [...flattenFonts(config.fonts), ...(astroConfig.experimental?.fonts ?? [])],
|
|
202
|
+
},
|
|
125
203
|
vite: {
|
|
126
|
-
ssr: {
|
|
127
|
-
noExternal: ['@stainless-api/ui-primitives'],
|
|
128
|
-
},
|
|
129
|
-
optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
|
|
130
204
|
plugins: [
|
|
131
205
|
{
|
|
132
206
|
name: 'stl-docs-vite',
|
|
133
207
|
resolveId(id) {
|
|
134
|
-
if (id
|
|
135
|
-
return resolvedId;
|
|
136
|
-
}
|
|
208
|
+
if (virtualModules.has(id)) return resolveVirtualModuleId(id);
|
|
137
209
|
},
|
|
138
210
|
load(id) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
TABS: config.tabs,
|
|
142
|
-
SPLIT_TABS_ENABLED: config.splitTabsEnabled,
|
|
143
|
-
HEADER_LINKS: config.header.links,
|
|
144
|
-
HEADER_LAYOUT: config.header.layout,
|
|
145
|
-
ENABLE_CLIENT_ROUTER: config.enableClientRouter,
|
|
146
|
-
INCLUDE_AI_DROPDOWN_OPTIONS: config.includeAIDropdownOptions,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
211
|
+
const bare = id.replace(/^\0/, '');
|
|
212
|
+
if (virtualModules.has(bare)) return virtualModules.get(bare);
|
|
149
213
|
},
|
|
150
214
|
},
|
|
151
215
|
],
|
|
216
|
+
optimizeDeps: {
|
|
217
|
+
include: config.aiChat
|
|
218
|
+
? [
|
|
219
|
+
'@stainless-api/docs-ai-chat > @stainless-api/ai-chat > lucide-react',
|
|
220
|
+
'@stainless-api/docs-ai-chat > @stainless-api/ai-chat > motion',
|
|
221
|
+
'@stainless-api/docs-ai-chat > @stainless-api/ai-chat > motion > framer-motion',
|
|
222
|
+
'@stainless-api/docs-ai-chat > @stainless-api/ai-chat > react-markdown',
|
|
223
|
+
'@stainless-api/docs-ai-chat > @stainless-api/ai-chat > react-syntax-highlighter',
|
|
224
|
+
'@stainless-api/docs-ai-chat > @stainless-api/ai-chat > remark-gfm',
|
|
225
|
+
]
|
|
226
|
+
: [],
|
|
227
|
+
},
|
|
152
228
|
},
|
|
153
229
|
build: {
|
|
154
230
|
...astroConfig.build,
|
|
@@ -159,7 +235,7 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
|
|
|
159
235
|
'astro:build:done': ({ dir }) => {
|
|
160
236
|
if (redirects !== null) {
|
|
161
237
|
const stainlessDir = join(dir.pathname, '_stainless');
|
|
162
|
-
mkdirSync(stainlessDir);
|
|
238
|
+
mkdirSync(stainlessDir, { recursive: true });
|
|
163
239
|
const outputPath = join(stainlessDir, 'redirects.json');
|
|
164
240
|
writeFileSync(outputPath, JSON.stringify(redirects, null, 2), {
|
|
165
241
|
encoding: 'utf-8',
|
|
@@ -170,7 +246,18 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
|
|
|
170
246
|
};
|
|
171
247
|
}
|
|
172
248
|
|
|
173
|
-
|
|
249
|
+
function sharedLoggerIntegration(): AstroIntegration {
|
|
250
|
+
return {
|
|
251
|
+
name: 'stainless',
|
|
252
|
+
hooks: {
|
|
253
|
+
'astro:config:setup': ({ logger }) => {
|
|
254
|
+
setSharedLogger(logger);
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function stainlessDocs(config: StainlessDocsUserConfig): StarlightPlugin[] {
|
|
174
261
|
const normalizedConfigResult = parseStlDocsConfig(config);
|
|
175
262
|
if (normalizedConfigResult.result === 'error') {
|
|
176
263
|
// TODO: would be good to use the astro logger somehow
|
|
@@ -179,9 +266,25 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
|
|
|
179
266
|
}
|
|
180
267
|
const normalizedConfig = normalizedConfigResult.config;
|
|
181
268
|
|
|
269
|
+
// TODO: need to refactor this, but this allows us to get the base path for the API reference _if_ it exists
|
|
270
|
+
// if it doesn't exist, the value of basePath is null.
|
|
271
|
+
// the stl-starlight virtual module has base path, but it's not available when there's no API reference
|
|
272
|
+
const hasApiReference = normalizedConfig.apiReference !== null;
|
|
273
|
+
let apiReferenceBasePath: string | null = null;
|
|
274
|
+
if (hasApiReference) {
|
|
275
|
+
apiReferenceBasePath = normalizedConfig.apiReference?.basePath ?? '/api';
|
|
276
|
+
}
|
|
277
|
+
|
|
182
278
|
return [
|
|
279
|
+
sharedLoggerIntegration(), // this **must** be first so it can set the shared logger used by our other integrations
|
|
183
280
|
react(),
|
|
184
281
|
stainlessDocsStarlightIntegration(normalizedConfig),
|
|
185
|
-
stainlessDocsIntegration(normalizedConfig),
|
|
282
|
+
stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
|
|
283
|
+
stainlessDocsMarkdownRenderer({
|
|
284
|
+
enabled: normalizedConfig.enableProseMarkdownRendering,
|
|
285
|
+
apiReferenceBasePath,
|
|
286
|
+
}),
|
|
287
|
+
stainlessDocsAlgoliaProseIndexing({ apiReferenceBasePath }),
|
|
288
|
+
stainlessDocsVectorProseIndexing(normalizedConfig, apiReferenceBasePath),
|
|
186
289
|
];
|
|
187
290
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { StainlessStarlightUserConfig } from '../plugin/loadPluginConfig';
|
|
2
|
-
import type { StarlightUserConfig } from '@astrojs/starlight/types';
|
|
2
|
+
import type { StarlightPlugin, StarlightUserConfig } from '@astrojs/starlight/types';
|
|
3
3
|
import type { ButtonVariant } from '@stainless-api/ui-primitives';
|
|
4
4
|
import type { AnchorHTMLAttributes } from 'react';
|
|
5
5
|
import type starlight from '@astrojs/starlight';
|
|
6
|
+
import { normalizeFonts, type StlDocsFontConfig } from './fonts';
|
|
6
7
|
|
|
7
8
|
type StarlightConfig = Parameters<typeof starlight>[0];
|
|
8
9
|
|
|
@@ -32,20 +33,22 @@ type PassThroughStarlightConfigOptions = Pick<
|
|
|
32
33
|
| 'lastUpdated'
|
|
33
34
|
| 'pagination'
|
|
34
35
|
| 'sidebar'
|
|
36
|
+
| 'expressiveCode'
|
|
35
37
|
>;
|
|
36
38
|
|
|
37
39
|
type ExperimentalStarlightCompatibilityConfig = Pick<
|
|
38
40
|
StarlightConfigDefined,
|
|
39
|
-
'components' | 'routeMiddleware' | 'plugins'
|
|
41
|
+
'components' | 'routeMiddleware' | 'plugins' | 'prerender'
|
|
40
42
|
>;
|
|
41
43
|
|
|
42
|
-
type Tabs = {
|
|
44
|
+
export type Tabs = {
|
|
43
45
|
label: string;
|
|
44
46
|
link: string;
|
|
45
47
|
sidebar?: SidebarEntry[];
|
|
46
48
|
/**
|
|
47
49
|
* Whether to hide the tab in the tab bar.
|
|
48
|
-
*
|
|
50
|
+
*
|
|
51
|
+
* @default false
|
|
49
52
|
*/
|
|
50
53
|
hidden?: boolean;
|
|
51
54
|
}[];
|
|
@@ -64,10 +67,42 @@ export type StainlessDocsUserConfig = {
|
|
|
64
67
|
layout?: HeaderLayout;
|
|
65
68
|
links?: HeaderLink[];
|
|
66
69
|
};
|
|
70
|
+
fonts?: StlDocsFontConfig;
|
|
67
71
|
experimental?: {
|
|
68
72
|
starlightCompat?: ExperimentalStarlightCompatibilityConfig;
|
|
69
73
|
enableClientRouter?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Disable markdown rendering for prose content. Only disable this if it is causing issues.
|
|
76
|
+
*
|
|
77
|
+
* @default false
|
|
78
|
+
*/
|
|
79
|
+
disableProseMarkdownRendering?: boolean;
|
|
80
|
+
aiChat?: { chatComponentPath: string };
|
|
81
|
+
/**
|
|
82
|
+
* Whether to link group titles to overview pages. Note: overview pages must already be present in the sidebar for this to work.
|
|
83
|
+
*
|
|
84
|
+
* @default false
|
|
85
|
+
*/
|
|
86
|
+
linkGroupTitlesToOverviewPages?: boolean;
|
|
70
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* Whether to show the context menu with options like "Copy as Markdown" and "Open in ChatGPT".
|
|
90
|
+
*
|
|
91
|
+
* @default true
|
|
92
|
+
*/
|
|
93
|
+
contextMenu?: boolean;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Whether to render page descriptions in prose page headers
|
|
97
|
+
*
|
|
98
|
+
* @default true
|
|
99
|
+
*/
|
|
100
|
+
renderPageDescriptions?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Stainless Docs plugins.
|
|
103
|
+
* Each plugin is a function that receives the normalized config and returns a Starlight plugin.
|
|
104
|
+
*/
|
|
105
|
+
plugins?: ((config: Exclude<NormalizedStainlessDocsConfig, 'plugins'>) => StarlightPlugin)[];
|
|
71
106
|
} & PassThroughStarlightConfigOptions;
|
|
72
107
|
|
|
73
108
|
type HeaderLayout = 'default' | 'stacked';
|
|
@@ -112,6 +147,7 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
|
|
|
112
147
|
layout: userConfig.header?.layout ?? 'default',
|
|
113
148
|
links: userConfig.header?.links ?? [],
|
|
114
149
|
},
|
|
150
|
+
fonts: normalizeFonts(userConfig.fonts),
|
|
115
151
|
starlightPassThrough: {
|
|
116
152
|
tableOfContents: userConfig.tableOfContents,
|
|
117
153
|
titleDelimiter: userConfig.titleDelimiter,
|
|
@@ -119,6 +155,13 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
|
|
|
119
155
|
description: userConfig.description,
|
|
120
156
|
tagline: userConfig.tagline,
|
|
121
157
|
logo: userConfig.logo,
|
|
158
|
+
favicon: userConfig.favicon,
|
|
159
|
+
disable404Route: userConfig.disable404Route,
|
|
160
|
+
editLink: userConfig.editLink,
|
|
161
|
+
locales: userConfig.locales,
|
|
162
|
+
lastUpdated: userConfig.lastUpdated,
|
|
163
|
+
pagination: userConfig.pagination,
|
|
164
|
+
prerender: userConfig.experimental?.starlightCompat?.prerender ?? true,
|
|
122
165
|
},
|
|
123
166
|
starlightCompat: {
|
|
124
167
|
components: userConfig.experimental?.starlightCompat?.components ?? {},
|
|
@@ -128,7 +171,14 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
|
|
|
128
171
|
enableClientRouter: userConfig.experimental?.enableClientRouter ?? false,
|
|
129
172
|
apiReference: userConfig.apiReference ?? null,
|
|
130
173
|
sidebar: userConfig.sidebar,
|
|
131
|
-
|
|
174
|
+
enableProseMarkdownRendering:
|
|
175
|
+
userConfig.experimental?.disableProseMarkdownRendering === true ? false : true,
|
|
176
|
+
contextMenu: userConfig.contextMenu ?? true,
|
|
177
|
+
expressiveCode: userConfig.expressiveCode,
|
|
178
|
+
renderPageDescriptions: userConfig.renderPageDescriptions ?? true,
|
|
179
|
+
plugins: userConfig.plugins ?? [],
|
|
180
|
+
aiChat: userConfig.experimental?.aiChat,
|
|
181
|
+
linkGroupTitlesToOverviewPages: userConfig.experimental?.linkGroupTitlesToOverviewPages ?? false,
|
|
132
182
|
};
|
|
133
183
|
|
|
134
184
|
return configWithDefaults;
|
|
@@ -137,12 +187,12 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
|
|
|
137
187
|
export type NormalizedStainlessDocsConfig = ReturnType<typeof normalizeConfig>;
|
|
138
188
|
|
|
139
189
|
/*
|
|
140
|
-
The goal of the code in this file is to take a user's config and normalize it.
|
|
190
|
+
The goal of the code in this file is to take a user's config and normalize it.
|
|
141
191
|
Specifically: we want a single complete config format used throughout the internals of the plugin.
|
|
142
192
|
|
|
143
193
|
We've tried to avoid any config values being optional/undefined. To accomplish this:
|
|
144
|
-
- Any optional config values should have their defaults set here: eg. basePath defaults to /api
|
|
145
|
-
- If a field is only used in certain contexts, we make each context a discriminated union (see
|
|
194
|
+
- Any optional config values should have their defaults set here: eg. basePath defaults to /api
|
|
195
|
+
- If a field is only used in certain contexts, we make each context a discriminated union (see SDKJSONInputs)
|
|
146
196
|
- We prefer empty arrays over undefined/null
|
|
147
197
|
*/
|
|
148
198
|
export function parseStlDocsConfig(userConfig: StainlessDocsUserConfig) {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
|
+
import { toMarkdown } from './toMarkdown';
|
|
4
|
+
import { resolveSrcFile } from '../../resolveSrcFile';
|
|
5
|
+
import { getSharedLogger } from '../../shared/getSharedLogger';
|
|
6
|
+
import { bold } from '../../shared/terminalUtils';
|
|
7
|
+
import { getProsePages } from '../../shared/getProsePages';
|
|
8
|
+
|
|
9
|
+
export function stainlessDocsMarkdownRenderer({
|
|
10
|
+
enabled,
|
|
11
|
+
apiReferenceBasePath,
|
|
12
|
+
}: {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
apiReferenceBasePath: string | null;
|
|
15
|
+
}): AstroIntegration {
|
|
16
|
+
return {
|
|
17
|
+
name: 'stl-docs-md',
|
|
18
|
+
hooks: {
|
|
19
|
+
'astro:config:setup': ({ addMiddleware }) => {
|
|
20
|
+
if (enabled) {
|
|
21
|
+
addMiddleware({
|
|
22
|
+
entrypoint: resolveSrcFile('/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts'),
|
|
23
|
+
order: 'post',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
'astro:build:done': async ({ logger: localLogger, dir }) => {
|
|
28
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
29
|
+
if (!enabled) {
|
|
30
|
+
logger.info('Stainless Docs prose Markdown rendering is disabled, skipping...');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const outputBasePath = dir.pathname;
|
|
34
|
+
const pagesToRender = await getProsePages({ apiReferenceBasePath, outputBasePath });
|
|
35
|
+
|
|
36
|
+
logger.info(bold(`Building ${pagesToRender.length} Markdown pages for prose content`));
|
|
37
|
+
|
|
38
|
+
let completedCount = 0;
|
|
39
|
+
|
|
40
|
+
for (const absHtmlPath of pagesToRender) {
|
|
41
|
+
const txt = await readFile(absHtmlPath, 'utf-8');
|
|
42
|
+
const md = await toMarkdown(txt);
|
|
43
|
+
if (md) {
|
|
44
|
+
const absMdPath = absHtmlPath.replace('.html', '.md');
|
|
45
|
+
await writeFile(absMdPath, md, 'utf-8');
|
|
46
|
+
|
|
47
|
+
completedCount++;
|
|
48
|
+
|
|
49
|
+
const relHtmlPath = absHtmlPath.replace(outputBasePath, '');
|
|
50
|
+
const relMdPath = absMdPath.replace(outputBasePath, '');
|
|
51
|
+
|
|
52
|
+
logger.info(`(${completedCount}/${pagesToRender.length}) ${relHtmlPath} -> ${relMdPath}`);
|
|
53
|
+
} else {
|
|
54
|
+
logger.error(`Failed to render ${absHtmlPath} as Markdown`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { defineMiddleware } from 'astro:middleware';
|
|
2
|
+
import { toMarkdown } from './toMarkdown';
|
|
3
|
+
import { API_REFERENCE_BASE_PATH } from 'virtual:stl-docs-virtual-module';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
// this is only run in `astro dev` for rendering prose content as Markdown on the fly.
|
|
7
|
+
export const onRequest = defineMiddleware(async (context, next) => {
|
|
8
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
9
|
+
if (!import.meta.env.DEV) {
|
|
10
|
+
return next();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const resolvedBasePath = path.posix.join(import.meta.env.BASE_URL ?? '', API_REFERENCE_BASE_PATH);
|
|
14
|
+
if (resolvedBasePath && context.url.pathname.startsWith(resolvedBasePath)) {
|
|
15
|
+
// handled by the API reference API route in stl-starlight plugin
|
|
16
|
+
return next();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!context.url.pathname.endsWith('/index.md')) {
|
|
20
|
+
return next();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const pathname = context.url.pathname.replace('index.md', '');
|
|
24
|
+
|
|
25
|
+
// We must trim the trailing slash to support astro configs with `trailingSlash: 'never'`
|
|
26
|
+
const cleanPathname = pathname !== '/' ? pathname.replace(/\/$/, '') : pathname;
|
|
27
|
+
const htmlUrl = new URL(cleanPathname, context.url);
|
|
28
|
+
|
|
29
|
+
const resp = await fetch(htmlUrl);
|
|
30
|
+
if (!resp.ok) {
|
|
31
|
+
return new Response('Failed to fetch HTML', { status: 400 });
|
|
32
|
+
}
|
|
33
|
+
const html = await resp.text();
|
|
34
|
+
const md = await toMarkdown(html);
|
|
35
|
+
|
|
36
|
+
if (!md) {
|
|
37
|
+
return new Response('Failed to render Markdown', { status: 400 });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new Response(md, { status: 200 });
|
|
41
|
+
});
|