@stainless-api/docs 0.1.0-beta.53 → 0.1.0-beta.56

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/plugin/index.ts CHANGED
@@ -4,7 +4,7 @@ import type { AstroIntegration, AstroIntegrationLogger } from 'astro';
4
4
  import type { BundledTheme } from 'shiki';
5
5
  import { config } from 'dotenv';
6
6
  import getPort from 'get-port';
7
- import { startDevServer } from './cms/server';
7
+ import { startDevServer, type SpecResp } from './cms/server';
8
8
  import { buildAlgoliaIndex } from './buildAlgoliaIndex';
9
9
  import {
10
10
  getAPIReferencePlaceholderItemFromSidebarConfig,
@@ -27,6 +27,9 @@ import path from 'path';
27
27
  import fs from 'fs';
28
28
  import { getSharedLogger } from '../shared/getSharedLogger';
29
29
  import { resolveSrcFile } from '../resolveSrcFile';
30
+ import { mkdir } from 'fs/promises';
31
+ import { fileURLToPath } from 'url';
32
+ import prebundleWorkers from 'vite-plugin-prebundle-workers';
30
33
 
31
34
  export { generateAPILink } from './generateAPIReferenceLink';
32
35
  export type { ReferenceSidebarConfigItem };
@@ -119,6 +122,8 @@ async function stlStarlightAstroIntegration(
119
122
  const virtualId = `virtual:stl-starlight-virtual-module`;
120
123
  // The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
121
124
  const resolvedId = `\0${virtualId}`;
125
+ let playgroundsBase: string | undefined;
126
+ let buildPlaygrounds;
122
127
 
123
128
  const CMS_PORT = await getPort();
124
129
 
@@ -139,6 +144,38 @@ async function stlStarlightAstroIntegration(
139
144
  },
140
145
  });
