@stainless-api/docs 0.1.0-beta.60 → 0.1.0-beta.62

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @stainless-api/docs
2
2
 
3
+ ## 0.1.0-beta.62
4
+
5
+ ### Patch Changes
6
+
7
+ - 3c4a030: increase minimum starlight depdendency version
8
+ - cd86726: Fix a crash when stl-starlight plugin isn’t being loaded
9
+ - aa9d333: fixes for markdown rendering when astro integrations override the starlight html entrypoint
10
+ - 07a2c87: Should override ThemeProvider for setting theme within the html head
11
+ - @stainless-api/docs-search@0.1.0-beta.3
12
+ - @stainless-api/docs-ui@0.1.0-beta.51
13
+ - @stainless-api/ui-primitives@0.1.0-beta.38
14
+
15
+ ## 0.1.0-beta.61
16
+
17
+ ### Patch Changes
18
+
19
+ - 88a9894: patch vite optimizeDeps for docs-ai-chat
20
+ - Updated dependencies [2a79bae]
21
+ - @stainless-api/ui-primitives@0.1.0-beta.38
22
+ - @stainless-api/docs-ui@0.1.0-beta.51
23
+ - @stainless-api/docs-search@0.1.0-beta.3
24
+
3
25
  ## 0.1.0-beta.60
4
26
 
5
27
  ### Patch Changes
package/locals.d.ts CHANGED
@@ -11,6 +11,7 @@ declare namespace App {
11
11
  fullSidebar?: SidebarEntry[];
12
12
  };
13
13
 
14
+ stainlessProject?: string;
14
15
  language?: import('@stainless-api/docs-ui/routing').DocsLanguage;
15
16
  }
16
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/docs",
3
- "version": "0.1.0-beta.60",
3
+ "version": "0.1.0-beta.62",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -25,7 +25,7 @@
25
25
  "node": ">=18.17.1"
26
26
  },
27
27
  "peerDependencies": {
28
- "@astrojs/starlight": ">=0.36.1",
28
+ "@astrojs/starlight": ">=0.37.0",
29
29
  "astro": ">=5.15.3",
30
30
  "react": ">=19.0.0",
31
31
  "react-dom": ">=19.0.0",
@@ -52,9 +52,9 @@
52
52
  "vite-plugin-prebundle-workers": "^0.2.0",
53
53
  "web-worker": "^1.5.0",
54
54
  "yaml": "^2.8.2",
55
- "@stainless-api/docs-ui": "0.1.0-beta.50",
56
- "@stainless-api/docs-search": "0.1.0-beta.2",
57
- "@stainless-api/ui-primitives": "0.1.0-beta.37"
55
+ "@stainless-api/docs-ui": "0.1.0-beta.51",
56
+ "@stainless-api/docs-search": "0.1.0-beta.3",
57
+ "@stainless-api/ui-primitives": "0.1.0-beta.38"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@astrojs/check": "^0.9.6",
@@ -68,7 +68,7 @@
68
68
  "typescript": "5.9.3",
69
69
  "vite": "^6.4.1",
70
70
  "zod": "^4.1.13",
71
- "@stainless/eslint-config": "0.1.0-beta.0",
71
+ "@stainless/eslint-config": "0.1.0-beta.1",
72
72
  "@stainless/sdk-json": "^0.1.0-beta.2"
73
73
  },
74
74
  "scripts": {
package/plugin/index.ts CHANGED
@@ -301,7 +301,6 @@ async function stlStarlightAstroIntegration(
301
301
  PROPERTY_SETTINGS: pluginConfig.propertySettings,
302
302
  ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
303
303
  EXPERIMENTAL_PLAYGROUNDS: !!pluginConfig.experimentalPlaygrounds,
304
- STAINLESS_PROJECT: version.stainlessProject,
305
304
  } satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
306
305
  vmMiddlewareExport,
307
306
  ].join('\n');
@@ -1,10 +1,8 @@
1
1
  import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
2
- import AiChat from 'virtual:stl-docs/components/AiChat.tsx';
3
- // right now loading AiChat without API reference plugin is unsupported
4
- // because the AiChat is for talking about the SDKs
5
- import { STAINLESS_PROJECT } from 'virtual:stl-starlight-virtual-module';
2
+ import AiChat, { STAINLESS_PROJECT } from 'virtual:stl-docs/components/AiChat.tsx';
6
3
 
