@stainless-api/docs 0.1.0-beta.5 → 0.1.0-beta.50

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 (115) hide show
  1. package/CHANGELOG.md +381 -0
  2. package/eslint-suppressions.json +47 -0
  3. package/locals.d.ts +14 -0
  4. package/package.json +42 -38
  5. package/plugin/buildAlgoliaIndex.ts +31 -6
  6. package/plugin/cms/server.ts +98 -56
  7. package/plugin/cms/sidebar-builder.ts +7 -26
  8. package/plugin/cms/worker.ts +3 -3
  9. package/plugin/components/MethodDescription.tsx +54 -0
  10. package/plugin/components/SDKSelect.astro +7 -87
  11. package/plugin/components/SnippetCode.tsx +11 -7
  12. package/plugin/components/search/SearchAlgolia.astro +5 -33
  13. package/plugin/components/search/SearchIsland.tsx +37 -23
  14. package/plugin/generateAPIReferenceLink.ts +2 -2
  15. package/plugin/globalJs/ai-dropdown-options.ts +235 -0
  16. package/plugin/globalJs/method-descriptions.ts +33 -0
  17. package/plugin/globalJs/navigation.ts +7 -27
  18. package/plugin/helpers/getPageLoadEvent.ts +1 -1
  19. package/plugin/index.ts +54 -34
  20. package/plugin/languages.ts +2 -2
  21. package/plugin/loadPluginConfig.ts +112 -32
  22. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
  23. package/plugin/react/Routing.tsx +176 -80
  24. package/plugin/referencePlaceholderUtils.ts +1 -1
  25. package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
  26. package/plugin/routes/Docs.astro +60 -85
  27. package/plugin/routes/Overview.astro +10 -16
  28. package/plugin/routes/markdown.ts +7 -7
  29. package/plugin/vendor/preview.worker.docs.js +17973 -16561
  30. package/plugin/vendor/templates/go.md +1 -1
  31. package/plugin/vendor/templates/python.md +1 -1
  32. package/resolveSrcFile.ts +10 -0
  33. package/scripts/vendor_deps.ts +1 -1
  34. package/shared/getSharedLogger.ts +15 -0
  35. package/shared/terminalUtils.ts +3 -0
  36. package/src/content.config.ts +9 -0
  37. package/stl-docs/components/AIDropdown.tsx +63 -0
  38. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  39. package/stl-docs/components/Head.astro +16 -0
  40. package/stl-docs/components/Header.astro +6 -8
  41. package/stl-docs/components/PageTitle.astro +82 -0
  42. package/stl-docs/components/TableOfContents.astro +34 -0
  43. package/stl-docs/components/ThemeSelect.astro +118 -141
  44. package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
  45. package/stl-docs/components/headers/DefaultHeader.astro +1 -1
  46. package/stl-docs/components/headers/HeaderLinks.astro +1 -1
  47. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
  48. package/stl-docs/components/headers/StackedHeader.astro +29 -24
  49. package/stl-docs/components/icons/chat-gpt.tsx +17 -0
  50. package/stl-docs/components/icons/claude.tsx +10 -0
  51. package/stl-docs/components/icons/cursor.tsx +10 -0
  52. package/stl-docs/components/icons/gemini.tsx +19 -0
  53. package/stl-docs/components/icons/markdown.tsx +10 -0
  54. package/stl-docs/components/index.ts +1 -0
  55. package/stl-docs/components/mintlify-compat/Accordion.astro +7 -38
  56. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +9 -23
  57. package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
  58. package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
  59. package/stl-docs/components/mintlify-compat/Step.astro +30 -32
  60. package/stl-docs/components/mintlify-compat/Steps.astro +8 -10
  61. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +10 -3
  62. package/stl-docs/components/mintlify-compat/callouts/Check.astro +7 -3
  63. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +7 -3
  64. package/stl-docs/components/mintlify-compat/callouts/Info.astro +7 -3
  65. package/stl-docs/components/mintlify-compat/callouts/Note.astro +7 -3
  66. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +7 -3
  67. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +7 -3
  68. package/stl-docs/components/mintlify-compat/card.css +33 -35
  69. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -75
  70. package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
  71. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
  72. package/stl-docs/components/nav-tabs/buildNavLinks.ts +4 -3
  73. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  74. package/stl-docs/components/pagination/Pagination.astro +174 -0
  75. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  76. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  77. package/stl-docs/components/pagination/util.ts +71 -0
  78. package/stl-docs/components/scripts.ts +1 -0
  79. package/stl-docs/components/{Sidebar.astro → sidebars/BaseSidebar.astro} +2 -3
  80. package/stl-docs/components/sidebars/SDKSelectSidebar.astro +8 -0
  81. package/stl-docs/disableCalloutSyntax.ts +36 -0
  82. package/stl-docs/index.ts +98 -26
  83. package/stl-docs/loadStlDocsConfig.ts +37 -5
  84. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +64 -0
  85. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +34 -0
  86. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  87. package/stl-docs/tabsMiddleware.ts +12 -4
  88. package/styles/code.css +104 -141
  89. package/styles/fonts.css +32 -17
  90. package/styles/links.css +11 -48
  91. package/styles/method-descriptions.css +36 -0
  92. package/styles/overrides.css +49 -57
  93. package/styles/page.css +90 -59
  94. package/styles/sdk_select.css +9 -7
  95. package/styles/search.css +58 -69
  96. package/styles/sidebar.css +211 -131
  97. package/styles/{variables.css → sl-variables.css} +3 -2
  98. package/styles/stldocs-variables.css +6 -0
  99. package/styles/toc.css +41 -34
  100. package/theme.css +12 -2
  101. package/tsconfig.json +2 -5
  102. package/virtual-module.d.ts +8 -4
  103. package/components/variables.css +0 -139
  104. package/plugin/globalJs/ai-dropdown.ts +0 -57
  105. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -86
  106. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -64
  107. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  108. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  109. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  110. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  111. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  112. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  113. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  114. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  115. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -0,0 +1,174 @@
