@stainless-api/docs 0.1.0-beta.13 → 0.1.0-beta.130

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 (188) hide show
  1. package/CHANGELOG.md +1102 -0
  2. package/ambient.d.ts +6 -0
  3. package/eslint-suppressions.json +90 -0
  4. package/{eslint.config.js → eslint.config.ts} +0 -2
  5. package/locals.d.ts +17 -0
  6. package/package.json +62 -44
  7. package/playground-virtual-modules.d.ts +96 -0
  8. package/plugin/assets/languages/cli.svg +14 -0
  9. package/plugin/assets/languages/csharp.svg +1 -0
  10. package/plugin/assets/languages/php.svg +4 -0
  11. package/plugin/buildAlgoliaIndex.ts +40 -39
  12. package/plugin/components/MethodDescription.tsx +54 -0
  13. package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
  14. package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
  15. package/plugin/components/RequestBuilder/index.tsx +40 -0
  16. package/plugin/components/RequestBuilder/props.ts +9 -0
  17. package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
  18. package/plugin/components/RequestBuilder/styles.css +67 -0
  19. package/plugin/components/SDKSelect.astro +18 -111
  20. package/plugin/components/SnippetCode.tsx +112 -70
  21. package/plugin/components/StainlessIslands.tsx +126 -0
  22. package/plugin/components/search/SearchAlgolia.astro +46 -29
  23. package/plugin/components/search/SearchIsland.tsx +61 -37
  24. package/plugin/generateAPIReferenceLink.ts +0 -40
  25. package/plugin/globalJs/ai-dropdown-options.ts +248 -0
  26. package/plugin/globalJs/code-snippets.ts +45 -16
  27. package/plugin/globalJs/copy.ts +115 -27
  28. package/plugin/globalJs/create-playground.shim.ts +3 -0
  29. package/plugin/globalJs/method-descriptions.ts +33 -0
  30. package/plugin/globalJs/navigation.ts +24 -44
  31. package/plugin/globalJs/playground-data.shim.ts +1 -0
  32. package/plugin/globalJs/playground-data.ts +14 -0
  33. package/plugin/globalJs/summary-selection-tweak.ts +29 -0
  34. package/plugin/helpers/generateDocsRoutes.ts +59 -0
  35. package/plugin/helpers/multiSpec.ts +8 -0
  36. package/plugin/index.ts +317 -141
  37. package/plugin/languages.ts +8 -2
  38. package/plugin/loadPluginConfig.ts +284 -109
  39. package/plugin/markdown/highlighter.ts +100 -0
  40. package/plugin/markdown/index.ts +39 -0
  41. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +3 -1
  42. package/plugin/react/Routing.tsx +98 -263
  43. package/plugin/referencePlaceholderUtils.ts +17 -14
  44. package/plugin/replaceSidebarPlaceholderMiddleware.ts +39 -35
  45. package/plugin/routes/Docs.astro +72 -111
  46. package/plugin/routes/DocsStatic.astro +6 -5
  47. package/plugin/routes/Overview.astro +46 -22
  48. package/plugin/routes/llms.ts +186 -0
  49. package/plugin/routes/markdown.ts +13 -12
  50. package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +84 -69
  51. package/plugin/specs/FileCache.ts +99 -0
  52. package/plugin/specs/fetchSpecSSR.ts +27 -0
  53. package/plugin/specs/generateSpec.ts +112 -0
  54. package/plugin/specs/index.ts +132 -0
  55. package/plugin/specs/inputResolver.ts +148 -0
  56. package/plugin/{cms → specs}/worker.ts +82 -5
  57. package/plugin/vendor/preview.worker.docs.js +27121 -16890
  58. package/plugin/vendor/templates/cli.md +1 -0
  59. package/plugin/vendor/templates/go.md +4 -2
  60. package/plugin/vendor/templates/java.md +5 -1
  61. package/plugin/vendor/templates/kotlin.md +5 -1
  62. package/plugin/vendor/templates/node.md +4 -2
  63. package/plugin/vendor/templates/python.md +4 -2
  64. package/plugin/vendor/templates/ruby.md +4 -2
  65. package/plugin/vendor/templates/terraform.md +1 -1
  66. package/plugin/vendor/templates/typescript.md +3 -1
  67. package/resolveSrcFile.ts +10 -0
  68. package/scripts/vendor_deps.ts +5 -5
  69. package/shared/conditionalIntegration.ts +28 -0
  70. package/shared/getProsePages.ts +41 -0
  71. package/shared/getSharedLogger.ts +15 -0
  72. package/shared/terminalUtils.ts +3 -0
  73. package/shared/virtualModule.ts +46 -1
  74. package/src/content.config.ts +9 -0
  75. package/stl-docs/aiChatExamples.ts +95 -0
  76. package/stl-docs/chat/docs-chat-handler.ts +18 -0
  77. package/stl-docs/chat/hook.ts +215 -0
  78. package/stl-docs/chat/schemas.ts +70 -0
  79. package/stl-docs/chat/stainless-handler/index.ts +126 -0
  80. package/stl-docs/chat/stream-util.ts +16 -0
  81. package/stl-docs/chat/ui/AiChat.module.css +591 -0
  82. package/stl-docs/chat/ui/AiChat.tsx +188 -0
  83. package/stl-docs/chat/ui/Trigger.tsx +154 -0
  84. package/stl-docs/chat/ui/components/ChatControls.tsx +51 -0
  85. package/stl-docs/chat/ui/components/ChatEmpty.tsx +42 -0
  86. package/stl-docs/chat/ui/components/ChatLog.tsx +96 -0
  87. package/stl-docs/chat/ui/components/ChatMessage.tsx +47 -0
  88. package/stl-docs/chat/ui/components/CodeBlock.tsx +33 -0
  89. package/stl-docs/chat/ui/components/MessageFeedback.tsx +109 -0
  90. package/stl-docs/chat/ui/components/Table.tsx +15 -0
  91. package/stl-docs/chat/ui/components/ToolCall.tsx +34 -0
  92. package/stl-docs/chat/ui/components/hljs-github.css +81 -0
  93. package/stl-docs/chat/ui/scroll-manager.ts +86 -0
  94. package/stl-docs/chat/ui/types.ts +45 -0
  95. package/stl-docs/components/AIDropdown.tsx +63 -0
  96. package/stl-docs/components/AiChatIsland.tsx +16 -0
  97. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  98. package/stl-docs/components/ContentPanel.astro +9 -0
  99. package/stl-docs/components/Footer.astro +89 -0
  100. package/stl-docs/components/Head.astro +20 -0
  101. package/stl-docs/components/Header.astro +3 -9
  102. package/stl-docs/components/PageFrame.astro +37 -0
  103. package/stl-docs/components/PageSidebar.astro +11 -0
  104. package/stl-docs/components/PageTitle.astro +82 -0
  105. package/stl-docs/components/StainlessLogo.svg +4 -0
  106. package/stl-docs/components/ThemeProvider.astro +36 -0
  107. package/stl-docs/components/ThemeSelect.astro +84 -146
  108. package/stl-docs/components/TwoColumnContent.astro +2 -0
  109. package/stl-docs/components/headers/DefaultHeader.astro +6 -8
  110. package/stl-docs/components/headers/StackedHeader.astro +10 -53
  111. package/stl-docs/components/icons/chat-gpt.tsx +2 -2
  112. package/stl-docs/components/icons/cursor.tsx +10 -0
  113. package/stl-docs/components/icons/gemini.tsx +19 -0
  114. package/stl-docs/components/icons/markdown.tsx +1 -1
  115. package/stl-docs/components/index.ts +1 -0
  116. package/stl-docs/components/mintlify-compat/Accordion.astro +2 -2
  117. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +0 -4
  118. package/stl-docs/components/mintlify-compat/Columns.astro +2 -2
  119. package/stl-docs/components/mintlify-compat/Frame.astro +6 -6
  120. package/stl-docs/components/mintlify-compat/Tab.astro +2 -2
  121. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +2 -2
  122. package/stl-docs/components/mintlify-compat/callouts/Check.astro +0 -4
  123. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +0 -4
  124. package/stl-docs/components/mintlify-compat/callouts/Info.astro +0 -4
  125. package/stl-docs/components/mintlify-compat/callouts/Note.astro +0 -4
  126. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +0 -4
  127. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +0 -4
  128. package/stl-docs/components/mintlify-compat/card.css +4 -4
  129. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  130. package/stl-docs/components/nav-tabs/NavDropdown.astro +38 -77
  131. package/stl-docs/components/nav-tabs/NavTabs.astro +81 -81
  132. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +1 -2
  133. package/stl-docs/components/nav-tabs/buildNavLinks.ts +5 -2
  134. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  135. package/stl-docs/components/pagination/Pagination.astro +177 -0
  136. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  137. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  138. package/stl-docs/components/pagination/util.ts +71 -0
  139. package/stl-docs/components/scripts.ts +1 -0
  140. package/stl-docs/components/sidebars/BaseSidebar.astro +80 -2
  141. package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
  142. package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
  143. package/stl-docs/disableCalloutSyntax.ts +36 -0
  144. package/stl-docs/fonts.ts +186 -0
  145. package/stl-docs/index.ts +176 -58
  146. package/stl-docs/loadStlDocsConfig.ts +73 -8
  147. package/stl-docs/proseDocSync.test.ts +74 -0
  148. package/stl-docs/proseDocSync.ts +344 -0
  149. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +53 -0
  150. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
  151. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  152. package/stl-docs/proseSearchIndexing.ts +218 -0
  153. package/stl-docs/tabsMiddleware.ts +14 -5
  154. package/styles/code.css +53 -49
  155. package/styles/links.css +2 -37
  156. package/styles/method-descriptions.css +36 -0
  157. package/styles/overrides.css +28 -46
  158. package/styles/page.css +228 -38
  159. package/styles/sdk_select.css +9 -6
  160. package/styles/search.css +11 -21
  161. package/styles/sidebar.css +28 -215
  162. package/styles/{variables.css → sl-variables.css} +4 -8
  163. package/styles/stldocs-variables.css +6 -0
  164. package/styles/toc.css +19 -8
  165. package/theme.css +11 -9
  166. package/tsconfig.json +1 -4
  167. package/virtual-module.d.ts +66 -8
  168. package/components/variables.css +0 -112
  169. package/plugin/cms/client.ts +0 -62
  170. package/plugin/cms/server.ts +0 -268
  171. package/plugin/globalJs/ai-dropdown.ts +0 -57
  172. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
  173. package/stl-docs/components/ClientRouterHead.astro +0 -41
  174. package/stl-docs/components/content-panel/ContentPanel.astro +0 -69
  175. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
  176. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +0 -49
  177. package/stl-docs/components/mintlify-compat/Step.astro +0 -56
  178. package/stl-docs/components/mintlify-compat/Steps.astro +0 -15
  179. package/styles/fonts.css +0 -68
  180. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  181. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  182. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  183. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  184. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  185. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  186. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  187. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  188. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -1,147 +1,57 @@
