@stainless-api/docs 0.1.0-beta.87 → 0.1.0-beta.88

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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # @stainless-api/docs
2
2
 
3
+ ## 0.1.0-beta.88
4
+
5
+ ### Minor Changes
6
+
7
+ - c1fb4e5: remove CMS server; refactor and simplify spec generation pipeline
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [65a1c9b]
12
+ - Updated dependencies [4f1cee7]
13
+ - Updated dependencies [4c72a83]
14
+ - Updated dependencies [068469b]
15
+ - @stainless-api/docs-ui@0.1.0-beta.66
16
+ - @stainless-api/docs-search@0.1.0-beta.19
17
+
3
18
  ## 0.1.0-beta.87
4
19
 
5
20
  ### Patch Changes
@@ -4,26 +4,6 @@
4
4
  "count": 2
5
5
  }
6
6
  },
7
- "plugin/cms/client.ts": {
8
- "@typescript-eslint/no-explicit-any": {
9
- "count": 1
10
- }
11
- },
12
- "plugin/cms/server.ts": {
13
- "@typescript-eslint/no-explicit-any": {
14
- "count": 3
15
- }
16
- },
17
- "plugin/cms/sidebar-builder.ts": {
18
- "@typescript-eslint/no-explicit-any": {
19
- "count": 1
20
- }
21
- },
22
- "plugin/cms/worker.ts": {
23
- "@typescript-eslint/no-explicit-any": {
24
- "count": 3
25
- }
26
- },
27
7
  "plugin/components/SnippetCode.tsx": {
28
8
  "@typescript-eslint/no-explicit-any": {
29
9
  "count": 1
@@ -44,9 +24,9 @@
44
24
  "count": 1
45
25
  }
46
26
  },
47
- "shared/virtualModule.ts": {
27
+ "plugin/specs/worker.ts": {
48
28
  "@typescript-eslint/no-explicit-any": {
49
- "count": 1
29
+ "count": 3
50
30
  }
51
31
  }
52
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/docs",
3
- "version": "0.1.0-beta.87",
3
+ "version": "0.1.0-beta.88",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -18,7 +18,7 @@
18
18
  "./components": "./stl-docs/components/index.ts",
19
19
  "./components/scripts": "./stl-docs/components/scripts.ts",
20
20
  "./docs-config": "./stl-docs/loadStlDocsConfig.ts",
21
- "./cms-client": "./plugin/cms/client.ts",
21
+ "./specs/fetchSpecSSR": "./plugin/specs/fetchSpecSSR.ts",
22
22
  "./generate-docs-routes": "./plugin/helpers/generateDocsRoutes.ts",
23
23
  "./components/Head": "./stl-docs/components/Head.astro",
24
24
  "./components/ContentBreadcrumbs": "./stl-docs/components/ContentBreadcrumbs.tsx"
@@ -44,7 +44,6 @@
44
44
  "cheerio": "^1.1.2",
45
45
  "clsx": "^2.1.1",
46
46
  "dotenv": "17.2.3",
47
- "get-port": "^7.1.0",
48
47
  "lucide-react": "^0.562.0",
49
48
  "marked": "^17.0.1",
50
49
  "node-html-parser": "^7.0.1",
@@ -58,8 +57,8 @@
58
57
  "vite-plugin-prebundle-workers": "^0.2.0",
59
58
  "web-worker": "^1.5.0",
60
59
  "yaml": "^2.8.2",
61
- "@stainless-api/docs-search": "0.1.0-beta.18",
62
- "@stainless-api/docs-ui": "0.1.0-beta.65",
60
+ "@stainless-api/docs-search": "0.1.0-beta.19",
61
+ "@stainless-api/docs-ui": "0.1.0-beta.66",
63
62
  "@stainless-api/ui-primitives": "0.1.0-beta.46"
64
63
  },
