@stainless-api/docs 0.1.0-beta.4 → 0.1.0-beta.40
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 +289 -0
- package/components/variables.css +2 -32
- package/eslint-suppressions.json +47 -0
- package/locals.d.ts +14 -0
- package/package.json +34 -30
- 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 -11
- package/plugin/components/search/SearchIsland.tsx +35 -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 -24
- package/plugin/languages.ts +2 -2
- package/plugin/loadPluginConfig.ts +105 -18
- 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 -2
- 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',
|
|
@@ -213,7 +222,8 @@ async function stlStarlightAstroIntegration(
|
|
|
213
222
|
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS: pluginConfig.experimentalCollapsibleSnippets,
|
|
214
223
|
PROPERTY_SETTINGS: pluginConfig.propertySettings,
|
|
215
224
|
SEARCH: pluginConfig.search,
|
|
216
|
-
|
|
225
|
+
ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
|
|
226
|
+
} satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
|
|
217
227
|
vmMiddlewareExport,
|
|
218
228
|
].join('\n');
|
|
219
229
|
}
|
|
@@ -241,15 +251,20 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
241
251
|
command,
|
|
242
252
|
config: starlightConfig,
|
|
243
253
|
astroConfig,
|
|
244
|
-
logger,
|
|
254
|
+
logger: localLogger,
|
|
245
255
|
}) => {
|
|
246
256
|
if (command !== 'build' && command !== 'dev') {
|
|
247
257
|
return;
|
|
248
258
|
}
|
|
249
259
|
|
|
260
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
261
|
+
|
|
250
262
|
const configParseResult = parseStarlightPluginConfig(someUserConfig, command);
|
|
251
263
|
if (configParseResult.result === 'error') {
|
|
252
|
-
|
|
264
|
+
const errorLines = configParseResult.message.split('\n');
|
|
265
|
+
for (const line of errorLines) {
|
|
266
|
+
logger.error(line);
|
|
267
|
+
}
|
|
253
268
|
process.exit(1);
|
|
254
269
|
}
|
|
255
270
|
const config = configParseResult.config;
|
|
@@ -260,17 +275,30 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
260
275
|
addIntegration(react());
|
|
261
276
|
}
|
|
262
277
|
|
|
278
|
+
if ('apiKey' in config.specRetrieverConfig) {
|
|
279
|
+
if (!config.specRetrieverConfig.apiKey) {
|
|
280
|
+
logger.info(`Stainless credentials not loaded`);
|
|
281
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'explicit-config') {
|
|
282
|
+
logger.info(`Stainless credentials loaded from user config`);
|
|
283
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'environment-variable') {
|
|
284
|
+
logger.info('Stainless credentials loaded from `STAINLESS_API_KEY` environment variable');
|
|
285
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'cli') {
|
|
286
|
+
logger.info('Stainless credentials loaded from `stl` CLI');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
263
290
|
if (
|
|
264
291
|
command === 'build' &&
|
|
265
292
|
config.specRetrieverConfig.kind === 'local_spec_server_with_remote_files'
|
|
266
293
|
) {
|
|
267
294
|
await buildAlgoliaIndex({
|
|
268
295
|
version: config.specRetrieverConfig.version,
|
|
269
|
-
apiKey: config.specRetrieverConfig.apiKey,
|
|
296
|
+
apiKey: config.specRetrieverConfig.apiKey.value,
|
|
297
|
+
logger,
|
|
270
298
|
});
|
|
271
299
|
}
|
|
272
300
|
|
|
273
|
-
addIntegration(await stlStarlightAstroIntegration(config));
|
|
301
|
+
addIntegration(await stlStarlightAstroIntegration(config, logger));
|
|
274
302
|
|
|
275
303
|
if (starlightConfig.sidebar) {
|
|
276
304
|
// for pagination (https://starlight.astro.build/reference/configuration/#pagination) to work correctly
|
|
@@ -295,7 +323,7 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
295
323
|
});
|
|
296
324
|
|
|
297
325
|
addRouteMiddleware({
|
|
298
|
-
entrypoint: '
|
|
326
|
+
entrypoint: resolveSrcFile('/plugin/replaceSidebarPlaceholderMiddleware.ts'),
|
|
299
327
|
order: 'post',
|
|
300
328
|
});
|
|
301
329
|
},
|
|
@@ -304,5 +332,5 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
304
332
|
}
|
|
305
333
|
|
|
306
334
|
// Additional exports we want for Stainless <-> docs integration.
|
|
307
|
-
export { parseStainlessPath } from '@stainless-api/docs-ui/
|
|
308
|
-
export { renderMarkdown } from '@stainless-api/docs-ui/
|
|
335
|
+
export { parseStainlessPath } from '@stainless-api/docs-ui/routing';
|
|
336
|
+
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)) {
|