1
1
  import * as React from 'react';
2
- import { marked } from 'marked';
3
- import hljs from 'highlight.js';
4
- import { createMarkdownProcessor, type MarkdownProcessor } from '@astrojs/markdown-remark';
5
- import remarkGfmAlerts from 'remark-github-alerts';
2
+ import { getDocsLanguages } from '../helpers/multiSpec';
3
+
4
+ import { astroMarkdownRenderText } from '../markdown';
5
+ import { highlight } from '../markdown/highlighter';
6
6
 
7
7
  import type { MarkdownHeading } from 'astro';
8
- import type { StarlightRouteData } from '@astrojs/starlight/route-data';
9
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
10
- import type { DocsLanguage } from '@stainless-api/docs-ui/src/routing';
8
+ import type * as SDKJSON from '@stainless/sdk-json';
9
+ import { LanguageNames, type DocsLanguage } from '@stainless-api/docs-ui/routing';
11
10
 
12
- import {
13
- generateRouteList,
14
- generateRoute,
15
- parseStainlessPath,
16
- walkTree,
17
- SupportedLanguageSyntaxes,
18
- getLanguageSnippet,
19
- } from '@stainless-api/docs-ui/src/routing';
11
+ import { parseStainlessPath, getLanguageSnippet } from '@stainless-api/docs-ui/routing';
20
12
 