1
+ ---
2
+ import HomeLink from './HomeLink.astro';
3
+ import PaginationLinkEmphasized from './PaginationLinkEmphasized.astro';
4
+
5
+ import { getPrevNextPage } from './util';
6
+ import config from 'virtual:starlight/user-config';
7
+ const { prev, next } = (await getPrevNextPage(Astro.locals.starlightRoute, config.pagination)) ?? {};
8
+ ---
9
+
10
+ {
11
+ next || prev ? (
12
+ <div class="pagination-links print:hidden stl-ui-not-prose">
13
+ {/* Previous */}
14
+ {!prev && <HomeLink />}
15
+ {/* TODO: intelligently decide whether or not to emphasize the previous page - including user config option (page level?) */}
16
+ {/* {prev && next && (
17
+ <PaginationLinkQuiet href={prev.href}>
18
+ <ChevronLeftIcon slot="icon" />
19
+ Previous
20
+ </PaginationLinkQuiet>
21
+ )} */}
22
+ {prev && (
23
+ <PaginationLinkEmphasized href={prev.href} direction="prev">
24
+ <h2 slot="page-title">{prev.label}</h2>
25
+ {prev.description && <p slot="page-description">{prev.description}</p>}
26
+ </PaginationLinkEmphasized>
27
+ )}
28
+
29
+ {/* Next */}
30
+ {!next && <HomeLink />}
31
+ {next && (
32
+ <PaginationLinkEmphasized href={next.href} direction="next">
33
+ <h2 slot="page-title">{next.label}</h2>
34
+ {next.description && <p slot="page-description">{next.description}</p>}
35
+ </PaginationLinkEmphasized>
36
+ )}
37
+ </div>
38
+ ) : null
39
+ }
40
+
41
+ <style is:global>
42
+ @layer starlight.core {
43
+ .pagination-links,
44
+ .pagination-links a,
45
+ .pagination-links a:hover,
46
+ .pagination-links a[rel='next'],
47
+ .link-title {
48
+ all: revert-layer;
49
+ }
50
+ }
51
+
52
+ .pagination-links {
53
+ --stl-ui-pagination-padding: 8px;
54
+ --stl-ui-pagination-border-radius-inner: var(--stl-ui-layout-border-radius-sml);
55
+
56
+ padding: var(--stl-ui-pagination-padding);
57
+ background-color: var(--stl-color-faint-background);
58
+ border: 1px solid var(--stl-color-border);
59
+ border-radius: calc(var(--stl-ui-pagination-border-radius-inner) + var(--stl-ui-pagination-padding));
60
+
61
+ font-size: var(--stl-typography-scale-sm);
62
+ letter-spacing: normal;
63
+
64
+ display: flex;
65
+ gap: 8px;
66
+
67
+ margin-bottom: 2rem;
68
+
69
+ a {
70
+ border-radius: var(--stl-ui-pagination-border-radius-inner);
71
+ }
72
+ }
73
+
74
+ .pagination-links__link {
75
+ display: flex;
76
+ border-radius: var(--stl-ui-pagination-border-radius-inner);
77
+ padding: 8px 12px;
78
+ display: flex;
79
+ text-decoration: none;
80
+ align-items: center;
81
+ color: inherit;
82
+ }
83
+
84
+ .pagination-links__link--emphasized {
85
+ background-color: var(--stl-color-background);
86
+ border: 1px solid var(--stl-color-border);
87
+ flex: 1 1 50%;
88
+ gap: 12px;
89
+ }
90
+
91
+ .pagination-links__link--quiet {
92
+ flex: 0 1 auto;
93
+ }
94
+
95
+ .pagination-links__button {
96
+ display: flex;
97
+ align-items: center;
98
+ padding: 8px 14px;
99
+ font-weight: 500;
100
+ line-height: 1;
101
+
102
+ svg {
103
+ width: 16px;
104
+ height: 16px;
105
+ margin-block: -4px;
106
+ margin-inline-start: -6px;
107
+ margin-inline-end: 6px;
108
+ }
109
+
110
+ &.pagination-links__link--quiet {
111
+ padding-inline: 22px;
112
+ }
113
+ }
114
+
115
+ .pagination-links__link__divider {
116
+ border: 0;
117
+ border-inline-start: 1px solid var(--stl-color-border);
118
+ align-self: stretch;
119
+ }
120
+
121
+ .pagination-links__page-description {
122
+ padding-block: 4px;
123
+ padding-inline-start: 8px;
124
+ padding-inline-end: 2px;
125
+ line-height: 1.5;
126
+ flex: 1 1 50%;
127
+ width: 0;
128
+
129
+ h2,
130
+ p {
131
+ white-space: nowrap;
132
+ overflow: hidden;
133
+ text-overflow: ellipsis;
134
+ }
135
+ h2 {
136
+ font-size: inherit;
137
+ font-weight: 500;
138
+ }
139
+ p {
140
+ font-size: var(--stl-typography-scale-xs);
141
+ color: var(--stl-color-foreground-muted);
142
+ }
143
+ }
144
+ .pagination-links__link--quiet:hover {
145
+ background-color: var(--stl-color-background-hover);
146
+ }
147
+ .pagination-links__link--emphasized:hover {
148
+ border-color: var(--stl-color-border-strong);
149
+ .pagination-links__page-description h2 {
150
+ text-decoration: underline;
151
+ text-decoration-color: var(--stl-color-foreground-reduced);
152
+ }
153
+ }
154
+
155
+ /* “next” link runs the opposite direction of the “previous” link */
156
+ .pagination-links__link:last-child {
157
+ flex-direction: row-reverse;
158
+
159
+ &.pagination-links__button,
160
+ .pagination-links__button {
161
+ flex-direction: row-reverse;
162
+ svg {
163
+ margin-inline-start: 6px;
164
+ margin-inline-end: -6px;
165
+ }
166
+ }
167
+
168
+ .pagination-links__page-description {
169
+ padding-inline-start: 2px;
170
+ padding-inline-end: 8px;
171
+ text-align: right;
172
+ }
173
+ }
174
+ </style>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
3
+ const { href, direction } = Astro.props;
4
+ export interface Props {
5
+ href: string;
6
+ direction: 'prev' | 'next';
7
+ }
8
+ ---
9
+
10
+ <a href={href} class="pagination-links__link pagination-links__link--emphasized">
11
+ <div class="pagination-links__button">
12
+ {{ prev: <ChevronLeftIcon />, next: <ChevronRightIcon /> }[direction]}
13
+ <span>{{ prev: 'Previous', next: 'Next' }[direction]}</span>
14
+ </div>
15
+
16
+ <hr class="pagination-links__link__divider" />
17
+
18
+ <article class="pagination-links__page-description">
19
+ <slot name="page-title" />
20
+ <slot name="page-description" />
21
+ </article>
22
+ </a>
@@ -0,0 +1,13 @@
1
+ ---
2
+ const { href } = Astro.props;
3
+ export interface Props {
4
+ href: string;
5
+ }
6
+ ---
7
+
8
+ <a href={href} class="pagination-links__link pagination-links__button pagination-links__link--quiet">
9
+ <slot name="icon" />
10
+ <span>
11
+ <slot />
12
+ </span>
13
+ </a>
@@ -0,0 +1,71 @@
1
+ import type { StarlightRouteData } from '@astrojs/starlight/route-data';
2
+ import { getCollection } from 'astro:content';
3
+
4
+ export type SidebarEntry = StarlightRouteData['sidebar'][number];
5
+ export type SidebarLink = Extract<SidebarEntry, { type: 'link' }>;
6
+ export type SidebarGroup = Extract<SidebarEntry, { type: 'group' }>;
7
+
8
+ export const flattenSidebar = (sidebar: SidebarEntry[]): SidebarLink[] =>
9
+ sidebar.flatMap((e) => (e.type === 'group' ? flattenSidebar(e.entries) : e));
10
+
11
+ function findParentOfSidebarEntry(sidebar: SidebarEntry[], targetEntry: SidebarEntry): SidebarGroup | null {
12
+ for (const entry of sidebar) {
13
+ if (entry.type === 'group') {
14
+ if (entry.entries.includes(targetEntry)) {
15
+ return entry;
16
+ }
17
+ const foundInChild = findParentOfSidebarEntry(entry.entries, targetEntry);
18
+ if (foundInChild) {
19
+ return foundInChild;
20
+ }
21
+ }
22
+ }
23
+ return null;
24
+ }
25
+
26
+ export async function getPrevNextPage(page: StarlightRouteData, paginationEnabled: boolean) {
27
+ // TODO: respect user `next` / `prev` config from frontmatter the way starlight does
28
+
29
+ if (!paginationEnabled) return null;
30
+
31
+ const docsContent = await getCollection('docs');
32
+ const findSidebarLinkInContent = (link: SidebarLink) =>
33
+ docsContent.find((doc) => {
34
+ if (doc.id === 'index' && link.href === '/') return true;
35
+ return doc.id === link.href.replace(/^\//, '').replace(/\/$/, '');
36
+ });
37
+
38
+ const currentSidebar = page.sidebar;
39
+
40
+ const paginationSequence: (SidebarLink & { description?: string })[] = flattenSidebar(currentSidebar)
41
+ // Remove injected stl-mobile-only-sidebar-item links - TODO: better solution for this
42
+ .filter((link) => !(link.attrs.class ?? '').trim().split(/\s+/).includes('stl-mobile-only-sidebar-item'))
43
+ // Remove data-stldocs-method links from pagination sequence
44
+ .filter((link) => !link.attrs['data-stldocs-method'])
45
+ // Map data-stldocs-overview=readme links so that their name is not just “Overview”
46
+ .map((link) => {
47
+ if (link.attrs['data-stldocs-overview'] && link.label === 'Overview') {
48
+ const parent = findParentOfSidebarEntry(currentSidebar, link);
49
+ if (parent) return { ...link, label: parent.label };
50
+ }
51
+ return link;
52
+ })
53
+ .map((link) => {
54
+ const contentEntry = findSidebarLinkInContent(link);
55
+ if (contentEntry) return { ...link, description: contentEntry.data.description };
56
+ return link;
57
+ });
58
+
59
+ const currentIndex = paginationSequence.findIndex((e) => e.isCurrent);
60
+ if (currentIndex === -1) return null;
61
+
62
+ const prevIndex = currentIndex > 0 ? currentIndex - 1 : null;
63
+ const nextIndex = currentIndex < paginationSequence.length - 1 ? currentIndex + 1 : null;
64
+ const prevSidebarEntry = prevIndex !== null ? (paginationSequence[prevIndex] ?? null) : null;
65
+ const nextSidebarEntry = nextIndex !== null ? (paginationSequence[nextIndex] ?? null) : null;
66
+
67
+ return {
68
+ prev: prevSidebarEntry,
69
+ next: nextSidebarEntry,
70
+ };
71
+ }
@@ -0,0 +1 @@
1
+ export * from '@stainless-api/ui-primitives/scripts';
@@ -1,11 +1,10 @@
1
1
  ---
2
2
  import Default from '@astrojs/starlight/components/Sidebar.astro';
3
- import SDKSelect from '../../plugin/components/SDKSelect.astro';
4
- import HeaderLinks from './headers/HeaderLinks.astro';
3
+ import HeaderLinks from '../headers/HeaderLinks.astro';
5
4
  ---
6
5
 
7
6
  <div class="stl-sidebar-header-links">
8
7
  <HeaderLinks />
9
8
  </div>
10
- <SDKSelect />
9
+ <slot name="sdk-select" />
11
10
  <Default><slot /></Default>
@@ -0,0 +1,8 @@
1
+ ---
2
+ import BaseSidebar from './BaseSidebar.astro';
3
+ import SDKSelect from '../../../plugin/components/SDKSelect.astro';
4
+ ---
5
+
6
+ <BaseSidebar>
7
+ <SDKSelect slot="sdk-select" />
8
+ </BaseSidebar>
@@ -0,0 +1,36 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ import type { StarlightPlugin } from '@astrojs/starlight/types';
3
+
4
+ export const disableCalloutSyntaxAstroIntegration = {
5
+ name: 'stl-starlight-remove-callout-syntax',
6
+ hooks: {
7
+ 'astro:config:setup': ({ config: astroConfig }) => {
8
+ // Remove starlight callout syntax in favor of our own callout component
9
+ // updateConfig always deeply merges arrays so we need to mutate remarkPlugins directly
10
+ // in order to remove plugins that starlight added
11
+ astroConfig.markdown.remarkPlugins = astroConfig.markdown.remarkPlugins.filter((plugin, i, arr) => {
12
+ if (typeof plugin !== 'function') return true;
13
+ // remove:
14
+ // 1. remarkDirective plugin
15
+ if (plugin.name === 'remarkDirective') return false;
16
+ // 2. directly followed by remarkAsides plugin (inner function named 'attacher')
17
+ if (plugin.name === 'attacher') {
18
+ const prev = arr[i - 1];
19
+ if (typeof prev === 'function' && prev.name === 'remarkDirective') return false;
20
+ }
21
+ // 3. remarkDirectivesRestoration plugin
22
+ if (plugin.name === 'remarkDirectivesRestoration') return false;
23
+ return true;
24
+ });
25
+ },
26
+ },
27
+ } satisfies AstroIntegration;
28
+
29
+ export const disableCalloutSyntaxStarlightPlugin = {
30
+ name: 'stl-starlight-remove-callout-syntax',
31
+ hooks: {
32
+ 'config:setup': ({ addIntegration }) => {
33
+ addIntegration(disableCalloutSyntaxAstroIntegration);
34
+ },
35
+ },
36
+ } satisfies StarlightPlugin;
package/stl-docs/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import starlight from '@astrojs/starlight';
2
2
  import react from '@astrojs/react';
3
+ import type { StarlightPlugin } from '@astrojs/starlight/types';
3
4
  import { stainlessStarlight } from '../plugin';
5
+ import { disableCalloutSyntaxStarlightPlugin } from './disableCalloutSyntax';
4
6
 
5
7
  import type { AstroIntegration } from 'astro';
6
8
 
@@ -16,11 +18,15 @@ import {
16
18
  type StarlightSidebarConfig,
17
19
  } from './loadStlDocsConfig';
18
20
  import { buildVirtualModuleString } from '../shared/virtualModule';
19
-
20
- import geistPath from '../plugin/assets/fonts/geist/geist-latin.woff2?url';
21
+ import type * as StlDocsVirtualModule from 'virtual:stl-docs-virtual-module';
22
+ import { resolveSrcFile } from '../resolveSrcFile';
23
+ import { stainlessDocsMarkdownRenderer } from './proseMarkdown/proseMarkdownIntegration';
24
+ import { setSharedLogger } from '../shared/getSharedLogger';
21
25
 
22
26
  export * from '../plugin';
23
27
 
28
+ const COMPONENTS_FOLDER = '/stl-docs/components';
29
+
24
30
  function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig) {
25
31
  // We transform our tabs into a Starlight sidebar
26
32
  // This gives them all the built-in features of Starlight (eg. auto-generated entries by directory)
@@ -41,13 +47,34 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
41
47
 
42
48
  type ComponentOverrides = StarlightConfigDefined['components'];
43
49
  const componentOverrides: ComponentOverrides = {
44
- Search: '@stainless-api/docs/Search',
45
- Sidebar: '@stainless-api/docs/Sidebar',
46
- Header: '@stainless-api/docs/Header',
47
- ThemeSelect: '@stainless-api/docs/ThemeSelect',
48
- ContentPanel: '@stainless-api/docs/ContentPanel',
50
+ Sidebar: resolveSrcFile(COMPONENTS_FOLDER, './sidebars/BaseSidebar.astro'),
51
+ Header: resolveSrcFile(COMPONENTS_FOLDER, './Header.astro'),
52
+ Head: resolveSrcFile(COMPONENTS_FOLDER, './Head.astro'),
53
+ ThemeSelect: resolveSrcFile(COMPONENTS_FOLDER, './ThemeSelect.astro'),
54
+ ContentPanel: resolveSrcFile(COMPONENTS_FOLDER, './content-panel/ContentPanel.astro'),
55
+ TableOfContents: resolveSrcFile(COMPONENTS_FOLDER, './TableOfContents.astro'),
56
+ PageTitle: resolveSrcFile(COMPONENTS_FOLDER, './PageTitle.astro'),
57
+ Pagination: resolveSrcFile(COMPONENTS_FOLDER, './pagination/Pagination.astro'),
49
58
  };
50
59
 
60
+ const plugins: StarlightPlugin[] = [
61
+ // Disable starlight callout syntax in favor of our own component
62
+ disableCalloutSyntaxStarlightPlugin,
63
+ ];
64
+
65
+ if (config.apiReference !== null) {
66
+ plugins.push(
67
+ stainlessStarlight({
68
+ ...config.apiReference,
69
+ contextMenu: config.contextMenu,
70
+ }),
71
+ );
72
+ componentOverrides.Sidebar = resolveSrcFile(COMPONENTS_FOLDER, './sidebars/SDKSelectSidebar.astro');
73
+ componentOverrides.Search = resolveSrcFile('/plugin/components/search/Search.astro');
74
+ }
75
+
76
+ plugins.push(...config.starlightCompat.plugins);
77
+
51
78
  // TODO: re-add once we figure out what to do with the client router
52
79
  // if (config.enableClientRouter) {
53
80
  // // logger.info(`Client router is enabled`);
@@ -56,6 +83,8 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
56
83
  // // logger.info(`Client router is disabled`);
57
84
  // }
58
85
 
86
+ const userExpressiveCode = typeof config.expressiveCode === 'object' ? config.expressiveCode : {};
87
+
59
88
  return starlight({
60
89
  ...config.starlightPassThrough,
61
90
  sidebar,
@@ -79,33 +108,48 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
79
108
  setupNavLinksInitial();
80
109
  `,
81
110
  },
82
- // TODO: for users who are overriding the font stack in their own styles, how can we know that
83
- // and preload their font instead of ours?
84
- {
85
- tag: 'link',
86
- attrs: {
87
- rel: 'preload',
88
- as: 'font',
89
- type: 'font/woff2',
90
- crossorigin: 'anonymous',
91
- href: geistPath,
111
+ ],
112
+ routeMiddleware: [
113
+ ...config.starlightCompat.routeMiddleware,
114
+ resolveSrcFile('/stl-docs/tabsMiddleware.ts'),
115
+ ],
116
+ customCss: [resolveSrcFile('/theme.css'), ...config.customCss],
117
+
118
+ expressiveCode: {
119
+ ...userExpressiveCode,
120
+ themes: userExpressiveCode.themes ?? ['github-light', 'github-dark'],
121
+ styleOverrides: {
122
+ ...userExpressiveCode.styleOverrides,
123
+ textMarkers: {
124
+ insBackground: 'var(--stl-color-green-muted-background)',
125
+ insBorderColor: 'var(--stl-color-green-border)',
126
+ insDiffIndicatorColor: 'var(--stl-color-green-foreground-reduced)',
127
+
128
+ delBackground: 'var(--stl-color-red-muted-background)',
129
+ delBorderColor: 'var(--stl-color-red-border)',
130
+ delDiffIndicatorColor: 'var(--stl-color-red-foreground-reduced)',
131
+
132
+ markBackground: 'var(--stl-color-blue-muted-background)',
133
+ markBorderColor: 'var(--stl-color-blue-border)',
134
+ ...userExpressiveCode.styleOverrides?.textMarkers,
92
135
  },
93
136
  },
94
- ],
95
- routeMiddleware: [...config.starlightCompat.routeMiddleware, '@stainless-api/docs/tabsMiddleware'],
96
- customCss: ['@stainless-api/docs/theme', ...config.customCss],
97
- plugins: [stainlessStarlight(config.apiReference), ...config.starlightCompat.plugins],
137
+ },
138
+ plugins,
98
139
  });
99
140
  }
100
141
 
101
- function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroIntegration {
102
- const virtualId = `virtual:stl-stl-starlight-virtual-module`;
142
+ function stainlessDocsIntegration(
143
+ config: NormalizedStainlessDocsConfig,
144
+ apiReferenceBasePath: string | null,
145
+ ): AstroIntegration {
146
+ const virtualId = `virtual:stl-docs-virtual-module`;
103
147
  // The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
104
148
  const resolvedId = `\0${virtualId}`;
105
149
  let redirects: NormalizedRedirectConfig | null = null;
106
150
 
107
151
  return {
108
- name: 'stl-docs-integration',
152
+ name: 'stl-docs-astro',
109
153
  hooks: {
110
154
  'astro:config:setup': ({ updateConfig, command, config: astroConfig }) => {
111
155
  // // we only handle redirects for builds
@@ -132,7 +176,12 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
132
176
  HEADER_LINKS: config.header.links,
133
177
  HEADER_LAYOUT: config.header.layout,
134
178
  ENABLE_CLIENT_ROUTER: config.enableClientRouter,
135
- });
179
+ API_REFERENCE_BASE_PATH: apiReferenceBasePath,
180
+ ENABLE_PROSE_MARKDOWN_RENDERING: config.enableProseMarkdownRendering,
181
+ // TODO: do not duplicate this between both virtual modules
182
+ ENABLE_CONTEXT_MENU: config.contextMenu,
183
+ RENDER_PAGE_DESCRIPTIONS: config.renderPageDescriptions,
184
+ } satisfies typeof StlDocsVirtualModule);
136
185
  }
137
186
  },
138
187
  },
@@ -158,6 +207,17 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
158
207
  };
159
208
  }
160
209
 
210
+ function sharedLoggerIntegration(): AstroIntegration {
211
+ return {
212
+ name: 'stainless',
213
+ hooks: {
214
+ 'astro:config:setup': ({ logger }) => {
215
+ setSharedLogger(logger);
216
+ },
217
+ },
218
+ };
219
+ }
220
+
161
221
  export function stainlessDocs(config: StainlessDocsUserConfig) {
162
222
  const normalizedConfigResult = parseStlDocsConfig(config);
163
223
  if (normalizedConfigResult.result === 'error') {
@@ -166,9 +226,21 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
166
226
  process.exit(1);
167
227
  }
168
228
  const normalizedConfig = normalizedConfigResult.config;
229
+
230
+ // TODO: need to refactor this, but this allows us to get the base path for the API reference _if_ it exists
231
+ // if it doesn't exist, the value of basePath is null.
232
+ // the stl-starlight virtual module has base path, but it's not available when there's no API reference
233
+ const hasApiReference = normalizedConfig.apiReference !== null;
234
+ let apiReferenceBasePath: string | null = null;
235
+ if (hasApiReference) {
236
+ apiReferenceBasePath = normalizedConfig.apiReference?.basePath ?? '/api';
237
+ }
238
+
169
239
  return [
240
+ sharedLoggerIntegration(), // this **must** be first so it can set the shared logger used by our other integrations
170
241
  react(),
171
242
  stainlessDocsStarlightIntegration(normalizedConfig),
172
- stainlessDocsIntegration(normalizedConfig),
243
+ stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
244
+ stainlessDocsMarkdownRenderer({ enabled: normalizedConfig.enableProseMarkdownRendering }),
173
245
  ];
174
246
  }
@@ -32,6 +32,7 @@ type PassThroughStarlightConfigOptions = Pick<
32
32
  | 'lastUpdated'
33
33
  | 'pagination'
34
34
  | 'sidebar'
35
+ | 'expressiveCode'
35
36
  >;
36
37
 
37
38
  type ExperimentalStarlightCompatibilityConfig = Pick<
@@ -45,7 +46,8 @@ type Tabs = {
45
46
  sidebar?: SidebarEntry[];
46
47
  /**
47
48
  * Whether to hide the tab in the tab bar.
48
- * Defaults to `false`.
49
+ *
50
+ * @default false
49
51
  */
50
52
  hidden?: boolean;
51
53
  }[];
@@ -58,7 +60,7 @@ export type HeaderLink = {
58
60
  };
59
61
 
60
62
  export type StainlessDocsUserConfig = {
61
- apiReference: StainlessStarlightUserConfig;
63
+ apiReference?: StainlessStarlightUserConfig;
62
64
  tabs?: Tabs;
63
65
  header?: {
64
66
  layout?: HeaderLayout;
@@ -67,7 +69,26 @@ export type StainlessDocsUserConfig = {
67
69
  experimental?: {
68
70
  starlightCompat?: ExperimentalStarlightCompatibilityConfig;
69
71
  enableClientRouter?: boolean;
72
+ /**
73
+ * Disable markdown rendering for prose content. Only disable this if it is causing issues.
74
+ *
75
+ * @default false
76
+ */
77
+ disableProseMarkdownRendering?: boolean;
70
78
  };
79
+ /**
80
+ * Whether to show the context menu with options like "Copy as Markdown" and "Open in ChatGPT".
81
+ *
82
+ * @default true
83
+ */
84
+ contextMenu?: boolean;
85
+
86
+ /**
87
+ * Whether to render page descriptions in prose page headers
88
+ *
89
+ * @default true
90
+ */
91
+ renderPageDescriptions?: boolean;
71
92
  } & PassThroughStarlightConfigOptions;
72
93
 
73
94
  type HeaderLayout = 'default' | 'stacked';
@@ -119,6 +140,12 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
119
140
  description: userConfig.description,
120
141
  tagline: userConfig.tagline,
121
142
  logo: userConfig.logo,
143
+ favicon: userConfig.favicon,
144
+ disable404Route: userConfig.disable404Route,
145
+ editLink: userConfig.editLink,
146
+ locales: userConfig.locales,
147
+ lastUpdated: userConfig.lastUpdated,
148
+ pagination: userConfig.pagination,
122
149
  },
123
150
  starlightCompat: {
124
151
  components: userConfig.experimental?.starlightCompat?.components ?? {},
@@ -126,8 +153,13 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
126
153
  routeMiddleware: normalizeRouteMiddleware(userConfig),
127
154
  },
128
155
  enableClientRouter: userConfig.experimental?.enableClientRouter ?? false,
129
- apiReference: userConfig.apiReference,
156
+ apiReference: userConfig.apiReference ?? null,
130
157
  sidebar: userConfig.sidebar,
158
+ enableProseMarkdownRendering:
159
+ userConfig.experimental?.disableProseMarkdownRendering === true ? false : true,
160
+ contextMenu: userConfig.contextMenu ?? true,
161
+ expressiveCode: userConfig.expressiveCode,
162
+ renderPageDescriptions: userConfig.renderPageDescriptions ?? true,
131
163
  };
132
164
 
133
165
  return configWithDefaults;
@@ -136,11 +168,11 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
136
168
  export type NormalizedStainlessDocsConfig = ReturnType<typeof normalizeConfig>;
137
169
 
138
170
  /*
139
- The goal of the code in this file is to take a user's config and normalize it.
171
+ The goal of the code in this file is to take a user's config and normalize it.
140
172
  Specifically: we want a single complete config format used throughout the internals of the plugin.
141
173
 
142
174
  We've tried to avoid any config values being optional/undefined. To accomplish this:
143
- - Any optional config values should have their defaults set here: eg. basePath defaults to /api
175
+ - Any optional config values should have their defaults set here: eg. basePath defaults to /api
144
176
  - If a field is only used in certain contexts, we make each context a discriminated union (see SpecRetrieverConfig)
145
177
  - We prefer empty arrays over undefined/null
146
178
  */