@stainless-api/docs 0.1.0-beta.1 → 0.1.0-beta.100

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 (158) hide show
  1. package/CHANGELOG.md +917 -0
  2. package/eslint-suppressions.json +27 -0
  3. package/locals.d.ts +17 -0
  4. package/package.json +50 -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/assets/languages/php.svg +4 -0
  9. package/plugin/buildAlgoliaIndex.ts +40 -39
  10. package/plugin/components/MethodDescription.tsx +54 -0
  11. package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
  12. package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
  13. package/plugin/components/RequestBuilder/index.tsx +37 -0
  14. package/plugin/components/RequestBuilder/props.ts +9 -0
  15. package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
  16. package/plugin/components/RequestBuilder/styles.css +67 -0
  17. package/plugin/components/SDKSelect.astro +18 -105
  18. package/plugin/components/SnippetCode.tsx +111 -66
  19. package/plugin/components/StainlessIslands.tsx +126 -0
  20. package/plugin/components/search/SearchAlgolia.astro +45 -35
  21. package/plugin/components/search/SearchIsland.tsx +47 -29
  22. package/plugin/generateAPIReferenceLink.ts +2 -2
  23. package/plugin/globalJs/ai-dropdown-options.ts +243 -0
  24. package/plugin/globalJs/code-snippets.ts +40 -11
  25. package/plugin/globalJs/copy.ts +95 -17
  26. package/plugin/globalJs/create-playground.shim.ts +3 -0
  27. package/plugin/globalJs/method-descriptions.ts +33 -0
  28. package/plugin/globalJs/navigation.ts +12 -33
  29. package/plugin/globalJs/playground-data.shim.ts +1 -0
  30. package/plugin/globalJs/playground-data.ts +14 -0
  31. package/plugin/helpers/generateDocsRoutes.ts +59 -0
  32. package/plugin/helpers/getPageLoadEvent.ts +1 -1
  33. package/plugin/helpers/multiSpec.ts +8 -0
  34. package/plugin/index.ts +299 -117
  35. package/plugin/languages.ts +8 -2
  36. package/plugin/loadPluginConfig.ts +254 -102
  37. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
  38. package/plugin/react/Routing.tsx +210 -140
  39. package/plugin/referencePlaceholderUtils.ts +18 -15
  40. package/plugin/replaceSidebarPlaceholderMiddleware.ts +40 -32
  41. package/plugin/routes/Docs.astro +70 -119
  42. package/plugin/routes/DocsStatic.astro +6 -5
  43. package/plugin/routes/Overview.astro +37 -27
  44. package/plugin/routes/markdown.ts +13 -12
  45. package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +49 -60
  46. package/plugin/specs/FileCache.ts +99 -0
  47. package/plugin/specs/fetchSpecSSR.ts +27 -0
  48. package/plugin/specs/generateSpec.ts +112 -0
  49. package/plugin/specs/index.ts +132 -0
  50. package/plugin/specs/inputResolver.ts +146 -0
  51. package/plugin/{cms → specs}/worker.ts +82 -5
  52. package/plugin/vendor/preview.worker.docs.js +22406 -17955
  53. package/plugin/vendor/templates/cli.md +1 -0
  54. package/plugin/vendor/templates/go.md +4 -2
  55. package/plugin/vendor/templates/java.md +3 -1
  56. package/plugin/vendor/templates/kotlin.md +3 -1
  57. package/plugin/vendor/templates/node.md +4 -2
  58. package/plugin/vendor/templates/python.md +4 -2
  59. package/plugin/vendor/templates/ruby.md +4 -2
  60. package/plugin/vendor/templates/terraform.md +1 -1
  61. package/plugin/vendor/templates/typescript.md +3 -1
  62. package/resolveSrcFile.ts +10 -0
  63. package/scripts/vendor_deps.ts +5 -5
  64. package/shared/getProsePages.ts +42 -0
  65. package/shared/getSharedLogger.ts +15 -0
  66. package/shared/terminalUtils.ts +3 -0
  67. package/shared/virtualModule.ts +54 -1
  68. package/src/content.config.ts +9 -0
  69. package/stl-docs/components/AIDropdown.tsx +63 -0
  70. package/stl-docs/components/AiChatIsland.tsx +14 -0
  71. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  72. package/stl-docs/components/Head.astro +20 -0
  73. package/stl-docs/components/Header.astro +7 -9
  74. package/stl-docs/components/PageFrame.astro +18 -0
  75. package/stl-docs/components/PageTitle.astro +82 -0
  76. package/stl-docs/components/TableOfContents.astro +34 -0
  77. package/stl-docs/components/ThemeProvider.astro +36 -0
  78. package/stl-docs/components/ThemeSelect.astro +84 -144
  79. package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
  80. package/stl-docs/components/headers/DefaultHeader.astro +1 -1
  81. package/stl-docs/components/headers/HeaderLinks.astro +1 -1
  82. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
  83. package/stl-docs/components/headers/StackedHeader.astro +29 -24
  84. package/stl-docs/components/icons/chat-gpt.tsx +17 -0
  85. package/stl-docs/components/icons/claude.tsx +10 -0
  86. package/stl-docs/components/icons/cursor.tsx +10 -0
  87. package/stl-docs/components/icons/gemini.tsx +19 -0
  88. package/stl-docs/components/icons/markdown.tsx +10 -0
  89. package/stl-docs/components/index.ts +1 -0
  90. package/stl-docs/components/mintlify-compat/Accordion.astro +7 -38
  91. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +9 -23
  92. package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
  93. package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
  94. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +10 -3
  95. package/stl-docs/components/mintlify-compat/callouts/Check.astro +7 -3
  96. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +7 -3
  97. package/stl-docs/components/mintlify-compat/callouts/Info.astro +7 -3
  98. package/stl-docs/components/mintlify-compat/callouts/Note.astro +7 -3
  99. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +7 -3
  100. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +7 -3
  101. package/stl-docs/components/mintlify-compat/card.css +33 -35
  102. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  103. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -75
  104. package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
  105. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
  106. package/stl-docs/components/nav-tabs/buildNavLinks.ts +4 -3
  107. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  108. package/stl-docs/components/pagination/Pagination.astro +175 -0
  109. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  110. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  111. package/stl-docs/components/pagination/util.ts +71 -0
  112. package/stl-docs/components/scripts.ts +1 -0
  113. package/stl-docs/components/sidebars/BaseSidebar.astro +87 -0
  114. package/stl-docs/components/sidebars/SDKSelectSidebar.astro +8 -0
  115. package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
  116. package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
  117. package/stl-docs/disableCalloutSyntax.ts +36 -0
  118. package/stl-docs/fonts.ts +186 -0
  119. package/stl-docs/index.ts +159 -43
  120. package/stl-docs/loadStlDocsConfig.ts +60 -9
  121. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
  122. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
  123. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  124. package/stl-docs/proseSearchIndexing.ts +606 -0
  125. package/stl-docs/tabsMiddleware.ts +14 -5
  126. package/styles/code.css +133 -136
  127. package/styles/links.css +11 -48
  128. package/styles/method-descriptions.css +36 -0
  129. package/styles/overrides.css +49 -57
  130. package/styles/page.css +100 -59
  131. package/styles/sdk_select.css +9 -7
  132. package/styles/search.css +57 -69
  133. package/styles/sidebar.css +26 -156
  134. package/styles/{variables.css → sl-variables.css} +3 -2
  135. package/styles/stldocs-variables.css +6 -0
  136. package/styles/toc.css +41 -34
  137. package/theme.css +13 -3
  138. package/tsconfig.json +2 -5
  139. package/virtual-module.d.ts +65 -7
  140. package/components/variables.css +0 -139
  141. package/plugin/cms/client.ts +0 -62
  142. package/plugin/cms/server.ts +0 -268
  143. package/plugin/globalJs/ai-dropdown.ts +0 -57
  144. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -86
  145. package/stl-docs/components/Sidebar.astro +0 -11
  146. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -64
  147. package/stl-docs/components/mintlify-compat/Step.astro +0 -58
  148. package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
  149. package/styles/fonts.css +0 -68
  150. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  151. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  152. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  153. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  154. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  155. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  156. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  157. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  158. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -0,0 +1,62 @@