21
13
  import {
22
14
  DocsProvider,
23
15
  MarkdownProvider,
24
16
  NavigationProvider,
25
- useSpec,
26
17
  type ContentPanelLayout,
27
- } from '@stainless-api/docs-ui/src/contexts';
18
+ } from '@stainless-api/docs-ui/contexts';
28
19
 
29
- import { flatResources, getResourceFromSpec } from '@stainless-api/docs-ui/src/utils';
20
+ import { flatResources, getResourceFromSpec } from '@stainless-api/docs-ui/utils';
30
21
 
31
22
  import {
32
23
  SDKMethod,
33
24
  SDKResource,
34
25
  type SDKRequestTitleProps,
35
26
  SDKBreadcrumbs,
36
- Dropdown,
37
- DropdownTrigger,
38
- DropdownMenu,
39
- DropdownItem,
40
27
  SDKIcon,
41
28
  SDKOverview,
42
29
  SDKLanguageBlock,
43
- } from '@stainless-api/docs-ui/src/components';
30
+ } from '@stainless-api/docs-ui/components';
31
+
32
+ import { Dropdown } from '@stainless-api/docs/components';
33
+
44
34
  import {
45
- BASE_PATH,
46
- EXCLUDE_LANGUAGES,
47
- EXPAND_RESOURCES,
48
- HIGHLIGHT_THEMES,
35
+ RESOLVED_API_REFERENCE_PATH,
49
36
  BREADCRUMB_CONFIG,
50
37
  PROPERTY_SETTINGS,
51
- INCLUDE_AI_DROPDOWN_OPTIONS,
38
+ ENABLE_CONTEXT_MENU,
39
+ EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS,
40
+ MIDDLEWARE,
52
41
  } from 'virtual:stl-starlight-virtual-module';
53
- import style from '@stainless-api/docs-ui/src/style';
54
- import { createHighlighter, type BundledLanguage, type BundledTheme, type HighlighterGeneric } from 'shiki';
55
- import { SnippetCode, SnippetContainer, SnippetRequestContainer } from '../components/SnippetCode';
56
- import clsx from 'clsx';
42
+ import style from '@stainless-api/docs-ui/style';
43
+ import {
44
+ SnippetCode,
45
+ SnippetContainer,
46
+ SnippetButtons,
47
+ SnippetFooter,
48
+ SnippetResponse,
49
+ } from '../components/SnippetCode';
57
50
  import type { StlStarlightMiddleware } from '../middlewareBuilder/stainlessMiddleware';
