@stainless-api/docs 0.1.0-beta.11 → 0.1.0-beta.111

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 (150) hide show
  1. package/CHANGELOG.md +931 -0
  2. package/eslint-suppressions.json +27 -0
  3. package/locals.d.ts +17 -0
  4. package/package.json +50 -41
  5. package/playground-virtual-modules.d.ts +96 -0
  6. package/plugin/assets/languages/cli.svg +14 -0
  7. package/plugin/assets/languages/csharp.svg +1 -0
  8. package/plugin/assets/languages/php.svg +4 -0
  9. package/plugin/buildAlgoliaIndex.ts +40 -39
  10. package/plugin/components/MethodDescription.tsx +54 -0
  11. package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
  12. package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
  13. package/plugin/components/RequestBuilder/index.tsx +37 -0
  14. package/plugin/components/RequestBuilder/props.ts +9 -0
  15. package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
  16. package/plugin/components/RequestBuilder/styles.css +67 -0
  17. package/plugin/components/SDKSelect.astro +18 -111
  18. package/plugin/components/SnippetCode.tsx +110 -68
  19. package/plugin/components/StainlessIslands.tsx +126 -0
  20. package/plugin/components/search/SearchAlgolia.astro +46 -29
  21. package/plugin/components/search/SearchIsland.tsx +47 -29
  22. package/plugin/generateAPIReferenceLink.ts +2 -2
  23. package/plugin/globalJs/ai-dropdown-options.ts +243 -0
  24. package/plugin/globalJs/code-snippets.ts +40 -11
  25. package/plugin/globalJs/copy.ts +95 -17
  26. package/plugin/globalJs/create-playground.shim.ts +3 -0
  27. package/plugin/globalJs/method-descriptions.ts +33 -0
  28. package/plugin/globalJs/navigation.ts +12 -32
  29. package/plugin/globalJs/playground-data.shim.ts +1 -0
  30. package/plugin/globalJs/playground-data.ts +14 -0
  31. package/plugin/globalJs/summary-selection-tweak.ts +29 -0
  32. package/plugin/helpers/generateDocsRoutes.ts +59 -0
  33. package/plugin/helpers/multiSpec.ts +8 -0
  34. package/plugin/index.ts +304 -138
  35. package/plugin/languages.ts +8 -2
  36. package/plugin/loadPluginConfig.ts +251 -107
  37. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +3 -1
  38. package/plugin/react/Routing.tsx +212 -141
  39. package/plugin/referencePlaceholderUtils.ts +18 -15
  40. package/plugin/replaceSidebarPlaceholderMiddleware.ts +38 -34
  41. package/plugin/routes/Docs.astro +71 -111
  42. package/plugin/routes/DocsStatic.astro +6 -5
  43. package/plugin/routes/Overview.astro +45 -21
  44. package/plugin/routes/markdown.ts +13 -12
  45. package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +49 -60
  46. package/plugin/specs/FileCache.ts +99 -0
  47. package/plugin/specs/fetchSpecSSR.ts +27 -0
  48. package/plugin/specs/generateSpec.ts +112 -0
  49. package/plugin/specs/index.ts +132 -0
  50. package/plugin/specs/inputResolver.ts +146 -0
  51. package/plugin/{cms → specs}/worker.ts +82 -5
  52. package/plugin/vendor/preview.worker.docs.js +27303 -18260
  53. package/plugin/vendor/templates/cli.md +1 -0
  54. package/plugin/vendor/templates/go.md +4 -2
  55. package/plugin/vendor/templates/java.md +5 -1
  56. package/plugin/vendor/templates/kotlin.md +5 -1
  57. package/plugin/vendor/templates/node.md +4 -2
  58. package/plugin/vendor/templates/python.md +4 -2
  59. package/plugin/vendor/templates/ruby.md +4 -2
  60. package/plugin/vendor/templates/terraform.md +1 -1
  61. package/plugin/vendor/templates/typescript.md +3 -1
  62. package/resolveSrcFile.ts +10 -0
  63. package/scripts/vendor_deps.ts +5 -5
  64. package/shared/conditionalIntegration.ts +28 -0
  65. package/shared/getProsePages.ts +41 -0
  66. package/shared/getSharedLogger.ts +15 -0
  67. package/shared/terminalUtils.ts +3 -0
  68. package/shared/virtualModule.ts +54 -1
  69. package/src/content.config.ts +9 -0
  70. package/stl-docs/components/AIDropdown.tsx +63 -0
  71. package/stl-docs/components/AiChatIsland.tsx +14 -0
  72. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  73. package/stl-docs/components/Footer.astro +89 -0
  74. package/stl-docs/components/Head.astro +20 -0
  75. package/stl-docs/components/Header.astro +3 -10
  76. package/stl-docs/components/PageFrame.astro +34 -0
  77. package/stl-docs/components/PageSidebar.astro +11 -0
  78. package/stl-docs/components/PageTitle.astro +82 -0
  79. package/stl-docs/components/StainlessLogo.svg +4 -0
  80. package/stl-docs/components/TableOfContents.astro +34 -0
  81. package/stl-docs/components/ThemeProvider.astro +36 -0
  82. package/stl-docs/components/ThemeSelect.astro +84 -146
  83. package/stl-docs/components/TwoColumnContent.astro +2 -0
  84. package/stl-docs/components/content-panel/ContentPanel.astro +4 -64
  85. package/stl-docs/components/headers/DefaultHeader.astro +4 -6
  86. package/stl-docs/components/headers/StackedHeader.astro +8 -51
  87. package/stl-docs/components/icons/chat-gpt.tsx +2 -2
  88. package/stl-docs/components/icons/cursor.tsx +10 -0
  89. package/stl-docs/components/icons/gemini.tsx +19 -0
  90. package/stl-docs/components/icons/markdown.tsx +1 -1
  91. package/stl-docs/components/index.ts +1 -0
  92. package/stl-docs/components/mintlify-compat/Frame.astro +4 -4
  93. package/stl-docs/components/mintlify-compat/card.css +4 -4
  94. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  95. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -75
  96. package/stl-docs/components/nav-tabs/NavTabs.astro +79 -81
  97. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -7
  98. package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
  99. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  100. package/stl-docs/components/pagination/Pagination.astro +177 -0
  101. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  102. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  103. package/stl-docs/components/pagination/util.ts +71 -0
  104. package/stl-docs/components/scripts.ts +1 -0
  105. package/stl-docs/components/sidebars/BaseSidebar.astro +79 -2
  106. package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
  107. package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
  108. package/stl-docs/disableCalloutSyntax.ts +36 -0
  109. package/stl-docs/fonts.ts +186 -0
  110. package/stl-docs/index.ts +171 -51
  111. package/stl-docs/loadStlDocsConfig.ts +64 -8
  112. package/stl-docs/proseDocSync.ts +314 -0
  113. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +53 -0
  114. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
  115. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  116. package/stl-docs/proseSearchIndexing.ts +222 -0
  117. package/stl-docs/tabsMiddleware.ts +13 -4
  118. package/styles/code.css +53 -49
  119. package/styles/links.css +2 -37
  120. package/styles/method-descriptions.css +36 -0
  121. package/styles/overrides.css +28 -46
  122. package/styles/page.css +230 -52
  123. package/styles/sdk_select.css +9 -6
  124. package/styles/search.css +11 -21
  125. package/styles/sidebar.css +25 -211
  126. package/styles/{variables.css → sl-variables.css} +4 -8
  127. package/styles/stldocs-variables.css +6 -0
  128. package/styles/toc.css +19 -8
  129. package/theme.css +11 -9
  130. package/tsconfig.json +1 -4
  131. package/virtual-module.d.ts +65 -8
  132. package/components/variables.css +0 -112
  133. package/plugin/cms/client.ts +0 -62
  134. package/plugin/cms/server.ts +0 -268
  135. package/plugin/globalJs/ai-dropdown.ts +0 -57
  136. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
  137. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
  138. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +0 -49
  139. package/stl-docs/components/mintlify-compat/Step.astro +0 -56
  140. package/stl-docs/components/mintlify-compat/Steps.astro +0 -15
  141. package/styles/fonts.css +0 -68
  142. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  143. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  144. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  145. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  146. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  147. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  148. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  149. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  150. /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, './content-panel/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,113 @@ 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