1
+ import { StlSidebarEntry } from '@stainless-api/docs-ui/components';
2
+ import { SidebarEntry } from '../pagination/util';
3
+ import { ReactNode } from 'react';
4
+ import { Badge, getHttpMethod } from '@stainless-api/ui-primitives';
5
+ import { FunctionIcon } from '@stainless-api/ui-primitives/icons';
6
+ import { BracesIcon } from 'lucide-react';
7
+
8
+ function getIcon(entry: SidebarEntry): ReactNode | undefined {
9
+ if (entry.type !== 'link') {
10
+ return undefined;
11
+ }
12
+ const methodAttr = entry.attrs['data-stldocs-method'];
13
+ const httpMethod = getHttpMethod(methodAttr);
14
+ if (httpMethod) {
15
+ return <Badge.HTTP method={httpMethod} iconOnly size="sm" />;
16
+ }
17
+
18
+ // special handling for the webhooks resource overview page
19
+ if (entry.attrs['data-stldocs-overview'] === 'webhooks') {
20
+ return (
21
+ <Badge size="sm" icon={<BracesIcon />} intent="info">
22
+ {''}
23
+ </Badge>
24
+ );
25
+ }
26
+
27
+ // Support empty string as method to show generic "Function" badge
28
+ else if (methodAttr === '') {
29
+ return (
30
+ <Badge size="sm" icon={<FunctionIcon />} intent="info">
31
+ {''}
32
+ </Badge>
33
+ );
34
+ }
35
+ return undefined;
36
+ }
37
+
38
+ export function convertAstroSidebarToStl(entries: SidebarEntry[]): StlSidebarEntry[] {
39
+ return entries.map((entry): StlSidebarEntry => {
40
+ if (entry.type === 'link') {
41
+ const icon = getIcon(entry);
42
+ return {
43
+ type: 'link',
44
+ attrs: entry.attrs,
45
+ label: entry.label,
46
+ target: {
47
+ type: 'href',
48
+ href: entry.href,
49
+ },
50
+ isCurrent: entry.isCurrent,
51
+ icon,
52
+ };
53
+ } else {
54
+ return {
55
+ type: 'group',
56
+ label: entry.label,
57
+ collapsed: entry.collapsed,
58
+ entries: convertAstroSidebarToStl(entry.entries),
59
+ };
60
+ }
61
+ });
62
+ }
@@ -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;
@@ -0,0 +1,186 @@
1
+ import type { AstroConfig } from 'astro';
2
+ import type { Defined } from './loadStlDocsConfig';
3
+ import { fontProviders } from 'astro/config';
4
+ import type { FontPreloadFilter } from 'astro:assets';
5
+
6
+ type AstroFontConfigEntry = Defined<AstroConfig['experimental']['fonts']>[number];
7
+
8
+ // Apply Omit to each member of the union while preserving union structure
9
+ type PreloadFilter = { preload?: FontPreloadFilter };
10
+ export type StlDocsFontConfigEntry = (AstroFontConfigEntry extends infer T
11
+ ? T extends unknown
12
+ ? Omit<T, 'cssVariable'>
13
+ : never
14
+ : never) &
15
+ PreloadFilter;
16
+
17
+ export type StlDocsFontConfig = {
18
+ primary?: StlDocsFontConfigEntry;
19
+ heading?: StlDocsFontConfigEntry;
20
+ mono?: StlDocsFontConfigEntry;
21
+ additional?: (AstroFontConfigEntry & PreloadFilter)[];
22
+ };
23
+ const latinFeatureSettings = "'ss01' on, 'ss03' on, 'ss04' on, 'ss06' on, 'ss08' on";
24
+ /* prettier-ignore */
25
+ const latinUnicodeRange: readonly string[] = ['U+0000-00FF', 'U+0131', 'U+0152-0153', 'U+02BB-02BC', 'U+02C6', 'U+02DA', 'U+02DC', 'U+0304', 'U+0308', 'U+0329', 'U+2000-206F', 'U+20AC', 'U+2122', 'U+2191', 'U+2193', 'U+2212', 'U+2215', 'U+FEFF', 'U+FFFD'];
26
+ // /* prettier-ignore */
27
+ // const latinExtUnicodeRange: readonly string[] = ['U+0100-02BA', 'U+02BD-02C5', 'U+02C7-02CC', 'U+02CE-02D7', 'U+02DD-02FF', 'U+0304', 'U+0308', 'U+0329', 'U+1D00-1DBF', 'U+1E00-1E9F', 'U+1EF2-1EFF', 'U+2020', 'U+20A0-20AB', 'U+20AD-20C0', 'U+2113', 'U+2C60-2C7F', 'U+A720-A7FF'];
28
+
29
+ export function getFontRoles(fonts: StlDocsFontConfig | undefined) {
30
+ if (!fonts) {
31
+ return {};
32
+ }
33
+ const fontConfigs: {
34
+ primary?: { cssVariable: string; preload?: FontPreloadFilter };
35
+ heading?: { cssVariable: string; preload?: FontPreloadFilter };
36
+ mono?: { cssVariable: string; preload?: FontPreloadFilter };
37
+ additional?: { cssVariable: string; preload?: FontPreloadFilter }[];
38
+ } = {};
39
+ if (fonts.primary) {
40
+ fontConfigs['primary'] = {
41
+ cssVariable: '--stl-typography-font' as const,
42
+ preload: fonts.primary.preload ?? [{ style: 'normal' }],
43
+ };
44
+ }
45
+ if (fonts.heading) {
46
+ fontConfigs['heading'] = {
47
+ cssVariable: '--stl-typography-font-heading' as const,
48
+ preload: fonts.heading.preload ?? [{ style: 'normal' }],
49
+ };
50
+ }
51
+ if (fonts.mono) {
52
+ fontConfigs['mono'] = {
53
+ cssVariable: '--stl-typography-font-mono' as const,
54
+ preload: fonts.mono.preload ?? [{ style: 'normal' }],
55
+ };
56
+ }
57
+ if (fonts.additional) {
58
+ fontConfigs['additional'] = fonts.additional.map((font) => ({
59
+ cssVariable: font.cssVariable,
60
+ preload: font.preload ?? [{ style: 'normal' }],
61
+ }));
62
+ }
63
+ return fontConfigs;
64
+ }
65
+
66
+ export function normalizeFonts(fonts: StlDocsFontConfig | undefined): StlDocsFontConfig {
67
+ const defaultPrimary: StlDocsFontConfigEntry = {
68
+ provider: fontProviders.local(),
69
+ name: 'Geist',
70
+ display: 'swap',
71
+ preload: [
72
+ {
73
+ weight: '100 900',
74
+ style: 'normal',
75
+ },
76
+ ],
77
+ options: {
78
+ variants: [
79
+ {
80
+ weight: '100 900',
81
+ style: 'normal',
82
+ src: [new URL('../assets/fonts/geist/geist-latin.woff2', import.meta.url)],
83
+ unicodeRange: latinUnicodeRange,
84
+ featureSettings: latinFeatureSettings,
85
+ },
86
+ {
87
+ weight: '100 900',
88
+ style: 'italic',
89
+ src: [new URL('../assets/fonts/geist/geist-italic-latin.woff2', import.meta.url)],
90
+ unicodeRange: latinUnicodeRange,
91
+ featureSettings: latinFeatureSettings,
92
+ },
93
+ // {
94
+ // weight: '100 900',
95
+ // style: 'normal',
96
+ // src: [new URL('../assets/fonts/geist/geist-latin-ext.woff2', import.meta.url)],
97
+ // unicodeRange: latinExtUnicodeRange,
98
+ // featureSettings: latinFeatureSettings,
99
+ // },
100
+ // {
101
+ // weight: '100 900',
102
+ // style: 'italic',
103
+ // src: [new URL('../assets/fonts/geist/geist-italic-latin-ext.woff2', import.meta.url)],
104
+ // unicodeRange: latinExtUnicodeRange,
105
+ // featureSettings: latinFeatureSettings,
106
+ // },
107
+ ],
108
+ },
109
+ };
110
+ const defaultMono: StlDocsFontConfigEntry = {
111
+ provider: fontProviders.local(),
112
+ name: 'Geist Mono',
113
+ display: 'swap',
114
+ preload: [
115
+ {
116
+ weight: '100 900',
117
+ style: 'normal',
118
+ },
119
+ ],
120
+ options: {
121
+ variants: [
122
+ {
123
+ weight: '100 900',
124
+ style: 'normal',
125
+ src: [new URL('../assets/fonts/geist/geist-mono-latin.woff2', import.meta.url)],
126
+ unicodeRange: latinUnicodeRange,
127
+ },
128
+ {
129
+ weight: '100 900',
130
+ style: 'italic',
131
+ src: [new URL('../assets/fonts/geist/geist-mono-italic-latin.woff2', import.meta.url)],
132
+ unicodeRange: latinUnicodeRange,
133
+ },
134
+ // {
135
+ // weight: '100 900',
136
+ // style: 'normal',
137
+ // src: [new URL('../assets/fonts/geist/geist-mono-latin-ext.woff2', import.meta.url)],
138
+ // unicodeRange: latinExtUnicodeRange,
139
+ // },
140
+ // {
141
+ // weight: '100 900',
142
+ // style: 'italic',
143
+ // src: [new URL('../assets/fonts/geist/geist-mono-italic-latin-ext.woff2', import.meta.url)],
144
+ // unicodeRange: latinExtUnicodeRange,
145
+ // },
146
+ ],
147
+ },
148
+ };
149
+
150
+ return {
151
+ primary: fonts?.primary ?? defaultPrimary,
152
+ heading: fonts?.heading ?? undefined,
153
+ mono: fonts?.mono ?? defaultMono,
154
+ additional: fonts?.additional ?? [],
155
+ };
156
+ }
157
+
158
+ // Normalize fonts for the Astro config
159
+ export function flattenFonts(fonts: StlDocsFontConfig | undefined): AstroFontConfigEntry[] {
160
+ if (!fonts) {
161
+ return [];
162
+ }
163
+ const fontConfigs: AstroFontConfigEntry[] = [];
164
+ if (fonts.primary) {
165
+ fontConfigs.push({
166
+ ...fonts.primary,
167
+ cssVariable: '--stl-typography-font' as const,
168
+ } as AstroFontConfigEntry);
169
+ }
170
+ if (fonts.heading) {
171
+ fontConfigs.push({
172
+ ...fonts.heading,
173
+ cssVariable: '--stl-typography-font-heading' as const,
174
+ } as AstroFontConfigEntry);
175
+ }
176
+ if (fonts.mono) {
177
+ fontConfigs.push({
178
+ ...fonts.mono,
179
+ cssVariable: '--stl-typography-font-mono' as const,
180
+ } as AstroFontConfigEntry);
181
+ }
182
+ if (fonts.additional) {
183
+ fontConfigs.push(...fonts.additional.map((font) => font as AstroFontConfigEntry));
184
+ }
185
+ return fontConfigs;
186
+ }
package/stl-docs/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import starlight from '@astrojs/starlight';
2
2
  import react from '@astrojs/react';