58
- import { ComponentProvider } from '@stainless-api/docs-ui/src/contexts/component';
59
- import { APIReferenceAIDropdown } from '../../stl-docs/components/APIReferenceAIDropdown';
60
-
61
- export function generateDocsRoutes(spec: SDKJSON.Spec) {
62
- const paths = generateRouteList({
63
- spec,
64
- excludeLanguages: EXCLUDE_LANGUAGES as DocsLanguage[],
65
- });
66
- const readmes = Object.entries(spec.readme)
67
- .filter(([language]) => language !== 'http')
68
- .filter(([language]) => !EXCLUDE_LANGUAGES.includes(language as DocsLanguage))
69
- .map(([language]) => ({
70
- slug: language,
71
- stainlessPath: null,
72
- language: language as DocsLanguage,
73
- title: 'Readme',
74
- kind: 'readme',
75
- }));
76
-
77
- return [...paths, ...readmes].map(({ slug, stainlessPath, language, title, kind }) => {
78
- return {
79
- params: { slug },
80
- props: { stainlessPath, language, title, kind },
81
- };
82
- });
83
- }
84
-
85
- function isResourceNonEmpty(resource: SDKJSON.Resource) {
86
- return (
87
- Object.keys(resource.methods ?? {}).length > 0 ||
88
- Object.keys(resource.subresources ?? {}).length > 0 ||
89
- Object.keys(resource.models ?? {}).length > 0
90
- );
91
- }
92
-
93
- type SidebarEntry = StarlightRouteData['sidebar'][number];
94
-
95
- export function buildSidebar(
96
- basePath: string,
97
- language: DocsLanguage,
98
- current: string,
99
- spec: SDKJSON.Spec,
100
- resources?: Record<string, SDKJSON.Resource>,
101
- nested?: boolean,
102
- ): StarlightRouteData['sidebar'] {
103
- const totalRoutes = Array.from(walkTree(spec, false)).filter(
104
- (item) => item.data.kind === 'http_method',
105
- ).length;
106
-
107
- return Object.values(resources ?? spec.resources ?? [])
108
- .filter((resource) => isResourceNonEmpty(resource))
109
- .sort((a, b) => (a.name.startsWith('$') === b.name.startsWith('$') ? 0 : a.name.startsWith('$') ? 1 : -1))
110
- .map((resource) => {
111
- const subs = buildSidebar(basePath, language, current, spec, resource.subresources, true);
112
-
113
- const overview: SidebarEntry = {
114
- type: 'link',
115
- isCurrent: current === resource.stainlessPath,
116
- attrs: { 'data-stldocs-overview': resource.name },
117
- label: 'Overview',
118
- href: generateRoute(basePath, language, resource.stainlessPath) ?? basePath,
119
- badge: undefined,
120
- };
121
-
122
- const meths: SidebarEntry[] = Object.values(resource.methods ?? [])
123
- .filter((method) => spec.decls?.[language]?.[method.stainlessPath])
124
- .toSorted((first, second) => first.name.localeCompare(second.name))
125
- .map((method) => ({
126
- type: 'link',
127
- isCurrent: current === method.stainlessPath,
128
- attrs: { 'data-stldocs-method': method.httpMethod },
129
- label: method.summary ?? method.name,
130
- href: generateRoute(basePath, language, method.stainlessPath) ?? basePath,
131
- badge: undefined,
132
- }));
133
-
134
- const shouldExpand = EXPAND_RESOURCES ?? totalRoutes < 20;
135
-
136
- return {
137
- type: 'group',
138
- label: resource.title,
139
- badge: undefined,
140
- collapsed: !shouldExpand || nested === true,
141
- entries: [...(resources ? [] : [overview]), ...meths, ...subs],
142
- };
143
- });
144
- }
51
+ import { ComponentProvider } from '@stainless-api/docs-ui/contexts/component';
52
+ import { AIDropdown } from '../../stl-docs/components/AIDropdown';
53
+ import { ChevronsUpDownIcon } from 'lucide-react';
54
+ import { MethodDescription } from '../components/MethodDescription';
145
55
 
