@stainless-api/docs 0.1.0-beta.9 → 0.1.0-beta.90

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 (142) hide show
  1. package/CHANGELOG.md +748 -0
  2. package/eslint-suppressions.json +32 -0
  3. package/locals.d.ts +17 -0
  4. package/package.json +49 -40
  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/buildAlgoliaIndex.ts +38 -11
  9. package/plugin/components/MethodDescription.tsx +54 -0
  10. package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
  11. package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
  12. package/plugin/components/RequestBuilder/index.tsx +31 -0
  13. package/plugin/components/RequestBuilder/props.ts +9 -0
  14. package/plugin/components/RequestBuilder/spec-helpers.ts +50 -0
  15. package/plugin/components/RequestBuilder/styles.css +67 -0
  16. package/plugin/components/SDKSelect.astro +20 -104
  17. package/plugin/components/SnippetCode.tsx +111 -66
  18. package/plugin/components/StainlessIslands.tsx +126 -0
  19. package/plugin/components/search/SearchAlgolia.astro +45 -28
  20. package/plugin/components/search/SearchIsland.tsx +47 -29
  21. package/plugin/generateAPIReferenceLink.ts +2 -2
  22. package/plugin/globalJs/ai-dropdown-options.ts +243 -0
  23. package/plugin/globalJs/code-snippets.ts +15 -8
  24. package/plugin/globalJs/copy.ts +94 -17
  25. package/plugin/globalJs/create-playground.shim.ts +3 -0
  26. package/plugin/globalJs/method-descriptions.ts +33 -0
  27. package/plugin/globalJs/navigation.ts +10 -29
  28. package/plugin/globalJs/playground-data.shim.ts +1 -0
  29. package/plugin/globalJs/playground-data.ts +14 -0
  30. package/plugin/helpers/generateDocsRoutes.ts +27 -0
  31. package/plugin/helpers/getDocsLanguages.ts +9 -0
  32. package/plugin/index.ts +292 -116
  33. package/plugin/languages.ts +7 -2
  34. package/plugin/loadPluginConfig.ts +155 -79
  35. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
  36. package/plugin/react/Routing.tsx +204 -132
  37. package/plugin/referencePlaceholderUtils.ts +18 -15
  38. package/plugin/replaceSidebarPlaceholderMiddleware.ts +38 -34
  39. package/plugin/routes/Docs.astro +65 -117
  40. package/plugin/routes/DocsStatic.astro +7 -4
  41. package/plugin/routes/Overview.astro +20 -24
  42. package/plugin/routes/markdown.ts +12 -11
  43. package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +30 -54
  44. package/plugin/specs/fetchSpecSSR.ts +21 -0
  45. package/plugin/specs/generateSpec.ts +50 -0
  46. package/plugin/specs/index.ts +238 -0
  47. package/plugin/{cms → specs}/worker.ts +82 -5
  48. package/plugin/vendor/preview.worker.docs.js +20928 -17830
  49. package/plugin/vendor/templates/go.md +1 -1
  50. package/plugin/vendor/templates/python.md +1 -1
  51. package/resolveSrcFile.ts +10 -0
  52. package/scripts/vendor_deps.ts +5 -5
  53. package/shared/getProsePages.ts +42 -0
  54. package/shared/getSharedLogger.ts +15 -0
  55. package/shared/terminalUtils.ts +3 -0
  56. package/shared/virtualModule.ts +54 -1
  57. package/src/content.config.ts +9 -0
  58. package/stl-docs/components/AIDropdown.tsx +63 -0
  59. package/stl-docs/components/AiChatIsland.tsx +14 -0
  60. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  61. package/stl-docs/components/Head.astro +20 -0
  62. package/stl-docs/components/Header.astro +6 -8
  63. package/stl-docs/components/PageFrame.astro +18 -0
  64. package/stl-docs/components/PageTitle.astro +82 -0
  65. package/stl-docs/components/TableOfContents.astro +34 -0
  66. package/stl-docs/components/ThemeProvider.astro +36 -0
  67. package/stl-docs/components/ThemeSelect.astro +84 -139
  68. package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
  69. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
  70. package/stl-docs/components/headers/StackedHeader.astro +29 -24
  71. package/stl-docs/components/icons/chat-gpt.tsx +2 -2
  72. package/stl-docs/components/icons/cursor.tsx +10 -0
  73. package/stl-docs/components/icons/gemini.tsx +19 -0
  74. package/stl-docs/components/icons/markdown.tsx +1 -1
  75. package/stl-docs/components/index.ts +1 -0
  76. package/stl-docs/components/mintlify-compat/Accordion.astro +7 -5
  77. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +7 -3
  78. package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
  79. package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
  80. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +1 -1
  81. package/stl-docs/components/mintlify-compat/callouts/Check.astro +1 -1
  82. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +1 -1
  83. package/stl-docs/components/mintlify-compat/callouts/Info.astro +1 -1
  84. package/stl-docs/components/mintlify-compat/callouts/Note.astro +1 -1
  85. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +1 -1
  86. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +1 -1
  87. package/stl-docs/components/mintlify-compat/card.css +33 -35
  88. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  89. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -70
  90. package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
  91. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
  92. package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
  93. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  94. package/stl-docs/components/pagination/Pagination.astro +175 -0
  95. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  96. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  97. package/stl-docs/components/pagination/util.ts +71 -0
  98. package/stl-docs/components/scripts.ts +1 -0
  99. package/stl-docs/components/sidebars/BaseSidebar.astro +9 -2
  100. package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
  101. package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
  102. package/stl-docs/disableCalloutSyntax.ts +36 -0
  103. package/stl-docs/fonts.ts +186 -0
  104. package/stl-docs/index.ts +153 -50
  105. package/stl-docs/loadStlDocsConfig.ts +51 -7
  106. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
  107. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
  108. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  109. package/stl-docs/proseSearchIndexing.ts +606 -0
  110. package/stl-docs/tabsMiddleware.ts +13 -4
  111. package/styles/code.css +128 -136
  112. package/styles/links.css +11 -48
  113. package/styles/method-descriptions.css +36 -0
  114. package/styles/overrides.css +49 -57
  115. package/styles/page.css +100 -59
  116. package/styles/sdk_select.css +9 -7
  117. package/styles/search.css +57 -69
  118. package/styles/sidebar.css +26 -156
  119. package/styles/{variables.css → sl-variables.css} +3 -2
  120. package/styles/stldocs-variables.css +6 -0
  121. package/styles/toc.css +41 -34
  122. package/theme.css +11 -11
  123. package/tsconfig.json +2 -5
  124. package/virtual-module.d.ts +47 -7
  125. package/components/variables.css +0 -135
  126. package/plugin/cms/client.ts +0 -62
  127. package/plugin/cms/server.ts +0 -268
  128. package/plugin/globalJs/ai-dropdown.ts +0 -57
  129. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
  130. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
  131. package/stl-docs/components/mintlify-compat/Step.astro +0 -58
  132. package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
  133. package/styles/fonts.css +0 -68
  134. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  135. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  136. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  137. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  138. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  139. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  140. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  141. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  142. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -1,22 +1,24 @@
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';
2
+ import { marked, Tokens } from 'marked';
3
+
4
+ import {
5
+ createMarkdownProcessor,
6
+ CreateShikiHighlighterOptions,
7
+ type MarkdownProcessor,
8
+ } from '@astrojs/markdown-remark';
5
9
  import remarkGfmAlerts from 'remark-github-alerts';