3
- import { stainlessStarlight } from '../plugin';
3
+ import type { StarlightPlugin } from '@astrojs/starlight/types';
4
+ import { disableCalloutSyntaxStarlightPlugin } from './disableCalloutSyntax';
4
5
 
5
6
  import type { AstroIntegration } from 'astro';
6
7
 
@@ -16,11 +17,18 @@ import {
16
17
  type StarlightSidebarConfig,
17
18
  } from './loadStlDocsConfig';
18
19
  import { buildVirtualModuleString } from '../shared/virtualModule';
19
-
20
- import geistPath from '../plugin/assets/fonts/geist/geist-latin.woff2?url';
20
+ import type * as StlDocsVirtualModule from 'virtual:stl-docs-virtual-module';
21
+ import { resolveSrcFile } from '../resolveSrcFile';
22
+ import { stainlessDocsMarkdownRenderer } from './proseMarkdown/proseMarkdownIntegration';
23
+ import { setSharedLogger } from '../shared/getSharedLogger';
24
+ import { stainlessDocsAlgoliaProseIndexing, stainlessDocsVectorProseIndexing } from './proseSearchIndexing';
25
+ import { stainlessStarlight } from '../plugin';
26
+ import { getFontRoles, flattenFonts } from './fonts';
21
27
 