141
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
+
142
179
  return {
143
180
  name: 'stl-starlight-astro',
144
181
  hooks: {
@@ -152,6 +189,12 @@ async function stlStarlightAstroIntegration(
152
189
  const logger = getSharedLogger({ fallback: localLogger });
153
190
  const projectDir = astroConfig.root.pathname;
154
191
 
192
+ reportError = (message: string) => logger.error(message);
193
+
194
+ if (pluginConfig.experimentalPlaygrounds) {
195
+ playgroundsBase = pluginConfig.experimentalPlaygrounds.playgroundsBase;
196
+ }
197
+
155
198
  const middlewareFile = path.join(projectDir, 'middleware.stainless.ts');
156
199
 
157
200
  let vmMiddlewareExport = 'export const MIDDLEWARE = {};';
@@ -184,7 +227,15 @@ async function stlStarlightAstroIntegration(
184
227
  plugins: [
185
228
  {
186
229
  name: 'stl-starlight-vite',
187
- configureServer(server) {
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
+
188
239
  for (const filePath of Object.values(devPaths)) {
189
240
  if (!filePath) {
190
241
  continue;
@@ -207,6 +258,30 @@ async function stlStarlightAstroIntegration(
207
258
  if (id === virtualId) {
208
259
  return resolvedId;
209
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
+ }
210
285
  },
211
286
  load(id) {
212
287
  if (id === resolvedId) {
@@ -214,7 +289,7 @@ async function stlStarlightAstroIntegration(
214
289
  buildVirtualModuleString({
215
290
  BASE_PATH: pluginConfig.basePath,
216
291
  CMS_PORT,
217
- EXCLUDE_LANGUAGES: pluginConfig.excludeLanguages,
292
+ EXCLUDE_LANGUAGES: ['php', ...pluginConfig.excludeLanguages],
218
293
  DEFAULT_LANGUAGE: pluginConfig.defaultLanguage,
219
294
  BREADCRUMB_CONFIG: pluginConfig.breadcrumbs,
220
295
  EXPAND_RESOURCES: pluginConfig.expandResources,
@@ -225,12 +300,28 @@ async function stlStarlightAstroIntegration(
225
300
  pluginConfig.experimentalCollapsibleMethodDescriptions,
226
301
  PROPERTY_SETTINGS: pluginConfig.propertySettings,
227
302
  ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
303
+ EXPERIMENTAL_PLAYGROUNDS: !!pluginConfig.experimentalPlaygrounds,
228
304
  } satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
229
305
  vmMiddlewareExport,
230
306
  ].join('\n');
231
307
  }
232
308
  },
233
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
+ }),
234
325
  ],
235
326
  },
236
327
  });
@@ -238,6 +329,24 @@ async function stlStarlightAstroIntegration(
238
329
  'astro:server:done': async () => {
239
330
  await cmsServer.destroy();
240
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
+ },
241
350
  },
242
351
  };
243
352
  }
@@ -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) {
@@ -129,7 +129,14 @@ export type StainlessStarlightUserConfig = {
129
129
  *
130
130
  * @default true
131
131
  */
132
+
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 };
133
140
  };
134
141
 
135
142
  export type ExternalSpecServerUserConfig = Omit<StainlessStarlightUserConfig, 'stainlessProject'> & {
@@ -259,10 +266,12 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, command: Ast
259
266
  propertySettings: {
260
267
  types: partial.propertySettings?.types ?? 'rich',
261
268
  collapseDescription: partial.propertySettings?.collapseDescription ?? true,
269
+ showTitle: partial.propertySettings?.showTitle ?? false,
262
270
  expandDepth: partial.propertySettings?.expandDepth ?? 0,
263
271
  includeModelProperties: partial.propertySettings?.includeModelProperties ?? true,
264
272
  },
265
273
  contextMenu: partial.contextMenu ?? true,
274
+ experimentalPlaygrounds: partial.experimentalPlaygrounds ?? undefined,
266
275
  };
267
276
 
268
277
  function getSpecRetrieverConfig(): SpecRetrieverConfig {
@@ -55,7 +55,12 @@ import {
55
55
  } from 'virtual:stl-starlight-virtual-module';
56
56
  import style from '@stainless-api/docs-ui/style';
57
57
  import { BundledTheme, createHighlighter, HighlighterGeneric, type BundledLanguage } from 'shiki';
58
- import { SnippetCode, SnippetContainer, SnippetRequestContainer } from '../components/SnippetCode';
58
+ import {
59
+ SnippetCode,
60
+ SnippetContainer,
61
+ SnippetRequestContainer,
62
+ SnippetButtons,
63
+ } from '../components/SnippetCode';
59
64
  import type { StlStarlightMiddleware } from '../middlewareBuilder/stainlessMiddleware';
60
65
  import { ComponentProvider } from '@stainless-api/docs-ui/contexts/component';
61
66
  import { AIDropdown } from '../../stl-docs/components/AIDropdown';
@@ -266,13 +271,13 @@ function SDKRequestTitle({ snippetLanguage }: SDKRequestTitleProps) {
266
271
  selected={selected || 'http'}
267
272
  languages={languages}
268
273
  id="stldocs-snippet-select"
269
- className="stl-sdk-select"
274
+ className="stl-sdk-select stl-ui-not-prose"
270
275
  />
271
276
  );
272
277
  }
273
278
 
274
279
  export type SpecMetadata = [
275
- 'http' | 'node' | 'python' | 'go' | 'typescript' | 'terraform' | 'ruby' | 'java' | 'kotlin',
280
+ DocsLanguage,
276
281
  {
277
282
  repo_url?: string;
278
283
  code_url?: string;
@@ -282,9 +287,18 @@ export type SpecMetadata = [
282
287
  },
283
288
  ][];
284
289
 
290
+ const componentOverrides = {
291
+ SDKRequestTitle,
292
+ SnippetCode,
293
+ SnippetContainer,
294
+ SnippetRequestContainer,
295
+ SnippetButtons,
296
+ ...(EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS ? { MethodDescription } : {}),
297
+ };
298
+
285
299
  export function RenderLibraries({ metadata }: { metadata: SpecMetadata }) {
286
300
  return (
287
- <ComponentProvider components={{}}>
301
+ <ComponentProvider components={componentOverrides}>
288
302
  {metadata.map(([language, data]) => (
289
303
  <SDKLanguageBlock
290
304
  language={language}
@@ -302,14 +316,7 @@ export function RenderSpecOverview({ spec, language }: { spec: SDKJSON.Spec; lan
302
316
 
303
317
  return (
304
318
  <DocsProvider spec={spec} language={language ?? 'node'}>
305
- <ComponentProvider
306
- components={{
307
- SDKRequestTitle,
308
- SnippetCode,
309
- SnippetContainer,
310
- SnippetRequestContainer,
311
- }}
312
- >
319
+ <ComponentProvider components={componentOverrides}>
313
320
  <NavigationProvider basePath={BASE_PATH}>
314
321
  <MarkdownProvider render={renderMarkdown} highlight={highlight}>
315
322
  <div className={style.Overview}>
@@ -365,15 +372,7 @@ export function RenderSpec({
365
372
  properties: PROPERTY_SETTINGS,
366
373
  }}
367
374
  >
368
- <ComponentProvider
369
- components={{
370
- SDKRequestTitle,
371
- SnippetCode,
372
- SnippetContainer,
373
- SnippetRequestContainer,
374
- ...(EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS ? { MethodDescription } : {}),
375
- }}
376
- >
375
+ <ComponentProvider components={componentOverrides}>
377
376
  <NavigationProvider basePath={BASE_PATH} selectedPath={path}>
378
377
  <MarkdownProvider render={renderMarkdown} highlight={highlight}>
379
378
  {
@@ -498,7 +497,7 @@ async function astroHighlight() {
498
497
  }
499
498
 
500
499
  // Astro's markdown processor is a singleton
501
- // Need to cache it instead of instanting per request
500
+ // Need to cache it instead of instantiating per request
502
501
  let astroMarkdownProcessor: MarkdownProcessor;
503
502
  async function astroMarkdown() {
504
503
  if (!astroMarkdownProcessor) {