@stainless-api/docs 0.1.0-beta.12 → 0.1.0-beta.120

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