22
28
  export * from '../plugin';
23
29
 
30
+ const COMPONENTS_FOLDER = '/stl-docs/components';
31
+
24
32
  function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig) {
25
33
  // We transform our tabs into a Starlight sidebar
26
34
  // This gives them all the built-in features of Starlight (eg. auto-generated entries by directory)
@@ -41,13 +49,43 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
41
49
 
42
50
  type ComponentOverrides = StarlightConfigDefined['components'];
43
51
  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',
52
+ PageFrame: resolveSrcFile(COMPONENTS_FOLDER, './PageFrame.astro'),
53
+
54
+ Head: resolveSrcFile(COMPONENTS_FOLDER, './Head.astro'),
55
+ Header: resolveSrcFile(COMPONENTS_FOLDER, './Header.astro'),
56
+ ThemeProvider: resolveSrcFile(COMPONENTS_FOLDER, './ThemeProvider.astro'),
57
+ ThemeSelect: resolveSrcFile(COMPONENTS_FOLDER, './ThemeSelect.astro'),
58
+
59
+ Sidebar: resolveSrcFile(COMPONENTS_FOLDER, './sidebars/BaseSidebar.astro'),
60
+ ContentPanel: resolveSrcFile(COMPONENTS_FOLDER, './content-panel/ContentPanel.astro'),
61
+ TableOfContents: resolveSrcFile(COMPONENTS_FOLDER, './TableOfContents.astro'),
62
+
63
+ PageTitle: resolveSrcFile(COMPONENTS_FOLDER, './PageTitle.astro'),
64
+ Pagination: resolveSrcFile(COMPONENTS_FOLDER, './pagination/Pagination.astro'),
49
65
  };