7
4
  export default function AiChatIsland({ currentLanguage }: { currentLanguage: DocsLanguage | undefined }) {
8
5
  if (!AiChat) throw new Error('AiChatIsland was rendered but could not load AiChat component');
6
+ if (!STAINLESS_PROJECT) return null;
9
7
  return <AiChat projectId={STAINLESS_PROJECT} language={currentLanguage} />;
10
8
  }
@@ -0,0 +1,36 @@
1
+ {/* Inlined to avoid FOUC. All theme selects are initialized here */}
2
+ <script is:inline>
3
+ window.didInitThemePickers = window.didInitThemePickers ?? false;
4
+
5
+ // Only run once.
6
+ if (!window.didInitThemePickers) {
7
+ window.didInitThemePickers = true;
8
+
9
+ // The stored theme will be either 'auto', 'light', 'dark' or null.
10
+ const storedTheme = typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
11
+
12
+ // This theme is either 'light' or 'dark'. It's used for setting the data-theme attribute.
13
+ const theme =
14
+ !storedTheme || storedTheme === 'auto'
15
+ ? window.matchMedia('(prefers-color-scheme: light)').matches
16
+ ? 'light'
17
+ : 'dark'
18
+ : storedTheme;
19
+
20
+ document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
21
+
22
+ const themeSelects = document.querySelectorAll('[data-theme-select]');
23
+ const selectedThemeValue = storedTheme || 'auto';
24
+
25
+ themeSelects.forEach((select) => {
26
+ const tmpl = select.querySelector(`[data-value="${selectedThemeValue}"] template`);
27
+ const selectedSlot = select.querySelector('[data-part="trigger-selected"]');
28
+
29
+ selectedSlot.innerHTML = '';
30
+ if (tmpl) {
31
+ selectedSlot.appendChild(tmpl.content.cloneNode(true));
32
+ return;
33
+ }
34
+ });
35
+ }
36
+ </script>
@@ -88,43 +88,6 @@ const options = [
88
88
  </Dropdown.Menu>
89
89
  </Dropdown>
90
90
 
91
- {/* Inlined to avoid FOUC. All theme selects are initialized here */}
92
- <script is:inline>
93
- window.didInitThemePickers = window.didInitThemePickers ?? false;
94
-
95
- // Only run once.
96
- if (!window.didInitThemePickers) {
97
- window.didInitThemePickers = true;
98
-
99
- // The stored theme will be either 'auto', 'light', 'dark' or null.
100
- const storedTheme = typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
101
-
102
- // This theme is either 'light' or 'dark'. It's used for setting the data-theme attribute.
103
- const theme =
104
- !storedTheme || storedTheme === 'auto'
105
- ? window.matchMedia('(prefers-color-scheme: light)').matches
106
- ? 'light'
107
- : 'dark'
108
- : storedTheme;
109
-
110
- document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
111
-
112
- const themeSelects = document.querySelectorAll('[data-theme-select]');
113
- const selectedThemeValue = storedTheme || 'auto';
114
-
115
- themeSelects.forEach((select) => {
116
- const tmpl = select.querySelector(`[data-value="${selectedThemeValue}"] template`);
117
- const selectedSlot = select.querySelector('[data-part="trigger-selected"]');
118
-
119
- selectedSlot.innerHTML = '';
120
- if (tmpl) {
121
- selectedSlot.appendChild(tmpl.content.cloneNode(true));
122
- return;
123
- }
124
- });
125
- }
126
- </script>
127
-
128
91
  <script>
129
92
  import { getPageLoadEvent } from '../../plugin/helpers/getPageLoadEvent';
130
93
  import { initDropdown } from '@stainless-api/docs/components/scripts';
package/stl-docs/index.ts CHANGED
@@ -52,6 +52,7 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
52
52
 
53
53
  Head: resolveSrcFile(COMPONENTS_FOLDER, './Head.astro'),
54
54
  Header: resolveSrcFile(COMPONENTS_FOLDER, './Header.astro'),
55
+ ThemeProvider: resolveSrcFile(COMPONENTS_FOLDER, './ThemeProvider.astro'),
55
56
  ThemeSelect: resolveSrcFile(COMPONENTS_FOLDER, './ThemeSelect.astro'),
56
57
 
57
58
  Sidebar: resolveSrcFile(COMPONENTS_FOLDER, './sidebars/BaseSidebar.astro'),
@@ -158,15 +159,19 @@ function stainlessDocsIntegration(
158
159
  ENABLE_CLIENT_ROUTER: config.enableClientRouter,
159
160
  API_REFERENCE_BASE_PATH: apiReferenceBasePath,
160
161
  ENABLE_PROSE_MARKDOWN_RENDERING: config.enableProseMarkdownRendering,
161
- // TODO: do not duplicate this between both virtual modules
162
- ENABLE_CONTEXT_MENU: config.contextMenu,
162
+ ENABLE_CONTEXT_MENU: config.contextMenu, // TODO: do not duplicate this between both virtual modules
163
163
  RENDER_PAGE_DESCRIPTIONS: config.renderPageDescriptions,
164
164
  } satisfies typeof StlDocsVirtualModule),
