@stainless-api/docs 0.1.0-beta.13 → 0.1.0-beta.130
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 +1102 -0
- package/ambient.d.ts +6 -0
- package/eslint-suppressions.json +90 -0
- package/{eslint.config.js → eslint.config.ts} +0 -2
- package/locals.d.ts +17 -0
- package/package.json +62 -44
- package/playground-virtual-modules.d.ts +96 -0
- package/plugin/assets/languages/cli.svg +14 -0
- package/plugin/assets/languages/csharp.svg +1 -0
- package/plugin/assets/languages/php.svg +4 -0
- package/plugin/buildAlgoliaIndex.ts +40 -39
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
- package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
- package/plugin/components/RequestBuilder/index.tsx +40 -0
- package/plugin/components/RequestBuilder/props.ts +9 -0
- package/plugin/components/RequestBuilder/spec-helpers.ts +47 -0
- package/plugin/components/RequestBuilder/styles.css +67 -0
- package/plugin/components/SDKSelect.astro +18 -111
- package/plugin/components/SnippetCode.tsx +112 -70
- package/plugin/components/StainlessIslands.tsx +126 -0
- package/plugin/components/search/SearchAlgolia.astro +46 -29
- package/plugin/components/search/SearchIsland.tsx +61 -37
- package/plugin/generateAPIReferenceLink.ts +0 -40
- package/plugin/globalJs/ai-dropdown-options.ts +248 -0
- package/plugin/globalJs/code-snippets.ts +45 -16
- package/plugin/globalJs/copy.ts +115 -27
- package/plugin/globalJs/create-playground.shim.ts +3 -0
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +24 -44
- package/plugin/globalJs/playground-data.shim.ts +1 -0
- package/plugin/globalJs/playground-data.ts +14 -0
- package/plugin/globalJs/summary-selection-tweak.ts +29 -0
- package/plugin/helpers/generateDocsRoutes.ts +59 -0
- package/plugin/helpers/multiSpec.ts +8 -0
- package/plugin/index.ts +317 -141
- package/plugin/languages.ts +8 -2
- package/plugin/loadPluginConfig.ts +284 -109
- package/plugin/markdown/highlighter.ts +100 -0
- package/plugin/markdown/index.ts +39 -0
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +3 -1
- package/plugin/react/Routing.tsx +98 -263
- package/plugin/referencePlaceholderUtils.ts +17 -14
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +39 -35
- package/plugin/routes/Docs.astro +72 -111
- package/plugin/routes/DocsStatic.astro +6 -5
- package/plugin/routes/Overview.astro +46 -22
- package/plugin/routes/llms.ts +186 -0
- package/plugin/routes/markdown.ts +13 -12
- package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +84 -69
- package/plugin/specs/FileCache.ts +99 -0
- package/plugin/specs/fetchSpecSSR.ts +27 -0
- package/plugin/specs/generateSpec.ts +112 -0
- package/plugin/specs/index.ts +132 -0
- package/plugin/specs/inputResolver.ts +148 -0
- package/plugin/{cms → specs}/worker.ts +82 -5
- package/plugin/vendor/preview.worker.docs.js +27121 -16890
- package/plugin/vendor/templates/cli.md +1 -0
- package/plugin/vendor/templates/go.md +4 -2
- package/plugin/vendor/templates/java.md +5 -1
- package/plugin/vendor/templates/kotlin.md +5 -1
- package/plugin/vendor/templates/node.md +4 -2
- package/plugin/vendor/templates/python.md +4 -2
- package/plugin/vendor/templates/ruby.md +4 -2
- package/plugin/vendor/templates/terraform.md +1 -1
- package/plugin/vendor/templates/typescript.md +3 -1
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +5 -5
- package/shared/conditionalIntegration.ts +28 -0
- package/shared/getProsePages.ts +41 -0
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/shared/virtualModule.ts +46 -1
- package/src/content.config.ts +9 -0
- package/stl-docs/aiChatExamples.ts +95 -0
- package/stl-docs/chat/docs-chat-handler.ts +18 -0
- package/stl-docs/chat/hook.ts +215 -0
- package/stl-docs/chat/schemas.ts +70 -0
- package/stl-docs/chat/stainless-handler/index.ts +126 -0
- package/stl-docs/chat/stream-util.ts +16 -0
- package/stl-docs/chat/ui/AiChat.module.css +591 -0
- package/stl-docs/chat/ui/AiChat.tsx +188 -0
- package/stl-docs/chat/ui/Trigger.tsx +154 -0
- package/stl-docs/chat/ui/components/ChatControls.tsx +51 -0
- package/stl-docs/chat/ui/components/ChatEmpty.tsx +42 -0
- package/stl-docs/chat/ui/components/ChatLog.tsx +96 -0
- package/stl-docs/chat/ui/components/ChatMessage.tsx +47 -0
- package/stl-docs/chat/ui/components/CodeBlock.tsx +33 -0
- package/stl-docs/chat/ui/components/MessageFeedback.tsx +109 -0
- package/stl-docs/chat/ui/components/Table.tsx +15 -0
- package/stl-docs/chat/ui/components/ToolCall.tsx +34 -0
- package/stl-docs/chat/ui/components/hljs-github.css +81 -0
- package/stl-docs/chat/ui/scroll-manager.ts +86 -0
- package/stl-docs/chat/ui/types.ts +45 -0
- package/stl-docs/components/AIDropdown.tsx +63 -0
- package/stl-docs/components/AiChatIsland.tsx +16 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
- package/stl-docs/components/ContentPanel.astro +9 -0
- package/stl-docs/components/Footer.astro +89 -0
- package/stl-docs/components/Head.astro +20 -0
- package/stl-docs/components/Header.astro +3 -9
- package/stl-docs/components/PageFrame.astro +37 -0
- package/stl-docs/components/PageSidebar.astro +11 -0
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/StainlessLogo.svg +4 -0
- package/stl-docs/components/ThemeProvider.astro +36 -0
- package/stl-docs/components/ThemeSelect.astro +84 -146
- package/stl-docs/components/TwoColumnContent.astro +2 -0
- package/stl-docs/components/headers/DefaultHeader.astro +6 -8
- package/stl-docs/components/headers/StackedHeader.astro +10 -53
- package/stl-docs/components/icons/chat-gpt.tsx +2 -2
- package/stl-docs/components/icons/cursor.tsx +10 -0
- package/stl-docs/components/icons/gemini.tsx +19 -0
- package/stl-docs/components/icons/markdown.tsx +1 -1
- package/stl-docs/components/index.ts +1 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +2 -2
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +0 -4
- package/stl-docs/components/mintlify-compat/Columns.astro +2 -2
- package/stl-docs/components/mintlify-compat/Frame.astro +6 -6
- package/stl-docs/components/mintlify-compat/Tab.astro +2 -2
- package/stl-docs/components/mintlify-compat/callouts/Callout.astro +2 -2
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +0 -4
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +0 -4
- package/stl-docs/components/mintlify-compat/card.css +4 -4
- package/stl-docs/components/mintlify-compat/index.ts +2 -4
- package/stl-docs/components/nav-tabs/NavDropdown.astro +38 -77
- package/stl-docs/components/nav-tabs/NavTabs.astro +81 -81
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +1 -2
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +5 -2
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +177 -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/scripts.ts +1 -0
- package/stl-docs/components/sidebars/BaseSidebar.astro +80 -2
- package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
- package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/fonts.ts +186 -0
- package/stl-docs/index.ts +176 -58
- package/stl-docs/loadStlDocsConfig.ts +73 -8
- package/stl-docs/proseDocSync.test.ts +74 -0
- package/stl-docs/proseDocSync.ts +344 -0
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +53 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/proseSearchIndexing.ts +218 -0
- package/stl-docs/tabsMiddleware.ts +14 -5
- package/styles/code.css +53 -49
- package/styles/links.css +2 -37
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +28 -46
- package/styles/page.css +228 -38
- package/styles/sdk_select.css +9 -6
- package/styles/search.css +11 -21
- package/styles/sidebar.css +28 -215
- package/styles/{variables.css → sl-variables.css} +4 -8
- package/styles/stldocs-variables.css +6 -0
- package/styles/toc.css +19 -8
- package/theme.css +11 -9
- package/tsconfig.json +1 -4
- package/virtual-module.d.ts +66 -8
- package/components/variables.css +0 -112
- package/plugin/cms/client.ts +0 -62
- package/plugin/cms/server.ts +0 -268
- package/plugin/globalJs/ai-dropdown.ts +0 -57
- package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
- package/stl-docs/components/ClientRouterHead.astro +0 -41
- package/stl-docs/components/content-panel/ContentPanel.astro +0 -69
- package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +0 -49
- package/stl-docs/components/mintlify-compat/Step.astro +0 -56
- package/stl-docs/components/mintlify-compat/Steps.astro +0 -15
- package/styles/fonts.css +0 -68
- /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
|
@@ -1,15 +1,24 @@
|
|
|
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
|
-
import type { DocsLanguage } from '@stainless-api/docs-ui/
|
|
5
|
-
import type { PropertySettingsType } from '@stainless-api/docs-ui/
|
|
6
|
-
import
|
|
6
|
+
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
7
|
+
import type { PropertySettingsType } from '@stainless-api/docs-ui/contexts';
|
|
8
|
+
import { bold } from '../shared/terminalUtils';
|
|
9
|
+
import { resolveSpec, SpecInputResolver } from './specs/inputResolver';
|
|
10
|
+
import { specCache, SpecCacheResult } from './specs/generateSpec';
|
|
11
|
+
|
|
12
|
+
export type LanguageGenerateQuery = {
|
|
13
|
+
mode: 'exclude' | 'only';
|
|
14
|
+
list: DocsLanguage[];
|
|
15
|
+
};
|
|
7
16
|
|
|
8
|
-
|
|
17
|
+
type AstroCommand = 'dev' | 'build' | 'preview' | 'sync';
|
|
9
18
|
|
|
10
|
-
|
|
19
|
+
type ContentLayout = 'double-pane' | 'single-pane';
|
|
11
20
|
|
|
12
|
-
|
|
21
|
+
type VersionUserConfig = {
|
|
13
22
|
version: string;
|
|
14
23
|
stainlessProject: string;
|
|
15
24
|
branch: string;
|
|
@@ -18,7 +27,7 @@ export type VersionUserConfig = {
|
|
|
18
27
|
type BreadcrumbUserConfig = {
|
|
19
28
|
/**
|
|
20
29
|
* Include the current page in the breadcrumb list.
|
|
21
|
-
*
|
|
30
|
+
* Default: `false`
|
|
22
31
|
*/
|
|
23
32
|
includeCurrentPage?: boolean;
|
|
24
33
|
};
|
|
@@ -26,7 +35,12 @@ type BreadcrumbUserConfig = {
|
|
|
26
35
|
export type StainlessStarlightUserConfig = {
|
|
27
36
|
/**
|
|
28
37
|
* Optional api key for Stainless API.
|
|
29
|
-
* If not provided,
|
|
38
|
+
* If not provided, we will handle Stainless auth via the `stl` CLI or look for the STAINLESS_API_KEY environment variable.
|
|
39
|
+
* Precedence:
|
|
40
|
+
* 1. Explicity `apiKey` option provided
|
|
41
|
+
* 2. `STAINLESS_API_KEY` environment variable
|
|
42
|
+
* 3. Login status from the `stl` CLI
|
|
43
|
+
* 4. Error (no auth found)
|
|
30
44
|
*/
|
|
31
45
|
apiKey?: string;
|
|
32
46
|
|
|
@@ -35,6 +49,19 @@ export type StainlessStarlightUserConfig = {
|
|
|
35
49
|
*/
|
|
36
50
|
stainlessProject: string;
|
|
37
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Powerful configuration options for customized use cases
|
|
54
|
+
*/
|
|
55
|
+
advanced?: {
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* More advanced replacement for versions, basePath, and excludeLanguages.
|
|
59
|
+
*/
|
|
60
|
+
overrideSpecs?: {
|
|
61
|
+
specs: SpecInputResolver[];
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
38
65
|
/**
|
|
39
66
|
* Optional list of versions to render in the API reference.
|
|
40
67
|
*/
|
|
@@ -42,8 +69,8 @@ export type StainlessStarlightUserConfig = {
|
|
|
42
69
|
|
|
43
70
|
/**
|
|
44
71
|
* Optional mount point for API reference docs.
|
|
45
|
-
* Defaults to `/api`.
|
|
46
72
|
* Example: `/my-api` → docs available at `/my-api/…`.
|
|
73
|
+
* @default `/api`
|
|
47
74
|
*/
|
|
48
75
|
basePath?: string;
|
|
49
76
|
|
|
@@ -55,8 +82,8 @@ export type StainlessStarlightUserConfig = {
|
|
|
55
82
|
|
|
56
83
|
/**
|
|
57
84
|
* Optional language to treat as the default when the user hasn't selected one.
|
|
58
|
-
*
|
|
59
|
-
*
|
|
85
|
+
* Example: `'python'`
|
|
86
|
+
* @default 'http'
|
|
60
87
|
*/
|
|
61
88
|
defaultLanguage?: DocsLanguage;
|
|
62
89
|
|
|
@@ -90,7 +117,7 @@ export type StainlessStarlightUserConfig = {
|
|
|
90
117
|
contentPanel?: {
|
|
91
118
|
/**
|
|
92
119
|
* Optional layout for the content panel.
|
|
93
|
-
*
|
|
120
|
+
* @default 'double-pane'
|
|
94
121
|
*/
|
|
95
122
|
layout?: ContentLayout;
|
|
96
123
|
};
|
|
@@ -100,78 +127,261 @@ export type StainlessStarlightUserConfig = {
|
|
|
100
127
|
*/
|
|
101
128
|
propertySettings?: PropertySettingsType;
|
|
102
129
|
|
|
103
|
-
/**
|
|
104
|
-
* Options to control the documentation site's search functionality
|
|
105
|
-
*/
|
|
106
|
-
search?: {
|
|
107
|
-
/**
|
|
108
|
-
* When set to `true`, the enableAISearch` setting turns on support for
|
|
109
|
-
* LLM-based conversations with the API documentation
|
|
110
|
-
*/
|
|
111
|
-
enableAISearch?: boolean;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
130
|
/**
|
|
115
131
|
* Enable experimental collapsible code snippets. Snippets will be collapsed by default for
|
|
116
132
|
* single-pane and mobile layouts.
|
|
117
|
-
*
|
|
133
|
+
*
|
|
134
|
+
* @default false
|
|
118
135
|
*/
|
|
119
136
|
experimentalCollapsibleSnippets?: boolean;
|
|
120
137
|
|
|
121
138
|
/**
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
139
|
+
* Enable experimental collapsible method descriptions. Method descriptions will be
|
|
140
|
+
* collapsed if their content exceeds a certain length.
|
|
141
|
+
*
|
|
142
|
+
* @default false
|
|
125
143
|
*/
|
|
126
|
-
|
|
127
|
-
};
|
|
144
|
+
experimentalCollapsibleMethodDescriptions?: boolean;
|
|
128
145
|
|
|
129
|
-
|
|
130
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Whether to show the context menu with options like "Copy as Markdown" and "Open in ChatGPT".
|
|
148
|
+
*
|
|
149
|
+
* @default true
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
contextMenu?: boolean;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* When set to `import playgrounds from '@stainless-api/playgrounds'`, code snippets will have a "Play" button,
|
|
156
|
+
* allowing users to edit and run code snippets in their browser.
|
|
157
|
+
*/
|
|
158
|
+
experimentalPlaygrounds?: { playgroundsBase: string };
|
|
159
|
+
|
|
160
|
+
/** When set to true, enables the experimental request builder interface for testing API endpoints. */
|
|
161
|
+
experimentalRequestBuilder?: boolean;
|
|
162
|
+
|
|
163
|
+
/** Whether to prerender the api reference pages.
|
|
164
|
+
*
|
|
165
|
+
* @default true
|
|
166
|
+
*/
|
|
167
|
+
experimentalPrerender?: boolean;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Configuration for the generated `/llms.txt` file.
|
|
171
|
+
*/
|
|
172
|
+
llmsTxt?: {
|
|
173
|
+
/**
|
|
174
|
+
* Whether to disable the generated `/llms.txt` file.
|
|
175
|
+
*
|
|
176
|
+
* @default false
|
|
177
|
+
*/
|
|
178
|
+
disabled?: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* A short description of the site, used as the blockquote summary at the top of the file.
|
|
181
|
+
* Falls back to the top-level Starlight `description` field if not set.
|
|
182
|
+
*/
|
|
183
|
+
description?: string;
|
|
184
|
+
/**
|
|
185
|
+
* The maximum number of total routes (prose + API reference) at which the file switches
|
|
186
|
+
* from compact mode (resources only) to detailed mode (resources and
|
|
187
|
+
* methods).
|
|
188
|
+
*
|
|
189
|
+
* @default 2000
|
|
190
|
+
*/
|
|
191
|
+
detailThreshold?: number;
|
|
192
|
+
};
|
|
131
193
|
};
|
|
132
194
|
|
|
133
|
-
|
|
195
|
+
// TODO: eventually? re-add support for external spec servers
|
|
196
|
+
// export type ExternalSpecServerUserConfig = Omit<StainlessStarlightUserConfig, 'stainlessProject'> & {
|
|
197
|
+
// externalSpecServerUrl: string;
|
|
198
|
+
// };
|
|
199
|
+
|
|
200
|
+
export type SomeStainlessStarlightUserConfig = StainlessStarlightUserConfig;
|
|
134
201
|
|
|
135
202
|
function resolvePath(inputPath: string) {
|
|
136
203
|
return path.resolve(process.cwd(), inputPath);
|
|
137
204
|
}
|
|
138
205
|
|
|
139
|
-
function getLocalFilePaths(command: AstroCommand)
|
|
206
|
+
function getLocalFilePaths(command: AstroCommand) {
|
|
140
207
|
if (command !== 'dev') {
|
|
141
208
|
return null;
|
|
142
209
|
}
|
|
143
|
-
|
|
210
|
+
|
|
211
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
212
|
+
const oasPath = process.env.OPENAPI_PATH;
|
|
213
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
214
|
+
const configPath = process.env.STAINLESS_CONFIG_PATH;
|
|
215
|
+
|
|
216
|
+
if (!oasPath || !configPath) {
|
|
144
217
|
return null;
|
|
145
218
|
}
|
|
219
|
+
|
|
146
220
|
return {
|
|
147
|
-
oasPath: resolvePath(
|
|
148
|
-
configPath: resolvePath(
|
|
221
|
+
oasPath: resolvePath(oasPath),
|
|
222
|
+
configPath: resolvePath(configPath),
|
|
149
223
|
};
|
|
150
224
|
}
|
|
151
225
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
226
|
+
type ApiKeySource = 'explicit-config' | 'environment-variable' | 'cli';
|
|
227
|
+
|
|
228
|
+
export type LoadedApiKey = {
|
|
229
|
+
value: string;
|
|
230
|
+
source: ApiKeySource;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
function parseAuthJson(authJsonStr: string) {
|
|
234
|
+
let json: unknown;
|
|
235
|
+
try {
|
|
236
|
+
json = JSON.parse(authJsonStr);
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
238
|
+
} catch (_error) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (typeof json !== 'object' || json === null) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
if (!('access_token' in json)) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const accessToken = json['access_token'];
|
|
249
|
+
if (typeof accessToken !== 'string') {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return accessToken;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function loadApiKey(configValue: string | undefined): LoadedApiKey | null {
|
|
256
|
+
if (typeof configValue === 'string') {
|
|
257
|
+
return { value: configValue, source: 'explicit-config' };
|
|
258
|
+
}
|
|
259
|
+
if (process.env.STAINLESS_API_KEY) {
|
|
260
|
+
return { value: process.env.STAINLESS_API_KEY, source: 'environment-variable' };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const homeDirPath = homedir();
|
|
264
|
+
|
|
265
|
+
const authJsonPath = path.join(homeDirPath, '.config', 'stainless', 'auth.json');
|
|
266
|
+
|
|
267
|
+
if (!existsSync(authJsonPath)) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const authJsonStr = readFileSync(authJsonPath, 'utf-8');
|
|
272
|
+
const accessToken = parseAuthJson(authJsonStr);
|
|
273
|
+
if (!accessToken) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return { value: accessToken, source: 'cli' };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** @public but discouraged - used by cloudflare via relative import */
|
|
281
|
+
export function forceLoadStainlessCredentials(): LoadedApiKey {
|
|
282
|
+
const v = loadApiKey(undefined);
|
|
283
|
+
if (!v) {
|
|
284
|
+
throw new Error(`Failed to load Stainless credentials.`);
|
|
285
|
+
}
|
|
286
|
+
return v;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
type AstroOptions = {
|
|
290
|
+
command: AstroCommand;
|
|
291
|
+
base: string;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
type ResolvedAPIConfigEntry = {
|
|
295
|
+
loadSpecs: () => Promise<SpecCacheResult[]>;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
function makeSimpleAPIConfig(
|
|
299
|
+
partial: SomeStainlessStarlightUserConfig,
|
|
300
|
+
astroOptions: AstroOptions,
|
|
301
|
+
): ResolvedAPIConfigEntry {
|
|
302
|
+
if (!('stainlessProject' in partial)) {
|
|
303
|
+
throw new Error('You must provide a stainlessProject when using Stainless Starlight');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const excludedLanguages = partial.excludeLanguages ?? [];
|
|
307
|
+
|
|
308
|
+
const apiKey = loadApiKey(partial.apiKey);
|
|
309
|
+
|
|
310
|
+
function getResolver() {
|
|
311
|
+
const localFilePaths = getLocalFilePaths(astroOptions.command);
|
|
312
|
+
if (localFilePaths) {
|
|
313
|
+
return resolveSpec.fromFiles({
|
|
314
|
+
oasPath: localFilePaths.oasPath,
|
|
315
|
+
configPath: localFilePaths.configPath,
|
|
316
|
+
languageOverrides: {
|
|
317
|
+
mode: 'exclude',
|
|
318
|
+
list: excludedLanguages,
|
|
319
|
+
},
|
|
320
|
+
stainlessProject: partial.stainlessProject,
|
|
321
|
+
});
|
|
157
322
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
323
|
+
|
|
324
|
+
if (!apiKey) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
[
|
|
327
|
+
bold(
|
|
328
|
+
'No Stainless credentials found. Please choose one of the following options to authenticate with Stainless:',
|
|
329
|
+
),
|
|
330
|
+
'- Run `stl auth login` to authenticate via the Stainless CLI',
|
|
331
|
+
'- Provide a Stainless API key via the `STAINLESS_API_KEY` environment variable (eg. in a .env file)',
|
|
332
|
+
'- Set the `apiKey` option in the Stainless Docs config',
|
|
333
|
+
].join('\n'),
|
|
334
|
+
);
|
|
164
335
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
apiKey:
|
|
169
|
-
|
|
336
|
+
return resolveSpec.fromStainlessApi({
|
|
337
|
+
stainlessProject: partial.stainlessProject,
|
|
338
|
+
branch: partial.versions?.[0]?.branch ?? 'main',
|
|
339
|
+
apiKey: apiKey,
|
|
340
|
+
languageOverrides: {
|
|
341
|
+
mode: 'exclude',
|
|
342
|
+
list: excludedLanguages,
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const resolver = getResolver();
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
loadSpecs: async function loadSpecs() {
|
|
351
|
+
const inputs = await resolver.resolve({ apiKey });
|
|
352
|
+
|
|
353
|
+
const result = await specCache.get(inputs);
|
|
354
|
+
|
|
355
|
+
return [result];
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function loadAPIConfig(
|
|
361
|
+
partial: SomeStainlessStarlightUserConfig,
|
|
362
|
+
astroOptions: AstroOptions,
|
|
363
|
+
): ResolvedAPIConfigEntry {
|
|
364
|
+
if (partial.advanced?.overrideSpecs) {
|
|
365
|
+
const overrides = partial.advanced.overrideSpecs;
|
|
366
|
+
const apiKey = loadApiKey(partial.apiKey);
|
|
367
|
+
return {
|
|
368
|
+
loadSpecs: async function loadSpecs() {
|
|
369
|
+
const specsPromises = overrides.specs.map(async (spec) => {
|
|
370
|
+
const inputs = await spec.resolve({ apiKey });
|
|
371
|
+
return await specCache.get(inputs);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
return await Promise.all(specsPromises);
|
|
375
|
+
},
|
|
170
376
|
};
|
|
377
|
+
}
|
|
378
|
+
return makeSimpleAPIConfig(partial, astroOptions);
|
|
379
|
+
}
|
|
171
380
|
|
|
172
|
-
function normalizeConfig(partial: SomeStainlessStarlightUserConfig,
|
|
381
|
+
function normalizeConfig(partial: SomeStainlessStarlightUserConfig, astroOptions: AstroOptions) {
|
|
173
382
|
const configWithDefaults = {
|
|
174
383
|
basePath: partial.basePath ?? '/api',
|
|
384
|
+
astroBase: astroOptions.base,
|
|
175
385
|
excludeLanguages: partial.excludeLanguages ?? [],
|
|
176
386
|
defaultLanguage: partial.defaultLanguage ?? 'http',
|
|
177
387
|
breadcrumbs: {
|
|
@@ -188,86 +398,51 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
188
398
|
layout: partial.contentPanel?.layout ?? 'double-pane',
|
|
189
399
|
},
|
|
190
400
|
experimentalCollapsibleSnippets: partial.experimentalCollapsibleSnippets ?? false,
|
|
401
|
+
experimentalCollapsibleMethodDescriptions: partial.experimentalCollapsibleMethodDescriptions ?? false,
|
|
191
402
|
propertySettings: {
|
|
192
403
|
types: partial.propertySettings?.types ?? 'rich',
|
|
193
404
|
collapseDescription: partial.propertySettings?.collapseDescription ?? true,
|
|
405
|
+
showTitle: partial.propertySettings?.showTitle ?? false,
|
|
194
406
|
expandDepth: partial.propertySettings?.expandDepth ?? 0,
|
|
195
407
|
includeModelProperties: partial.propertySettings?.includeModelProperties ?? true,
|
|
196
408
|
},
|
|
197
|
-
|
|
198
|
-
|
|
409
|
+
contextMenu: partial.contextMenu ?? true,
|
|
410
|
+
experimentalPlaygrounds: partial.experimentalPlaygrounds ?? undefined,
|
|
411
|
+
experimentalRequestBuilder: partial.experimentalRequestBuilder ?? false,
|
|
412
|
+
experimentalPrerender: partial.experimentalPrerender ?? true,
|
|
413
|
+
stainlessProject: partial.stainlessProject,
|
|
414
|
+
llmsTxt: {
|
|
415
|
+
enabled: partial.llmsTxt?.disabled ?? true,
|
|
416
|
+
description: partial.llmsTxt?.description ?? null,
|
|
417
|
+
detailThreshold: partial.llmsTxt?.detailThreshold ?? 2000,
|
|
199
418
|
},
|
|
200
|
-
includeAIDropdownOptions: partial.includeAIDropdownOptions ?? false,
|
|
201
419
|
};
|
|
202
420
|
|
|
203
|
-
|
|
204
|
-
if ('externalSpecServerUrl' in partial) {
|
|
205
|
-
return {
|
|
206
|
-
kind: 'external_spec_server',
|
|
207
|
-
specServerUrl: partial.externalSpecServerUrl,
|
|
208
|
-
stainlessProject: null,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!('stainlessProject' in partial)) {
|
|
213
|
-
throw new Error('You must provide a stainlessProject when using Stainless Starlight');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const apiKey = partial.apiKey ?? process.env.STAINLESS_API_KEY ?? null;
|
|
217
|
-
|
|
218
|
-
const version = {
|
|
219
|
-
stainlessProject: partial.stainlessProject,
|
|
220
|
-
branch: partial.versions?.[0]?.branch ?? 'main',
|
|
221
|
-
version: partial.versions?.[0]?.version ?? 'v1',
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
const localFilePaths = getLocalFilePaths(command);
|
|
225
|
-
if (localFilePaths) {
|
|
226
|
-
return {
|
|
227
|
-
kind: 'local_spec_server_with_files',
|
|
228
|
-
devPaths: localFilePaths,
|
|
229
|
-
stainlessProject: partial.stainlessProject,
|
|
230
|
-
apiKey,
|
|
231
|
-
version,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (!apiKey) {
|
|
236
|
-
throw new Error(
|
|
237
|
-
'Please provide a Stainless API key via the STAINLESS_API_KEY environment variable or the apiKey option in the Stainless Starlight config.',
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
kind: 'local_spec_server_with_remote_files',
|
|
243
|
-
apiKey,
|
|
244
|
-
stainlessProject: partial.stainlessProject,
|
|
245
|
-
version,
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const specRetrieverConfig = getSpecRetrieverConfig();
|
|
421
|
+
const api = loadAPIConfig(partial, astroOptions);
|
|
250
422
|
|
|
251
423
|
return {
|
|
252
424
|
...configWithDefaults,
|
|
253
|
-
|
|
425
|
+
api,
|
|
254
426
|
};
|
|
255
427
|
}
|
|
256
428
|
|
|
257
429
|
export type NormalizedStainlessStarlightConfig = ReturnType<typeof normalizeConfig>;
|
|
258
430
|
|
|
259
431
|
/*
|
|
260
|
-
The goal of the code in this file is to take a user's config and normalize it.
|
|
432
|
+
The goal of the code in this file is to take a user's config and normalize it.
|
|
261
433
|
Specifically: we want a single complete config format used throughout the internals of the plugin.
|
|
262
434
|
|
|
263
435
|
We've tried to avoid any config values being optional/undefined. To accomplish this:
|
|
264
|
-
- Any optional config values should have their defaults set here: eg. basePath defaults to /api
|
|
265
|
-
- If a field is only used in certain contexts, we make each context a discriminated union (see
|
|
436
|
+
- Any optional config values should have their defaults set here: eg. basePath defaults to /api
|
|
437
|
+
- If a field is only used in certain contexts, we make each context a discriminated union (see SDKJSONInputs)
|
|
266
438
|
- We prefer empty arrays over undefined/null
|
|
267
439
|
*/
|
|
268
|
-
export function parseStarlightPluginConfig(
|
|
440
|
+
export function parseStarlightPluginConfig(
|
|
441
|
+
partial: SomeStainlessStarlightUserConfig,
|
|
442
|
+
astroOptions: AstroOptions,
|
|
443
|
+
) {
|
|
269
444
|
try {
|
|
270
|
-
const config = normalizeConfig(partial,
|
|
445
|
+
const config = normalizeConfig(partial, astroOptions);
|
|
271
446
|
return {
|
|
272
447
|
result: 'success' as const,
|
|
273
448
|
config,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createHighlighter,
|
|
3
|
+
type HighlighterGeneric,
|
|
4
|
+
type ThemeInput,
|
|
5
|
+
type BundledTheme,
|
|
6
|
+
type BundledLanguage,
|
|
7
|
+
} from 'shiki';
|
|
8
|
+
import { HIGHLIGHT_THEMES } from 'virtual:stl-starlight-virtual-module';
|
|
9
|
+
import { SupportedLanguageSyntaxes } from '@stainless-api/docs-ui/routing';
|
|
10
|
+
import type { CreateShikiHighlighterOptions } from '@astrojs/markdown-remark';
|
|
11
|
+
|
|
12
|
+
const STAINLESS_DOCS_JSON_THEME = {
|
|
13
|
+
name: 'stainless-docs-json',
|
|
14
|
+
colors: {
|
|
15
|
+
'editor.background': 'var(--stl-color-background)',
|
|
16
|
+
'editor.foreground': 'var(--stl-color-foreground)',
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
tokenColors: [
|
|
20
|
+
{
|
|
21
|
+
scope: ['comment', 'punctuation.definition.comment'],
|
|
22
|
+
settings: { foreground: 'var(--stl-color-foreground-muted)' },
|
|
23
|
+
},
|
|
24
|
+
// numbers, booleans, null
|
|
25
|
+
{
|
|
26
|
+
scope: ['constant.numeric', 'constant.language'],
|
|
27
|
+
settings: { foreground: 'var(--stl-color-orange-foreground)' },
|
|
28
|
+
},
|
|
29
|
+
// strings
|
|
30
|
+
{
|
|
31
|
+
scope: ['string', 'string.quoted', 'string.template'],
|
|
32
|
+
settings: { foreground: 'var(--stl-color-green-foreground)' },
|
|
33
|
+
},
|
|
34
|
+
// Keys, brackets
|
|
35
|
+
{
|
|
36
|
+
scope: ['support.type', 'meta'],
|
|
37
|
+
settings: { foreground: 'var(--stl-color-foreground)' },
|
|
38
|
+
},
|
|
39
|
+
// brackets
|
|
40
|
+
{
|
|
41
|
+
scope: ['meta'],
|
|
42
|
+
settings: { foreground: 'var(--stl-color-foreground-muted)' },
|
|
43
|
+
},
|
|
44
|
+
// built-in types
|
|
45
|
+
{
|
|
46
|
+
scope: ['support.type.builtin'],
|
|
47
|
+
settings: { foreground: 'var(--stl-color-purple-foreground)' },
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
} satisfies ThemeInput;
|
|
51
|
+
|
|
52
|
+
// singleton
|
|
53
|
+
let astroShikiHighlighter:
|
|
54
|
+
| HighlighterGeneric<BundledLanguage, BundledTheme>
|
|
55
|
+
| Promise<HighlighterGeneric<BundledLanguage, BundledTheme>>
|
|
56
|
+
| null = null;
|
|
57
|
+
async function getAstroHighlighter() {
|
|
58
|
+
if (astroShikiHighlighter) {
|
|
59
|
+
return astroShikiHighlighter;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
astroShikiHighlighter = createHighlighter({
|
|
63
|
+
themes: [
|
|
64
|
+
HIGHLIGHT_THEMES?.dark ?? 'github-dark',
|
|
65
|
+
HIGHLIGHT_THEMES?.light ?? 'github-light',
|
|
66
|
+
STAINLESS_DOCS_JSON_THEME,
|
|
67
|
+
],
|
|
68
|
+
langs: SupportedLanguageSyntaxes,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return astroShikiHighlighter;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function runHighlight({
|
|
75
|
+
highlighter,
|
|
76
|
+
content,
|
|
77
|
+
language,
|
|
78
|
+
themes,
|
|
79
|
+
}: {
|
|
80
|
+
highlighter: HighlighterGeneric<BundledLanguage, BundledTheme>;
|
|
81
|
+
content: string;
|
|
82
|
+
language?: string;
|
|
83
|
+
themes?: CreateShikiHighlighterOptions['themes'] | Record<string, 'stainless-docs-json'>;
|
|
84
|
+
}) {
|
|
85
|
+
return highlighter.codeToHtml(content, {
|
|
86
|
+
lang: language ?? 'javascript',
|
|
87
|
+
themes:
|
|
88
|
+
// Default to user-provided themes except in case of json
|
|
89
|
+
themes ??
|
|
90
|
+
(language === 'JSON'
|
|
91
|
+
? { light: 'stainless-docs-json', dark: 'stainless-docs-json' }
|
|
92
|
+
: HIGHLIGHT_THEMES) ??
|
|
93
|
+
{},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function highlight(content: string, language?: string) {
|
|
98
|
+
const highlighter = await getAstroHighlighter();
|
|
99
|
+
return runHighlight({ highlighter, content, language });
|
|
100
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createMarkdownProcessor, type MarkdownProcessor } from '@astrojs/markdown-remark';
|
|
2
|
+
import remarkGfmAlerts from 'remark-github-alerts';
|
|
3
|
+
import { HIGHLIGHT_THEMES } from 'virtual:stl-starlight-virtual-module';
|
|
4
|
+
|
|
5
|
+
// singleton
|
|
6
|
+
let astroMarkdownProcessor: MarkdownProcessor;
|
|
7
|
+
async function getAstroMarkdown() {
|
|
8
|
+
if (!astroMarkdownProcessor) {
|
|
9
|
+
astroMarkdownProcessor = await createMarkdownProcessor({
|
|
10
|
+
gfm: true,
|
|
11
|
+
remarkPlugins: [remarkGfmAlerts],
|
|
12
|
+
shikiConfig: { themes: HIGHLIGHT_THEMES },
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return astroMarkdownProcessor;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function astroMarkdownRender(content: string) {
|
|
20
|
+
const md = await getAstroMarkdown();
|
|
21
|
+
const output = await md.render(content);
|
|
22
|
+
|
|
23
|
+
// Map GFM callouts to the closest Starlight equivalent
|
|
24
|
+
// TODO: this sucks; we should be rendering via ui-primitives callouts instead of ugly theme-incompatible starlight ones
|
|
25
|
+
output.code = output.code
|
|
26
|
+
.replaceAll('markdown-alert-caution', 'markdown-alert-danger')
|
|
27
|
+
.replaceAll('markdown-alert-warning', 'markdown-alert-caution')
|
|
28
|
+
.replaceAll('markdown-alert-important', 'markdown-alert-caution')
|
|
29
|
+
.replaceAll('markdown-alert-title', 'starlight-aside__title')
|
|
30
|
+
.replaceAll('markdown-alert-', 'starlight-aside--')
|
|
31
|
+
.replaceAll('markdown-alert', 'starlight-aside');
|
|
32
|
+
|
|
33
|
+
return output;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function astroMarkdownRenderText(content: string) {
|
|
37
|
+
const result = await astroMarkdownRender(content);
|
|
38
|
+
return result.code;
|
|
39
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type { TransformRequestSnippetFn } from '@stainless-api/docs-ui/
|
|
1
|
+
import type { TransformRequestSnippetFn } from '@stainless-api/docs-ui/components/sdk';
|
|
2
|
+
import type { AppComponents } from '@stainless-api/docs-ui/contexts/component';
|
|
2
3
|
|
|
3
4
|
export type StlStarlightMiddleware = {
|
|
4
5
|
transformRequestSnippet?: TransformRequestSnippetFn;
|
|
6
|
+
componentOverrides?: Partial<AppComponents>;
|
|
5
7
|
};
|