146
56
  export function buildPageNavigation(resource: SDKJSON.Resource, depth: number = 2): MarkdownHeading[] {
147
57
  const output: MarkdownHeading[] = [{ depth, slug: resource.stainlessPath, text: resource.title }];
@@ -153,78 +63,68 @@ export function buildPageNavigation(resource: SDKJSON.Resource, depth: number =
153
63
  return [...output, ...subs];
154
64
  }
155
65
 
156
- function renderMarkdown(content: string) {
157
- return marked.parse(content, { gfm: true }) as string;
158
- }
159
-
160
- async function highlight(content: string, language?: string) {
161
- if (language === 'json') return hljs.highlight(content, { language }).value;
162
- const highlighter = await astroHighlight();
163
- return highlighter.codeToHtml(content, {
164
- lang: language ?? 'javascript',
165
- themes: HIGHLIGHT_THEMES || {},
166
- });
167
- }
168
-
169
66
  export function SDKSelectReactComponent({
170
67
  selected,
171
68
  languages,
172
- id,
173
69
  className,
70
+ ...rest
174
71
  }: {
175
72
  selected: DocsLanguage;
176
73
  languages: DocsLanguage[];
177
- id: string;
178
74
  className?: string;
179
- }) {
75
+ } & Omit<React.ComponentProps<'div'>, 'children'>) {
180
76
  return (
181
- <Dropdown id={id} data-current-value={selected} className={className}>
182
- <DropdownTrigger
183
- className="dropdown-toggle"
184
- type="button"
185
- id="stldocs-snippet-title-button"
186
- aria-expanded="false"
187
- withChevron
188
- >
189
- <SDKIcon language={getLanguageSnippet(selected)} size={16} />
190
- <span className={clsx('stl-snippet-dropdown-button-text', selected)}>{selected}</span>
191
- </DropdownTrigger>
192
- <DropdownMenu
77
+ <Dropdown data-current-value={selected} className={className} {...rest}>
78
+ <Dropdown.Trigger>
79
+ <Dropdown.TriggerSelectedItem>
80
+ <Dropdown.Icon>
81
+ <SDKIcon language={getLanguageSnippet(selected)} />
82
+ </Dropdown.Icon>
83
+ <span className="stl-snippet-dropdown-button-text">{LanguageNames[selected]}</span>
84
+ </Dropdown.TriggerSelectedItem>
85
+ <Dropdown.TriggerIcon>
86
+ <ChevronsUpDownIcon size={16} />
87
+ </Dropdown.TriggerIcon>
88
+ </Dropdown.Trigger>
89
+ <Dropdown.Menu
193
90
  className="dropdown-menu stl-sdk-select-dropdown-menu"
194
- position="below"
195
- aria-labelledby="stldocs-snippet-title-button"
91
+ aria-labelledby="stl-docs-snippet-title-button"
196
92
  >
197
93
  {languages.map((item) => (
198
- <DropdownItem key={item} value={item} selected={item === selected}>
199
- <div>
94
+ <Dropdown.MenuItem key={item} value={item} isSelected={item === selected}>
95
+ <Dropdown.Icon>
200
96
  <SDKIcon language={getLanguageSnippet(item)} size={16} />
201
- <span className={clsx('stl-snippet-dropdown-button-text', item)}>{item}</span>
202
- </div>
203
- </DropdownItem>
97
+ </Dropdown.Icon>
98
+ <Dropdown.MenuItemText>{LanguageNames[item]}</Dropdown.MenuItemText>
99
+ <Dropdown.MenuItemTemplate>
100
+ <Dropdown.Icon>
101
+ <SDKIcon language={getLanguageSnippet(item)} size={16} />
102
+ </Dropdown.Icon>
103
+ <span className="stl-snippet-dropdown-button-text">{LanguageNames[item]}</span>
104
+ </Dropdown.MenuItemTemplate>
105
+ </Dropdown.MenuItem>
204
106
  ))}
205
- </DropdownMenu>
107
+ </Dropdown.Menu>
206
108
  </Dropdown>
207
109
  );
208
110
  }
209
111
 
210
112
  function SDKRequestTitle({ snippetLanguage }: SDKRequestTitleProps) {
211
- const spec = useSpec();
212
-
213
113
  const selected = snippetLanguage.split('.').at(0) as DocsLanguage;
214
- const languages = (spec?.docs?.languages ?? ['http']).filter((lang) => !EXCLUDE_LANGUAGES.includes(lang));
114
+ const languages = getDocsLanguages();
215
115
 
216
116
  return (
217
117
  <SDKSelectReactComponent
218
118
  selected={selected || 'http'}
219
119
  languages={languages}
220
- id="stldocs-snippet-select"
221
- className="stl-sdk-select"
120
+ data-stldocs-snippet-select
121
+ className="stl-sdk-select stl-ui-not-prose"
222
122
  />
223
123
  );
224
124
  }
225
125
 