+ experimental: {
209
+ fonts: [...flattenFonts(config.fonts), ...(astroConfig.experimental?.fonts ?? [])],
210
+ },
125
211
  vite: {
126
- ssr: {
127
- noExternal: ['@stainless-api/ui-primitives'],
128
- },
129
- optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
130
212
  plugins: [
131
213
  {
132
214
  name: 'stl-docs-vite',
133
215
  resolveId(id) {
134
- if (id === virtualId) {
135
- return resolvedId;
136
- }
216
+ if (virtualModules.has(id)) return resolveVirtualModuleId(id);
137
217
  },
138
218
  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
- }
219
+ const bare = id.replace(/^\0/, '');
220
+ if (virtualModules.has(bare)) return virtualModules.get(bare);
149
221
  },
150
222
  },
151
223
  ],
224
+ optimizeDeps: {
225
+ include: config.aiChat
226
+ ? [
227
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > lucide-react',
228
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > motion',
229
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > motion > framer-motion',
230
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > react-markdown',
231
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > react-syntax-highlighter',
232
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > remark-gfm',
233
+ ]
234
+ : [],
235
+ },
152
236
  },
153
237
  build: {
154
238
  ...astroConfig.build,
@@ -159,7 +243,7 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
159
243
  'astro:build:done': ({ dir }) => {
160
244
  if (redirects !== null) {
161
245
  const stainlessDir = join(dir.pathname, '_stainless');
162
- mkdirSync(stainlessDir);
246
+ mkdirSync(stainlessDir, { recursive: true });
163
247
  const outputPath = join(stainlessDir, 'redirects.json');
164
248
  writeFileSync(outputPath, JSON.stringify(redirects, null, 2), {
165
249
  encoding: 'utf-8',
@@ -170,7 +254,18 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
170
254
  };
171
255
  }
172
256
 
173
- export function stainlessDocs(config: StainlessDocsUserConfig) {
257
+ function sharedLoggerIntegration(): AstroIntegration {
258
+ return {
259
+ name: 'stainless',
260
+ hooks: {
261
+ 'astro:config:setup': ({ logger }) => {
262
+ setSharedLogger(logger);
263
+ },
264
+ },
265
+ };
266
+ }
267
+
268
+ export function stainlessDocs(config: StainlessDocsUserConfig): StarlightPlugin[] {
174
269
  const normalizedConfigResult = parseStlDocsConfig(config);
175
270
  if (normalizedConfigResult.result === 'error') {
176
271
  // TODO: would be good to use the astro logger somehow
@@ -179,9 +274,34 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
179
274
  }
180
275
  const normalizedConfig = normalizedConfigResult.config;
181
276
 
277
+ // TODO: need to refactor this, but this allows us to get the base path for the API reference _if_ it exists
278
+ // if it doesn't exist, the value of basePath is null.
279
+ // the stl-starlight virtual module has base path, but it's not available when there's no API reference
280
+ const hasApiReference = normalizedConfig.apiReference !== null;
281
+ let apiReferenceBasePath: string | null = null;
282
+ if (hasApiReference) {
283
+ apiReferenceBasePath = normalizedConfig.apiReference?.basePath ?? '/api';
284
+ }
285
+
182
286
  return [
287
+ sharedLoggerIntegration(), // this **must** be first so it can set the shared logger used by our other integrations
183
288
  react(),
184
289
  stainlessDocsStarlightIntegration(normalizedConfig),
185
- stainlessDocsIntegration(normalizedConfig),
290
+ stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
291
+ conditionalIntegration({
292
+ condition: !config.experimental?.disableProseMarkdownRendering,
293
+ integration: stainlessDocsMarkdownRenderer({ apiReferenceBasePath }),
294
+ reason: 'disabled by experimental config "disableProseMarkdownRendering"',
295
+ }),
296
+ conditionalIntegration({
297
+ condition: !config.experimental?.disableStainlessProseIndexing,
298
+ integration: stainlessDocsAlgoliaProseIndexing({ apiReferenceBasePath }),
299
+ reason: 'disabled by experimental config "disableStainlessProseIndexing"',
300
+ }),
301
+ conditionalIntegration({
302
+ condition: !config.experimental?.disableStainlessProseIndexing,
303
+ integration: stainlessDocsVectorProseIndexing(normalizedConfig, apiReferenceBasePath),
304
+ reason: 'disabled by experimental config "disableStainlessProseIndexing"',
305
+ }),
186
306
  ];
187
307
  }
@@ -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) {