@stainless-api/docs 0.1.0-beta.4 → 0.1.0-beta.41
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 +297 -0
- package/components/variables.css +2 -32
- package/eslint-suppressions.json +47 -0
- package/locals.d.ts +14 -0
- package/package.json +35 -31
- package/plugin/buildAlgoliaIndex.ts +31 -6
- package/plugin/cms/server.ts +98 -55
- package/plugin/cms/sidebar-builder.ts +7 -26
- package/plugin/cms/worker.ts +3 -3
- package/plugin/components/SDKSelect.astro +7 -5
- package/plugin/components/SnippetCode.tsx +11 -7
- package/plugin/components/search/SearchAlgolia.astro +5 -20
- package/plugin/components/search/SearchIsland.tsx +33 -22
- package/plugin/generateAPIReferenceLink.ts +2 -2
- package/plugin/globalJs/ai-dropdown-options.ts +235 -0
- package/plugin/globalJs/navigation.ts +7 -27
- package/plugin/helpers/getPageLoadEvent.ts +1 -1
- package/plugin/index.ts +52 -25
- package/plugin/languages.ts +2 -2
- package/plugin/loadPluginConfig.ts +103 -32
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
- package/plugin/react/Routing.tsx +60 -57
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
- package/plugin/routes/Docs.astro +59 -85
- package/plugin/routes/Overview.astro +10 -16
- package/plugin/routes/markdown.ts +7 -7
- package/plugin/vendor/preview.worker.docs.js +7566 -6784
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +1 -1
- 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 +63 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
- package/stl-docs/components/Head.astro +16 -0
- package/stl-docs/components/Header.astro +3 -2
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeSelect.astro +80 -112
- 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/SplashMobileMenuToggle.astro +19 -0
- 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/cursor.tsx +10 -0
- package/stl-docs/components/icons/gemini.tsx +19 -0
- package/stl-docs/components/icons/markdown.tsx +10 -0
- package/stl-docs/components/index.ts +1 -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 +29 -63
- package/stl-docs/components/nav-tabs/NavTabs.astro +79 -65
- 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/scripts.ts +1 -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 -27
- package/stl-docs/loadStlDocsConfig.ts +35 -5
- 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 +53 -57
- package/styles/page.css +90 -59
- package/styles/sdk_select.css +9 -7
- package/styles/search.css +59 -69
- package/styles/sidebar.css +190 -127
- package/styles/toc.css +37 -33
- package/theme.css +9 -1
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +7 -4
- 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
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { initDropdownButton } from '@stainless-api/ui-primitives/scripts';
|
|
2
|
+
import { getPageLoadEvent } from '../helpers/getPageLoadEvent';
|
|
3
|
+
|
|
4
|
+
export type DropdownIcon = 'markdown' | 'copy' | 'claude' | 'chatgpt' | 'gemini' | 'cursor';
|
|
5
|
+
|
|
6
|
+
interface DropdownOptionInputProps {
|
|
7
|
+
onClick: () => void;
|
|
8
|
+
icon: DropdownIcon;
|
|
9
|
+
primaryAction?: boolean;
|
|
10
|
+
clientHidden?: boolean;
|
|
11
|
+
external: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function option(label: string[] | string, props: DropdownOptionInputProps) {
|
|
15
|
+
const labelArr = typeof label === 'string' ? [label] : label;
|
|
16
|
+
return {
|
|
17
|
+
...props,
|
|
18
|
+
label: labelArr,
|
|
19
|
+
primaryAction: props.primaryAction ?? false,
|
|
20
|
+
clientHidden: props.clientHidden ?? false,
|
|
21
|
+
id: labelArr.join('').toLowerCase().replace(/ /g, '-'),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type DropdownOption = ReturnType<typeof option>;
|
|
26
|
+
|
|
27
|
+
function getMarkdownUrl(type: 'relative' | 'absolute') {
|
|
28
|
+
const currentUrl = new URL(window.location.href);
|
|
29
|
+
const hasTrailingSlash = currentUrl.pathname.endsWith('/');
|
|
30
|
+
|
|
31
|
+
const markdownUrl = [
|
|
32
|
+
type === 'absolute' ? currentUrl.origin : '',
|
|
33
|
+
currentUrl.pathname,
|
|
34
|
+
hasTrailingSlash ? '' : '/',
|
|
35
|
+
'index.md',
|
|
36
|
+
].join('');
|
|
37
|
+
|
|
38
|
+
return markdownUrl;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getURLEncodedPrompt() {
|
|
42
|
+
const mdUrl = getMarkdownUrl('absolute');
|
|
43
|
+
const aiPrompt = encodeURIComponent(
|
|
44
|
+
`Load the contents of ${mdUrl} into this chat's context so we can discuss it.`,
|
|
45
|
+
);
|
|
46
|
+
return aiPrompt;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function openDeepLink({ deepLinkUrl, fallbackUrl }: { deepLinkUrl: string; fallbackUrl: string }) {
|
|
50
|
+
if (navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrom')) {
|
|
51
|
+
// safari doesn't let us detect if the deep link worked
|
|
52
|
+
window.open(fallbackUrl, '_blank');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
let frame: HTMLIFrameElement | null;
|
|
58
|
+
|
|
59
|
+
// We are using a native deep link with a fallback web url.
|
|
60
|
+
if (navigator.userAgent.includes('Chrom')) {
|
|
61
|
+
// In Chrome, load it in a hidden frame, this shows the "Do you want to open ...?" prompt, but unlike
|
|
62
|
+
// top level navigation this preserves our userActivation, so we can open the fallback if it fails.
|
|
63
|
+
frame = Object.assign(document.createElement('iframe'), { src: deepLinkUrl });
|
|
64
|
+
document.head.append(frame);
|
|
65
|
+
} else {
|
|
66
|
+
// In Firefox do the opposite.
|
|
67
|
+
location.href = deepLinkUrl;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The popup (in non-Safari browsers) fires a `blur` event.
|
|
71
|
+
window.addEventListener(
|
|
72
|
+
'blur',
|
|
73
|
+
() => {
|
|
74
|
+
controller.abort();
|
|
75
|
+
},
|
|
76
|
+
controller,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// If it's been 300ms with no popup, open the fallback web url.
|
|
80
|
+
const timeout = setTimeout(() => {
|
|
81
|
+
window.open(fallbackUrl, '_blank');
|
|
82
|
+
}, 300);
|
|
83
|
+
|
|
84
|
+
controller.signal.addEventListener('abort', () => {
|
|
85
|
+
clearTimeout(timeout);
|
|
86
|
+
frame?.remove();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent#mobile_tablet_or_desktop
|
|
91
|
+
const hasMobileUserAgent = navigator.userAgent.includes('Mobi');
|
|
92
|
+
|
|
93
|
+
// 2d array of dropdown options
|
|
94
|
+
// each sub-array is a group, separated by a horizontal rule in the UI
|
|
95
|
+
const aiDropdownOptions: DropdownOption[][] = [
|
|
96
|
+
[
|
|
97
|
+
option(['Open in ', 'Claude'], {
|
|
98
|
+
onClick: () => {
|
|
99
|
+
window.open(`https://claude.ai/new?q=${getURLEncodedPrompt()}`, '_blank');
|
|
100
|
+
},
|
|
101
|
+
icon: 'claude',
|
|
102
|
+
primaryAction: false,
|
|
103
|
+
external: true,
|
|
104
|
+
}),
|
|
105
|
+
option(['Open in ', 'ChatGPT'], {
|
|
106
|
+
onClick: () => {
|
|
107
|
+
window.open(`https://chatgpt.com/?hints=search&prompt=${getURLEncodedPrompt()}`, '_blank');
|
|
108
|
+
},
|
|
109
|
+
icon: 'chatgpt',
|
|
110
|
+
primaryAction: false,
|
|
111
|
+
external: true,
|
|
112
|
+
}),
|
|
113
|
+
option(['Open in ', 'Cursor'], {
|
|
114
|
+
onClick: () => {
|
|
115
|
+
const aiPrompt = getURLEncodedPrompt();
|
|
116
|
+
openDeepLink({
|
|
117
|
+
deepLinkUrl: `cursor://anysphere.cursor-deeplink/prompt?text=${aiPrompt}`,
|
|
118
|
+
fallbackUrl: `https://cursor.com/link/prompt?text=${aiPrompt}`,
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
clientHidden: hasMobileUserAgent,
|
|
122
|
+
icon: 'cursor',
|
|
123
|
+
primaryAction: false,
|
|
124
|
+
external: true,
|
|
125
|
+
}),
|
|
126
|
+
],
|
|
127
|
+
[
|
|
128
|
+
option('Copy Markdown', {
|
|
129
|
+
onClick: () => {
|
|
130
|
+
// Source: https://wolfgangrittner.dev/how-to-use-clipboard-api-in-firefox/
|
|
131
|
+
const markdownUrl = getMarkdownUrl('relative');
|
|
132
|
+
// ClipboardItem doesn't exist in every browser
|
|
133
|
+
// eslint-disable-next-line no-constant-binary-expression
|
|
134
|
+
if (typeof ClipboardItem && navigator.clipboard.write) {
|
|
135
|
+
// NOTE: Safari locks down the clipboard API to only work when triggered
|
|
136
|
+
// by a direct user interaction. You can't use it async in a promise.
|
|
137
|
+
// But! You can wrap the promise in a ClipboardItem, and give that to
|
|
138
|
+
// the clipboard API.
|
|
139
|
+
// Found this on https://developer.apple.com/forums/thread/691873
|
|
140
|
+
const text = new ClipboardItem({
|
|
141
|
+
'text/plain': fetch(markdownUrl)
|
|
142
|
+
.then((response) => response.text())
|
|
143
|
+
.then((text) => new Blob([text], { type: 'text/plain' })),
|
|
144
|
+
});
|
|
145
|
+
navigator.clipboard.write([text]);
|
|
146
|
+
} else {
|
|
147
|
+
// NOTE: Firefox has support for ClipboardItem and navigator.clipboard.write,
|
|
148
|
+
// but those are behind `dom.events.asyncClipboard.clipboardItem` preference.
|
|
149
|
+
// Good news is that other than Safari, Firefox does not care about
|
|
150
|
+
// Clipboard API being used async in a Promise.
|
|
151
|
+
fetch(markdownUrl)
|
|
152
|
+
.then((response) => response.text())
|
|
153
|
+
.then((text) => navigator.clipboard.writeText(text));
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
icon: 'copy',
|
|
157
|
+
primaryAction: true,
|
|
158
|
+
external: false,
|
|
159
|
+
}),
|
|
160
|
+
option('View as Markdown', {
|
|
161
|
+
onClick: () => {
|
|
162
|
+
window.open(getMarkdownUrl('absolute'), '_blank');
|
|
163
|
+
},
|
|
164
|
+
icon: 'markdown',
|
|
165
|
+
primaryAction: false,
|
|
166
|
+
external: true,
|
|
167
|
+
}),
|
|
168
|
+
],
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
// TODO: Add support for more LLMs
|
|
172
|
+
// {
|
|
173
|
+
// label: ['Open in ', 'Gemini'],
|
|
174
|
+
// onClick: () => {
|
|
175
|
+
// openInLLM('https://gemini.google.com?prompt_action=prefill&prompt_text=');
|
|
176
|
+
// },
|
|
177
|
+
// icon: 'gemini',
|
|
178
|
+
// primaryAction: false,
|
|
179
|
+
// },
|
|
180
|
+
|
|
181
|
+
export function getAIDropdownOptions() {
|
|
182
|
+
const renderedOptions = aiDropdownOptions.map((group, index) => {
|
|
183
|
+
return {
|
|
184
|
+
options: group,
|
|
185
|
+
isLast: index === aiDropdownOptions.length - 1,
|
|
186
|
+
reactKey: index,
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const allOptions = renderedOptions.flatMap((group) => group.options);
|
|
191
|
+
const primaryAction = allOptions.find((o) => o.primaryAction) ?? allOptions[0]!;
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
primaryAction,
|
|
195
|
+
groups: renderedOptions,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function wireAIDropdown() {
|
|
200
|
+
const { primaryAction, groups } = getAIDropdownOptions();
|
|
201
|
+
const flatOptions = groups.flatMap((group) => group.options);
|
|
202
|
+
function triggerOption(id: string) {
|
|
203
|
+
const option = flatOptions.find((option) => option.id === id);
|
|
204
|
+
if (!option) return;
|
|
205
|
+
option.onClick();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
document.addEventListener(getPageLoadEvent(), () => {
|
|
209
|
+
// we hide the Cursor option on non-desktop devices
|
|
210
|
+
for (const option of flatOptions) {
|
|
211
|
+
if (option.clientHidden === true) {
|
|
212
|
+
const el = document.querySelector(
|
|
213
|
+
`[data-dropdown-id="ai-dropdown-button"] [data-value="${option.id}"]`,
|
|
214
|
+
);
|
|
215
|
+
if (el) {
|
|
216
|
+
el.remove();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const dropdowns = document.querySelectorAll('[data-dropdown-id="ai-dropdown-button"]');
|
|
222
|
+
|
|
223
|
+
dropdowns.forEach((dropdown) => {
|
|
224
|
+
initDropdownButton({
|
|
225
|
+
dropdown: dropdown,
|
|
226
|
+
onSelect: (value) => {
|
|
227
|
+
triggerOption(value);
|
|
228
|
+
},
|
|
229
|
+
onPrimaryAction: () => {
|
|
230
|
+
triggerOption(primaryAction.id);
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { parseRoute, scrollToPath } from '@stainless-api/docs-ui/
|
|
1
|
+
import { parseRoute, scrollToPath } from '@stainless-api/docs-ui/routing';
|
|
2
2
|
import { BASE_PATH } from 'virtual:stl-starlight-virtual-module';
|
|
3
3
|
import { updateSelectedLanguage } from '../languages';
|
|
4
4
|
import { navigate } from 'astro:transitions/client';
|
|
5
5
|
import { getPageLoadEvent } from '../helpers/getPageLoadEvent.ts';
|
|
6
6
|
|
|
7
|
-
import { initDropdown } from '@stainless-api/docs
|
|
8
|
-
import { initDropdownButton } from '@stainless-api/ui-primitives/scripts';
|
|
9
|
-
import { copyCurrentPageAsMarkdown, onSelectAIOption } from './ai-dropdown.ts';
|
|
7
|
+
import { initDropdown } from '@stainless-api/docs/components/scripts';
|
|
10
8
|
|
|
11
9
|
history.scrollRestoration = 'auto';
|
|
12
10
|
|
|
@@ -24,10 +22,13 @@ window.addEventListener('popstate', (ev: PopStateEvent) => {
|
|
|
24
22
|
});
|
|
25
23
|
|
|
26
24
|
document.addEventListener(getPageLoadEvent(), () => {
|
|
25
|
+
const rootElement = document.getElementById('stldocs-snippet-select');
|
|
26
|
+
if (!rootElement) return;
|
|
27
|
+
|
|
27
28
|
initDropdown({
|
|
28
|
-
|
|
29
|
+
root: rootElement,
|
|
29
30
|
onSelect: (value) => {
|
|
30
|
-
const originalLanguage =
|
|
31
|
+
const originalLanguage = rootElement?.dataset.currentValue;
|
|
31
32
|
navigate(updateSelectedLanguage(BASE_PATH, originalLanguage, value));
|
|
32
33
|
},
|
|
33
34
|
});
|
|
@@ -36,27 +37,6 @@ document.addEventListener(getPageLoadEvent(), () => {
|
|
|
36
37
|
if (path) setTimeout(() => scrollToPath(path.slice(1)), 10);
|
|
37
38
|
});
|
|
38
39
|
|
|
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
40
|
document.addEventListener('click', (event) => {
|
|
61
41
|
const toggle = (event.target as HTMLElement).closest(
|
|
62
42
|
'[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';
|
|
@@ -21,13 +21,18 @@ import {
|
|
|
21
21
|
type SpecRetrieverConfig,
|
|
22
22
|
} from './loadPluginConfig';
|
|
23
23
|
import { buildVirtualModuleString } from '../shared/virtualModule';
|
|
24
|
+
import type * as StlStarlightVirtualModule from 'virtual:stl-starlight-virtual-module';
|
|
24
25
|
import path from 'path';
|
|
25
26
|
import fs from 'fs';
|
|
27
|
+
import { getSharedLogger } from '../shared/getSharedLogger';
|
|
28
|
+
import { resolveSrcFile } from '../resolveSrcFile';
|
|
26
29
|
|
|
27
30
|
export { generateAPILink } from './generateAPIReferenceLink';
|
|
28
31
|
export type { ReferenceSidebarConfigItem };
|
|
29
32
|
|
|
30
|
-
config(
|
|
33
|
+
config({
|
|
34
|
+
quiet: true,
|
|
35
|
+
});
|
|
31
36
|
|
|
32
37
|
let sidebarIdCounter = 0;
|
|
33
38
|
|
|
@@ -108,6 +113,7 @@ function tmpGetCMSServerConfig(specRetrieverConfig: SpecRetrieverConfig) {
|
|
|
108
113
|
|
|
109
114
|
async function stlStarlightAstroIntegration(
|
|
110
115
|
pluginConfig: NormalizedStainlessStarlightConfig,
|
|
116
|
+
stlStarlightPluginLogger: AstroIntegrationLogger,
|
|
111
117
|
): Promise<AstroIntegration> {
|
|
112
118
|
const virtualId = `virtual:stl-starlight-virtual-module`;
|
|
113
119
|
// The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
|
|
@@ -117,11 +123,12 @@ async function stlStarlightAstroIntegration(
|
|
|
117
123
|
|
|
118
124
|
const { apiKey, version, devPaths } = tmpGetCMSServerConfig(pluginConfig.specRetrieverConfig);
|
|
119
125
|
|
|
120
|
-
const cmsServer =
|
|
126
|
+
const cmsServer = startDevServer({
|
|
121
127
|
port: CMS_PORT,
|
|
122
|
-
apiKey,
|
|
128
|
+
apiKey: apiKey.value,
|
|
123
129
|
version,
|
|
124
130
|
devPaths,
|
|
131
|
+
logger: stlStarlightPluginLogger,
|
|
125
132
|
getGeneratedSidebarConfig: (id: number) => {
|
|
126
133
|
const config = sidebarConfigs.get(id);
|
|
127
134
|
if (!config) {
|
|
@@ -134,43 +141,45 @@ async function stlStarlightAstroIntegration(
|
|
|
134
141
|
return {
|
|
135
142
|
name: 'stl-starlight-astro',
|
|
136
143
|
hooks: {
|
|
137
|
-
'astro:config:setup': async ({
|
|
144
|
+
'astro:config:setup': async ({
|
|
145
|
+
injectRoute,
|
|
146
|
+
updateConfig,
|
|
147
|
+
logger: localLogger,
|
|
148
|
+
command,
|
|
149
|
+
config: astroConfig,
|
|
150
|
+
}) => {
|
|
151
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
138
152
|
const projectDir = astroConfig.root.pathname;
|
|
139
153
|
|
|
140
154
|
const middlewareFile = path.join(projectDir, 'middleware.stainless.ts');
|
|
141
155
|
|
|
142
156
|
let vmMiddlewareExport = 'export const MIDDLEWARE = {};';
|
|
143
157
|
if (fs.existsSync(middlewareFile)) {
|
|
144
|
-
logger.
|
|
158
|
+
logger.debug(`Loading middleware from ${middlewareFile}`);
|
|
145
159
|
vmMiddlewareExport = `export { default as MIDDLEWARE } from '${middlewareFile}';`;
|
|
146
160
|
}
|
|
147
161
|
|
|
148
162
|
injectRoute({
|
|
149
|
-
pattern: `${pluginConfig.basePath}/[...slug].md`,
|
|
150
|
-
entrypoint: '
|
|
163
|
+
pattern: `${pluginConfig.basePath}/[...slug]/index.md`,
|
|
164
|
+
entrypoint: resolveSrcFile('/plugin/routes/markdown.ts'),
|
|
151
165
|
prerender: command === 'build',
|
|
152
166
|
});
|
|
153
167
|
|
|
154
|
-
const astroFile = command === 'build' ? '
|
|
168
|
+
const astroFile = command === 'build' ? 'DocsStatic' : 'Docs';
|
|
155
169
|
injectRoute({
|
|
156
170
|
pattern: `${pluginConfig.basePath}/[...slug]`,
|
|
157
|
-
|
|
158
|
-
entrypoint: `@stainless-api/docs/${astroFile}`,
|
|
171
|
+
entrypoint: resolveSrcFile(`/plugin/routes/${astroFile}.astro`),
|
|
159
172
|
prerender: command === 'build',
|
|
160
173
|
});
|
|
161
174
|
|
|
162
175
|
injectRoute({
|
|
163
176
|
pattern: pluginConfig.basePath,
|
|
164
|
-
entrypoint: '
|
|
177
|
+
entrypoint: resolveSrcFile('/plugin/routes/Overview.astro'),
|
|
165
178
|
prerender: command === 'build',
|
|
166
179
|
});
|
|
167
180
|
|
|
168
181
|
updateConfig({
|
|
169
182
|
vite: {
|
|
170
|
-
ssr: {
|
|
171
|
-
noExternal: ['@stainless-api/ui-primitives'],
|
|
172
|
-
},
|
|
173
|
-
optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
|
|
174
183
|
plugins: [
|
|
175
184
|
{
|
|
176
185
|
name: 'stl-starlight-vite',
|
|
@@ -212,8 +221,8 @@ async function stlStarlightAstroIntegration(
|
|
|
212
221
|
CONTENT_PANEL_LAYOUT: pluginConfig.contentPanel.layout,
|
|
213
222
|
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS: pluginConfig.experimentalCollapsibleSnippets,
|
|
214
223
|
PROPERTY_SETTINGS: pluginConfig.propertySettings,
|
|
215
|
-
|
|
216
|
-
}),
|
|
224
|
+
ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
|
|
225
|
+
} satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
|
|
217
226
|
vmMiddlewareExport,
|
|
218
227
|
].join('\n');
|
|
219
228
|
}
|
|
@@ -241,15 +250,20 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
241
250
|
command,
|
|
242
251
|
config: starlightConfig,
|
|
243
252
|
astroConfig,
|
|
244
|
-
logger,
|
|
253
|
+
logger: localLogger,
|
|
245
254
|
}) => {
|
|
246
255
|
if (command !== 'build' && command !== 'dev') {
|
|
247
256
|
return;
|
|
248
257
|
}
|
|
249
258
|
|
|
259
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
260
|
+
|
|
250
261
|
const configParseResult = parseStarlightPluginConfig(someUserConfig, command);
|
|
251
262
|
if (configParseResult.result === 'error') {
|
|
252
|
-
|
|
263
|
+
const errorLines = configParseResult.message.split('\n');
|
|
264
|
+
for (const line of errorLines) {
|
|
265
|
+
logger.error(line);
|
|
266
|
+
}
|
|
253
267
|
process.exit(1);
|
|
254
268
|
}
|
|
255
269
|
const config = configParseResult.config;
|
|
@@ -260,17 +274,30 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
260
274
|
addIntegration(react());
|
|
261
275
|
}
|
|
262
276
|
|
|
277
|
+
if ('apiKey' in config.specRetrieverConfig) {
|
|
278
|
+
if (!config.specRetrieverConfig.apiKey) {
|
|
279
|
+
logger.info(`Stainless credentials not loaded`);
|
|
280
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'explicit-config') {
|
|
281
|
+
logger.info(`Stainless credentials loaded from user config`);
|
|
282
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'environment-variable') {
|
|
283
|
+
logger.info('Stainless credentials loaded from `STAINLESS_API_KEY` environment variable');
|
|
284
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'cli') {
|
|
285
|
+
logger.info('Stainless credentials loaded from `stl` CLI');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
263
289
|
if (
|
|
264
290
|
command === 'build' &&
|
|
265
291
|
config.specRetrieverConfig.kind === 'local_spec_server_with_remote_files'
|
|
266
292
|
) {
|
|
267
293
|
await buildAlgoliaIndex({
|
|
268
294
|
version: config.specRetrieverConfig.version,
|
|
269
|
-
apiKey: config.specRetrieverConfig.apiKey,
|
|
295
|
+
apiKey: config.specRetrieverConfig.apiKey.value,
|
|
296
|
+
logger,
|
|
270
297
|
});
|
|
271
298
|
}
|
|
272
299
|
|
|
273
|
-
addIntegration(await stlStarlightAstroIntegration(config));
|
|
300
|
+
addIntegration(await stlStarlightAstroIntegration(config, logger));
|
|
274
301
|
|
|
275
302
|
if (starlightConfig.sidebar) {
|
|
276
303
|
// for pagination (https://starlight.astro.build/reference/configuration/#pagination) to work correctly
|
|
@@ -295,7 +322,7 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
295
322
|
});
|
|
296
323
|
|
|
297
324
|
addRouteMiddleware({
|
|
298
|
-
entrypoint: '
|
|
325
|
+
entrypoint: resolveSrcFile('/plugin/replaceSidebarPlaceholderMiddleware.ts'),
|
|
299
326
|
order: 'post',
|
|
300
327
|
});
|
|
301
328
|
},
|
|
@@ -304,5 +331,5 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
304
331
|
}
|
|
305
332
|
|
|
306
333
|
// Additional exports we want for Stainless <-> docs integration.
|
|
307
|
-
export { parseStainlessPath } from '@stainless-api/docs-ui/
|
|
308
|
-
export { renderMarkdown } from '@stainless-api/docs-ui/
|
|
334
|
+
export { parseStainlessPath } from '@stainless-api/docs-ui/routing';
|
|
335
|
+
export { renderMarkdown } from '@stainless-api/docs-ui/markdown';
|
package/plugin/languages.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocsLanguage } from '@stainless-api/docs-ui/
|
|
1
|
+
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
2
2
|
import KotlinIcon from './assets/languages/kotlin.svg';
|
|
3
3
|
import RubyIcon from './assets/languages/ruby.svg';
|
|
4
4
|
import TerraformIcon from './assets/languages/terraform.svg';
|
|
@@ -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)) {
|