6
10
 
7
11
  import type { MarkdownHeading } from 'astro';
8
12
  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';
13
+ import type * as SDKJSON from '@stainless/sdk-json';
14
+ import { LanguageNames, SupportedLanguageSyntaxes, type DocsLanguage } from '@stainless-api/docs-ui/routing';
11
15
 
12
16
  import {
13
- generateRouteList,
14
17
  generateRoute,
15
18
  parseStainlessPath,
16
19
  walkTree,
17
- SupportedLanguageSyntaxes,
18
20
  getLanguageSnippet,
19
- } from '@stainless-api/docs-ui/src/routing';
21
+ } from '@stainless-api/docs-ui/routing';
20
22
 
21
23
  import {
22
24
  DocsProvider,
@@ -24,63 +26,46 @@ import {
24
26
  NavigationProvider,
25
27
  useSpec,
26
28
  type ContentPanelLayout,
27
- } from '@stainless-api/docs-ui/src/contexts';
29
+ } from '@stainless-api/docs-ui/contexts';
28
30
 
29
- import { flatResources, getResourceFromSpec } from '@stainless-api/docs-ui/src/utils';
31
+ import { flatResources, getResourceFromSpec } from '@stainless-api/docs-ui/utils';
30
32
 
31
33
  import {
32
34
  SDKMethod,
33
35
  SDKResource,
34
36
  type SDKRequestTitleProps,
35
37
  SDKBreadcrumbs,
36
- Dropdown,
37
- DropdownTrigger,
38
- DropdownMenu,
39
- DropdownItem,
40
38
  SDKIcon,
41
39
  SDKOverview,
42
40
  SDKLanguageBlock,
43
- } from '@stainless-api/docs-ui/src/components';
41
+ } from '@stainless-api/docs-ui/components';
42
+
43
+ import { Dropdown } from '@stainless-api/docs/components';
44
+
44
45
  import {
45
- BASE_PATH,
46
+ RESOLVED_API_REFERENCE_PATH,
46
47
  EXCLUDE_LANGUAGES,
47
48
  EXPAND_RESOURCES,
48
49
  HIGHLIGHT_THEMES,
49
50
  BREADCRUMB_CONFIG,
50
51
  PROPERTY_SETTINGS,
51
- INCLUDE_AI_DROPDOWN_OPTIONS,
52
+ ENABLE_CONTEXT_MENU,
53
+ EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS,
52
54
  } 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';
