@stainless-api/docs 0.1.0-beta.129 → 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 +24 -0
- package/ambient.d.ts +6 -0
- package/eslint-suppressions.json +0 -5
- package/package.json +19 -15
- package/plugin/generateAPIReferenceLink.ts +0 -40
- package/plugin/index.ts +12 -0
- package/plugin/loadPluginConfig.ts +36 -5
- package/plugin/markdown/highlighter.ts +1 -1
- package/plugin/react/Routing.tsx +1 -85
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/routes/llms.ts +186 -0
- package/plugin/sidebar-utils/sidebar-builder.ts +2 -7
- package/plugin/specs/FileCache.ts +1 -1
- package/plugin/specs/index.ts +1 -6
- package/plugin/vendor/preview.worker.docs.js +9001 -8694
- package/shared/virtualModule.ts +1 -9
- 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/AiChatIsland.tsx +14 -12
- package/stl-docs/components/PageFrame.astro +7 -4
- package/stl-docs/components/headers/DefaultHeader.astro +2 -2
- package/stl-docs/components/headers/StackedHeader.astro +2 -2
- 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 +2 -2
- 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/nav-tabs/NavDropdown.astro +1 -1
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +2 -2
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +2 -2
- package/stl-docs/components/pagination/util.ts +3 -3
- package/stl-docs/disableCalloutSyntax.ts +1 -1
- package/stl-docs/index.ts +14 -28
- package/stl-docs/loadStlDocsConfig.ts +15 -4
- package/stl-docs/proseSearchIndexing.ts +2 -6
- package/virtual-module.d.ts +8 -17
- package/stl-docs/components/ClientRouterHead.astro +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @stainless-api/docs
|
|
2
2
|
|
|
3
|
+
## 0.1.0-beta.130
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- da5debb: Move ai chat packages into stl-starlight, and extract to a generic interface
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 3019a8b: Adds support for generating an llms.txt
|
|
12
|
+
- 4d3b938: Remove dead code flagged by knip
|
|
13
|
+
- b887dbb: Fix off-axis rotation of loading spinner in safari
|
|
14
|
+
- cfd8ea1: Minor fixes for Python and Ruby
|
|
15
|
+
- Updated dependencies [3019a8b]
|
|
16
|
+
- Updated dependencies [4d3b938]
|
|
17
|
+
- Updated dependencies [0791fb6]
|
|
18
|
+
- Updated dependencies [01b77d0]
|
|
19
|
+
- Updated dependencies [15e07d8]
|
|
20
|
+
- Updated dependencies [ebc039a]
|
|
21
|
+
- Updated dependencies [cfd8ea1]
|
|
22
|
+
- Updated dependencies [68a7bf8]
|
|
23
|
+
- @stainless-api/docs-ui@0.1.0-beta.93
|
|
24
|
+
- @stainless-api/ui-primitives@0.1.0-beta.53
|
|
25
|
+
- @stainless-api/docs-search@0.1.0-beta.46
|
|
26
|
+
|
|
3
27
|
## 0.1.0-beta.129
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/ambient.d.ts
ADDED
package/eslint-suppressions.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stainless-api/docs",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.130",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,46 +42,50 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@astrojs/markdown-remark": "^7.1.0",
|
|
45
|
-
"@astrojs/react": "^5.0.
|
|
45
|
+
"@astrojs/react": "^5.0.3",
|
|
46
46
|
"@markdoc/markdoc": "^0.5.7",
|
|
47
47
|
"@stainless-api/sdk": "0.5.0",
|
|
48
|
-
"
|
|
48
|
+
"@streamparser/json-whatwg": "^0.0.22",
|
|
49
49
|
"cheerio": "^1.2.0",
|
|
50
50
|
"clsx": "^2.1.1",
|
|
51
|
-
"dotenv": "17.4.
|
|
51
|
+
"dotenv": "17.4.1",
|
|
52
52
|
"lucide-react": "^0.577.0",
|
|
53
|
+
"motion": "^12.38.0",
|
|
53
54
|
"node-html-parser": "^7.1.0",
|
|
54
55
|
"rehype-parse": "^9.0.1",
|
|
55
56
|
"rehype-remark": "^10.0.1",
|
|
57
|
+
"react-markdown": "^10.1.0",
|
|
58
|
+
"react-syntax-highlighter": "^16.1.1",
|
|
56
59
|
"remark-gfm": "^4.0.1",
|
|
57
60
|
"remark-github-alerts": "^0.1.1",
|
|
58
61
|
"remark-stringify": "^11.0.0",
|
|
62
|
+
"remend": "^1.3.0",
|
|
59
63
|
"shiki": "^4.0.2",
|
|
60
64
|
"unified": "^11.0.5",
|
|
61
65
|
"vite-plugin-prebundle-workers": "^0.2.0",
|
|
62
66
|
"web-worker": "^1.5.0",
|
|
63
|
-
"
|
|
64
|
-
"@stainless-api/docs-
|
|
65
|
-
"@stainless-api/
|
|
66
|
-
"@stainless-api/ui-primitives": "0.1.0-beta.52"
|
|
67
|
+
"@stainless-api/docs-search": "0.1.0-beta.46",
|
|
68
|
+
"@stainless-api/docs-ui": "0.1.0-beta.93",
|
|
69
|
+
"@stainless-api/ui-primitives": "0.1.0-beta.53"
|
|
67
70
|
},
|
|
68
71
|
"devDependencies": {
|
|
69
72
|
"@astrojs/check": "^0.9.8",
|
|
70
|
-
"@types/node": "24.12.
|
|
73
|
+
"@types/node": "24.12.2",
|
|
71
74
|
"@types/react": "19.2.14",
|
|
72
75
|
"@types/react-dom": "^19.2.3",
|
|
76
|
+
"@types/react-syntax-highlighter": "^15.5.13",
|
|
77
|
+
"astro": "^6.1.5",
|
|
73
78
|
"react": "^19.2.4",
|
|
74
79
|
"react-dom": "^19.2.4",
|
|
75
|
-
"tsx": "^4.21.0",
|
|
76
80
|
"typescript": "6.0.2",
|
|
77
|
-
"vite": "^7.3.
|
|
78
|
-
"vitest": "^4.1.
|
|
81
|
+
"vite": "^7.3.2",
|
|
82
|
+
"vitest": "^4.1.3",
|
|
79
83
|
"zod": "^4.3.6",
|
|
80
|
-
"@stainless/eslint-config": "0.1.0-beta.
|
|
81
|
-
"@stainless/sdk-json": "^0.1.0-beta.
|
|
84
|
+
"@stainless/eslint-config": "0.1.0-beta.2",
|
|
85
|
+
"@stainless/sdk-json": "^0.1.0-beta.10"
|
|
82
86
|
},
|
|
83
87
|
"scripts": {
|
|
84
|
-
"vendor-deps": "
|
|
88
|
+
"vendor-deps": "node scripts/vendor_deps.ts",
|
|
85
89
|
"lint": "eslint --flag unstable_native_nodejs_ts_config . --max-warnings 0",
|
|
86
90
|
"sync": "astro sync",
|
|
87
91
|
"check:types": "astro check",
|
|
@@ -1,47 +1,7 @@
|
|
|
1
1
|
// This is probably temporary, but it fills in functionality needed for Mintlify imports
|
|
2
2
|
|
|
3
|
-
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
4
|
-
import type * as SDKJSON from '@stainless/sdk-json';
|
|
5
|
-
import { walkTree } from '@stainless-api/docs-ui/routing';
|
|
6
|
-
|
|
7
3
|
const INTERNAL_REFERENCE_ENTRY_MARKER = 'STL_STARLIGHT_API_REFERENCE_METHOD_LINK_PLACEHOLDER';
|
|
8
4
|
|
|
9
|
-
type SidebarEntry = StarlightRouteData['sidebar'][number];
|
|
10
|
-
|
|
11
|
-
type SidebarLink = Extract<SidebarEntry, { href: string }>;
|
|
12
|
-
|
|
13
|
-
export function getMethodFromSDKJSON(spec: SDKJSON.Spec, endpoint: string) {
|
|
14
|
-
for (const entry of walkTree(spec)) {
|
|
15
|
-
if (entry.data.kind === 'http_method' && entry.data.endpoint === endpoint) {
|
|
16
|
-
return entry.data;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
throw new Error(`Endpoint ${endpoint} not found in API`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function recursiveReplacePlaceholderItems(
|
|
23
|
-
sidebar: SidebarEntry[],
|
|
24
|
-
modifyFn: (entry: SidebarLink, props: { endpoint: string; label?: string }) => void,
|
|
25
|
-
) {
|
|
26
|
-
for (const entry of sidebar) {
|
|
27
|
-
const endpoint = 'attrs' in entry && entry.attrs?.['data-stldocs-endpoint'];
|
|
28
|
-
if (
|
|
29
|
-
'attrs' in entry &&
|
|
30
|
-
entry.attrs?.about === INTERNAL_REFERENCE_ENTRY_MARKER &&
|
|
31
|
-
endpoint &&
|
|
32
|
-
typeof endpoint === 'string'
|
|
33
|
-
) {
|
|
34
|
-
modifyFn(entry, {
|
|
35
|
-
endpoint,
|
|
36
|
-
label: entry.attrs?.['data-stldocs-label'],
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
if ('entries' in entry) {
|
|
40
|
-
recursiveReplacePlaceholderItems(entry.entries, modifyFn);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
5
|
type GenerateProps = string | { label?: string; endpoint: string };
|
|
46
6
|
|
|
47
7
|
function normalizeGenerateProps(generateProps: GenerateProps) {
|
package/plugin/index.ts
CHANGED
|
@@ -190,6 +190,16 @@ function stlStarlightAstroIntegration(pluginConfig: NormalizedStainlessStarlight
|
|
|
190
190
|
prerender: pluginConfig.experimentalPrerender ? command === 'build' : false,
|
|
191
191
|
});
|
|
192
192
|
|
|
193
|
+
if (pluginConfig.llmsTxt.enabled) {
|
|
194
|
+
injectRoute({
|
|
195
|
+
pattern: '/llms.txt',
|
|
196
|
+
entrypoint: resolveSrcFile('/plugin/routes/llms.ts'),
|
|
197
|
+
prerender: pluginConfig.experimentalPrerender ? command === 'build' : false,
|
|
198
|
+
});
|
|
199
|
+
} else {
|
|
200
|
+
logger.info('LLMS.txt generation is disabled.');
|
|
201
|
+
}
|
|
202
|
+
|
|
193
203
|
updateConfig({
|
|
194
204
|
vite: {
|
|
195
205
|
plugins: [
|
|
@@ -314,6 +324,8 @@ function stlStarlightAstroIntegration(pluginConfig: NormalizedStainlessStarlight
|
|
|
314
324
|
EXPERIMENTAL_PLAYGROUNDS: !!pluginConfig.experimentalPlaygrounds,
|
|
315
325
|
EXPERIMENTAL_REQUEST_BUILDER: pluginConfig.experimentalRequestBuilder,
|
|
316
326
|
STAINLESS_PROJECT: pluginConfig.stainlessProject,
|
|
327
|
+
LLMS_TXT_DESCRIPTION: pluginConfig.llmsTxt.description,
|
|
328
|
+
LLMS_TXT_DETAIL_THRESHOLD: pluginConfig.llmsTxt.detailThreshold,
|
|
317
329
|
} satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
|
|
318
330
|
vmMiddlewareExport,
|
|
319
331
|
].join('\n');
|
|
@@ -14,11 +14,11 @@ export type LanguageGenerateQuery = {
|
|
|
14
14
|
list: DocsLanguage[];
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
type AstroCommand = 'dev' | 'build' | 'preview' | 'sync';
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
type ContentLayout = 'double-pane' | 'single-pane';
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
type VersionUserConfig = {
|
|
22
22
|
version: string;
|
|
23
23
|
stainlessProject: string;
|
|
24
24
|
branch: string;
|
|
@@ -165,6 +165,31 @@ export type StainlessStarlightUserConfig = {
|
|
|
165
165
|
* @default true
|
|
166
166
|
*/
|
|
167
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
|
+
};
|
|
168
193
|
};
|
|
169
194
|
|
|
170
195
|
// TODO: eventually? re-add support for external spec servers
|
|
@@ -198,7 +223,7 @@ function getLocalFilePaths(command: AstroCommand) {
|
|
|
198
223
|
};
|
|
199
224
|
}
|
|
200
225
|
|
|
201
|
-
|
|
226
|
+
type ApiKeySource = 'explicit-config' | 'environment-variable' | 'cli';
|
|
202
227
|
|
|
203
228
|
export type LoadedApiKey = {
|
|
204
229
|
value: string;
|
|
@@ -252,6 +277,7 @@ function loadApiKey(configValue: string | undefined): LoadedApiKey | null {
|
|
|
252
277
|
return { value: accessToken, source: 'cli' };
|
|
253
278
|
}
|
|
254
279
|
|
|
280
|
+
/** @public but discouraged - used by cloudflare via relative import */
|
|
255
281
|
export function forceLoadStainlessCredentials(): LoadedApiKey {
|
|
256
282
|
const v = loadApiKey(undefined);
|
|
257
283
|
if (!v) {
|
|
@@ -265,7 +291,7 @@ type AstroOptions = {
|
|
|
265
291
|
base: string;
|
|
266
292
|
};
|
|
267
293
|
|
|
268
|
-
|
|
294
|
+
type ResolvedAPIConfigEntry = {
|
|
269
295
|
loadSpecs: () => Promise<SpecCacheResult[]>;
|
|
270
296
|
};
|
|
271
297
|
|
|
@@ -385,6 +411,11 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, astroOptions
|
|
|
385
411
|
experimentalRequestBuilder: partial.experimentalRequestBuilder ?? false,
|
|
386
412
|
experimentalPrerender: partial.experimentalPrerender ?? true,
|
|
387
413
|
stainlessProject: partial.stainlessProject,
|
|
414
|
+
llmsTxt: {
|
|
415
|
+
enabled: partial.llmsTxt?.disabled ?? true,
|
|
416
|
+
description: partial.llmsTxt?.description ?? null,
|
|
417
|
+
detailThreshold: partial.llmsTxt?.detailThreshold ?? 2000,
|
|
418
|
+
},
|
|
388
419
|
};
|
|
389
420
|
|
|
390
421
|
const api = loadAPIConfig(partial, astroOptions);
|
|
@@ -54,7 +54,7 @@ let astroShikiHighlighter:
|
|
|
54
54
|
| HighlighterGeneric<BundledLanguage, BundledTheme>
|
|
55
55
|
| Promise<HighlighterGeneric<BundledLanguage, BundledTheme>>
|
|
56
56
|
| null = null;
|
|
57
|
-
|
|
57
|
+
async function getAstroHighlighter() {
|
|
58
58
|
if (astroShikiHighlighter) {
|
|
59
59
|
return astroShikiHighlighter;
|
|
60
60
|
}
|
package/plugin/react/Routing.tsx
CHANGED
|
@@ -5,22 +5,15 @@ import { astroMarkdownRenderText } from '../markdown';
|
|
|
5
5
|
import { highlight } from '../markdown/highlighter';
|
|
6
6
|
|
|
7
7
|
import type { MarkdownHeading } from 'astro';
|
|
8
|
-
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
9
8
|
import type * as SDKJSON from '@stainless/sdk-json';
|
|
10
9
|
import { LanguageNames, type DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
11
10
|
|
|
12
|
-
import {
|
|
13
|
-
generateRoute,
|
|
14
|
-
parseStainlessPath,
|
|
15
|
-
walkTree,
|
|
16
|
-
getLanguageSnippet,
|
|
17
|
-
} from '@stainless-api/docs-ui/routing';
|
|
11
|
+
import { parseStainlessPath, getLanguageSnippet } from '@stainless-api/docs-ui/routing';
|
|
18
12
|
|
|
19
13
|
import {
|
|
20
14
|
DocsProvider,
|
|
21
15
|
MarkdownProvider,
|
|
22
16
|
NavigationProvider,
|
|
23
|
-
useSpec,
|
|
24
17
|
type ContentPanelLayout,
|
|
25
18
|
} from '@stainless-api/docs-ui/contexts';
|
|
26
19
|
|
|
@@ -40,7 +33,6 @@ import { Dropdown } from '@stainless-api/docs/components';
|
|
|
40
33
|
|
|
41
34
|
import {
|
|
42
35
|
RESOLVED_API_REFERENCE_PATH,
|
|
43
|
-
EXPAND_RESOURCES,
|
|
44
36
|
BREADCRUMB_CONFIG,
|
|
45
37
|
PROPERTY_SETTINGS,
|
|
46
38
|
ENABLE_CONTEXT_MENU,
|
|
@@ -61,66 +53,6 @@ import { AIDropdown } from '../../stl-docs/components/AIDropdown';
|
|
|
61
53
|
import { ChevronsUpDownIcon } from 'lucide-react';
|
|
62
54
|
import { MethodDescription } from '../components/MethodDescription';
|
|
63
55
|
|
|
64
|
-
function isResourceNonEmpty(resource: SDKJSON.Resource) {
|
|
65
|
-
return (
|
|
66
|
-
Object.keys(resource.methods ?? {}).length > 0 ||
|
|
67
|
-
Object.keys(resource.subresources ?? {}).length > 0 ||
|
|
68
|
-
Object.keys(resource.models ?? {}).length > 0
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
type SidebarEntry = StarlightRouteData['sidebar'][number];
|
|
73
|
-
|
|
74
|
-
export function buildSidebar(
|
|
75
|
-
basePath: string,
|
|
76
|
-
language: DocsLanguage,
|
|
77
|
-
current: string,
|
|
78
|
-
spec: SDKJSON.Spec,
|
|
79
|
-
resources?: Record<string, SDKJSON.Resource>,
|
|
80
|
-
nested?: boolean,
|
|
81
|
-
): StarlightRouteData['sidebar'] {
|
|
82
|
-
const totalRoutes = Array.from(walkTree(spec, false)).filter(
|
|
83
|
-
(item) => item.data.kind === 'http_method',
|
|
84
|
-
).length;
|
|
85
|
-
|
|
86
|
-
return Object.values(resources ?? spec.resources ?? [])
|
|
87
|
-
.filter((resource) => isResourceNonEmpty(resource))
|
|
88
|
-
.sort((a, b) => (a.name.startsWith('$') === b.name.startsWith('$') ? 0 : a.name.startsWith('$') ? 1 : -1))
|
|
89
|
-
.map((resource) => {
|
|
90
|
-
const subs = buildSidebar(basePath, language, current, spec, resource.subresources, true);
|
|
91
|
-
|
|
92
|
-
const overview: SidebarEntry = {
|
|
93
|
-
type: 'link',
|
|
94
|
-
isCurrent: current === resource.stainlessPath,
|
|
95
|
-
attrs: { 'data-stldocs-overview': resource.name },
|
|
96
|
-
label: 'Overview',
|
|
97
|
-
href: generateRoute(basePath, language, resource.stainlessPath) ?? basePath,
|
|
98
|
-
badge: undefined,
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const meths: SidebarEntry[] = Object.values(resource.methods ?? [])
|
|
102
|
-
.filter((method) => spec.decls?.[language]?.[method.stainlessPath])
|
|
103
|
-
.map((method) => ({
|
|
104
|
-
type: 'link',
|
|
105
|
-
isCurrent: current === method.stainlessPath,
|
|
106
|
-
attrs: { 'data-stldocs-method': method.httpMethod },
|
|
107
|
-
label: method.summary ?? method.name,
|
|
108
|
-
href: generateRoute(basePath, language, method.stainlessPath) ?? basePath,
|
|
109
|
-
badge: undefined,
|
|
110
|
-
}));
|
|
111
|
-
|
|
112
|
-
const shouldExpand = EXPAND_RESOURCES ?? totalRoutes < 20;
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
type: 'group',
|
|
116
|
-
label: resource.title,
|
|
117
|
-
badge: undefined,
|
|
118
|
-
collapsed: !shouldExpand || nested === true,
|
|
119
|
-
entries: [...(resources ? [] : [overview]), ...meths, ...subs],
|
|
120
|
-
};
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
56
|
export function buildPageNavigation(resource: SDKJSON.Resource, depth: number = 2): MarkdownHeading[] {
|
|
125
57
|
const output: MarkdownHeading[] = [{ depth, slug: resource.stainlessPath, text: resource.title }];
|
|
126
58
|
|
|
@@ -321,22 +253,6 @@ export function RenderSpec({
|
|
|
321
253
|
);
|
|
322
254
|
}
|
|
323
255
|
|
|
324
|
-
export function RenderMethod({ path }: { path: string }) {
|
|
325
|
-
const spec = useSpec();
|
|
326
|
-
if (!spec) return null;
|
|
327
|
-
|
|
328
|
-
const parsed = parseStainlessPath(path);
|
|
329
|
-
const resource = getResourceFromSpec(path, spec);
|
|
330
|
-
|
|
331
|
-
if (!resource || !parsed) {
|
|
332
|
-
console.warn(`Could not find resource or parsed path for '${path}'`);
|
|
333
|
-
return null;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const method = resource.methods[parsed.method!]!;
|
|
337
|
-
return <SDKMethod method={method} />;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
256
|
export async function getReadmeContent(spec: SDKJSON.Spec, language: DocsLanguage) {
|
|
341
257
|
const repoUrl = spec.metadata?.[language]?.repo_url;
|
|
342
258
|
|
|
@@ -21,7 +21,7 @@ export function makePlaceholderItems(id: number) {
|
|
|
21
21
|
|
|
22
22
|
type StarlightConfig = Parameters<typeof starlight>[0];
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
type SidebarConfigEntry = Exclude<StarlightConfig['sidebar'], undefined>[number];
|
|
25
25
|
|
|
26
26
|
export function getAPIReferencePlaceholderItemFromSidebarConfig(
|
|
27
27
|
sidebar: SidebarConfigEntry[],
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
import { base as ASTRO_BASE } from 'astro:config/server';
|
|
4
|
+
import { SITE_TITLE, API_REFERENCE_BASE_PATH } from 'virtual:stl-docs-virtual-module';
|
|
5
|
+
import { LLMS_TXT_DESCRIPTION, LLMS_TXT_DETAIL_THRESHOLD } from 'virtual:stl-starlight-virtual-module';
|
|
6
|
+
import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
|
|
7
|
+
import Markdoc from '@markdoc/markdoc';
|
|
8
|
+
import type { Node } from '@markdoc/markdoc';
|
|
9
|
+
import * as md from '@stainless-api/docs-ui/markdown/md';
|
|
10
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
11
|
+
import { generateRoute, walkTree } from '@stainless-api/docs-ui/routing';
|
|
12
|
+
|
|
13
|
+
export const prerender = true;
|
|
14
|
+
|
|
15
|
+
function joinUrlParts(...parts: (string | boolean | null | undefined)[]) {
|
|
16
|
+
return (
|
|
17
|
+
'/' +
|
|
18
|
+
parts
|
|
19
|
+
.map((p) => {
|
|
20
|
+
if (typeof p === 'string') {
|
|
21
|
+
return p.split('/');
|
|
22
|
+
}
|
|
23
|
+
return p;
|
|
24
|
+
})
|
|
25
|
+
.flat()
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join('/')
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ProsePageEntry = {
|
|
32
|
+
id: string;
|
|
33
|
+
title: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function isResourceEmpty(resource: SDKJSON.Resource) {
|
|
38
|
+
return Object.values(resource.methods).length < 1 && Object.values(resource.subresources ?? {}).length < 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function trimPath(path: string) {
|
|
42
|
+
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function apiHref(basePath: string, language: string, stainlessPath: string) {
|
|
46
|
+
const href = generateRoute(basePath, language, stainlessPath);
|
|
47
|
+
if (!href) return null;
|
|
48
|
+
return joinUrlParts(ASTRO_BASE, href, 'index.md');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function linkListItem(title: string, url: string, description?: string): Node {
|
|
52
|
+
const children = [md.link(url, title)];
|
|
53
|
+
if (description) children.push(md.text(`: ${description}`));
|
|
54
|
+
return md.item(md.inline(...children));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function generateProseIndex(routes: ProsePageEntry[], detailed: boolean) {
|
|
58
|
+
const pageEntryLink = (page: ProsePageEntry) =>
|
|
59
|
+
linkListItem(
|
|
60
|
+
page.title,
|
|
61
|
+
joinUrlParts(ASTRO_BASE, page.id === 'index' ? null : page.id, 'index.md'),
|
|
62
|
+
detailed ? page.description : undefined,
|
|
63
|
+
);
|
|
64
|
+
return [md.heading(2, 'Docs'), md.list(...routes.map(pageEntryLink))];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function renderMethods(basePath: string, language: string, methods: Record<string, SDKJSON.Method>) {
|
|
68
|
+
const output: Node[] = [];
|
|
69
|
+
|
|
70
|
+
for (const method of Object.values(methods)) {
|
|
71
|
+
const href = apiHref(basePath, language, method.stainlessPath);
|
|
72
|
+
if (href) output.push(linkListItem(method.title, href, method.summary));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return md.list(...output);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function renderResource(
|
|
79
|
+
basePath: string,
|
|
80
|
+
language: string,
|
|
81
|
+
detailed: boolean,
|
|
82
|
+
resource: SDKJSON.Resource,
|
|
83
|
+
): Node {
|
|
84
|
+
const href = apiHref(basePath, language, resource.stainlessPath);
|
|
85
|
+
const output = [md.paragraph(href ? md.link(href, resource.title) : md.text(resource.title))];
|
|
86
|
+
if (resource.methods && detailed) output.push(renderMethods(basePath, language, resource.methods));
|
|
87
|
+
if (resource.subresources) output.push(renderSubs(basePath, language, detailed, resource.subresources));
|
|
88
|
+
return md.item(...output);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function renderSubs(
|
|
92
|
+
basePath: string,
|
|
93
|
+
language: string,
|
|
94
|
+
detailed: boolean,
|
|
95
|
+
resources: Record<string, SDKJSON.Resource>,
|
|
96
|
+
): Node {
|
|
97
|
+
return md.list(
|
|
98
|
+
...Object.values(resources)
|
|
99
|
+
.filter((res) => !isResourceEmpty(res))
|
|
100
|
+
.map((sub) => renderResource(basePath, language, detailed, sub)),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function renderLanguageNote(basePath: string, languages: string[]) {
|
|
105
|
+
return [
|
|
106
|
+
md.paragraph(
|
|
107
|
+
md.text('Links below point to language-neutral HTTP documentation. '),
|
|
108
|
+
md.text(
|
|
109
|
+
'SDK-specific docs follow the same URL structure with the language inserted after the base path: ',
|
|
110
|
+
),
|
|
111
|
+
md.code(`${trimPath(basePath)}/{language}/resources/...`),
|
|
112
|
+
md.text('.'),
|
|
113
|
+
),
|
|
114
|
+
md.paragraph(md.text(`Available languages: ${languages.join(', ')}`)),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function generateRefIndex(
|
|
119
|
+
basePath: string,
|
|
120
|
+
languages: string[],
|
|
121
|
+
language: string,
|
|
122
|
+
detailed: boolean,
|
|
123
|
+
spec: SDKJSON.Spec,
|
|
124
|
+
) {
|
|
125
|
+
const output = [md.heading(2, 'API Reference'), ...renderLanguageNote(basePath, languages)];
|
|
126
|
+
|
|
127
|
+
for (const resource of Object.values(spec.resources)) {
|
|
128
|
+
if (isResourceEmpty(resource)) continue;
|
|
129
|
+
const href = apiHref(basePath, language, resource.stainlessPath);
|
|
130
|
+
output.push(md.heading(3, [href ? md.link(href, resource.title) : md.text(resource.title)]));
|
|
131
|
+
if (resource.methods && detailed) output.push(renderMethods(basePath, language, resource.methods));
|
|
132
|
+
if (resource.subresources) output.push(renderSubs(basePath, language, detailed, resource.subresources));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return output;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function generateMarkdownIndex({
|
|
139
|
+
siteTitle,
|
|
140
|
+
description,
|
|
141
|
+
basePath,
|
|
142
|
+
languages,
|
|
143
|
+
spec,
|
|
144
|
+
detailed,
|
|
145
|
+
proseRoutes,
|
|
146
|
+
}: {
|
|
147
|
+
siteTitle: string;
|
|
148
|
+
description: string | null;
|
|
149
|
+
basePath: string;
|
|
150
|
+
languages: string[];
|
|
151
|
+
spec: SDKJSON.Spec;
|
|
152
|
+
detailed: boolean;
|
|
153
|
+
proseRoutes: ProsePageEntry[];
|
|
154
|
+
}) {
|
|
155
|
+
const output: Node[] = [md.heading(1, siteTitle)];
|
|
156
|
+
if (description) output.push(md.paragraph(md.text(description)));
|
|
157
|
+
if (proseRoutes.length > 0) output.push(...generateProseIndex(proseRoutes, detailed));
|
|
158
|
+
if (languages.length > 0) output.push(...generateRefIndex(basePath, languages, 'http', detailed, spec));
|
|
159
|
+
|
|
160
|
+
const doc = new Markdoc.Ast.Node('document', {}, output);
|
|
161
|
+
return Markdoc.format(doc);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const GET: APIRoute = async () => {
|
|
165
|
+
const [docsCollection, spec] = await Promise.all([getCollection('docs'), getSDKJSONInSSR('http')]);
|
|
166
|
+
const apiEntries = [...walkTree(spec)].filter((n) => n.data.kind !== 'model');
|
|
167
|
+
const proseRoutes = docsCollection.map((entry) => ({
|
|
168
|
+
id: entry.id,
|
|
169
|
+
title: entry.data.title,
|
|
170
|
+
description: entry.data.description,
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
const content = generateMarkdownIndex({
|
|
174
|
+
siteTitle: SITE_TITLE,
|
|
175
|
+
description: LLMS_TXT_DESCRIPTION,
|
|
176
|
+
basePath: API_REFERENCE_BASE_PATH,
|
|
177
|
+
languages: spec.docs?.languages ?? [],
|
|
178
|
+
detailed: apiEntries.length + proseRoutes.length < LLMS_TXT_DETAIL_THRESHOLD,
|
|
179
|
+
spec,
|
|
180
|
+
proseRoutes,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return new Response(content, {
|
|
184
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
185
|
+
});
|
|
186
|
+
};
|
|
@@ -173,8 +173,8 @@ export class SidebarConfigItemsBuilder {
|
|
|
173
173
|
const decls = this.spec.decls[this.language] ?? {};
|
|
174
174
|
const decl = decls[entry.stainlessPath];
|
|
175
175
|
if (decl !== undefined) {
|
|
176
|
-
if ('ident' in decl) {
|
|
177
|
-
return decl;
|
|
176
|
+
if ('ident' in decl && decl.ident !== undefined) {
|
|
177
|
+
return decl as MethodDecl;
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
return null;
|
|
@@ -338,11 +338,6 @@ function forceGenerateRoute({
|
|
|
338
338
|
return route;
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
export type BuildSidebarParams = {
|
|
342
|
-
basePath: string;
|
|
343
|
-
currentSlug: string;
|
|
344
|
-
};
|
|
345
|
-
|
|
346
341
|
type ToStarlightSidebarParams = {
|
|
347
342
|
basePath: string;
|
|
348
343
|
spec: SDKJSON.Spec;
|
package/plugin/specs/index.ts
CHANGED
|
@@ -5,17 +5,12 @@ import type * as VirtualManifestModule from 'virtual:stainless-apis-manifest';
|
|
|
5
5
|
|
|
6
6
|
import { makeAsyncVirtualModPlugin } from '../../shared/virtualModule';
|
|
7
7
|
|
|
8
|
-
import { NormalizedStainlessStarlightConfig
|
|
8
|
+
import { NormalizedStainlessStarlightConfig } from '../loadPluginConfig';
|
|
9
9
|
|
|
10
10
|
import { specCache, SpecCacheResult } from './generateSpec';
|
|
11
11
|
import { AstroIntegrationLogger } from 'astro';
|
|
12
12
|
import type * as SDKJSON from '@stainless/sdk-json';
|
|
13
13
|
|
|
14
|
-
export type LoadedAPIConfigEntry = Omit<ResolvedAPIConfigEntry, 'loadSpecs'> & {
|
|
15
|
-
specs: SpecCacheResult[];
|
|
16
|
-
languages: SDKJSON.SpecLanguage[];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
14
|
/**
|
|
20
15
|
* A helper class to manage multiple spec cache results for a single API
|
|
21
16
|
* An API may have multiple spec cache results if it has multiple languages
|