165
165
 
166
- 'virtual:stl-docs/components/AiChat.tsx': config.aiChat
167
- ? `export { default } from ${JSON.stringify(config.aiChat.chatComponentPath)};`
168
- : // export null when no AI chat component is provided
169
- `export default null;`,
166
+ 'virtual:stl-docs/components/AiChat.tsx': `
167
+ ${
168
+ config.aiChat
169
+ ? `export { default } from ${JSON.stringify(config.aiChat.chatComponentPath)};`
170
+ : // export null when no AI chat component is provided
171
+ `export default null;`
172
+ }
173
+ export const STAINLESS_PROJECT = ${config.apiReference ? JSON.stringify(config.apiReference.stainlessProject) : 'undefined'};
174
+ `,
170
175
  }),
171
176
  );
172
177
 
@@ -198,6 +203,15 @@ function stainlessDocsIntegration(
198
203
  },
199
204
  },
200
205
  ],
206
+ optimizeDeps: {
207
+ include: config.aiChat
208
+ ? [
209
+ '@stainless-api/docs-ai-chat > motion',
210
+ '@stainless-api/docs-ai-chat > react-markdown',
211
+ '@stainless-api/docs-ai-chat > react-syntax-highlighter',
212
+ ]
213
+ : [],
214
+ },
201
215
  },
202
216
  build: {
203
217
  ...astroConfig.build,
@@ -253,7 +267,10 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
253
267
  react(),
254
268
  stainlessDocsStarlightIntegration(normalizedConfig),
255
269
  stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
256
- stainlessDocsMarkdownRenderer({ enabled: normalizedConfig.enableProseMarkdownRendering }),
270
+ stainlessDocsMarkdownRenderer({
271
+ enabled: normalizedConfig.enableProseMarkdownRendering,
272
+ apiReferenceBasePath,
273
+ }),
257
274
  stainlessDocsProseIndexing(),
258
275
  ];
259
276
  }
@@ -1,11 +1,18 @@
1
1
  import type { AstroIntegration } from 'astro';
2
- import { readFile, writeFile } from 'fs/promises';
2
+ import { readdir, readFile, writeFile } from 'fs/promises';
3
3
  import { toMarkdown } from './toMarkdown';
4
4
  import { resolveSrcFile } from '../../resolveSrcFile';
5
5
  import { getSharedLogger } from '../../shared/getSharedLogger';
6
+ import { join, relative } from 'path';
6
7
  import { bold } from '../../shared/terminalUtils';
7
8
 
8
- export function stainlessDocsMarkdownRenderer({ enabled }: { enabled: boolean }): AstroIntegration {
9
+ export function stainlessDocsMarkdownRenderer({
10
+ enabled,
11
+ apiReferenceBasePath,
12
+ }: {
13
+ enabled: boolean;
14
+ apiReferenceBasePath: string | null;
15
+ }): AstroIntegration {
9
16
  return {
10
17
  name: 'stl-docs-md',
11
18
  hooks: {
@@ -17,29 +24,44 @@ export function stainlessDocsMarkdownRenderer({ enabled }: { enabled: boolean })
17
24
  });
18
25
  }
19
26
  },