226
126
  export type SpecMetadata = [
227
- 'http' | 'node' | 'python' | 'go' | 'typescript' | 'terraform' | 'ruby' | 'java' | 'kotlin',
127
+ DocsLanguage,
228
128
  {
229
129
  repo_url?: string;
230
130
  code_url?: string;
@@ -234,15 +134,27 @@ export type SpecMetadata = [
234
134
  },
235
135
  ][];
236
136
 
137
+ const componentOverrides = {
138
+ SDKRequestTitle,
139
+ SnippetCode,
140
+ SnippetContainer,
141
+ SnippetButtons,
142
+ SnippetFooter,
143
+ SnippetResponse,
144
+ ...(EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS ? { MethodDescription } : {}),
145
+ ...MIDDLEWARE.componentOverrides,
146
+ } satisfies React.ComponentProps<typeof ComponentProvider>['components'];
147
+
237
148
  export function RenderLibraries({ metadata }: { metadata: SpecMetadata }) {
238
149
  return (
239
- <ComponentProvider components={{}}>
150
+ <ComponentProvider components={componentOverrides}>
240
151
  {metadata.map(([language, data]) => (
241
152
  <SDKLanguageBlock
153
+ key={language}
242
154
  language={language}
243
155
  version={data.version || ''}
244
156
  install={data.install || ''}
245
- links={{ repo: data.repo_url || '#', docs: `${BASE_PATH}/${language}` }}
157
+ links={{ repo: data.repo_url || '#', docs: `${RESOLVED_API_REFERENCE_PATH}/${language}` }}
246
158
  />
247
159
  ))}
248
160
  </ComponentProvider>
@@ -254,16 +166,9 @@ export function RenderSpecOverview({ spec, language }: { spec: SDKJSON.Spec; lan
254
166
 
255
167
  return (
256
168
  <DocsProvider spec={spec} language={language ?? 'node'}>
257
- <ComponentProvider
258
- components={{
259
- SDKRequestTitle,
260
- SnippetCode,
261
- SnippetContainer,
262
- SnippetRequestContainer,
263
- }}
264
- >
265
- <NavigationProvider basePath={BASE_PATH}>
266
- <MarkdownProvider render={renderMarkdown} highlight={highlight}>
169
+ <ComponentProvider components={componentOverrides}>
170
+ <NavigationProvider basePath={RESOLVED_API_REFERENCE_PATH}>
171
+ <MarkdownProvider render={astroMarkdownRenderText} highlight={highlight}>
267
172
  <div className={style.Overview}>
268
173
  {resources
269
174
  .filter(({ resource }) => !resource.name.startsWith('$'))
@@ -303,57 +208,44 @@ export function RenderSpec({
303
208
  const parsed = parseStainlessPath(path);
304
209
  const resource = getResourceFromSpec(path, spec);
305
210
 
306
- if (!resource || !parsed) return null;
211
+ if (!resource || !parsed) {
212
+ console.warn(`Could not find resource or parsed path for '${path}'`);
213
+ return null;
214
+ }
307
215
 
308
216
  return (
309
217
  <DocsProvider
310
- spec={spec as SDKJSON.Spec}
218
+ spec={spec}
311
219
  language={language ?? 'node'}
312
220
  settings={{
313
221
  contentPanelLayout,
314
222
  properties: PROPERTY_SETTINGS,
315
223
  }}
316
224
  >
317
- <ComponentProvider
318
- components={{
319
- SDKRequestTitle,
320
- SnippetCode,
321
- SnippetContainer,
322
- SnippetRequestContainer,
323
- }}
324
- >
325
- <NavigationProvider basePath={BASE_PATH} selectedPath={path}>
326
- <MarkdownProvider render={renderMarkdown} highlight={highlight}>
327
- {kind === 'http_method' ? (
225
+ <ComponentProvider components={componentOverrides}>
226
+ <NavigationProvider basePath={RESOLVED_API_REFERENCE_PATH} selectedPath={path}>
227
+ <MarkdownProvider render={astroMarkdownRenderText} highlight={highlight}>
228
+ {
328
229
  <div className="stldocs-root stl-ui-not-prose">
329
230
  <div className="stl-page-nav-container">
330
231
  <SDKBreadcrumbs
331
- spec={spec as SDKJSON.Spec}
232
+ spec={spec}
332
233
  currentPath={currentPath}
333
- basePath={BASE_PATH}
234
+ basePath={RESOLVED_API_REFERENCE_PATH}
334
235
  config={BREADCRUMB_CONFIG}
335
236
  />
336
- {INCLUDE_AI_DROPDOWN_OPTIONS && <APIReferenceAIDropdown />}
237
+ {ENABLE_CONTEXT_MENU && <AIDropdown />}
337
238
  </div>
338
- <SDKMethod
339
- method={resource.methods[parsed.method]}
340
- transformRequestSnippet={transformRequestSnippet}
341
- />
342
- </div>
343
- ) : (
344
- <div className="stldocs-root stl-ui-not-prose">
345
- <div className="stl-page-nav-container">
346
- <SDKBreadcrumbs
347
- spec={spec as SDKJSON.Spec}
348
- currentPath={currentPath}
349
- basePath={BASE_PATH}
350
- config={BREADCRUMB_CONFIG}
239
+ {kind === 'http_method' ? (
240
+ <SDKMethod
241
+ method={resource.methods[parsed.method!]!}
242
+ transformRequestSnippet={transformRequestSnippet}
351
243
  />
352
- {INCLUDE_AI_DROPDOWN_OPTIONS && <APIReferenceAIDropdown />}
353
- </div>
354
- <SDKOverview resource={resource} />
244
+ ) : (
245
+ <SDKOverview resource={resource} />
246
+ )}
355
247
  </div>
356
- )}
248
+ }
357
249
  </MarkdownProvider>
358
250
  </NavigationProvider>
359
251
  </ComponentProvider>
@@ -361,18 +253,6 @@ export function RenderSpec({
361
253
  );
362
254
  }
363
255
 
364
- export function RenderMethod({ path }: { path: string }) {
365
- const spec = useSpec();
366
- if (!spec) return null;
367
-
368
- const parsed = parseStainlessPath(path);
369
- const resource = getResourceFromSpec(path, spec);
370
- if (!resource || !parsed) return null;
371
-
372
- const meth = resource.methods[parsed.method];
373
- return <SDKMethod method={meth} />;
374
- }
375
-
376
256
  export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguage) {
377
257
  const repoUrl = spec.metadata?.[language]?.repo_url;
378
258
 
@@ -389,48 +269,3 @@ export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguag
389
269
 
390
270
  return spec.readme[language];
391
271
  }
392
-
393
- // Astro's markdown processor is a singleton
394
- // Need to cache it instead of instanting per request
395
- let astroMarkdownProcessor: MarkdownProcessor;
396
- async function astroMarkdown() {
397
- if (!astroMarkdownProcessor) {
398
- astroMarkdownProcessor = await createMarkdownProcessor({
399
- gfm: true,
400
- remarkPlugins: [remarkGfmAlerts],
401
- shikiConfig: {
402
- themes: HIGHLIGHT_THEMES,
403
- },
404
- });
405
- }
406
-
407
- return astroMarkdownProcessor;
408
- }
409
-
410
- let astroShikiHighlighter: HighlighterGeneric<BundledLanguage, BundledTheme>;
411
- async function astroHighlight() {
412
- if (!astroShikiHighlighter) {
413
- astroShikiHighlighter = await createHighlighter({
414
- themes: ['github-light', 'github-dark'],
415
- langs: SupportedLanguageSyntaxes,
416
- });
417
- }
418
-
419
- return astroShikiHighlighter;
420
- }
421
-
422
- export async function astroMarkdownRender(content: string) {
423
- const md = await astroMarkdown();
424
- const output = await md.render(content);
425
-
426
- // Map GFM callouts to the closest Starlight equivalent
427
- output.code = output.code
428
- .replaceAll('markdown-alert-caution', 'markdown-alert-danger')
429
- .replaceAll('markdown-alert-warning', 'markdown-alert-caution')
430
- .replaceAll('markdown-alert-important', 'markdown-alert-caution')
431
- .replaceAll('markdown-alert-title', 'starlight-aside__title')
432
- .replaceAll('markdown-alert-', 'starlight-aside--')
433
- .replaceAll('markdown-alert', 'starlight-aside');
434
-
435
- return output;
436
- }
@@ -25,23 +25,26 @@ type SidebarConfigEntry = Exclude<StarlightConfig['sidebar'], undefined>[number]
25
25
 
26
26
  export function getAPIReferencePlaceholderItemFromSidebarConfig(
27
27
  sidebar: SidebarConfigEntry[],
28
- ): SidebarConfigEntry | null {
29
- for (const item of sidebar) {
30
- if (typeof item === 'string') {
31
- continue;
32
- }
33
- if ('items' in item) {
34
- const found = getAPIReferencePlaceholderItemFromSidebarConfig(item.items);
35
- if (found) {
36
- return found;
28
+ ): SidebarConfigEntry[] {
29
+ const items: SidebarConfigEntry[] = [];
30
+
31
+ function recursiveGetPlaceholderItems(entries: SidebarConfigEntry[]) {
32
+ for (const item of entries) {
33
+ if (typeof item === 'string') {
34
+ continue;
35
+ }
36
+ if ('attrs' in item && item.attrs?.about === INTERNAL_REFERENCE_ENTRY_MARKER) {
37
+ items.push(item);
38
+ }
39
+ if ('items' in item) {
40
+ recursiveGetPlaceholderItems(item.items);
37
41
  }
38
- }
39
- if ('attrs' in item && item.attrs?.about === INTERNAL_REFERENCE_ENTRY_MARKER) {
40
- return item;
41
42
  }
42
43
  }
43
44
 
44
- return null;
45
+ recursiveGetPlaceholderItems(sidebar);
46
+
47
+ return items;
45
48
  }
46
49
 
47
50
  type SidebarEntry = StarlightRouteData['sidebar'][number];
@@ -58,7 +61,7 @@ function recursiveGetPlaceholderItems(
58
61
  items: PlaceholderItemResult[],
59
62
  ): PlaceholderItemResult[] {
60
63
  for (let i = 0; i < sidebar.length; i++) {
61
- const entry = sidebar[i];
64
+ const entry = sidebar[i]!;
62
65
  if ('attrs' in entry && entry.attrs?.about === INTERNAL_REFERENCE_ENTRY_MARKER) {
63
66
  items.push({
64
67
  index: i,
@@ -1,54 +1,58 @@
1
- import { defineRouteMiddleware } from '@astrojs/starlight/route-data';
1
+ import { defineRouteMiddleware, StarlightRouteData } from '@astrojs/starlight/route-data';
2
2
 
3
- import { cmsClient } from './cms/client';
4
- import { BASE_PATH } from 'virtual:stl-starlight-virtual-module';
3
+ import { RESOLVED_API_REFERENCE_PATH } from 'virtual:stl-starlight-virtual-module';
5
4
  import { getAPIReferencePlaceholderItems } from './referencePlaceholderUtils';
6
- import { getMethodFromSDKJSON, recursiveReplacePlaceholderItems } from './generateAPIReferenceLink';
7
- import { forceGenerateRoute } from './cms/sidebar-builder';
8
- import { parseRoute } from '@stainless-api/docs-ui/src/routing';
5
+ import { parseRoute } from '@stainless-api/docs-ui/routing';
6
+ import path from 'path';
7
+ import { sidebars } from 'virtual:stl-starlight-reference-sidebars';
9
8
 
10
9
  // this fn is loaded in the plugin via addRouteMiddleware
11
10
 
12
- export const onRequest = defineRouteMiddleware(async (context) => {
11
+ type SidebarEntry = StarlightRouteData['sidebar'][number];
12
+
13
+ const removeTrailingSlash = (value: string) => (value.endsWith('/') ? value.slice(0, -1) : value);
14
+
15
+ function markCurrentItems(sidebar: SidebarEntry[], currentSlug: string) {
16
+ // IMPORTANT: we need to clone the sidebar to avoid mutating the original sidebar
17
+ const mutableSidebarInstance = structuredClone(sidebar);
18
+ const normalizedCurrentSlug = removeTrailingSlash(currentSlug);
19
+
20
+ function recursiveMarkCurrent(entries: SidebarEntry[]) {
21
+ for (const entry of entries) {
22
+ if (entry.type === 'link') {
23
+ entry.isCurrent = removeTrailingSlash(entry.href) === normalizedCurrentSlug;
24
+ }
25
+ if (entry.type === 'group') {
26
+ recursiveMarkCurrent(entry.entries);
27
+ }
28
+ }
29
+ }
30
+ recursiveMarkCurrent(mutableSidebarInstance);
31
+
32
+ return mutableSidebarInstance;
33
+ }
34
+
35
+ export const onRequest = defineRouteMiddleware((context) => {
13
36
  // if using content collection schema, use: context.locals.starlightRoute.entry.data.stainlessStarlight
14
37
  // this worked without collections but relied on hijacking starlightRoute: context.props.frontmatter.stainlessStarlight
15
-
16
- const slug = `/${context.locals.starlightRoute.id}`; // same as .slug but not deprecated
38
+ const slug = path.posix.join(import.meta.env.BASE_URL ?? '', `/${context.locals.starlightRoute.id}`); // same as .slug but not deprecated
17
39
 
18
40
  context.locals.starlightRoute._stlStarlight = {
19
- basePath: BASE_PATH,
41
+ basePath: RESOLVED_API_REFERENCE_PATH,
20
42
  };
21
43
 
22
44
  const apiReferencePlaceholderItems = getAPIReferencePlaceholderItems(context.locals.starlightRoute.sidebar);
23
45
 
24
- const spec = await cmsClient.getSpec();
25
-
26
- const { language, stainlessPath } = parseRoute(BASE_PATH, slug);
27
-
28
- // This is probably temporary, but it fills in functionality needed for Mintlify imports
29
- recursiveReplacePlaceholderItems(context.locals.starlightRoute.sidebar, (entry, { endpoint, label }) => {
30
- const method = getMethodFromSDKJSON(spec, endpoint);
31
-
32
- const route = forceGenerateRoute({
33
- basePath: BASE_PATH,
34
- stainlessPath: method.stainlessPath,
35
- language,
36
- });
37
- entry.href = route;
38
- entry.isCurrent = method.stainlessPath === stainlessPath;
39
- if (!label) {
40
- entry.label = method.summary ?? method.name;
41
- }
42
- entry.attrs['data-stldocs-method'] = method.httpMethod;
43
- });
46
+ const { language } = parseRoute(RESOLVED_API_REFERENCE_PATH, slug);
44
47
 
45
48
  for (const item of apiReferencePlaceholderItems) {
46
- const entries = await cmsClient.buildSidebar({
47
- basePath: BASE_PATH,
48
- currentSlug: slug,
49
- sidebarId: item.sidebarId,
50
- });
49
+ const entries = sidebars.find((sb) => sb.id === item.sidebarId && sb.language === language)?.entries;
50
+ if (!entries) {
51
+ throw new Error(`Expected sidebar entries for sidebar ID ${item.sidebarId} and language ${language}`);
52
+ }
51
53
 
52
54
  item.group.splice(item.index, 1, ...entries);
53
55
  }
56
+
57
+ context.locals.starlightRoute.sidebar = markCurrentItems(context.locals.starlightRoute.sidebar, slug);
54
58
  });