@stainless-api/docs 0.1.0-beta.7 → 0.1.0-beta.70
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 +554 -0
- package/README.md +1 -1
- package/eslint-suppressions.json +52 -0
- package/locals.d.ts +17 -0
- package/package.json +51 -40
- package/plugin/assets/languages/csharp.svg +1 -0
- package/plugin/buildAlgoliaIndex.ts +32 -7
- package/plugin/cms/server.ts +130 -58
- package/plugin/cms/sidebar-builder.ts +7 -26
- package/plugin/cms/worker.ts +83 -5
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/SDKSelect.astro +7 -87
- package/plugin/components/SnippetCode.tsx +53 -8
- package/plugin/components/search/SearchAlgolia.astro +45 -28
- package/plugin/components/search/SearchIsland.tsx +38 -24
- package/plugin/create-playground.shim.tsx +3 -0
- package/plugin/generateAPIReferenceLink.ts +2 -2
- package/plugin/globalJs/ai-dropdown-options.ts +243 -0
- package/plugin/globalJs/code-snippets.ts +15 -8
- package/plugin/globalJs/copy.ts +81 -16
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +7 -4
- package/plugin/helpers/generateDocsRoutes.ts +27 -0
- package/plugin/index.ts +178 -35
- package/plugin/languages.ts +5 -2
- package/plugin/loadPluginConfig.ts +121 -32
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
- package/plugin/react/Routing.tsx +208 -129
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
- package/plugin/routes/Docs.astro +62 -89
- package/plugin/routes/DocsStatic.astro +1 -1
- package/plugin/routes/Overview.astro +10 -16
- package/plugin/routes/markdown.ts +9 -8
- package/plugin/vendor/preview.worker.docs.js +19768 -17702
- package/plugin/vendor/templates/go.md +1 -1
- package/plugin/vendor/templates/python.md +1 -1
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +5 -5
- package/shared/getProsePages.ts +42 -0
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/src/content.config.ts +9 -0
- package/stl-docs/components/AIDropdown.tsx +63 -0
- package/stl-docs/components/AiChatIsland.tsx +14 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +10 -18
- package/stl-docs/components/Head.astro +16 -0
- package/stl-docs/components/Header.astro +6 -8
- package/stl-docs/components/PageFrame.astro +18 -0
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeProvider.astro +36 -0
- package/stl-docs/components/ThemeSelect.astro +84 -139
- package/stl-docs/components/content-panel/ContentPanel.astro +16 -25
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
- package/stl-docs/components/headers/StackedHeader.astro +29 -24
- package/stl-docs/components/icons/chat-gpt.tsx +17 -0
- package/stl-docs/components/icons/claude.tsx +10 -0
- package/stl-docs/components/icons/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 -5
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +7 -3
- 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/callouts/Callout.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +1 -1
- package/stl-docs/components/mintlify-compat/card.css +33 -35
- package/stl-docs/components/mintlify-compat/index.ts +2 -4
- package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -70
- package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +175 -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/disableCalloutSyntax.ts +36 -0
- package/stl-docs/index.ts +141 -50
- package/stl-docs/loadStlDocsConfig.ts +45 -5
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +39 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/proseSearchIndexing.ts +450 -0
- package/stl-docs/tabsMiddleware.ts +11 -3
- package/styles/code.css +108 -140
- package/styles/fonts.css +32 -17
- package/styles/links.css +11 -48
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +48 -60
- package/styles/page.css +92 -52
- package/styles/sdk_select.css +9 -7
- package/styles/search.css +56 -69
- package/styles/sidebar.css +211 -131
- package/styles/{variables.css → sl-variables.css} +3 -2
- package/styles/stldocs-variables.css +6 -0
- package/styles/toc.css +41 -34
- package/theme.css +10 -10
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +26 -4
- package/components/variables.css +0 -135
- package/stl-docs/components/mintlify-compat/Step.astro +0 -58
- package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
- /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
package/plugin/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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
|
+
import type { BundledTheme } from 'shiki';
|
|
4
5
|
import { config } from 'dotenv';
|
|
5
6
|
import getPort from 'get-port';
|
|
6
|
-
import { startDevServer } from './cms/server';
|
|
7
|
+
import { startDevServer, type SpecResp } from './cms/server';
|
|
7
8
|
import { buildAlgoliaIndex } from './buildAlgoliaIndex';
|
|
8
9
|
import {
|
|
9
10
|
getAPIReferencePlaceholderItemFromSidebarConfig,
|
|
@@ -21,13 +22,21 @@ import {
|
|
|
21
22
|
type SpecRetrieverConfig,
|
|
22
23
|
} from './loadPluginConfig';
|
|
23
24
|
import { buildVirtualModuleString } from '../shared/virtualModule';
|
|
25
|
+
import type * as StlStarlightVirtualModule from 'virtual:stl-starlight-virtual-module';
|
|
24
26
|
import path from 'path';
|
|
25
27
|
import fs from 'fs';
|
|
28
|
+
import { getSharedLogger } from '../shared/getSharedLogger';
|
|
29
|
+
import { resolveSrcFile } from '../resolveSrcFile';
|
|
30
|
+
import { mkdir } from 'fs/promises';
|
|
31
|
+
import { fileURLToPath } from 'url';
|
|
32
|
+
import prebundleWorkers from 'vite-plugin-prebundle-workers';
|
|
26
33
|
|
|
27
34
|
export { generateAPILink } from './generateAPIReferenceLink';
|
|
28
35
|
export type { ReferenceSidebarConfigItem };
|
|
29
36
|
|
|
30
|
-
config(
|
|
37
|
+
config({
|
|
38
|
+
quiet: true,
|
|
39
|
+
});
|
|
31
40
|
|
|
32
41
|
let sidebarIdCounter = 0;
|
|
33
42
|
|
|
@@ -108,20 +117,24 @@ function tmpGetCMSServerConfig(specRetrieverConfig: SpecRetrieverConfig) {
|
|
|
108
117
|
|
|
109
118
|
async function stlStarlightAstroIntegration(
|
|
110
119
|
pluginConfig: NormalizedStainlessStarlightConfig,
|
|
120
|
+
stlStarlightPluginLogger: AstroIntegrationLogger,
|
|
111
121
|
): Promise<AstroIntegration> {
|
|
112
122
|
const virtualId = `virtual:stl-starlight-virtual-module`;
|
|
113
123
|
// The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
|
|
114
124
|
const resolvedId = `\0${virtualId}`;
|
|
125
|
+
let playgroundsBase: string | undefined;
|
|
126
|
+
let buildPlaygrounds;
|
|
115
127
|
|
|
116
128
|
const CMS_PORT = await getPort();
|
|
117
129
|
|
|
118
130
|
const { apiKey, version, devPaths } = tmpGetCMSServerConfig(pluginConfig.specRetrieverConfig);
|
|
119
131
|
|
|
120
|
-
const cmsServer =
|
|
132
|
+
const cmsServer = startDevServer({
|
|
121
133
|
port: CMS_PORT,
|
|
122
|
-
apiKey,
|
|
134
|
+
apiKey: apiKey.value,
|
|
123
135
|
version,
|
|
124
136
|
devPaths,
|
|
137
|
+
logger: stlStarlightPluginLogger,
|
|
125
138
|
getGeneratedSidebarConfig: (id: number) => {
|
|
126
139
|
const config = sidebarConfigs.get(id);
|
|
127
140
|
if (!config) {
|
|
@@ -131,50 +144,98 @@ async function stlStarlightAstroIntegration(
|
|
|
131
144
|
},
|
|
132
145
|
});
|
|
133
146
|
|
|
147
|
+
let building: Promise<void> | undefined;
|
|
148
|
+
let reportError: ((message: string) => void) | null = null;
|
|
149
|
+
let collectedErrors: string[] | null = null;
|
|
150
|
+
|
|
151
|
+
function startPlaygroundsBuild(playgroundsCachePath: string) {
|
|
152
|
+
if (!pluginConfig.experimentalPlaygrounds) return;
|
|
153
|
+
if (building) return building;
|
|
154
|
+
return (building = (async () => {
|
|
155
|
+
const { data: spec, auth } = (await (
|
|
156
|
+
await fetch(`http://localhost:${CMS_PORT}/retrieve_spec`, {
|
|
157
|
+
method: 'POST',
|
|
158
|
+
body: JSON.stringify({}),
|
|
159
|
+
})
|
|
160
|
+
).json()) as SpecResp;
|
|
161
|
+
if (!spec || !auth) throw new Error('expected spec');
|
|
162
|
+
|
|
163
|
+
const langs = (spec.docs?.languages ?? ['http'])
|
|
164
|
+
.filter((lang) => lang !== 'terraform')
|
|
165
|
+
.filter((lang) => !pluginConfig.excludeLanguages?.includes(lang));
|
|
166
|
+
|
|
167
|
+
await buildPlaygrounds!({
|
|
168
|
+
spec,
|
|
169
|
+
langs,
|
|
170
|
+
auth,
|
|
171
|
+
playPath: playgroundsCachePath,
|
|
172
|
+
reportError(message: string) {
|
|
173
|
+
(reportError ?? console.error)(message);
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
})());
|
|
177
|
+
}
|
|
178
|
+
|
|
134
179
|
return {
|
|
135
180
|
name: 'stl-starlight-astro',
|
|
136
181
|
hooks: {
|
|
137
|
-
'astro:config:setup': async ({
|
|
182
|
+
'astro:config:setup': async ({
|
|
183
|
+
injectRoute,
|
|
184
|
+
updateConfig,
|
|
185
|
+
logger: localLogger,
|
|
186
|
+
command,
|
|
187
|
+
config: astroConfig,
|
|
188
|
+
}) => {
|
|
189
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
138
190
|
const projectDir = astroConfig.root.pathname;
|
|
139
191
|
|
|
192
|
+
reportError = (message: string) => logger.error(message);
|
|
193
|
+
|
|
194
|
+
if (pluginConfig.experimentalPlaygrounds) {
|
|
195
|
+
playgroundsBase = pluginConfig.experimentalPlaygrounds.playgroundsBase;
|
|
196
|
+
}
|
|
197
|
+
|
|
140
198
|
const middlewareFile = path.join(projectDir, 'middleware.stainless.ts');
|
|
141
199
|
|
|
142
200
|
let vmMiddlewareExport = 'export const MIDDLEWARE = {};';
|
|
143
201
|
if (fs.existsSync(middlewareFile)) {
|
|
144
|
-
logger.
|
|
202
|
+
logger.debug(`Loading middleware from ${middlewareFile}`);
|
|
145
203
|
vmMiddlewareExport = `export { default as MIDDLEWARE } from '${middlewareFile}';`;
|
|
146
204
|
}
|
|
147
205
|
|
|
148
206
|
injectRoute({
|
|
149
|
-
pattern: `${pluginConfig.basePath}/[...slug].md`,
|
|
150
|
-
entrypoint: '
|
|
207
|
+
pattern: `${pluginConfig.basePath}/[...slug]/index.md`,
|
|
208
|
+
entrypoint: resolveSrcFile('/plugin/routes/markdown.ts'),
|
|
151
209
|
prerender: command === 'build',
|
|
152
210
|
});
|
|
153
211
|
|
|
154
|
-
const astroFile = command === 'build' ? '
|
|
212
|
+
const astroFile = command === 'build' ? 'DocsStatic' : 'Docs';
|
|
155
213
|
injectRoute({
|
|
156
214
|
pattern: `${pluginConfig.basePath}/[...slug]`,
|
|
157
|
-
|
|
158
|
-
entrypoint: `@stainless-api/docs/${astroFile}`,
|
|
215
|
+
entrypoint: resolveSrcFile(`/plugin/routes/${astroFile}.astro`),
|
|
159
216
|
prerender: command === 'build',
|
|
160
217
|
});
|
|
161
218
|
|
|
162
219
|
injectRoute({
|
|
163
220
|
pattern: pluginConfig.basePath,
|
|
164
|
-
entrypoint: '
|
|
221
|
+
entrypoint: resolveSrcFile('/plugin/routes/Overview.astro'),
|
|
165
222
|
prerender: command === 'build',
|
|
166
223
|
});
|
|
167
224
|
|
|
168
225
|
updateConfig({
|
|
169
226
|
vite: {
|
|
170
|
-
ssr: {
|
|
171
|
-
noExternal: ['@stainless-api/ui-primitives'],
|
|
172
|
-
},
|
|
173
|
-
optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
|
|
174
227
|
plugins: [
|
|
175
228
|
{
|
|
176
229
|
name: 'stl-starlight-vite',
|
|
177
|
-
|
|
230
|
+
buildStart() {
|
|
231
|
+
building = undefined;
|
|
232
|
+
},
|
|
233
|
+
async configureServer(server) {
|
|
234
|
+
if (playgroundsBase) {
|
|
235
|
+
buildPlaygrounds = (await server.ssrLoadModule(playgroundsBase + '/src/build.ts'))
|
|
236
|
+
.buildPlaygrounds;
|
|
237
|
+
}
|
|
238
|
+
|
|
178
239
|
for (const filePath of Object.values(devPaths)) {
|
|
179
240
|
if (!filePath) {
|
|
180
241
|
continue;
|
|
@@ -197,6 +258,30 @@ async function stlStarlightAstroIntegration(
|
|
|
197
258
|
if (id === virtualId) {
|
|
198
259
|
return resolvedId;
|
|
199
260
|
}
|
|
261
|
+
if (id === 'virtual:stl-playground/unstable-update-language') {
|
|
262
|
+
return resolveSrcFile('plugin/languages.ts');
|
|
263
|
+
}
|
|
264
|
+
if (id === 'virtual:stl-playground/create') {
|
|
265
|
+
return fileURLToPath(
|
|
266
|
+
new URL(
|
|
267
|
+
pluginConfig.experimentalPlaygrounds
|
|
268
|
+
? path.join(playgroundsBase!, '/src/create.tsx')
|
|
269
|
+
: './create-playground.shim.tsx',
|
|
270
|
+
import.meta.url,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (id.startsWith('virtual:stl-playground/')) {
|
|
275
|
+
const result = path.join(
|
|
276
|
+
this.environment.getTopLevelConfig().cacheDir,
|
|
277
|
+
'stl-playground',
|
|
278
|
+
id.slice('virtual:stl-playground/'.length),
|
|
279
|
+
);
|
|
280
|
+
const config = this.environment.getTopLevelConfig();
|
|
281
|
+
return startPlaygroundsBuild(path.join(config.cacheDir, 'stl-playground'))?.then(
|
|
282
|
+
() => result,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
200
285
|
},
|
|
201
286
|
load(id) {
|
|
202
287
|
if (id === resolvedId) {
|
|
@@ -204,21 +289,39 @@ async function stlStarlightAstroIntegration(
|
|
|
204
289
|
buildVirtualModuleString({
|
|
205
290
|
BASE_PATH: pluginConfig.basePath,
|
|
206
291
|
CMS_PORT,
|
|
207
|
-
EXCLUDE_LANGUAGES: pluginConfig.excludeLanguages,
|
|
292
|
+
EXCLUDE_LANGUAGES: ['php', ...pluginConfig.excludeLanguages],
|
|
208
293
|
DEFAULT_LANGUAGE: pluginConfig.defaultLanguage,
|
|
209
294
|
BREADCRUMB_CONFIG: pluginConfig.breadcrumbs,
|
|
210
295
|
EXPAND_RESOURCES: pluginConfig.expandResources,
|
|
211
296
|
HIGHLIGHT_THEMES: pluginConfig.highlighting.themes,
|
|
212
297
|
CONTENT_PANEL_LAYOUT: pluginConfig.contentPanel.layout,
|
|
213
298
|
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS: pluginConfig.experimentalCollapsibleSnippets,
|
|
299
|
+
EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS:
|
|
300
|
+
pluginConfig.experimentalCollapsibleMethodDescriptions,
|
|
214
301
|
PROPERTY_SETTINGS: pluginConfig.propertySettings,
|
|
215
|
-
|
|
216
|
-
|
|
302
|
+
ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
|
|
303
|
+
EXPERIMENTAL_PLAYGROUNDS: !!pluginConfig.experimentalPlaygrounds,
|
|
304
|
+
} satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
|
|
217
305
|
vmMiddlewareExport,
|
|
218
306
|
].join('\n');
|
|
219
307
|
}
|
|
220
308
|
},
|
|
221
309
|
},
|
|
310
|
+
prebundleWorkers({
|
|
311
|
+
include: [
|
|
312
|
+
'**/typescript/runner*',
|
|
313
|
+
'**/typescript/worker*',
|
|
314
|
+
'**/pyright.worker*',
|
|
315
|
+
'**/python/pyodide*',
|
|
316
|
+
],
|
|
317
|
+
configureEsBuild(_, opts) {
|
|
318
|
+
opts.external ??= [];
|
|
319
|
+
opts.external.push('url');
|
|
320
|
+
opts.loader ??= {};
|
|
321
|
+
opts.loader['.wasm'] = 'dataurl';
|
|
322
|
+
return opts;
|
|
323
|
+
},
|
|
324
|
+
}),
|
|
222
325
|
],
|
|
223
326
|
},
|
|
224
327
|
});
|
|
@@ -226,6 +329,24 @@ async function stlStarlightAstroIntegration(
|
|
|
226
329
|
'astro:server:done': async () => {
|
|
227
330
|
await cmsServer.destroy();
|
|
228
331
|
},
|
|
332
|
+
'astro:build:start'({ logger }) {
|
|
333
|
+
collectedErrors = [];
|
|
334
|
+
reportError = (message: string) => {
|
|
335
|
+
logger.error(message);
|
|
336
|
+
collectedErrors!.push(message);
|
|
337
|
+
};
|
|
338
|
+
},
|
|
339
|
+
'astro:build:done': async ({ dir, logger }) => {
|
|
340
|
+
const dist = fileURLToPath(dir);
|
|
341
|
+
const stainlessDir = path.join(dist, '_stainless');
|
|
342
|
+
await mkdir(stainlessDir, { recursive: true });
|
|
343
|
+
if (collectedErrors) {
|
|
344
|
+
for (const error of collectedErrors) {
|
|
345
|
+
logger.error(error);
|
|
346
|
+
}
|
|
347
|
+
collectedErrors = null;
|
|
348
|
+
}
|
|
349
|
+
},
|
|
229
350
|
},
|
|
230
351
|
};
|
|
231
352
|
}
|
|
@@ -241,15 +362,20 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
241
362
|
command,
|
|
242
363
|
config: starlightConfig,
|
|
243
364
|
astroConfig,
|
|
244
|
-
logger,
|
|
365
|
+
logger: localLogger,
|
|
245
366
|
}) => {
|
|
246
367
|
if (command !== 'build' && command !== 'dev') {
|
|
247
368
|
return;
|
|
248
369
|
}
|
|
249
370
|
|
|
371
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
372
|
+
|
|
250
373
|
const configParseResult = parseStarlightPluginConfig(someUserConfig, command);
|
|
251
374
|
if (configParseResult.result === 'error') {
|
|
252
|
-
|
|
375
|
+
const errorLines = configParseResult.message.split('\n');
|
|
376
|
+
for (const line of errorLines) {
|
|
377
|
+
logger.error(line);
|
|
378
|
+
}
|
|
253
379
|
process.exit(1);
|
|
254
380
|
}
|
|
255
381
|
const config = configParseResult.config;
|
|
@@ -260,17 +386,30 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
260
386
|
addIntegration(react());
|
|
261
387
|
}
|
|
262
388
|
|
|
389
|
+
if ('apiKey' in config.specRetrieverConfig) {
|
|
390
|
+
if (!config.specRetrieverConfig.apiKey) {
|
|
391
|
+
logger.info(`Stainless credentials not loaded`);
|
|
392
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'explicit-config') {
|
|
393
|
+
logger.info(`Stainless credentials loaded from user config`);
|
|
394
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'environment-variable') {
|
|
395
|
+
logger.info('Stainless credentials loaded from `STAINLESS_API_KEY` environment variable');
|
|
396
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'cli') {
|
|
397
|
+
logger.info('Stainless credentials loaded from `stl` CLI');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
263
401
|
if (
|
|
264
402
|
command === 'build' &&
|
|
265
403
|
config.specRetrieverConfig.kind === 'local_spec_server_with_remote_files'
|
|
266
404
|
) {
|
|
267
405
|
await buildAlgoliaIndex({
|
|
268
406
|
version: config.specRetrieverConfig.version,
|
|
269
|
-
apiKey: config.specRetrieverConfig.apiKey,
|
|
407
|
+
apiKey: config.specRetrieverConfig.apiKey.value,
|
|
408
|
+
logger,
|
|
270
409
|
});
|
|
271
410
|
}
|
|
272
411
|
|
|
273
|
-
addIntegration(await stlStarlightAstroIntegration(config));
|
|
412
|
+
addIntegration(await stlStarlightAstroIntegration(config, logger));
|
|
274
413
|
|
|
275
414
|
if (starlightConfig.sidebar) {
|
|
276
415
|
// for pagination (https://starlight.astro.build/reference/configuration/#pagination) to work correctly
|
|
@@ -281,21 +420,25 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
281
420
|
}
|
|
282
421
|
}
|
|
283
422
|
|
|
284
|
-
const
|
|
423
|
+
const expressiveCodeConfig =
|
|
285
424
|
typeof starlightConfig.expressiveCode === 'object' ? starlightConfig.expressiveCode : {};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
},
|
|
291
|
-
});
|
|
425
|
+
|
|
426
|
+
const themes = expressiveCodeConfig.themes
|
|
427
|
+
? (expressiveCodeConfig.themes as BundledTheme[])
|
|
428
|
+
: (['github-light', 'github-dark'] as BundledTheme[]);
|
|
292
429
|
|
|
293
430
|
updateConfig({
|
|
294
431
|
sidebar: starlightConfig.sidebar,
|
|
432
|
+
...(expressiveCodeConfig && {
|
|
433
|
+
expressiveCode: {
|
|
434
|
+
...expressiveCodeConfig,
|
|
435
|
+
themes,
|
|
436
|
+
},
|
|
437
|
+
}),
|
|
295
438
|
});
|
|
296
439
|
|
|
297
440
|
addRouteMiddleware({
|
|
298
|
-
entrypoint: '
|
|
441
|
+
entrypoint: resolveSrcFile('/plugin/replaceSidebarPlaceholderMiddleware.ts'),
|
|
299
442
|
order: 'post',
|
|
300
443
|
});
|
|
301
444
|
},
|
|
@@ -304,5 +447,5 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
304
447
|
}
|
|
305
448
|
|
|
306
449
|
// Additional exports we want for Stainless <-> docs integration.
|
|
307
|
-
export { parseStainlessPath } from '@stainless-api/docs-ui/
|
|
308
|
-
export { renderMarkdown } from '@stainless-api/docs-ui/
|
|
450
|
+
export { parseStainlessPath } from '@stainless-api/docs-ui/routing';
|
|
451
|
+
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';
|
|
@@ -7,6 +7,7 @@ import PythonIcon from './assets/languages/python.svg';
|
|
|
7
7
|
import JavaIcon from './assets/languages/java.svg';
|
|
8
8
|
import GoIcon from './assets/languages/go.svg';
|
|
9
9
|
import CurlIcon from './assets/languages/curl.svg';
|
|
10
|
+
import CSharpIcon from './assets/languages/csharp.svg';
|
|
10
11
|
|
|
11
12
|
export const Languages: Record<
|
|
12
13
|
DocsLanguage,
|
|
@@ -29,6 +30,8 @@ export const Languages: Record<
|
|
|
29
30
|
http: { name: 'HTTP', icon: CurlIcon, alt: 'HTTP logo' },
|
|
30
31
|
terraform: { name: 'Terraform', icon: TerraformIcon, alt: 'Terraform logo' },
|
|
31
32
|
ruby: { name: 'Ruby', icon: RubyIcon, alt: 'Ruby logo' },
|
|
33
|
+
csharp: { name: 'C#', icon: CSharpIcon, alt: 'C# logo' },
|
|
34
|
+
php: { name: 'PHP', icon: CSharpIcon, alt: 'PHP logo' }, // TODO update PHP icon
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
export function generatePrefix(basePath: string, language: string) {
|
|
@@ -44,7 +47,7 @@ export function applyLanguageToLinks(basePath?: string, defaultLanguage?: string
|
|
|
44
47
|
`[data-stldocs-overview],[data-stldocs-method],a.nav-link[href^='${basePath}']`,
|
|
45
48
|
);
|
|
46
49
|
|
|
47
|
-
for (
|
|
50
|
+
for (const link of links) {
|
|
48
51
|
const href = link.getAttribute('href');
|
|
49
52
|
const prefix = generatePrefix(basePath, language);
|
|
50
53
|
if (href?.startsWith(basePath) && !href?.startsWith(prefix)) {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
4
|
|
|
3
5
|
import type { CreateShikiHighlighterOptions } from '@astrojs/markdown-remark';
|
|
4
|
-
import type { DocsLanguage } from '@stainless-api/docs-ui/
|
|
5
|
-
import type { PropertySettingsType } from '@stainless-api/docs-ui/
|
|
6
|
+
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
7
|
+
import type { PropertySettingsType } from '@stainless-api/docs-ui/contexts';
|
|
6
8
|
import type { InputFilePaths } from '../plugin/cms/server';
|
|
9
|
+
import { bold } from '../shared/terminalUtils';
|
|
7
10
|
|
|
8
11
|
export type AstroCommand = 'dev' | 'build' | 'preview' | 'sync';
|
|
9
12
|
|
|
@@ -18,7 +21,7 @@ export type VersionUserConfig = {
|
|
|
18
21
|
type BreadcrumbUserConfig = {
|
|
19
22
|
/**
|
|
20
23
|
* Include the current page in the breadcrumb list.
|
|
21
|
-
*
|
|
24
|
+
* Default: `false`
|
|
22
25
|
*/
|
|
23
26
|
includeCurrentPage?: boolean;
|
|
24
27
|
};
|
|
@@ -26,7 +29,12 @@ type BreadcrumbUserConfig = {
|
|
|
26
29
|
export type StainlessStarlightUserConfig = {
|
|
27
30
|
/**
|
|
28
31
|
* Optional api key for Stainless API.
|
|
29
|
-
* If not provided,
|
|
32
|
+
* If not provided, we will handle Stainless auth via the `stl` CLI or look for the STAINLESS_API_KEY environment variable.
|
|
33
|
+
* Precedence:
|
|
34
|
+
* 1. Explicity `apiKey` option provided
|
|
35
|
+
* 2. `STAINLESS_API_KEY` environment variable
|
|
36
|
+
* 3. Login status from the `stl` CLI
|
|
37
|
+
* 4. Error (no auth found)
|
|
30
38
|
*/
|
|
31
39
|
apiKey?: string;
|
|
32
40
|
|
|
@@ -42,8 +50,8 @@ export type StainlessStarlightUserConfig = {
|
|
|
42
50
|
|
|
43
51
|
/**
|
|
44
52
|
* Optional mount point for API reference docs.
|
|
45
|
-
* Defaults to `/api`.
|
|
46
53
|
* Example: `/my-api` → docs available at `/my-api/…`.
|
|
54
|
+
* @default `/api`
|
|
47
55
|
*/
|
|
48
56
|
basePath?: string;
|
|
49
57
|
|
|
@@ -55,8 +63,8 @@ export type StainlessStarlightUserConfig = {
|
|
|
55
63
|
|
|
56
64
|
/**
|
|
57
65
|
* Optional language to treat as the default when the user hasn't selected one.
|
|
58
|
-
*
|
|
59
|
-
*
|
|
66
|
+
* Example: `'python'`
|
|
67
|
+
* @default 'http'
|
|
60
68
|
*/
|
|
61
69
|
defaultLanguage?: DocsLanguage;
|
|
62
70
|
|
|
@@ -90,7 +98,7 @@ export type StainlessStarlightUserConfig = {
|
|
|
90
98
|
contentPanel?: {
|
|
91
99
|
/**
|
|
92
100
|
* Optional layout for the content panel.
|
|
93
|
-
*
|
|
101
|
+
* @default 'double-pane'
|
|
94
102
|
*/
|
|
95
103
|
layout?: ContentLayout;
|
|
96
104
|
};
|
|
@@ -100,23 +108,35 @@ export type StainlessStarlightUserConfig = {
|
|
|
100
108
|
*/
|
|
101
109
|
propertySettings?: PropertySettingsType;
|
|
102
110
|
|
|
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
111
|
/**
|
|
115
112
|
* Enable experimental collapsible code snippets. Snippets will be collapsed by default for
|
|
116
113
|
* single-pane and mobile layouts.
|
|
117
|
-
*
|
|
114
|
+
*
|
|
115
|
+
* @default false
|
|
118
116
|
*/
|
|
119
117
|
experimentalCollapsibleSnippets?: boolean;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Enable experimental collapsible method descriptions. Method descriptions will be
|
|
121
|
+
* collapsed if their content exceeds a certain length.
|
|
122
|
+
*
|
|
123
|
+
* @default false
|
|
124
|
+
*/
|
|
125
|
+
experimentalCollapsibleMethodDescriptions?: boolean;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Whether to show the context menu with options like "Copy as Markdown" and "Open in ChatGPT".
|
|
129
|
+
*
|
|
130
|
+
* @default true
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
contextMenu?: boolean;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* When set to `import playgrounds from '@stainless-api/playgrounds'`, code snippets will have a "Play" button,
|
|
137
|
+
* allowing users to edit and run code snippets in their browser.
|
|
138
|
+
*/
|
|
139
|
+
experimentalPlaygrounds?: { playgroundsBase: string };
|
|
120
140
|
};
|
|
121
141
|
|
|
122
142
|
export type ExternalSpecServerUserConfig = Omit<StainlessStarlightUserConfig, 'stainlessProject'> & {
|
|
@@ -133,15 +153,29 @@ function getLocalFilePaths(command: AstroCommand): InputFilePaths | null {
|
|
|
133
153
|
if (command !== 'dev') {
|
|
134
154
|
return null;
|
|
135
155
|
}
|
|
136
|
-
|
|
156
|
+
|
|
157
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
158
|
+
const oasPath = process.env.OPENAPI_PATH;
|
|
159
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
160
|
+
const configPath = process.env.STAINLESS_CONFIG_PATH;
|
|
161
|
+
|
|
162
|
+
if (!oasPath || !configPath) {
|
|
137
163
|
return null;
|
|
138
164
|
}
|
|
165
|
+
|
|
139
166
|
return {
|
|
140
|
-
oasPath: resolvePath(
|
|
141
|
-
configPath: resolvePath(
|
|
167
|
+
oasPath: resolvePath(oasPath),
|
|
168
|
+
configPath: resolvePath(configPath),
|
|
142
169
|
};
|
|
143
170
|
}
|
|
144
171
|
|
|
172
|
+
export type ApiKeySource = 'explicit-config' | 'environment-variable' | 'cli';
|
|
173
|
+
|
|
174
|
+
export type LoadedApiKey = {
|
|
175
|
+
value: string;
|
|
176
|
+
source: ApiKeySource;
|
|
177
|
+
};
|
|
178
|
+
|
|
145
179
|
export type SpecRetrieverConfig =
|
|
146
180
|
| {
|
|
147
181
|
kind: 'external_spec_server';
|
|
@@ -152,16 +186,63 @@ export type SpecRetrieverConfig =
|
|
|
152
186
|
kind: 'local_spec_server_with_files';
|
|
153
187
|
stainlessProject: string;
|
|
154
188
|
devPaths: InputFilePaths;
|
|
155
|
-
apiKey:
|
|
189
|
+
apiKey: LoadedApiKey | null;
|
|
156
190
|
version: VersionUserConfig;
|
|
157
191
|
}
|
|
158
192
|
| {
|
|
159
193
|
kind: 'local_spec_server_with_remote_files';
|
|
160
194
|
stainlessProject: string;
|
|
161
|
-
apiKey:
|
|
195
|
+
apiKey: LoadedApiKey;
|
|
162
196
|
version: VersionUserConfig;
|
|
163
197
|
};
|
|
164
198
|
|
|
199
|
+
function parseAuthJson(authJsonStr: string) {
|
|
200
|
+
let json: unknown;
|
|
201
|
+
try {
|
|
202
|
+
json = JSON.parse(authJsonStr);
|
|
203
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
204
|
+
} catch (_error) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (typeof json !== 'object' || json === null) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
if (!('access_token' in json)) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const accessToken = json['access_token'];
|
|
215
|
+
if (typeof accessToken !== 'string') {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
return accessToken;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function loadApiKey(configValue: string | undefined): LoadedApiKey | null {
|
|
222
|
+
if (typeof configValue === 'string') {
|
|
223
|
+
return { value: configValue, source: 'explicit-config' };
|
|
224
|
+
}
|
|
225
|
+
if (process.env.STAINLESS_API_KEY) {
|
|
226
|
+
return { value: process.env.STAINLESS_API_KEY, source: 'environment-variable' };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const homeDirPath = homedir();
|
|
230
|
+
|
|
231
|
+
const authJsonPath = path.join(homeDirPath, '.config', 'stainless', 'auth.json');
|
|
232
|
+
|
|
233
|
+
if (!existsSync(authJsonPath)) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const authJsonStr = readFileSync(authJsonPath, 'utf-8');
|
|
238
|
+
const accessToken = parseAuthJson(authJsonStr);
|
|
239
|
+
if (!accessToken) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { value: accessToken, source: 'cli' };
|
|
244
|
+
}
|
|
245
|
+
|
|
165
246
|
function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: AstroCommand) {
|
|
166
247
|
const configWithDefaults = {
|
|
167
248
|
basePath: partial.basePath ?? '/api',
|
|
@@ -181,15 +262,16 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
181
262
|
layout: partial.contentPanel?.layout ?? 'double-pane',
|
|
182
263
|
},
|
|
183
264
|
experimentalCollapsibleSnippets: partial.experimentalCollapsibleSnippets ?? false,
|
|
265
|
+
experimentalCollapsibleMethodDescriptions: partial.experimentalCollapsibleMethodDescriptions ?? false,
|
|
184
266
|
propertySettings: {
|
|
185
267
|
types: partial.propertySettings?.types ?? 'rich',
|
|
186
268
|
collapseDescription: partial.propertySettings?.collapseDescription ?? true,
|
|
269
|
+
showTitle: partial.propertySettings?.showTitle ?? false,
|
|
187
270
|
expandDepth: partial.propertySettings?.expandDepth ?? 0,
|
|
188
271
|
includeModelProperties: partial.propertySettings?.includeModelProperties ?? true,
|
|
189
272
|
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
},
|
|
273
|
+
contextMenu: partial.contextMenu ?? true,
|
|
274
|
+
experimentalPlaygrounds: partial.experimentalPlaygrounds ?? undefined,
|
|
193
275
|
};
|
|
194
276
|
|
|
195
277
|
function getSpecRetrieverConfig(): SpecRetrieverConfig {
|
|
@@ -205,7 +287,7 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
205
287
|
throw new Error('You must provide a stainlessProject when using Stainless Starlight');
|
|
206
288
|
}
|
|
207
289
|
|
|
208
|
-
const apiKey = partial.apiKey
|
|
290
|
+
const apiKey = loadApiKey(partial.apiKey);
|
|
209
291
|
|
|
210
292
|
const version = {
|
|
211
293
|
stainlessProject: partial.stainlessProject,
|
|
@@ -226,7 +308,14 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
226
308
|
|
|
227
309
|
if (!apiKey) {
|
|
228
310
|
throw new Error(
|
|
229
|
-
|
|
311
|
+
[
|
|
312
|
+
bold(
|
|
313
|
+
'No Stainless credentials found. Please choose one of the following options to authenticate with Stainless:',
|
|
314
|
+
),
|
|
315
|
+
'- Run `stl auth login` to authenticate via the Stainless CLI',
|
|
316
|
+
'- Provide a Stainless API key via the `STAINLESS_API_KEY` environment variable (eg. in a .env file)',
|
|
317
|
+
'- Set the `apiKey` option in the Stainless Docs config',
|
|
318
|
+
].join('\n'),
|
|
230
319
|
);
|
|
231
320
|
}
|
|
232
321
|
|
|
@@ -249,11 +338,11 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
|
|
|
249
338
|
export type NormalizedStainlessStarlightConfig = ReturnType<typeof normalizeConfig>;
|
|
250
339
|
|
|
251
340
|
/*
|
|
252
|
-
The goal of the code in this file is to take a user's config and normalize it.
|
|
341
|
+
The goal of the code in this file is to take a user's config and normalize it.
|
|
253
342
|
Specifically: we want a single complete config format used throughout the internals of the plugin.
|
|
254
343
|
|
|
255
344
|
We've tried to avoid any config values being optional/undefined. To accomplish this:
|
|
256
|
-
- Any optional config values should have their defaults set here: eg. basePath defaults to /api
|
|
345
|
+
- Any optional config values should have their defaults set here: eg. basePath defaults to /api
|
|
257
346
|
- If a field is only used in certain contexts, we make each context a discriminated union (see SpecRetrieverConfig)
|
|
258
347
|
- We prefer empty arrays over undefined/null
|
|
259
348
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TransformRequestSnippetFn } from '@stainless-api/docs-ui/
|
|
1
|
+
import type { TransformRequestSnippetFn } from '@stainless-api/docs-ui/components/sdk';
|
|
2
2
|
|
|
3
3
|
export type StlStarlightMiddleware = {
|
|
4
4
|
transformRequestSnippet?: TransformRequestSnippetFn;
|