55
+ import style from '@stainless-api/docs-ui/style';
56
+ import { BundledTheme, createHighlighter, HighlighterGeneric, type BundledLanguage } from 'shiki';
57
+ import {
58
+ SnippetCode,
59
+ SnippetContainer,
60
+ SnippetButtons,
61
+ SnippetFooter,
62
+ SnippetResponse,
63
+ } from '../components/SnippetCode';
57
64
  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
- }
65
+ import { ComponentProvider } from '@stainless-api/docs-ui/contexts/component';
66
+ import { AIDropdown } from '../../stl-docs/components/AIDropdown';
67
+ import { ChevronsUpDownIcon } from 'lucide-react';
68
+ import { MethodDescription } from '../components/MethodDescription';
84
69
 
85
70
  function isResourceNonEmpty(resource: SDKJSON.Resource) {
86
71
  return (
@@ -121,7 +106,6 @@ export function buildSidebar(
121
106
 
122
107
  const meths: SidebarEntry[] = Object.values(resource.methods ?? [])
123
108
  .filter((method) => spec.decls?.[language]?.[method.stainlessPath])
124
- .toSorted((first, second) => first.name.localeCompare(second.name))
125
109
  .map((method) => ({
126
110
  type: 'link',
127
111
  isCurrent: current === method.stainlessPath,
@@ -153,19 +137,58 @@ export function buildPageNavigation(resource: SDKJSON.Resource, depth: number =
153
137
  return [...output, ...subs];
154
138
  }
155
139
 
156
- function renderMarkdown(content: string) {
157
- return marked.parse(content, { gfm: true }) as string;
140
+ async function renderMarkdown(content: string) {
141
+ const highlighter = await astroHighlight();
142
+
143
+ const renderer = {
144
+ code({ text, lang }: Tokens.Code) {
145
+ return shikiHighlight({
146
+ highlighter,
147
+ content: text,
148
+ language: lang,
149
+ });
150
+ },
151
+ };
152
+
153
+ marked.use({ renderer });
154
+ return marked.parse(content, {
155
+ gfm: true,
156
+ }) as string;
158
157
  }
159
158
 
160
- async function highlight(content: string, language?: string) {
161
- if (language === 'json') return hljs.highlight(content, { language }).value;
162
- const highlighter = await astroHighlight();
159
+ function shikiHighlight({
160
+ highlighter,
161
+ content,
162
+ language,
163
+ themes,
164
+ }: {
165
+ highlighter: HighlighterGeneric<BundledLanguage, BundledTheme>;
166
+ content: string;
167
+ language?: string;
168
+ themes?: CreateShikiHighlighterOptions['themes'] | Record<string, 'stainless-docs-json'>;
169
+ }) {
170
+ let _themes = themes;
171
+ if (!themes && language === 'json') {
172
+ _themes = {
173
+ light: 'stainless-docs-json',
174
+ dark: 'stainless-docs-json',
175
+ };
176
+ }
177
+
178
+ if (!_themes) {
179
+ _themes = HIGHLIGHT_THEMES;
180
+ }
163
181
  return highlighter.codeToHtml(content, {
164
182
  lang: language ?? 'javascript',
165
- themes: HIGHLIGHT_THEMES || {},
183
+ themes: _themes || {},
166
184
  });
167
185
  }
168
186
 
187
+ async function highlight(content: string, language?: string) {
188
+ const highlighter = await astroHighlight();
189
+ return shikiHighlight({ highlighter, content, language });
190
+ }
191
+
169
192
  export function SDKSelectReactComponent({
170
193
  selected,
171
194
  languages,
@@ -179,30 +202,36 @@ export function SDKSelectReactComponent({
179
202
  }) {
180
203
  return (
181
204
  <Dropdown id={id} data-current-value={selected} className={className}>
182
- <DropdownTrigger
183
- className="dropdown-toggle stldocs-button-tertiary"
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
205
+ <Dropdown.Trigger>
206
+ <Dropdown.TriggerSelectedItem>
207
+ <Dropdown.Icon>
208
+ <SDKIcon language={getLanguageSnippet(selected)} />
209
+ </Dropdown.Icon>
210
+ <span className="stl-snippet-dropdown-button-text">{LanguageNames[selected]}</span>
211
+ </Dropdown.TriggerSelectedItem>
212
+ <Dropdown.TriggerIcon>
213
+ <ChevronsUpDownIcon size={16} />
214
+ </Dropdown.TriggerIcon>
215
+ </Dropdown.Trigger>
216
+ <Dropdown.Menu
193
217
  className="dropdown-menu stl-sdk-select-dropdown-menu"
194
- position="below"
195
- aria-labelledby="stldocs-snippet-title-button"
218
+ aria-labelledby="stl-docs-snippet-title-button"
196
219
  >
197
220
  {languages.map((item) => (
198
- <DropdownItem key={item} value={item} selected={item === selected}>
199
- <div>
221
+ <Dropdown.MenuItem key={item} value={item} isSelected={item === selected}>
222
+ <Dropdown.Icon>
200
223
  <SDKIcon language={getLanguageSnippet(item)} size={16} />
201
- <span className={clsx('stl-snippet-dropdown-button-text', item)}>{item}</span>
202
- </div>
203
- </DropdownItem>
224
+ </Dropdown.Icon>
225
+ <Dropdown.MenuItemText>{LanguageNames[item]}</Dropdown.MenuItemText>
226
+ <Dropdown.MenuItemTemplate>
227
+ <Dropdown.Icon>
228
+ <SDKIcon language={getLanguageSnippet(item)} size={16} />
229
+ </Dropdown.Icon>
230
+ <span className="stl-snippet-dropdown-button-text">{LanguageNames[item]}</span>
231
+ </Dropdown.MenuItemTemplate>
232
+ </Dropdown.MenuItem>
204
233
  ))}
205
- </DropdownMenu>
234
+ </Dropdown.Menu>
206
235
  </Dropdown>
207
236
  );
208
237
  }
@@ -218,13 +247,13 @@ function SDKRequestTitle({ snippetLanguage }: SDKRequestTitleProps) {
218
247
  selected={selected || 'http'}
219
248
  languages={languages}
220
249
  id="stldocs-snippet-select"
221
- className="stl-sdk-select"
250
+ className="stl-sdk-select stl-ui-not-prose"
222
251
  />
223
252
  );
224
253
  }
225
254
 
226
255
  export type SpecMetadata = [
227
- 'http' | 'node' | 'python' | 'go' | 'typescript' | 'terraform' | 'ruby' | 'java' | 'kotlin',
256
+ DocsLanguage,
228
257
  {
229
258
  repo_url?: string;
230
259
  code_url?: string;
@@ -234,15 +263,26 @@ export type SpecMetadata = [
234
263
  },
235
264
  ][];
236
265
 
266
+ const componentOverrides = {
267
+ SDKRequestTitle,
268
+ SnippetCode,
269
+ SnippetContainer,
270
+ SnippetButtons,
271
+ SnippetFooter,
272
+ SnippetResponse,
273
+ ...(EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS ? { MethodDescription } : {}),
274
+ } satisfies React.ComponentProps<typeof ComponentProvider>['components'];
275
+
237
276
  export function RenderLibraries({ metadata }: { metadata: SpecMetadata }) {
238
277
  return (
239
- <ComponentProvider components={{}}>
278
+ <ComponentProvider components={componentOverrides}>
240
279
  {metadata.map(([language, data]) => (
241
280
  <SDKLanguageBlock
281
+ key={language}
242
282
  language={language}
243
283
  version={data.version || ''}
244
284
  install={data.install || ''}
245
- links={{ repo: data.repo_url || '#', docs: `${BASE_PATH}/${language}` }}
285
+ links={{ repo: data.repo_url || '#', docs: `${RESOLVED_API_REFERENCE_PATH}/${language}` }}
246
286
  />
247
287
  ))}
248
288
  </ComponentProvider>
@@ -254,15 +294,8 @@ export function RenderSpecOverview({ spec, language }: { spec: SDKJSON.Spec; lan
254
294
 
255
295
  return (
256
296
  <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}>
297
+ <ComponentProvider components={componentOverrides}>
298
+ <NavigationProvider basePath={RESOLVED_API_REFERENCE_PATH}>
266
299
  <MarkdownProvider render={renderMarkdown} highlight={highlight}>
267
300
  <div className={style.Overview}>
268
301
  {resources
@@ -303,7 +336,10 @@ export function RenderSpec({
303
336
  const parsed = parseStainlessPath(path);
304
337
  const resource = getResourceFromSpec(path, spec);
305
338
 
306
- if (!resource || !parsed) return null;
339
+ if (!resource || !parsed) {
340
+ console.warn(`Could not find resource or parsed path for '${path}'`);
341
+ return null;
342
+ }
307
343
 
308
344
  return (
309
345
  <DocsProvider
@@ -314,46 +350,30 @@ export function RenderSpec({
314
350
  properties: PROPERTY_SETTINGS,
315
351
  }}
316
352
  >
317
- <ComponentProvider
318
- components={{
319
- SDKRequestTitle,
320
- SnippetCode,
321
- SnippetContainer,
322
- SnippetRequestContainer,
323
- }}
324
- >
325
- <NavigationProvider basePath={BASE_PATH} selectedPath={path}>
353
+ <ComponentProvider components={componentOverrides}>
354
+ <NavigationProvider basePath={RESOLVED_API_REFERENCE_PATH} selectedPath={path}>
326
355
  <MarkdownProvider render={renderMarkdown} highlight={highlight}>
327
- {kind === 'http_method' ? (
356
+ {
328
357
  <div className="stldocs-root stl-ui-not-prose">
329
358
  <div className="stl-page-nav-container">
330
359
  <SDKBreadcrumbs
331
360
  spec={spec as SDKJSON.Spec}
332
361
  currentPath={currentPath}
333
- basePath={BASE_PATH}
362
+ basePath={RESOLVED_API_REFERENCE_PATH}
334
363
  config={BREADCRUMB_CONFIG}
335
364
  />
336
- {INCLUDE_AI_DROPDOWN_OPTIONS && <APIReferenceAIDropdown />}
365
+ {ENABLE_CONTEXT_MENU && <AIDropdown />}
337
366
  </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}
367
+ {kind === 'http_method' ? (
368
+ <SDKMethod
369
+ method={resource.methods[parsed.method!]!}
370
+ transformRequestSnippet={transformRequestSnippet}
351
371
  />
352
- {INCLUDE_AI_DROPDOWN_OPTIONS && <APIReferenceAIDropdown />}
353
- </div>
354
- <SDKOverview resource={resource} />
372
+ ) : (
373
+ <SDKOverview resource={resource} />
374
+ )}
355
375
  </div>
356
- )}
376
+ }
357
377
  </MarkdownProvider>
358
378
  </NavigationProvider>
359
379
  </ComponentProvider>
@@ -367,10 +387,14 @@ export function RenderMethod({ path }: { path: string }) {
367
387
 
368
388
  const parsed = parseStainlessPath(path);
369
389
  const resource = getResourceFromSpec(path, spec);
370
- if (!resource || !parsed) return null;
371
390
 
372
- const meth = resource.methods[parsed.method];
373
- return <SDKMethod method={meth} />;
391
+ if (!resource || !parsed) {
392
+ console.warn(`Could not find resource or parsed path for '${path}'`);
393
+ return null;
394
+ }
395
+
396
+ const method = resource.methods[parsed.method!]!;
397
+ return <SDKMethod method={method} />;
374
398
  }
375
399
 
376
400
  export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguage) {
@@ -390,8 +414,68 @@ export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguag
390
414
  return spec.readme[language];
391
415
  }
392
416
 
417
+ let astroShikiHighlighter:
418
+ | HighlighterGeneric<BundledLanguage, BundledTheme>
419
+ | Promise<HighlighterGeneric<BundledLanguage, BundledTheme>>
420
+ | null = null;
421
+
422
+ async function astroHighlight() {
423
+ if (astroShikiHighlighter) {
424
+ return astroShikiHighlighter;
425
+ }
426
+
427
+ astroShikiHighlighter = createHighlighter({
428
+ themes: [
429
+ 'github-light',
430
+ 'github-dark',
431
+ {
432
+ name: 'stainless-docs-json',
433
+ colors: {
434
+ 'editor.background': 'var(--stl-color-background)',
435
+ 'editor.foreground': 'var(--stl-color-foreground)',
436
+ },
437
+
438
+ tokenColors: [
439
+ {
440
+ scope: ['comment', 'punctuation.definition.comment'],
441
+ settings: { foreground: 'var(--stl-color-foreground-muted)' },
442
+ },
443
+ // numbers, booleans, null
444
+ {
445
+ scope: ['constant.numeric', 'constant.language'],
446
+ settings: { foreground: 'var(--stl-color-orange-foreground)' },
447
+ },
448
+ // strings
449
+ {
450
+ scope: ['string', 'string.quoted', 'string.template'],
451
+ settings: { foreground: 'var(--stl-color-green-foreground)' },
452
+ },
453
+ // Keys, brackets
454
+ {
455
+ scope: ['support.type', 'meta'],
456
+ settings: { foreground: 'var(--stl-color-foreground)' },
457
+ },
458
+ // brackets
459
+ {
460
+ scope: ['meta'],
461
+ settings: { foreground: 'var(--stl-color-foreground-muted)' },
462
+ },
463
+ // built-in types
464
+ {
465
+ scope: ['support.type.builtin'],
466
+ settings: { foreground: 'var(--stl-color-purple-foreground)' },
467
+ },
468
+ ],
469
+ },
470
+ ],
471
+ langs: SupportedLanguageSyntaxes,
472
+ });
473
+
474
+ return astroShikiHighlighter;
475
+ }
476
+
393
477
  // Astro's markdown processor is a singleton
394
- // Need to cache it instead of instanting per request
478
+ // Need to cache it instead of instantiating per request
395
479
  let astroMarkdownProcessor: MarkdownProcessor;
396
480
  async function astroMarkdown() {
397
481
  if (!astroMarkdownProcessor) {
@@ -407,18 +491,6 @@ async function astroMarkdown() {
407
491
  return astroMarkdownProcessor;
408
492
  }
409
493
 
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
494
  export async function astroMarkdownRender(content: string) {
423
495
  const md = await astroMarkdown();
424
496
  const output = await md.render(content);
@@ -21,27 +21,30 @@ export function makePlaceholderItems(id: number) {
21
21
 
22
22
  type StarlightConfig = Parameters<typeof starlight>[0];
23
23
 
24
- type SidebarConfigEntry = Exclude<StarlightConfig['sidebar'], undefined>[number];
24
+ export 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
 
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
+
12
35
  export const onRequest = defineRouteMiddleware(async (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
  });