50
66
 
67
+ const plugins: StarlightPlugin[] = [
68
+ // Disable starlight callout syntax in favor of our own component
69
+ disableCalloutSyntaxStarlightPlugin,
70
+ ];
71
+
72
+ if (config.apiReference !== null) {
73
+ plugins.push(
74
+ stainlessStarlight({
75
+ ...config.apiReference,
76
+ contextMenu: config.contextMenu,
77
+ experimentalPrerender:
78
+ config.apiReference.experimentalPrerender === undefined
79
+ ? config.starlightPassThrough.prerender
80
+ : config.apiReference.experimentalPrerender,
81
+ }),
82
+ );
83
+ componentOverrides.Sidebar = resolveSrcFile(COMPONENTS_FOLDER, './sidebars/SDKSelectSidebar.astro');
84
+ componentOverrides.Search = resolveSrcFile('/plugin/components/search/Search.astro');
85
+ }
86
+
87
+ plugins.push(...config.starlightCompat.plugins, ...config.plugins.map((p) => p(config)));
88
+
51
89
  // TODO: re-add once we figure out what to do with the client router
52
90
  // if (config.enableClientRouter) {
53
91
  // // logger.info(`Client router is enabled`);
@@ -56,6 +94,8 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
56
94
  // // logger.info(`Client router is disabled`);