20
- 'astro:build:done': async ({ assets, logger: localLogger, dir }) => {
27
+ 'astro:build:done': async ({ logger: localLogger, dir }) => {
21
28
  const logger = getSharedLogger({ fallback: localLogger });
22
29
  if (!enabled) {
23
30
  logger.info('Stainless Docs prose Markdown rendering is disabled, skipping...');
24
31
  return;
25
32
  }
26
- const starlightPagePatterns = ['/[...slug]'];
27
- const pagesToRender = Array.from(assets.entries())
28
- .filter(([k]) => {
29
- if (starlightPagePatterns.includes(k)) {
30
- return true;
31
- }
32
- return false;
33
- })
34
- .map(([, v]) => v)
35
- .flat()
36
- .map((v) => v.pathname);
33
+ const outputBasePath = dir.pathname;
37
34
 
38
- logger.info(bold(`Building ${pagesToRender.length} Markdown pages for prose content`));
35
+ // Read all HTML files from output directory, and not from assets.
36
+ // We cannot use the `assets` map here because it is not guaranteed to
37
+ // contain all files, especially if they were generated by other integrations.
38
+ // Other astro integrations may hijack the "[...slug]" entrypoint, and any files
39
+ // previously in the [...slug] asset map entry would be lost (this is where starlight stores
40
+ // its prose HTML files).
41
+ const allFiles = await readdir(outputBasePath, {
42
+ recursive: true,
43
+ withFileTypes: true,
44
+ });
39
45
 
40
- const outputBasePath = dir.pathname;
46
+ const htmlFiles = allFiles
47
+ .filter((file) => file.isFile() && file.name.endsWith('.html'))
48
+ .map((file) => join(file.parentPath, file.name));
49
+
50
+ // Filter out API reference pages
51
+ const pagesToRender = htmlFiles.filter((absPath) => {
52
+ if (!apiReferenceBasePath) {
53
+ return true;
54
+ }
55
+ const relPath = relative(outputBasePath, absPath);
56
+ // Normalize by removing leading/trailing slashes from apiReferenceBasePath
57
+ const normalizedApiPath = apiReferenceBasePath.replace(/^\/+|\/+$/g, '');
58
+ return !relPath.startsWith(normalizedApiPath);
59
+ });
60
+
61
+ logger.info(bold(`Building ${pagesToRender.length} Markdown pages for prose content`));
41
62
 
42
63
  let completedCount = 0;
64
+
43
65
  for (const absHtmlPath of pagesToRender) {
44
66
  const txt = await readFile(absHtmlPath, 'utf-8');
45
67
  const md = await toMarkdown(txt);
@@ -18,7 +18,12 @@ export const onRequest = defineMiddleware(async (context, next) => {
18
18
  return next();
19
19
  }
20
20
 
21
- const htmlUrl = new URL(context.url.pathname.replace('index.md', ''), context.url);
21
+ const pathname = context.url.pathname.replace('index.md', '');
22
+
23
+ // We must trim the trailing slash to support astro configs with `trailingSlash: 'never'`
24
+ const cleanPathname = pathname !== '/' ? pathname.replace(/\/$/, '') : pathname;
25
+ const htmlUrl = new URL(cleanPathname, context.url);
26
+
22
27
  const resp = await fetch(htmlUrl);
23
28
  if (!resp.ok) {
24
29
  return new Response('Failed to fetch HTML', { status: 400 });
@@ -23,7 +23,6 @@ declare module 'virtual:stl-starlight-virtual-module' {
23
23
  export const PROPERTY_SETTINGS: PropertySettingsType;
24
24
  export const MIDDLEWARE: StlStarlightMiddleware;
25
25
  export const ENABLE_CONTEXT_MENU: boolean;
26
- export const STAINLESS_PROJECT: string;
27
26
  }
28
27
 
29
28
  declare module 'virtual:stl-docs-virtual-module' {
@@ -60,4 +59,5 @@ declare module 'virtual:stl-docs/components/AiChat.tsx' {
60
59
  }>
61
60
  | null;
62
61
  export default AiChatComponent;
62
+ export const STAINLESS_PROJECT: string | undefined;
63
63
  }