65
64
  "devDependencies": {
@@ -0,0 +1,96 @@
1
+ declare module 'virtual:stl-playground/typescript.json' {
2
+ const data: {
3
+ links: [string, string][];
4
+ files: [string, string][];
5
+ } | null;
6
+ export { data as default };
7
+ }
8
+ declare module 'virtual:stl-playground/python.json' {
9
+ const data: { files: Record<string, string>; wheel: string } | null;
10
+ export { data as default };
11
+ }
12
+ declare module 'virtual:stl-playground/auth.json' {
13
+ const data:
14
+ | ({
15
+ type: 'http_bearer' | 'query' | 'header' | 'oauth2' | 'http_basic' | 'http_digest';
16
+ description?: string;
17
+ name: string;
18
+ title: string;
19
+ header: string | undefined;
20
+ example: string | undefined;
21
+ } & {
22
+ opts: {
23
+ name: string;
24
+ type: 'string' | 'number' | 'boolean' | 'null' | 'integer';
25
+ nullable: boolean;
26
+ description?: string | undefined;
27
+ example?: unknown;
28
+ default?: unknown;
29
+ read_env?: string | undefined;
30
+ auth?:
31
+ | {
32
+ security_scheme: string;
33
+ role?: 'value' | 'password' | 'username' | 'client_id' | 'client_secret' | undefined;
34
+ }
35
+ | undefined;
36
+ }[];
37
+ })[]
38
+ | null;
39
+ export { data as default };
40
+ }
41
+ declare module 'virtual:stl-playground/data' {
42
+ import type { Config } from 'virtual:stl-playground/create';
43
+ declare const data: Config;
44
+ export { data as default };
45
+ }
46
+ declare module 'virtual:stl-playground/create' {
47
+ export type PlaygroundLanguage = 'python' | 'typescript' | 'http';
48
+ export type Config = {
49
+ wheelUrl: string;
50
+ pyTypes: {
51
+ files: Record<string, string>;
52
+ wheel: string;
53
+ } | null;
54
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ HIGHLIGHT_THEMES: any;
56
+ tsTypes: {
57
+ links: [string, string][];
58
+ files: [string, string][];
59
+ } | null;
60
+ authData:
61
+ | ({
62
+ type: 'http_bearer' | 'query' | 'header' | 'oauth2' | 'http_basic' | 'http_digest';
63
+ description?: string;
64
+ name: string;
65
+ title: string;
66
+ header: string | undefined;
67
+ example: string | undefined;
68
+ } & {
69
+ opts: {
70
+ name: string;
71
+ type: 'string' | 'number' | 'boolean' | 'null' | 'integer';
72
+ nullable: boolean;
73
+ description?: string | undefined;
74
+ example?: unknown;
75
+ default?: unknown;
76
+ read_env?: string | undefined;
77
+ auth?:
78
+ | {
79
+ security_scheme: string;
80
+ role?: 'value' | 'password' | 'username' | 'client_id' | 'client_secret' | undefined;
81
+ }
82
+ | undefined;
83
+ }[];
84
+ })[]
85
+ | null;
86
+ };
87
+ export function createPlayground(
88
+ props: {
89
+ lang: PlaygroundLanguage;
90
+ doc: string;
91
+ /** div.stl-snippet-request-container */
92
+ container: HTMLElement;
93
+ onLanguageSelect: (value: string) => void;
94
+ } & Config,
95
+ ): () => Promise<void>;
96
+ }
@@ -1,10 +1,9 @@
1
1
  import Markdoc from '@markdoc/markdoc';
2
2
  import Stainless from '@stainless-api/sdk';
3
- import { createSDKJSON, parseInputs, transformOAS } from './cms/worker';
3
+ import { createSDKJSON, parseInputs, transformOAS } from './specs/worker';
4
4
  import type * as SDKJSON from '@stainless/sdk-json';
5
5
  import { Languages } from '@stainless-api/docs-ui/routing';
6
6
  import { buildIndex } from '@stainless-api/docs-search/providers/algolia';
7
- import type { VersionUserConfig } from './loadPluginConfig';
8
7
  import type { AstroIntegrationLogger } from 'astro';
9
8
 
10
9
  const markdocConfig = {
@@ -22,11 +21,13 @@ function renderMarkdown(content?: string) {
22
21
  }
23
22
 
24
23
  export async function buildAlgoliaIndex({
25
- version,
24
+ stainlessProject,
25
+ branch,
26
26
  apiKey,
27
27
  logger,
28
28
  }: {
29
- version: VersionUserConfig;
29
+ stainlessProject: string;
30
+ branch: string;
30
31
  apiKey: string;
31
32
  logger?: AstroIntegrationLogger;
32
33
  }) {
@@ -46,10 +47,11 @@ export async function buildAlgoliaIndex({
46
47
  }
47
48
  }
48
49
 
50
+ // TODO: this is all redundant with the spec code and should be DRYed
49
51
  const client = new Stainless({ apiKey });
50
52
  const configs = await client.projects.configs.retrieve({
51
- project: version.stainlessProject,
52
- branch: version.branch,
53
+ project: stainlessProject,
54
+ branch,
53
55
  include: 'openapi',
54
56
  });
55
57
 
@@ -74,7 +76,7 @@ export async function buildAlgoliaIndex({
74
76
  oas: transformedOAS,
75
77
  config,
76
78
  languages,
77
- projectName: version.stainlessProject,
79
+ projectName: stainlessProject,
78
80
  });
79
81
 
80
82
  const {
@@ -1,10 +1,10 @@
1
1
  ---
2
- import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
3
2
  import { parseRoute } from '@stainless-api/docs-ui/routing';
4
- import { cmsClient } from '../cms/client';
5
3
  import { BASE_PATH, DEFAULT_LANGUAGE, EXCLUDE_LANGUAGES } from 'virtual:stl-starlight-virtual-module';
6
4
  import { Languages } from '../languages';
7
5
  import { SDKSelectReactComponent } from '../react/Routing';
6
+ import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
7
+ import { getDocsLanguages } from '../helpers/getDocsLanguages';
8
8
 
9
9
  const slug = `/${Astro.locals.starlightRoute.id}`;
10
10
 
@@ -19,17 +19,13 @@ const data = {
19
19
  defaultLanguage,
20
20
  };
21
21
 
22
- const spec = await cmsClient.getSpec();
22
+ const spec = await getSDKJSONInSSR();
23
23
 
24
- // TODO: should not force unwrap this
25
- const languages: DocsLanguage[] = spec.docs!.languages ?? ['http'];
26
- const options = languages
27
- .filter((language) => !EXCLUDE_LANGUAGES.includes(language))
28
- .map((value) => ({
29
- value,
30
- label: Languages[value].name,
31
- selected: data.language === value,
32
- }));
24
+ const options = getDocsLanguages(spec, EXCLUDE_LANGUAGES).map((value) => ({
25
+ value,
26
+ label: Languages[value].name,
27
+ selected: data.language === value,
28
+ }));
33
29
 
34
30
  const readmeSlug = language === 'http' ? BASE_PATH : `${BASE_PATH}/${language}`;
35
31
  ---
@@ -0,0 +1,9 @@
1
+ import { DocsLanguage } from '@stainless-api/docs-ui/routing';
2
+ import type * as SDKJSON from '@stainless/sdk-json';
3
+
4
+ export function getDocsLanguages(spec: SDKJSON.Spec, excludeLanguages: DocsLanguage[]) {
5
+ // TODO: should not force unwrap this
6
+ const languages: DocsLanguage[] = spec.docs!.languages ?? ['http'];
7
+
8
+ return languages.filter((language) => !excludeLanguages.includes(language));
9
+ }
package/plugin/index.ts CHANGED
@@ -1,27 +1,26 @@
1
1
  import react from '@astrojs/react';
2
2
  import type { StarlightPlugin } from '@astrojs/starlight/types';
3
- import type { AstroIntegration, AstroIntegrationLogger } from 'astro';
3
+ import type { AstroIntegration } from 'astro';
4
4
  import type { BundledTheme } from 'shiki';
5
5
  import { config } from 'dotenv';
6
- import getPort from 'get-port';
7
- import { DevSpecServer, startDevServer, type SpecResp } from './cms/server';
8
6
  import { buildAlgoliaIndex } from './buildAlgoliaIndex';
9
7
  import {
10
8
  getAPIReferencePlaceholderItemFromSidebarConfig,
11
9
  makePlaceholderItems,
12
10
  } from './referencePlaceholderUtils';
13
- import type {
14
- GeneratedSidebarConfig,
15
- ReferenceSidebarConfigGenerateOptions,
16
- ReferenceSidebarConfigItem,
17
- } from './cms/sidebar-builder';
11
+ import {
12
+ SidebarConfigItemsBuilder,
13
+ toStarlightSidebar,
14
+ type GeneratedSidebarConfig,
15
+ type ReferenceSidebarConfigGenerateOptions,
16
+ type ReferenceSidebarConfigItem,
17
+ } from './sidebar-utils/sidebar-builder';
18
18
  import {
19
19
  parseStarlightPluginConfig,
20
20
  type NormalizedStainlessStarlightConfig,
21
21
  type SomeStainlessStarlightUserConfig,
22
- type SpecRetrieverConfig,
23
22
  } from './loadPluginConfig';
24
- import { buildVirtualModuleString } from '../shared/virtualModule';
23
+ import { buildVirtualModuleString, makeAsyncVirtualModPlugin } from '../shared/virtualModule';
25
24
  import type * as StlStarlightVirtualModule from 'virtual:stl-starlight-virtual-module';
26
25
  import path from 'path';
27
26
  import fs from 'fs';
@@ -30,6 +29,10 @@ import { resolveSrcFile } from '../resolveSrcFile';
30
29
  import { mkdir, writeFile } from 'fs/promises';
31
30
  import { fileURLToPath } from 'url';
32
31
  import prebundleWorkers from 'vite-plugin-prebundle-workers';
32
+ import { SpecLoader, startSpecLoader } from './specs';
33
+
34
+ import type * as ReferenceSidebarsVirtualModule from 'virtual:stl-starlight-reference-sidebars';
35
+ import { getDocsLanguages } from './helpers/getDocsLanguages';
33
36
  import { generateMissingRouteList } from '@stainless-api/docs-ui/routing';
34
37
 
35
38
  export { generateAPILink } from './generateAPIReferenceLink';
@@ -88,37 +91,8 @@ export function generateAPIReferenceItems(
88
91
  return makePlaceholderItems(id);
89
92
  }
90
93
 
91
- function tmpGetCMSServerConfig(specRetrieverConfig: SpecRetrieverConfig) {
92
- if (specRetrieverConfig.kind === 'external_spec_server') {
93
- throw new Error('External spec server is not yet supported');
94
- }
95
- if (specRetrieverConfig.kind === 'local_spec_server_with_files') {
96
- if (!specRetrieverConfig.apiKey) {
97
- throw new Error('API key is required');
98
- }
99
- return {
100
- apiKey: specRetrieverConfig.apiKey,
101
- version: specRetrieverConfig.version,
102
- devPaths: specRetrieverConfig.devPaths,
103
- };
104
- }
105
-
106
- if (specRetrieverConfig.kind === 'local_spec_server_with_remote_files') {
107
- return {
108
- apiKey: specRetrieverConfig.apiKey,
109
- version: specRetrieverConfig.version,
110
- devPaths: {
111
- oasPath: undefined,
112
- configPath: undefined,
113
- },
114
- };
115
- }
116
- throw new Error('Invalid spec retriever config');
117
- }
118
-
119
94
  async function stlStarlightAstroIntegration(
120
95
  pluginConfig: NormalizedStainlessStarlightConfig,
121
- stlStarlightPluginLogger: AstroIntegrationLogger,
122
96
  ): Promise<AstroIntegration> {
123
97
  const virtualId = `virtual:stl-starlight-virtual-module`;
124
98
  // The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
@@ -127,11 +101,15 @@ async function stlStarlightAstroIntegration(
127
101
  let buildPlaygrounds;
128
102
  let astroBase = '/';
129
103
 
130
- const CMS_PORT = await getPort();
131
-
132
- const { apiKey, version, devPaths } = tmpGetCMSServerConfig(pluginConfig.specRetrieverConfig);
133
-
134
- let cmsServer: DevSpecServer | undefined;
104
+ let specLoader: SpecLoader | undefined;
105
+ async function getSpec() {
106
+ if (!specLoader) throw new Error('Expected spec loader to exist');
107
+ const result = await specLoader.specPromise;
108
+ return {
109
+ spec: result.spec.data,
110
+ auth: result.spec.auth,
111
+ };
112
+ }
135
113
 
136
114
  let building: Promise<void> | undefined;
137
115
  let reportError: ((message: string) => void) | null = null;
@@ -141,17 +119,9 @@ async function stlStarlightAstroIntegration(
141
119
  if (!pluginConfig.experimentalPlaygrounds) return;
142
120
  if (building) return building;
143
121
  return (building = (async () => {
144
- const { data: spec, auth } = (await (
145
- await fetch(`http://localhost:${CMS_PORT}/retrieve_spec`, {
146
- method: 'POST',
147
- body: JSON.stringify({}),
148
- })
149
- ).json()) as SpecResp;
150
- if (!spec || !auth) throw new Error('expected spec');
151
-
152
- const langs = (spec.docs?.languages ?? ['http']).filter(
153
- (lang) => !pluginConfig.excludeLanguages?.includes(lang),
154
- );
122
+ const { spec, auth } = await getSpec();
123
+
124
+ const langs = getDocsLanguages(spec, pluginConfig.excludeLanguages);
155
125
 
156
126
  await buildPlaygrounds!({
157
127
  spec,
@@ -180,28 +150,13 @@ async function stlStarlightAstroIntegration(
180
150
  const projectDir = astroConfig.root.pathname;
181
151
  astroBase = astroConfig.base;
182
152
 
183
- const codegenDir = createCodegenDir().pathname;
184
-
185
- let specCacheDirectory: string | null = null;
186
- if (command === 'dev') {
187
- specCacheDirectory = path.join(codegenDir, 'spec_cache');
188
- fs.mkdirSync(specCacheDirectory, { recursive: true });
189
- }
190
-
191
- cmsServer = startDevServer({
192
- port: CMS_PORT,
193
- apiKey: apiKey.value,
194
- version,
195
- devPaths,
196
- logger: stlStarlightPluginLogger,
197
- specCacheDirectory,
198
- getGeneratedSidebarConfig: (id: number) => {
199
- const config = sidebarConfigs.get(id);
200
- if (!config) {
201
- return null;
202
- }
203
- return config;
204
- },
153
+ specLoader = await startSpecLoader(pluginConfig, logger, createCodegenDir());
154
+ specLoader.specPromise.then((specResult) => {
155
+ if (specResult.result === 'generated') {
156
+ logger.info(`Generated new SDKJSON`);
157
+ } else if (specResult.result === 'exists') {
158
+ logger.info(`Loaded SDKJSON`);
159
+ }
205
160
  });
206
161
 
207
162
  reportError = (message: string) => logger.error(message);
@@ -240,6 +195,55 @@ async function stlStarlightAstroIntegration(
240
195
  updateConfig({
241
196
  vite: {
242
197
  plugins: [
198
+ makeAsyncVirtualModPlugin<typeof ReferenceSidebarsVirtualModule>(
199
+ 'virtual:stl-starlight-reference-sidebars',
200
+ async () => {
201
+ const { spec } = await getSpec();
202
+ const languages = getDocsLanguages(spec, pluginConfig.excludeLanguages);
203
+
204
+ const sidebars = [...sidebarConfigs.entries()]
205
+ // produce all { id, language } combos with the attached config
206
+ // flattens to one item per language * id combo
207
+ .flatMap(([id, config]) =>
208
+ languages.map((language) => ({
209
+ id,
210
+ config,
211
+ language,
212
+ })),
213
+ )
214
+ // produce a sidebar for each
215
+ // later we will .find() the sidebar that matches the (id, language)
216
+ .map(({ id, config, language }) => {
217
+ const configItemsBuilder = new SidebarConfigItemsBuilder(
218
+ spec,
219
+ language,
220
+ config.options,
221
+ );
222
+
223
+ let userSidebarConfig = configItemsBuilder.generateItems();
224
+ if (config.transformFn) {
225
+ const transformedSidebarConfig = config.transformFn(userSidebarConfig, language);
226
+ if (transformedSidebarConfig) userSidebarConfig = transformedSidebarConfig;
227
+ }
228
+
229
+ return {
230
+ id,
231
+ language,
232
+ // this has to run multpile times because it depends on the
233
+ // userSidebarConfig (which is per-id) and the language
234
+ entries: toStarlightSidebar({
235
+ basePath: path.posix.join(astroBase, pluginConfig.basePath), // TODO, is this right?
236
+ spec,
237
+ entries: userSidebarConfig,
238
+ currentLanguage: language,
239
+ }),
240
+ };
241
+ });
242
+
243
+ return { sidebars };
244
+ },
245
+ ),
246
+ specLoader.vitePlugin,
243
247
  {
244
248
  name: 'stl-starlight-vite',
245
249
  buildStart() {
@@ -251,23 +255,7 @@ async function stlStarlightAstroIntegration(
251
255
  .buildPlaygrounds;
252
256
  }
253
257
 
254
- for (const filePath of Object.values(devPaths)) {
255
- if (!filePath) {
256
- continue;
257
- }
258
- server.watcher.add(filePath);
259
- }
260
-
261
- server.watcher.on('change', async (changed) => {
262
- if (Object.values(devPaths).includes(changed)) {
263
- logger.info(`${changed} changed, reloading...`);
264
- cmsServer?.invalidate();
265
- server.hot.send({
266
- type: 'full-reload',
267
- path: '*',
268
- });
269
- }
270
- });
258
+ // TODO: eventually - re-add support for watching local input changes (eg. reloading when OAS/config files change)
271
259
  },
272
260
  resolveId(id) {
273
261
  if (id === virtualId) {
@@ -313,8 +301,7 @@ async function stlStarlightAstroIntegration(
313
301
  return [
314
302
  buildVirtualModuleString({
315
303
  BASE_PATH: path.posix.join(astroConfig.base, pluginConfig.basePath),
316
- CMS_PORT,
317
- EXCLUDE_LANGUAGES: ['php', ...pluginConfig.excludeLanguages],
304
+ EXCLUDE_LANGUAGES: pluginConfig.excludeLanguages,
318
305
  DEFAULT_LANGUAGE: pluginConfig.defaultLanguage,
319
306
  BREADCRUMB_CONFIG: pluginConfig.breadcrumbs,
320
307
  EXPAND_RESOURCES: pluginConfig.expandResources,
@@ -327,7 +314,7 @@ async function stlStarlightAstroIntegration(
327
314
  ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
328
315
  EXPERIMENTAL_PLAYGROUNDS: !!pluginConfig.experimentalPlaygrounds,
329
316
  EXPERIMENTAL_REQUEST_BUILDER: pluginConfig.experimentalRequestBuilder,
330
- STAINLESS_PROJECT: version.stainlessProject,
317
+ STAINLESS_PROJECT: pluginConfig.specInputs.project,
331
318
  } satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
332
319
  vmMiddlewareExport,
333
320
  ].join('\n');
@@ -353,9 +340,6 @@ async function stlStarlightAstroIntegration(
353
340
  },
354
341
  });
355
342
  },
356
- 'astro:server:done': async () => {
357
- await cmsServer?.destroy();
358
- },
359
343
  'astro:build:start'({ logger }) {
360
344
  collectedErrors = [];
361
345
  reportError = (message: string) => {
@@ -384,25 +368,16 @@ async function stlStarlightAstroIntegration(
384
368
  // Instead of showing a generic 404, we statically generate pages for these routes and mark them
385
369
  // in this file so Cloudflare can serve them with a 404 status. These pages display helpful information
386
370
  // about the missing method and provide links to SDKs where it is available.
387
- const { data: spec } = (await (
388
- await fetch(`http://localhost:${CMS_PORT}/retrieve_spec`, {
389
- method: 'POST',
390
- body: JSON.stringify({}),
391
- })
392
- ).json()) as SpecResp;
393
- if (spec) {
394
- const missingRoutes = await generateMissingRouteList({
395
- spec,
396
- basePath: path.posix.join(astroBase, pluginConfig.basePath),
397
- });
398
- await mkdir(stainlessDir, { recursive: true });
399
- await writeFile(
400
- path.join(stainlessDir, 'missing-routes.json'),
401
- JSON.stringify(missingRoutes, null, 2),
402
- );
403
- } else {
404
- console.log('Could not retrieve spec for missing routes check');
405
- }
371
+ const { spec } = await getSpec();
372
+ const missingRoutes = generateMissingRouteList({
373
+ spec,
374
+ basePath: path.posix.join(astroBase, pluginConfig.basePath),
375
+ });
376
+ await mkdir(stainlessDir, { recursive: true });
377
+ await writeFile(
378
+ path.join(stainlessDir, 'missing-routes.json'),
379
+ JSON.stringify(missingRoutes, null, 2),
380
+ );
406
381
  },
407
382
  },
408
383
  };
@@ -444,40 +419,41 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
444
419
  addIntegration(react());
445
420
  }
446
421
 
447
- if ('apiKey' in config.specRetrieverConfig) {
448
- if (!config.specRetrieverConfig.apiKey) {
422
+ if ('apiKey' in config.specInputs) {
423
+ if (!config.specInputs.apiKey) {
449
424
  logger.info(`Stainless credentials not loaded`);
450
- } else if (config.specRetrieverConfig.apiKey.source === 'explicit-config') {
425
+ } else if (config.specInputs.apiKey.source === 'explicit-config') {
451
426
  logger.info(`Stainless credentials loaded from user config`);
452
- } else if (config.specRetrieverConfig.apiKey.source === 'environment-variable') {
427
+ } else if (config.specInputs.apiKey.source === 'environment-variable') {
453
428
  logger.info('Stainless credentials loaded from `STAINLESS_API_KEY` environment variable');
454
- } else if (config.specRetrieverConfig.apiKey.source === 'cli') {
429
+ } else if (config.specInputs.apiKey.source === 'cli') {
455
430
  logger.info('Stainless credentials loaded from `stl` CLI');
456
431
  }
457
432
  }
458
433
 
459
- if (
460
- command === 'build' &&
461
- config.specRetrieverConfig.kind === 'local_spec_server_with_remote_files'
462
- ) {
434
+ if (command === 'build' && config.specInputs.kind === 'stainless_api_inputs') {
463
435
  await buildAlgoliaIndex({
464
- version: config.specRetrieverConfig.version,
465
- apiKey: config.specRetrieverConfig.apiKey.value,
436
+ stainlessProject: config.specInputs.project,
437
+ branch: config.specInputs.branch,
438
+ apiKey: config.specInputs.apiKey.value,
466
439
  logger,
467
440
  });
468
441
  }
469
442
 
470
- addIntegration(await stlStarlightAstroIntegration(config, logger));
471
-
472
443
  if (starlightConfig.sidebar) {
473
444
  // for pagination (https://starlight.astro.build/reference/configuration/#pagination) to work correctly
474
445
  // update the placeholder link to be correct
475
- const item = getAPIReferencePlaceholderItemFromSidebarConfig(starlightConfig.sidebar);
476
- if (item && typeof item === 'object' && 'link' in item) {
477
- item.link = config.basePath;
446
+ for (const placeholder of getAPIReferencePlaceholderItemFromSidebarConfig(
447
+ starlightConfig.sidebar,
448
+ )) {
449
+ if (placeholder && typeof placeholder === 'object' && 'link' in placeholder) {
450
+ placeholder.link = config.basePath;
451
+ }
478
452
  }
479
453
  }
480
454
 
455
+ addIntegration(await stlStarlightAstroIntegration(config));
456
+
481
457
  const expressiveCodeConfig =
482
458
  typeof starlightConfig.expressiveCode === 'object' ? starlightConfig.expressiveCode : {};
483
459