@stainless-api/docs 0.1.0-beta.3 → 0.1.0-beta.30
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 +214 -0
- package/components/variables.css +1 -27
- package/eslint-suppressions.json +47 -0
- package/locals.d.ts +14 -0
- package/package.json +30 -27
- package/plugin/buildAlgoliaIndex.ts +29 -4
- package/plugin/cms/server.ts +97 -54
- package/plugin/cms/sidebar-builder.ts +6 -25
- package/plugin/cms/worker.ts +2 -2
- package/plugin/components/SnippetCode.tsx +7 -4
- package/plugin/components/search/SearchAlgolia.astro +0 -7
- package/plugin/components/search/SearchIsland.tsx +30 -17
- package/plugin/generateAPIReferenceLink.ts +1 -1
- package/plugin/globalJs/ai-dropdown-options.ts +161 -0
- package/plugin/globalJs/navigation.ts +0 -23
- package/plugin/helpers/getPageLoadEvent.ts +1 -1
- package/plugin/index.ts +48 -18
- package/plugin/languages.ts +1 -1
- package/plugin/loadPluginConfig.ts +100 -13
- package/plugin/react/Routing.tsx +30 -33
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +4 -0
- package/plugin/routes/Docs.astro +59 -85
- package/plugin/routes/Overview.astro +9 -15
- package/plugin/routes/markdown.ts +1 -1
- package/plugin/vendor/preview.worker.docs.js +7566 -6784
- package/resolveSrcFile.ts +10 -0
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/src/content.config.ts +9 -0
- package/stl-docs/components/AIDropdown.tsx +52 -0
- package/stl-docs/components/Head.astro +16 -0
- package/stl-docs/components/Header.astro +3 -2
- package/stl-docs/components/PageTitle.astro +64 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeSelect.astro +4 -2
- package/stl-docs/components/content-panel/ContentPanel.astro +9 -39
- package/stl-docs/components/headers/DefaultHeader.astro +1 -1
- package/stl-docs/components/headers/HeaderLinks.astro +1 -1
- package/stl-docs/components/headers/StackedHeader.astro +29 -24
- package/stl-docs/components/icons/chat-gpt.tsx +17 -0
- package/stl-docs/components/icons/claude.tsx +10 -0
- package/stl-docs/components/icons/markdown.tsx +10 -0
- package/stl-docs/components/index.ts +2 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +7 -38
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +9 -23
- package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
- package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
- package/stl-docs/components/mintlify-compat/Step.astro +30 -32
- package/stl-docs/components/mintlify-compat/Steps.astro +8 -10
- package/stl-docs/components/mintlify-compat/callouts/Callout.astro +10 -3
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +7 -3
- package/stl-docs/components/mintlify-compat/card.css +33 -35
- package/stl-docs/components/nav-tabs/NavDropdown.astro +1 -1
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -7
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +4 -3
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +173 -0
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
- package/stl-docs/components/pagination/util.ts +71 -0
- package/stl-docs/components/{Sidebar.astro → sidebars/BaseSidebar.astro} +2 -3
- package/stl-docs/components/sidebars/SDKSelectSidebar.astro +8 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/index.ts +76 -26
- package/stl-docs/loadStlDocsConfig.ts +25 -3
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +64 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +34 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/tabsMiddleware.ts +12 -4
- package/styles/code.css +115 -127
- package/styles/fonts.css +32 -17
- package/styles/links.css +10 -49
- package/styles/overrides.css +54 -57
- package/styles/page.css +89 -59
- package/styles/sdk_select.css +6 -7
- package/styles/search.css +65 -67
- package/styles/sidebar.css +199 -128
- package/styles/toc.css +37 -33
- package/theme.css +9 -1
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +5 -1
- package/plugin/globalJs/ai-dropdown.ts +0 -57
- package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -86
- package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -64
- /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
- /package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +0 -0
|
@@ -5,8 +5,6 @@ import { navigate } from 'astro:transitions/client';
|
|
|
5
5
|
import { getPageLoadEvent } from '../helpers/getPageLoadEvent.ts';
|
|
6
6
|
|
|
7
7
|
import { initDropdown } from '@stainless-api/docs-ui/src/components/scripts/dropdown';
|
|
8
|
-
import { initDropdownButton } from '@stainless-api/ui-primitives/scripts';
|
|
9
|
-
import { copyCurrentPageAsMarkdown, onSelectAIOption } from './ai-dropdown.ts';
|
|
10
8
|
|
|
11
9
|
history.scrollRestoration = 'auto';
|
|
12
10
|
|
|
@@ -36,27 +34,6 @@ document.addEventListener(getPageLoadEvent(), () => {
|
|
|
36
34
|
if (path) setTimeout(() => scrollToPath(path.slice(1)), 10);
|
|
37
35
|
});
|
|
38
36
|
|
|
39
|
-
document.addEventListener(getPageLoadEvent(), () => {
|
|
40
|
-
console.log('Initializing AI Dropdown');
|
|
41
|
-
initDropdownButton({
|
|
42
|
-
dropdownId: 'ai-dropdown-button',
|
|
43
|
-
onSelect: onSelectAIOption,
|
|
44
|
-
onPrimaryAction: (el) => {
|
|
45
|
-
copyCurrentPageAsMarkdown();
|
|
46
|
-
const innerText = el.querySelector('[data-part="primary-action-text"]');
|
|
47
|
-
if (!innerText) return;
|
|
48
|
-
|
|
49
|
-
const originalInnerHtml = innerText.innerHTML;
|
|
50
|
-
innerText.innerHTML = 'Copied!';
|
|
51
|
-
el.classList.add('disabled');
|
|
52
|
-
setTimeout(() => {
|
|
53
|
-
innerText.innerHTML = originalInnerHtml;
|
|
54
|
-
el.classList.remove('disabled');
|
|
55
|
-
}, 1000);
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
37
|
document.addEventListener('click', (event) => {
|
|
61
38
|
const toggle = (event.target as HTMLElement).closest(
|
|
62
39
|
'[data-stldocs-property-toggle-expanded] > .stldocs-expand-toggle-content',
|
package/plugin/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import react from '@astrojs/react';
|
|
2
2
|
import type { StarlightPlugin } from '@astrojs/starlight/types';
|
|
3
|
-
import type { AstroIntegration } from 'astro';
|
|
3
|
+
import type { AstroIntegration, AstroIntegrationLogger } from 'astro';
|
|
4
4
|
import { config } from 'dotenv';
|
|
5
5
|
import getPort from 'get-port';
|
|
6
6
|
import { startDevServer } from './cms/server';
|
|
@@ -23,11 +23,15 @@ import {
|
|
|
23
23
|
import { buildVirtualModuleString } from '../shared/virtualModule';
|
|
24
24
|
import path from 'path';
|
|
25
25
|
import fs from 'fs';
|
|
26
|
+
import { getSharedLogger } from '../shared/getSharedLogger';
|
|
27
|
+
import { resolveSrcFile } from '../resolveSrcFile';
|
|
26
28
|
|
|
27
29
|
export { generateAPILink } from './generateAPIReferenceLink';
|
|
28
30
|
export type { ReferenceSidebarConfigItem };
|
|
29
31
|
|
|
30
|
-
config(
|
|
32
|
+
config({
|
|
33
|
+
quiet: true,
|
|
34
|
+
});
|
|
31
35
|
|
|
32
36
|
let sidebarIdCounter = 0;
|
|
33
37
|
|
|
@@ -108,6 +112,7 @@ function tmpGetCMSServerConfig(specRetrieverConfig: SpecRetrieverConfig) {
|
|
|
108
112
|
|
|
109
113
|
async function stlStarlightAstroIntegration(
|
|
110
114
|
pluginConfig: NormalizedStainlessStarlightConfig,
|
|
115
|
+
stlStarlightPluginLogger: AstroIntegrationLogger,
|
|
111
116
|
): Promise<AstroIntegration> {
|
|
112
117
|
const virtualId = `virtual:stl-starlight-virtual-module`;
|
|
113
118
|
// The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
|
|
@@ -117,11 +122,12 @@ async function stlStarlightAstroIntegration(
|
|
|
117
122
|
|
|
118
123
|
const { apiKey, version, devPaths } = tmpGetCMSServerConfig(pluginConfig.specRetrieverConfig);
|
|
119
124
|
|
|
120
|
-
const cmsServer =
|
|
125
|
+
const cmsServer = startDevServer({
|
|
121
126
|
port: CMS_PORT,
|
|
122
|
-
apiKey,
|
|
127
|
+
apiKey: apiKey.value,
|
|
123
128
|
version,
|
|
124
129
|
devPaths,
|
|
130
|
+
logger: stlStarlightPluginLogger,
|
|
125
131
|
getGeneratedSidebarConfig: (id: number) => {
|
|
126
132
|
const config = sidebarConfigs.get(id);
|
|
127
133
|
if (!config) {
|
|
@@ -134,34 +140,40 @@ async function stlStarlightAstroIntegration(
|
|
|
134
140
|
return {
|
|
135
141
|
name: 'stl-starlight-astro',
|
|
136
142
|
hooks: {
|
|
137
|
-
'astro:config:setup': async ({
|
|
143
|
+
'astro:config:setup': async ({
|
|
144
|
+
injectRoute,
|
|
145
|
+
updateConfig,
|
|
146
|
+
logger: localLogger,
|
|
147
|
+
command,
|
|
148
|
+
config: astroConfig,
|
|
149
|
+
}) => {
|
|
150
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
138
151
|
const projectDir = astroConfig.root.pathname;
|
|
139
152
|
|
|
140
153
|
const middlewareFile = path.join(projectDir, 'middleware.stainless.ts');
|
|
141
154
|
|
|
142
155
|
let vmMiddlewareExport = 'export const MIDDLEWARE = {};';
|
|
143
156
|
if (fs.existsSync(middlewareFile)) {
|
|
144
|
-
logger.
|
|
157
|
+
logger.debug(`Loading middleware from ${middlewareFile}`);
|
|
145
158
|
vmMiddlewareExport = `export { default as MIDDLEWARE } from '${middlewareFile}';`;
|
|
146
159
|
}
|
|
147
160
|
|
|
148
161
|
injectRoute({
|
|
149
|
-
pattern: `${pluginConfig.basePath}/[...slug].md`,
|
|
150
|
-
entrypoint: '
|
|
162
|
+
pattern: `${pluginConfig.basePath}/[...slug]/index.md`,
|
|
163
|
+
entrypoint: resolveSrcFile('/plugin/routes/markdown.ts'),
|
|
151
164
|
prerender: command === 'build',
|
|
152
165
|
});
|
|
153
166
|
|
|
154
|
-
const astroFile = command === 'build' ? '
|
|
167
|
+
const astroFile = command === 'build' ? 'DocsStatic' : 'Docs';
|
|
155
168
|
injectRoute({
|
|
156
169
|
pattern: `${pluginConfig.basePath}/[...slug]`,
|
|
157
|
-
|
|
158
|
-
entrypoint: `@stainless-api/docs/${astroFile}`,
|
|
170
|
+
entrypoint: resolveSrcFile(`/plugin/routes/${astroFile}.astro`),
|
|
159
171
|
prerender: command === 'build',
|
|
160
172
|
});
|
|
161
173
|
|
|
162
174
|
injectRoute({
|
|
163
175
|
pattern: pluginConfig.basePath,
|
|
164
|
-
entrypoint: '
|
|
176
|
+
entrypoint: resolveSrcFile('/plugin/routes/Overview.astro'),
|
|
165
177
|
prerender: command === 'build',
|
|
166
178
|
});
|
|
167
179
|
|
|
@@ -170,7 +182,6 @@ async function stlStarlightAstroIntegration(
|
|
|
170
182
|
ssr: {
|
|
171
183
|
noExternal: ['@stainless-api/ui-primitives'],
|
|
172
184
|
},
|
|
173
|
-
optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
|
|
174
185
|
plugins: [
|
|
175
186
|
{
|
|
176
187
|
name: 'stl-starlight-vite',
|
|
@@ -213,6 +224,7 @@ async function stlStarlightAstroIntegration(
|
|
|
213
224
|
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS: pluginConfig.experimentalCollapsibleSnippets,
|
|
214
225
|
PROPERTY_SETTINGS: pluginConfig.propertySettings,
|
|
215
226
|
SEARCH: pluginConfig.search,
|
|
227
|
+
ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
|
|
216
228
|
}),
|
|
217
229
|
vmMiddlewareExport,
|
|
218
230
|
].join('\n');
|
|
@@ -241,15 +253,20 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
241
253
|
command,
|
|
242
254
|
config: starlightConfig,
|
|
243
255
|
astroConfig,
|
|
244
|
-
logger,
|
|
256
|
+
logger: localLogger,
|
|
245
257
|
}) => {
|
|
246
258
|
if (command !== 'build' && command !== 'dev') {
|
|
247
259
|
return;
|
|
248
260
|
}
|
|
249
261
|
|
|
262
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
263
|
+
|
|
250
264
|
const configParseResult = parseStarlightPluginConfig(someUserConfig, command);
|
|
251
265
|
if (configParseResult.result === 'error') {
|
|
252
|
-
|
|
266
|
+
const errorLines = configParseResult.message.split('\n');
|
|
267
|
+
for (const line of errorLines) {
|
|
268
|
+
logger.error(line);
|
|
269
|
+
}
|
|
253
270
|
process.exit(1);
|
|
254
271
|
}
|
|
255
272
|
const config = configParseResult.config;
|
|
@@ -260,17 +277,30 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
260
277
|
addIntegration(react());
|
|
261
278
|
}
|
|
262
279
|
|
|
280
|
+
if ('apiKey' in config.specRetrieverConfig) {
|
|
281
|
+
if (!config.specRetrieverConfig.apiKey) {
|
|
282
|
+
logger.info(`Stainless credentials not loaded`);
|
|
283
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'explicit-config') {
|
|
284
|
+
logger.info(`Stainless credentials loaded from user config`);
|
|
285
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'environment-variable') {
|
|
286
|
+
logger.info('Stainless credentials loaded from `STAINLESS_API_KEY` environment variable');
|
|
287
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'cli') {
|
|
288
|
+
logger.info('Stainless credentials loaded from `stl` CLI');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
263
292
|
if (
|
|
264
293
|
command === 'build' &&
|
|
265
294
|
config.specRetrieverConfig.kind === 'local_spec_server_with_remote_files'
|
|
266
295
|
) {
|
|
267
296
|
await buildAlgoliaIndex({
|
|
268
297
|
version: config.specRetrieverConfig.version,
|
|
269
|
-
apiKey: config.specRetrieverConfig.apiKey,
|
|
298
|
+
apiKey: config.specRetrieverConfig.apiKey.value,
|
|
299
|
+
logger,
|
|
270
300
|
});
|
|
271
301
|
}
|
|
272
302
|
|
|
273
|
-
addIntegration(await stlStarlightAstroIntegration(config));
|
|
303
|
+
addIntegration(await stlStarlightAstroIntegration(config, logger));
|
|
274
304
|
|
|
275
305
|
if (starlightConfig.sidebar) {
|
|
276
306
|
// for pagination (https://starlight.astro.build/reference/configuration/#pagination) to work correctly
|
|
@@ -295,7 +325,7 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
295
325
|
});
|
|
296
326
|
|
|
297
327
|
addRouteMiddleware({
|
|
298
|
-
entrypoint: '
|
|
328
|
+
entrypoint: resolveSrcFile('/plugin/replaceSidebarPlaceholderMiddleware.ts'),
|
|
299
329
|
order: 'post',
|
|
300
330
|
});
|
|
301
331
|
},
|
package/plugin/languages.ts
CHANGED
|
@@ -44,7 +44,7 @@ export function applyLanguageToLinks(basePath?: string, defaultLanguage?: string
|
|
|
44
44
|
`[data-stldocs-overview],[data-stldocs-method],a.nav-link[href^='${basePath}']`,
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
-
for (
|
|
47
|
+
for (const link of links) {
|
|
48
48
|
const href = link.getAttribute('href');
|
|
49
49
|
const prefix = generatePrefix(basePath, language);
|
|
50
50
|
if (href?.startsWith(basePath) && !href?.startsWith(prefix)) {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
4
|
|
|
3
5
|
import type { CreateShikiHighlighterOptions } from '@astrojs/markdown-remark';
|
|
4
6
|
import type { DocsLanguage } from '@stainless-api/docs-ui/src/routing';
|
|
5
7
|
import type { PropertySettingsType } from '@stainless-api/docs-ui/src/contexts';
|
|
6
8
|
import type { InputFilePaths } from '../plugin/cms/server';
|
|
9
|
+
import { bold } from '../shared/terminalUtils';
|
|
7
10
|
|
|
8
11
|
export type AstroCommand = 'dev' | 'build' | 'preview' | 'sync';
|
|
9
12
|
|
|
@@ -18,7 +21,7 @@ export type VersionUserConfig = {
|
|
|
18
21
|
type BreadcrumbUserConfig = {
|
|
19
22
|
/**
|
|
20
23
|
* Include the current page in the breadcrumb list.
|
|
21
|
-
*
|
|
24
|
+
* Default: `false`
|
|
22
25
|
*/
|
|
23
26
|
includeCurrentPage?: boolean;
|
|
24
27
|
};
|
|
@@ -26,7 +29,12 @@ type BreadcrumbUserConfig = {
|
|
|
26
29
|
export type StainlessStarlightUserConfig = {
|
|
27
30
|
/**
|
|
28
31
|
* Optional api key for Stainless API.
|
|
29
|
-
* If not provided,
|
|
32
|
+
* If not provided, we will handle Stainless auth via the `stl` CLI or look for the STAINLESS_API_KEY environment variable.
|
|
33
|
+
* Precedence:
|
|
34
|
+
* 1. Explicity `apiKey` option provided
|
|
35
|
+
* 2. `STAINLESS_API_KEY` environment variable
|
|
36
|
+
* 3. Login status from the `stl` CLI
|
|
37
|
+
* 4. Error (no auth found)
|
|
30
38
|
*/
|
|
31
39
|
apiKey?: string;
|
|
32
40
|
|
|
@@ -42,7 +50,7 @@ export type StainlessStarlightUserConfig = {
|
|
|
42
50
|
|
|
43
51
|
/**
|
|
44
52
|
* Optional mount point for API reference docs.
|
|
45
|
-
*
|
|
53
|
+
* Default: `/api`
|
|
46
54
|
* Example: `/my-api` → docs available at `/my-api/…`.
|
|
47
55
|
*/
|
|
48
56
|
basePath?: string;
|
|
@@ -55,7 +63,7 @@ export type StainlessStarlightUserConfig = {
|
|
|
55
63
|
|
|
56
64
|
/**
|
|
57
65
|
* Optional language to treat as the default when the user hasn't selected one.
|
|
58
|
-
*
|
|
66
|
+
* Default: `"http"`
|
|
59
67
|
* Example: `"python"`
|
|
60
68
|
*/
|
|
61
69
|
defaultLanguage?: DocsLanguage;
|
|
@@ -90,7 +98,7 @@ export type StainlessStarlightUserConfig = {
|
|
|
90
98
|
contentPanel?: {
|
|
91
99
|
/**
|
|
92
100
|
* Optional layout for the content panel.
|
|
93
|
-
*
|
|
101
|
+
* Default: `"double-pane"`
|
|
94
102
|
*/
|
|
95
103
|
layout?: ContentLayout;
|
|
96
104
|
};
|
|
@@ -107,6 +115,8 @@ export type StainlessStarlightUserConfig = {
|
|
|
107
115
|
/**
|
|
108
116
|
* When set to `true`, the enableAISearch` setting turns on support for
|
|
109
117
|
* LLM-based conversations with the API documentation
|
|
118
|
+
*
|
|
119
|
+
* Default: `false`
|
|
110
120
|
*/
|
|
111
121
|
enableAISearch?: boolean;
|
|
112
122
|
};
|
|
@@ -114,9 +124,17 @@ export type StainlessStarlightUserConfig = {
|
|
|
114
124
|
/**
|
|
115
125
|
* Enable experimental collapsible code snippets. Snippets will be collapsed by default for
|
|
116
126
|
* single-pane and mobile layouts.
|
|
117
|
-
*
|
|
127
|
+
*
|
|
128
|
+
* Default: `false`
|
|
118
129
|
*/
|
|
119
130
|
experimentalCollapsibleSnippets?: boolean;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Whether to show the context menu with options like "Copy as Markdown" and "Open in ChatGPT".
|
|
134
|
+
*
|
|
135
|
+
* Default: `true`
|
|
136
|
+
*/
|
|
137
|
+
contextMenu?: boolean;
|
|
120
138
|
};
|
|
121
139
|
|
|
122
140
|
export type ExternalSpecServerUserConfig = Omit<StainlessStarlightUserConfig, 'stainlessProject'> & {
|
|
@@ -133,15 +151,29 @@ function getLocalFilePaths(command: AstroCommand): InputFilePaths | null {
|
|
|
133
151
|
if (command !== 'dev') {
|
|
134
152
|
return null;
|
|
135
153
|
}
|
|
136
|
-
|
|
154
|
+
|
|
155
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
156
|
+
const oasPath = process.env.OPENAPI_PATH;
|
|
157
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
158
|
+
const configPath = process.env.STAINLESS_CONFIG_PATH;
|
|
159
|
+
|
|
160
|
+
if (!oasPath || !configPath) {
|
|
137
161
|
return null;
|
|
138
162
|
}
|
|
163
|
+
|
|
139
164
|
return {
|
|
140
|
-
oasPath: resolvePath(
|
|
141
|
-
configPath: resolvePath(
|
|
165
|
+
oasPath: resolvePath(oasPath),
|
|
166
|
+
configPath: resolvePath(configPath),
|
|
142
167
|
};
|
|
143
168
|
}
|
|
144
169
|
|
|
170
|
+
export type ApiKeySource = 'explicit-config' | 'environment-variable' | 'cli';
|
|
171
|
+
|
|
172
|
+
export type LoadedApiKey = {
|
|
173
|
+
value: string;
|
|
174
|
+
source: ApiKeySource;
|
|
175
|
+
};
|
|
176
|
+
|
|
145
177
|
export type SpecRetrieverConfig =
|
|
146
178
|
| {
|
|
147
179
|
kind: 'external_spec_server';
|
|
@@ -152,16 +184,63 @@ export type SpecRetrieverConfig =
|
|
|
152
184
|
kind: 'local_spec_server_with_files';
|
|
153
185
|
stainlessProject: string;
|
|
154
186
|
devPaths: InputFilePaths;
|
|
155
|
-
apiKey:
|
|
187
|
+
apiKey: LoadedApiKey | null;
|
|
156
188
|
version: VersionUserConfig;
|
|
157
189
|
}
|
|
158
190
|
| {
|
|
159
191
|
kind: 'local_spec_server_with_remote_files';
|
|
160
192
|
stainlessProject: string;
|
|
161
|
-
apiKey:
|
|
193
|
+
apiKey: LoadedApiKey;
|
|
162
194
|
version: VersionUserConfig;
|
|
163
195
|
};
|
|
164
196
|
|
|
197
|
+
function parseAuthJson(authJsonStr: string) {
|
|
198
|
+
let json: unknown;
|
|
199
|
+
try {
|
|
200
|
+
json = JSON.parse(authJsonStr);
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
202
|
+
} catch (_error) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (typeof json !== 'object' || json === null) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
if (!('access_token' in json)) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
const accessToken = json['access_token'];
|
|
213
|
+
if (typeof accessToken !== 'string') {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return accessToken;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function loadApiKey(configValue: string | undefined): LoadedApiKey | null {
|
|
220
|
+
if (typeof configValue === 'string') {
|
|
221
|
+
return { value: configValue, source: 'explicit-config' };
|
|
222
|
+
}
|
|
223
|
+
if (process.env.STAINLESS_API_KEY) {
|
|
224
|
+
return { value: process.env.STAINLESS_API_KEY, source: 'environment-variable' };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const homeDirPath = homedir();
|
|
228
|
+
|
|
229
|
+
const authJsonPath = path.join(homeDirPath, '.config', 'stainless', 'auth.json');
|
|
230
|
+
|
|
231
|
+
if (!existsSync(authJsonPath)) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const authJsonStr = readFileSync(authJsonPath, 'utf-8');
|
|
236
|
+
const accessToken = parseAuthJson(authJsonStr);
|
|
237
|
+
if (!accessToken) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return { value: accessToken, source: 'cli' };
|
|
242
|
+
}
|
|
243
|
+
|
|
165
244
|
function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: AstroCommand) {
|
|
166
245
|
const configWithDefaults = {
|
|
167
246
|
basePath: partial.basePath ?? '/api',
|
|
@@ -190,6 +269,7 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
190
269
|
search: {
|
|
191
270
|
enableAISearch: partial.search?.enableAISearch ?? false,
|
|
192
271
|
},
|
|
272
|
+
contextMenu: partial.contextMenu ?? true,
|
|
193
273
|
};
|
|
194
274
|
|
|
195
275
|
function getSpecRetrieverConfig(): SpecRetrieverConfig {
|
|
@@ -205,7 +285,7 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
205
285
|
throw new Error('You must provide a stainlessProject when using Stainless Starlight');
|
|
206
286
|
}
|
|
207
287
|
|
|
208
|
-
const apiKey = partial.apiKey
|
|
288
|
+
const apiKey = loadApiKey(partial.apiKey);
|
|
209
289
|
|
|
210
290
|
const version = {
|
|
211
291
|
stainlessProject: partial.stainlessProject,
|
|
@@ -226,7 +306,14 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
226
306
|
|
|
227
307
|
if (!apiKey) {
|
|
228
308
|
throw new Error(
|
|
229
|
-
|
|
309
|
+
[
|
|
310
|
+
bold(
|
|
311
|
+
'No Stainless credentials found. Please choose one of the following options to authenticate with Stainless:',
|
|
312
|
+
),
|
|
313
|
+
'- Run `stl auth login` to authenticate via the Stainless CLI',
|
|
314
|
+
'- Provide a Stainless API key via the `STAINLESS_API_KEY` environment variable (eg. in a .env file)',
|
|
315
|
+
'- Set the `apiKey` option in the Stainless Docs config',
|
|
316
|
+
].join('\n'),
|
|
230
317
|
);
|
|
231
318
|
}
|
|
232
319
|
|
package/plugin/react/Routing.tsx
CHANGED
|
@@ -6,8 +6,8 @@ import remarkGfmAlerts from 'remark-github-alerts';
|
|
|
6
6
|
|
|
7
7
|
import type { MarkdownHeading } from 'astro';
|
|
8
8
|
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
9
|
-
import type * as SDKJSON from '
|
|
10
|
-
import type
|
|
9
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
10
|
+
import { LanguageNames, type DocsLanguage } from '@stainless-api/docs-ui/src/routing';
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
generateRouteList,
|
|
@@ -48,14 +48,14 @@ import {
|
|
|
48
48
|
HIGHLIGHT_THEMES,
|
|
49
49
|
BREADCRUMB_CONFIG,
|
|
50
50
|
PROPERTY_SETTINGS,
|
|
51
|
+
ENABLE_CONTEXT_MENU,
|
|
51
52
|
} from 'virtual:stl-starlight-virtual-module';
|
|
52
53
|
import style from '@stainless-api/docs-ui/src/style';
|
|
53
54
|
import { createHighlighter, type BundledLanguage, type BundledTheme, type HighlighterGeneric } from 'shiki';
|
|
54
55
|
import { SnippetCode, SnippetContainer, SnippetRequestContainer } from '../components/SnippetCode';
|
|
55
|
-
import clsx from 'clsx';
|
|
56
56
|
import type { StlStarlightMiddleware } from '../middlewareBuilder/stainlessMiddleware';
|
|
57
57
|
import { ComponentProvider } from '@stainless-api/docs-ui/src/contexts/component';
|
|
58
|
-
import {
|
|
58
|
+
import { AIDropdown } from '../../stl-docs/components/AIDropdown';
|
|
59
59
|
|
|
60
60
|
export function generateDocsRoutes(spec: SDKJSON.Spec) {
|
|
61
61
|
const paths = generateRouteList({
|
|
@@ -120,7 +120,6 @@ export function buildSidebar(
|
|
|
120
120
|
|
|
121
121
|
const meths: SidebarEntry[] = Object.values(resource.methods ?? [])
|
|
122
122
|
.filter((method) => spec.decls?.[language]?.[method.stainlessPath])
|
|
123
|
-
.toSorted((first, second) => first.name.localeCompare(second.name))
|
|
124
123
|
.map((method) => ({
|
|
125
124
|
type: 'link',
|
|
126
125
|
isCurrent: current === method.stainlessPath,
|
|
@@ -179,25 +178,25 @@ export function SDKSelectReactComponent({
|
|
|
179
178
|
return (
|
|
180
179
|
<Dropdown id={id} data-current-value={selected} className={className}>
|
|
181
180
|
<DropdownTrigger
|
|
182
|
-
className="dropdown-toggle
|
|
181
|
+
className="dropdown-toggle"
|
|
183
182
|
type="button"
|
|
184
|
-
id="
|
|
183
|
+
id="stl-docs-snippet-title-button"
|
|
185
184
|
aria-expanded="false"
|
|
186
185
|
withChevron
|
|
187
186
|
>
|
|
188
187
|
<SDKIcon language={getLanguageSnippet(selected)} size={16} />
|
|
189
|
-
<span className=
|
|
188
|
+
<span className="stl-snippet-dropdown-button-text">{LanguageNames[selected]}</span>
|
|
190
189
|
</DropdownTrigger>
|
|
191
190
|
<DropdownMenu
|
|
192
191
|
className="dropdown-menu stl-sdk-select-dropdown-menu"
|
|
193
192
|
position="below"
|
|
194
|
-
aria-labelledby="
|
|
193
|
+
aria-labelledby="stl-docs-snippet-title-button"
|
|
195
194
|
>
|
|
196
195
|
{languages.map((item) => (
|
|
197
196
|
<DropdownItem key={item} value={item} selected={item === selected}>
|
|
198
197
|
<div>
|
|
199
198
|
<SDKIcon language={getLanguageSnippet(item)} size={16} />
|
|
200
|
-
<span className=
|
|
199
|
+
<span className="stl-snippet-dropdown-button-text">{LanguageNames[item]}</span>
|
|
201
200
|
</div>
|
|
202
201
|
</DropdownItem>
|
|
203
202
|
))}
|
|
@@ -302,7 +301,10 @@ export function RenderSpec({
|
|
|
302
301
|
const parsed = parseStainlessPath(path);
|
|
303
302
|
const resource = getResourceFromSpec(path, spec);
|
|
304
303
|
|
|
305
|
-
if (!resource || !parsed)
|
|
304
|
+
if (!resource || !parsed) {
|
|
305
|
+
console.warn(`Could not find resource or parsed path for '${path}'`);
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
306
308
|
|
|
307
309
|
return (
|
|
308
310
|
<DocsProvider
|
|
@@ -323,7 +325,7 @@ export function RenderSpec({
|
|
|
323
325
|
>
|
|
324
326
|
<NavigationProvider basePath={BASE_PATH} selectedPath={path}>
|
|
325
327
|
<MarkdownProvider render={renderMarkdown} highlight={highlight}>
|
|
326
|
-
{
|
|
328
|
+
{
|
|
327
329
|
<div className="stldocs-root stl-ui-not-prose">
|
|
328
330
|
<div className="stl-page-nav-container">
|
|
329
331
|
<SDKBreadcrumbs
|
|
@@ -332,27 +334,18 @@ export function RenderSpec({
|
|
|
332
334
|
basePath={BASE_PATH}
|
|
333
335
|
config={BREADCRUMB_CONFIG}
|
|
334
336
|
/>
|
|
335
|
-
<
|
|
337
|
+
{ENABLE_CONTEXT_MENU && <AIDropdown />}
|
|
336
338
|
</div>
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
</div>
|
|
342
|
-
) : (
|
|
343
|
-
<div className="stldocs-root stl-ui-not-prose">
|
|
344
|
-
<div className="stl-page-nav-container">
|
|
345
|
-
<SDKBreadcrumbs
|
|
346
|
-
spec={spec as SDKJSON.Spec}
|
|
347
|
-
currentPath={currentPath}
|
|
348
|
-
basePath={BASE_PATH}
|
|
349
|
-
config={BREADCRUMB_CONFIG}
|
|
339
|
+
{kind === 'http_method' ? (
|
|
340
|
+
<SDKMethod
|
|
341
|
+
method={resource.methods[parsed.method!]!}
|
|
342
|
+
transformRequestSnippet={transformRequestSnippet}
|
|
350
343
|
/>
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
344
|
+
) : (
|
|
345
|
+
<SDKOverview resource={resource} />
|
|
346
|
+
)}
|
|
354
347
|
</div>
|
|
355
|
-
|
|
348
|
+
}
|
|
356
349
|
</MarkdownProvider>
|
|
357
350
|
</NavigationProvider>
|
|
358
351
|
</ComponentProvider>
|
|
@@ -366,10 +359,14 @@ export function RenderMethod({ path }: { path: string }) {
|
|
|
366
359
|
|
|
367
360
|
const parsed = parseStainlessPath(path);
|
|
368
361
|
const resource = getResourceFromSpec(path, spec);
|
|
369
|
-
if (!resource || !parsed) return null;
|
|
370
362
|
|
|
371
|
-
|
|
372
|
-
|
|
363
|
+
if (!resource || !parsed) {
|
|
364
|
+
console.warn(`Could not find resource or parsed path for '${path}'`);
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const method = resource.methods[parsed.method!]!;
|
|
369
|
+
return <SDKMethod method={method} />;
|
|
373
370
|
}
|
|
374
371
|
|
|
375
372
|
export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguage) {
|
|
@@ -58,7 +58,7 @@ function recursiveGetPlaceholderItems(
|
|
|
58
58
|
items: PlaceholderItemResult[],
|
|
59
59
|
): PlaceholderItemResult[] {
|
|
60
60
|
for (let i = 0; i < sidebar.length; i++) {
|
|
61
|
-
const entry = sidebar[i]
|
|
61
|
+
const entry = sidebar[i]!;
|
|
62
62
|
if ('attrs' in entry && entry.attrs?.about === INTERNAL_REFERENCE_ENTRY_MARKER) {
|
|
63
63
|
items.push({
|
|
64
64
|
index: i,
|
|
@@ -15,6 +15,10 @@ export const onRequest = defineRouteMiddleware(async (context) => {
|
|
|
15
15
|
|
|
16
16
|
const slug = `/${context.locals.starlightRoute.id}`; // same as .slug but not deprecated
|
|
17
17
|
|
|
18
|
+
context.locals.starlightRoute._stlStarlight = {
|
|
19
|
+
basePath: BASE_PATH,
|
|
20
|
+
};
|
|
21
|
+
|
|
18
22
|
const apiReferencePlaceholderItems = getAPIReferencePlaceholderItems(context.locals.starlightRoute.sidebar);
|
|
19
23
|
|
|
20
24
|
const spec = await cmsClient.getSpec();
|