57
95
  // }
58
96
 
97
+ const userExpressiveCode = typeof config.expressiveCode === 'object' ? config.expressiveCode : {};
98
+
59
99
  return starlight({
60
100
  ...config.starlightPassThrough,
61
101
  sidebar,
@@ -79,64 +119,112 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
79
119
  setupNavLinksInitial();
80
120
  `,
81
121
  },
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,
122
+ ],
123
+ routeMiddleware: [
124
+ ...config.starlightCompat.routeMiddleware,
125
+ resolveSrcFile('/stl-docs/tabsMiddleware.ts'),
126
+ ],
127
+ customCss: [resolveSrcFile('/theme.css'), ...config.customCss],
128
+
129
+ expressiveCode: {
130
+ ...userExpressiveCode,
131
+ themes: userExpressiveCode.themes ?? ['github-light', 'github-dark'],
132
+ styleOverrides: {
133
+ ...userExpressiveCode.styleOverrides,
134
+ textMarkers: {
135
+ insBackground: 'var(--stl-color-green-muted-background)',
136
+ insBorderColor: 'var(--stl-color-green-border)',
137
+ insDiffIndicatorColor: 'var(--stl-color-green-foreground-reduced)',
138
+
139
+ delBackground: 'var(--stl-color-red-muted-background)',
140
+ delBorderColor: 'var(--stl-color-red-border)',
141
+ delDiffIndicatorColor: 'var(--stl-color-red-foreground-reduced)',
142
+
143
+ markBackground: 'var(--stl-color-blue-muted-background)',
144
+ markBorderColor: 'var(--stl-color-blue-border)',
145
+ ...userExpressiveCode.styleOverrides?.textMarkers,
92
146
  },
93
147
  },
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],
148
+ },
149
+ plugins,
98
150
  });
99
151
  }
100
152
 
101
- function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroIntegration {
102
- const virtualId = `virtual:stl-stl-starlight-virtual-module`;
153
+ function stainlessDocsIntegration(
154
+ config: NormalizedStainlessDocsConfig,
155
+ apiReferenceBasePath: string | null,
156
+ ): AstroIntegration {
103
157
  // The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
104
- const resolvedId = `\0${virtualId}`;
158
+ const resolveVirtualModuleId = (id: string) => `\0${id}`;
105
159
  let redirects: NormalizedRedirectConfig | null = null;
106
160
 
107
161
  return {
108
- name: 'stl-docs-integration',
162
+ name: 'stl-docs-astro',
109
163
  hooks: {
110
164
  'astro:config:setup': ({ updateConfig, command, config: astroConfig }) => {
111
- // // we only handle redirects for builds
112
- // // in dev, Astro handles them for us
165
+ // we only handle redirects for builds
166
+ // in dev, Astro handles them for us
113
167
  if (command === 'build' && astroConfig.redirects) {
114
168
  redirects = normalizeRedirects(astroConfig.redirects);
115
169
  }
116
170
 
171
+ const virtualModules = new Map(
172
+ Object.entries({
173
+ 'virtual:stl-docs-virtual-module': buildVirtualModuleString({
174
+ TABS: config.tabs,
175
+ SPLIT_TABS_ENABLED: config.splitTabsEnabled,
176
+ HEADER_LINKS: config.header.links,
177
+ HEADER_LAYOUT: config.header.layout,
178
+ ENABLE_CLIENT_ROUTER: config.enableClientRouter,
179
+ API_REFERENCE_BASE_PATH: apiReferenceBasePath ?? '/api',
180
+ ENABLE_PROSE_MARKDOWN_RENDERING: config.enableProseMarkdownRendering,
181
+ ENABLE_CONTEXT_MENU: config.contextMenu, // TODO: do not duplicate this between both virtual modules
182
+ RENDER_PAGE_DESCRIPTIONS: config.renderPageDescriptions,
183
+ FONTS: getFontRoles(config.fonts),
184
+ LINK_GROUP_TITLES_TO_OVERVIEW_PAGES: config.linkGroupTitlesToOverviewPages,
185
+ } satisfies typeof StlDocsVirtualModule),
186
+
187
+ 'virtual:stl-docs/components/AiChat.tsx': `
188
+ ${
189
+ config.aiChat
190
+ ? `export { default } from ${JSON.stringify(config.aiChat.chatComponentPath)};`
191
+ : // export null when no AI chat component is provided
192
+ `export default null;`
193
+ }
194
+ export const STAINLESS_PROJECT = ${config.apiReference ? JSON.stringify(config.apiReference.stainlessProject) : 'undefined'};
195
+ `,
196
+ }),
197
+ );
198
+
117
199
  updateConfig({
200
+ experimental: {
201
+ fonts: [...flattenFonts(config.fonts), ...(astroConfig.experimental?.fonts ?? [])],
202
+ },
118
203
  vite: {
119
204
  plugins: [
120
205
  {
121
206
  name: 'stl-docs-vite',
122
207
  resolveId(id) {
123
- if (id === virtualId) {
124
- return resolvedId;
125
- }
208
+ if (virtualModules.has(id)) return resolveVirtualModuleId(id);
126
209
  },
127
210
  load(id) {
128
- if (id === resolvedId) {
129
- return buildVirtualModuleString({
130
- TABS: config.tabs,
131
- SPLIT_TABS_ENABLED: config.splitTabsEnabled,
132
- HEADER_LINKS: config.header.links,
133
- HEADER_LAYOUT: config.header.layout,
134
- ENABLE_CLIENT_ROUTER: config.enableClientRouter,
135
- });
136
- }
211
+ const bare = id.replace(/^\0/, '');
212
+ if (virtualModules.has(bare)) return virtualModules.get(bare);
137
213
  },
138
214
  },
139
215
  ],
216
+ optimizeDeps: {
217
+ include: config.aiChat
218
+ ? [
219
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > lucide-react',
220
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > motion',
221
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > motion > framer-motion',
222
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > react-markdown',
223
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > react-syntax-highlighter',
224
+ '@stainless-api/docs-ai-chat > @stainless-api/ai-chat > remark-gfm',
225
+ ]
226
+ : [],
227
+ },
140
228
  },
141
229
  build: {
142
230
  ...astroConfig.build,
@@ -147,7 +235,7 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
147
235
  'astro:build:done': ({ dir }) => {
148
236
  if (redirects !== null) {
149
237
  const stainlessDir = join(dir.pathname, '_stainless');
150
- mkdirSync(stainlessDir);
238
+ mkdirSync(stainlessDir, { recursive: true });
151
239
  const outputPath = join(stainlessDir, 'redirects.json');
152
240
  writeFileSync(outputPath, JSON.stringify(redirects, null, 2), {
153
241
  encoding: 'utf-8',
@@ -158,7 +246,18 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
158
246
  };
159
247
  }
160
248
 
161
- export function stainlessDocs(config: StainlessDocsUserConfig) {
249
+ function sharedLoggerIntegration(): AstroIntegration {
250
+ return {
251
+ name: 'stainless',
252
+ hooks: {
253
+ 'astro:config:setup': ({ logger }) => {
254
+ setSharedLogger(logger);
255
+ },
256
+ },
257
+ };
258
+ }
259
+
260
+ export function stainlessDocs(config: StainlessDocsUserConfig): StarlightPlugin[] {
162
261
  const normalizedConfigResult = parseStlDocsConfig(config);
163
262
  if (normalizedConfigResult.result === 'error') {
164
263
  // TODO: would be good to use the astro logger somehow
@@ -166,9 +265,26 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
166
265
  process.exit(1);
167
266
  }
168
267
  const normalizedConfig = normalizedConfigResult.config;
268
+
269
+ // TODO: need to refactor this, but this allows us to get the base path for the API reference _if_ it exists
270
+ // if it doesn't exist, the value of basePath is null.
271
+ // the stl-starlight virtual module has base path, but it's not available when there's no API reference
272
+ const hasApiReference = normalizedConfig.apiReference !== null;
273
+ let apiReferenceBasePath: string | null = null;
274
+ if (hasApiReference) {
275
+ apiReferenceBasePath = normalizedConfig.apiReference?.basePath ?? '/api';
276
+ }
277
+
169
278
  return [
279
+ sharedLoggerIntegration(), // this **must** be first so it can set the shared logger used by our other integrations
170
280
  react(),
171
281
  stainlessDocsStarlightIntegration(normalizedConfig),
172
- stainlessDocsIntegration(normalizedConfig),
282
+ stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
283
+ stainlessDocsMarkdownRenderer({
284
+ enabled: normalizedConfig.enableProseMarkdownRendering,
285
+ apiReferenceBasePath,
286
+ }),
287
+ stainlessDocsAlgoliaProseIndexing({ apiReferenceBasePath }),
288
+ stainlessDocsVectorProseIndexing(normalizedConfig, apiReferenceBasePath),
173
289
  ];
174
290
  }