@stainless-api/docs 1.0.0-beta.141 → 1.0.0-beta.142
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 +14 -0
- package/package.json +4 -4
- package/plugin/index.ts +2 -1
- package/plugin/loadPluginConfig.ts +4 -4
- package/plugin/specs/{defaultSpecLoader.ts → defaultSDKJSONLoader.ts} +7 -7
- package/plugin/specs/fetchSpecSSR.ts +10 -14
- package/plugin/specs/makeFileSystemSDKJSONFilesLoader.ts +63 -0
- package/plugin/specs/utils.ts +4 -4
- package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +17 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @stainless-api/docs
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.142
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 28bb924: updated API for SDKJSON
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 65c8fa0: Uses CSS for sidebar http icons instead of inline svg
|
|
12
|
+
- Updated dependencies [65c8fa0]
|
|
13
|
+
- Updated dependencies [28bb924]
|
|
14
|
+
- @stainless-api/docs-ui@1.0.0-beta.98
|
|
15
|
+
- @stainless-api/docs-search@1.0.0-beta.52
|
|
16
|
+
|
|
3
17
|
## 1.0.0-beta.141
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stainless-api/docs",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.142",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
"remend": "^1.3.0",
|
|
77
77
|
"shiki": "^4.0.2",
|
|
78
78
|
"unified": "^11.0.5",
|
|
79
|
-
"@stainless-api/docs-search": "1.0.0-beta.
|
|
80
|
-
"@stainless-api/docs-ui": "1.0.0-beta.
|
|
79
|
+
"@stainless-api/docs-search": "1.0.0-beta.52",
|
|
80
|
+
"@stainless-api/docs-ui": "1.0.0-beta.98",
|
|
81
81
|
"@stainless-api/ui-primitives": "1.0.0-beta.55",
|
|
82
82
|
"@stainless/sdk-json": "^0.1.0-beta.11"
|
|
83
83
|
},
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"react": "^19.2.6",
|
|
93
93
|
"react-dom": "^19.2.6",
|
|
94
94
|
"typescript": "6.0.3",
|
|
95
|
-
"vite": "^7.3.
|
|
95
|
+
"vite": "^7.3.3",
|
|
96
96
|
"vitest": "^4.1.5",
|
|
97
97
|
"zod": "^4.4.3",
|
|
98
98
|
"@stainless/eslint-config": "0.1.0-beta.2"
|
package/plugin/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ import { buildAlgoliaIndex } from './buildAlgoliaIndex';
|
|
|
39
39
|
import { flatSpecsList, loadAllSpecs, LoadedSpecs } from './specs/utils';
|
|
40
40
|
|
|
41
41
|
export { generateAPILink } from './generateAPIReferenceLink';
|
|
42
|
+
export { makeFileSystemSDKJSONFilesLoader } from './specs/makeFileSystemSDKJSONFilesLoader';
|
|
42
43
|
export type { ReferenceSidebarConfigItem };
|
|
43
44
|
|
|
44
45
|
config({
|
|
@@ -124,7 +125,7 @@ function stlStarlightAstroIntegration(pluginConfig: NormalizedStainlessStarlight
|
|
|
124
125
|
astroBase = astroConfig.base;
|
|
125
126
|
|
|
126
127
|
specsPromise = loadAllSpecs(
|
|
127
|
-
pluginConfig.
|
|
128
|
+
pluginConfig.loadSDKJSONFiles({
|
|
128
129
|
stainlessProject: pluginConfig.stainlessProject,
|
|
129
130
|
branch: pluginConfig.branch,
|
|
130
131
|
apiKey: pluginConfig.apiKey?.value ?? null,
|
|
@@ -6,8 +6,8 @@ import type { CreateShikiHighlighterOptions } from '@astrojs/markdown-remark';
|
|
|
6
6
|
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
7
7
|
import type { PropertySettingsType } from '@stainless-api/docs-ui/contexts';
|
|
8
8
|
|
|
9
|
-
import { defaultSpecLoader } from './specs/
|
|
10
|
-
import {
|
|
9
|
+
import { defaultSpecLoader } from './specs/defaultSDKJSONLoader';
|
|
10
|
+
import { SDKJSONFilesLoaderFn as SDKJSONFilesLoaderFn } from './specs/utils';
|
|
11
11
|
|
|
12
12
|
type ApiKeySource = 'explicit-config' | 'environment-variable' | 'cli';
|
|
13
13
|
|
|
@@ -54,7 +54,7 @@ export type StainlessStarlightUserConfig = {
|
|
|
54
54
|
/**
|
|
55
55
|
* Optional function to provide your own loader for API reference data.
|
|
56
56
|
*/
|
|
57
|
-
|
|
57
|
+
loadSDKJSONFiles?: SDKJSONFilesLoaderFn;
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Optional list of versions to render in the API reference.
|
|
@@ -286,7 +286,7 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, astroOptions
|
|
|
286
286
|
detailThreshold: partial.llmsTxt?.detailThreshold ?? 2000,
|
|
287
287
|
},
|
|
288
288
|
apiKey: loadApiKey(partial.apiKey),
|
|
289
|
-
|
|
289
|
+
loadSDKJSONFiles: partial.loadSDKJSONFiles ?? defaultSpecLoader,
|
|
290
290
|
branch: partial.versions?.[0]?.branch ?? 'main',
|
|
291
291
|
};
|
|
292
292
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams } from './utils';
|
|
3
3
|
import Stainless, { APIError } from '@stainless-api/sdk';
|
|
4
4
|
import { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
5
5
|
import { bold } from '../../shared/terminalUtils';
|
|
@@ -44,7 +44,7 @@ function redactApiKey(apiKey: string) {
|
|
|
44
44
|
.join('');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
async function loadInputs({ apiKey, logger, stainlessProject, branch }:
|
|
47
|
+
async function loadInputs({ apiKey, logger, stainlessProject, branch }: SDKJSONFilesLoaderParams) {
|
|
48
48
|
const localFilePaths = getLocalFilePaths();
|
|
49
49
|
|
|
50
50
|
if (localFilePaths) {
|
|
@@ -133,7 +133,7 @@ async function cleanupDirectory(directory: string, filesToKeep: string[]) {
|
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
export const defaultSpecLoader:
|
|
136
|
+
export const defaultSpecLoader: SDKJSONFilesLoaderFn = async (params) => {
|
|
137
137
|
const { createCodegenDir } = params;
|
|
138
138
|
|
|
139
139
|
const inputs = await loadInputs(params);
|
|
@@ -163,7 +163,7 @@ export const defaultSpecLoader: SpecLoaderFn = async (params) => {
|
|
|
163
163
|
];
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
const
|
|
166
|
+
const { sdkJson, languages } = await generateSpecFromStrings({
|
|
167
167
|
oasStr: inputs.oasStr,
|
|
168
168
|
configStr: inputs.configStr,
|
|
169
169
|
languageOverrides: {
|
|
@@ -174,7 +174,7 @@ export const defaultSpecLoader: SpecLoaderFn = async (params) => {
|
|
|
174
174
|
stainlessProject: params.stainlessProject,
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
-
await writeFile(filePath, JSON.stringify(
|
|
177
|
+
await writeFile(filePath, JSON.stringify(sdkJson), 'utf8');
|
|
178
178
|
params.logger.info(`Generated: ${fileName}`);
|
|
179
179
|
|
|
180
180
|
const { deletedCount } = await cleanupDirectory(specsDirectory, [fileName]);
|
|
@@ -185,8 +185,8 @@ export const defaultSpecLoader: SpecLoaderFn = async (params) => {
|
|
|
185
185
|
return [
|
|
186
186
|
{
|
|
187
187
|
filePath,
|
|
188
|
-
languages:
|
|
189
|
-
sdkJson
|
|
188
|
+
languages: languages.filter((language) => language !== 'sql' && language !== 'openapi'),
|
|
189
|
+
sdkJson,
|
|
190
190
|
},
|
|
191
191
|
];
|
|
192
192
|
};
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import { readFile } from 'fs/promises';
|
|
2
2
|
|
|
3
3
|
import { api } from 'virtual:stainless-apis-manifest';
|
|
4
|
-
import
|
|
4
|
+
import { Spec } from '@stainless/sdk-json';
|
|
5
5
|
import { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
async function getSpecWithAuthInSSR(filePath: string) {
|
|
10
|
-
if (cachedSpecWithAuth[filePath]) {
|
|
11
|
-
return cachedSpecWithAuth[filePath];
|
|
12
|
-
}
|
|
13
|
-
const specStr = await readFile(filePath, 'utf8');
|
|
14
|
-
const json = JSON.parse(specStr) as SpecWithAuth;
|
|
15
|
-
cachedSpecWithAuth[filePath] = json;
|
|
16
|
-
return json;
|
|
17
|
-
}
|
|
7
|
+
const cachedSpecs: Record<string, Spec> = {};
|
|
18
8
|
|
|
19
9
|
export async function getSDKJSONInSSR(language: DocsLanguage) {
|
|
20
10
|
const filePath = api.languages.find((l) => l.language === language)?.sdkJSONFilePath;
|
|
@@ -22,6 +12,12 @@ export async function getSDKJSONInSSR(language: DocsLanguage) {
|
|
|
22
12
|
throw new Error(`No SDK JSON file path for language: ${language}`);
|
|
23
13
|
}
|
|
24
14
|
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
if (cachedSpecs[filePath]) {
|
|
16
|
+
return cachedSpecs[filePath];
|
|
17
|
+
}
|
|
18
|
+
const specStr = await readFile(filePath, 'utf8');
|
|
19
|
+
const json = JSON.parse(specStr) as Spec;
|
|
20
|
+
cachedSpecs[filePath] = json;
|
|
21
|
+
|
|
22
|
+
return json;
|
|
27
23
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Spec, SpecLanguage } from '@stainless/sdk-json';
|
|
2
|
+
import { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams } from './utils';
|
|
3
|
+
import { mkdir, readFile, writeFile } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
interface GenerateSDKJSONOptions {
|
|
7
|
+
/** Raw OpenAPI spec contents (JSON or YAML). */
|
|
8
|
+
spec: string;
|
|
9
|
+
/** Raw Stainless config contents (YAML). */
|
|
10
|
+
config: string;
|
|
11
|
+
/** Language to build the SDK JSON spec for. */
|
|
12
|
+
language: SpecLanguage;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type GenerateSDKJSONFn<T> = (options: GenerateSDKJSONOptions) => Promise<T>;
|
|
16
|
+
|
|
17
|
+
type FileSystemSpecLoaderParams<T> = {
|
|
18
|
+
specPath: string;
|
|
19
|
+
configFilePath: string;
|
|
20
|
+
generateSDKJSON: GenerateSDKJSONFn<T>;
|
|
21
|
+
languages: SpecLanguage[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function makeFileSystemSDKJSONFilesLoader<T>({
|
|
25
|
+
specPath,
|
|
26
|
+
configFilePath,
|
|
27
|
+
generateSDKJSON,
|
|
28
|
+
languages,
|
|
29
|
+
}: FileSystemSpecLoaderParams<T>): SDKJSONFilesLoaderFn {
|
|
30
|
+
return async function fileSystemSpecLoader(opts: SDKJSONFilesLoaderParams) {
|
|
31
|
+
const { createCodegenDir, logger } = opts;
|
|
32
|
+
const [spec, config] = await Promise.all([readFile(specPath, 'utf8'), readFile(configFilePath, 'utf8')]);
|
|
33
|
+
|
|
34
|
+
const specsDirectory = path.join(createCodegenDir().pathname, 'fsSpecLoaderSpecs');
|
|
35
|
+
await mkdir(specsDirectory, { recursive: true });
|
|
36
|
+
|
|
37
|
+
const r = languages.map(async (language) => {
|
|
38
|
+
// type casting here is a little weird
|
|
39
|
+
// it prevents type errors from slightly incompatible SDKJSON types (since generateSDKJSON comes from the user)
|
|
40
|
+
const sdkJson = (await generateSDKJSON({
|
|
41
|
+
spec,
|
|
42
|
+
config,
|
|
43
|
+
language,
|
|
44
|
+
})) as unknown as Spec;
|
|
45
|
+
|
|
46
|
+
const filePath = path.join(specsDirectory, `${language}.json`);
|
|
47
|
+
|
|
48
|
+
await writeFile(filePath, JSON.stringify(sdkJson));
|
|
49
|
+
|
|
50
|
+
logger.info(`Loaded SDKJSON for ${language} to ${filePath}`);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
filePath: filePath,
|
|
54
|
+
languages: [language],
|
|
55
|
+
sdkJson,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const results = await Promise.all(r);
|
|
60
|
+
|
|
61
|
+
return results;
|
|
62
|
+
};
|
|
63
|
+
}
|
package/plugin/specs/utils.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { AstroIntegrationLogger } from 'astro';
|
|
|
5
5
|
|
|
6
6
|
type PossibleLanguage = NonNullable<NonNullable<NonNullable<Spec['docs']>['languages']>[number]>;
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type SDKJSONFilesLoaderParams = {
|
|
9
9
|
/**
|
|
10
10
|
* The slug of your Stainless project.
|
|
11
11
|
*/
|
|
@@ -32,7 +32,7 @@ export type SpecLoaderParams = {
|
|
|
32
32
|
createCodegenDir: () => URL;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
type
|
|
35
|
+
type SDKJSONFilesLoaderResult = {
|
|
36
36
|
/**
|
|
37
37
|
* The file path to the loaded spec. The spec MUST be written to a path on disk.
|
|
38
38
|
* If you are not sure where to place it, create a directory in .astro using the `createCodegenDir` function passed in the parameters of the spec loader function.
|
|
@@ -49,7 +49,7 @@ type SpecLoaderResult = {
|
|
|
49
49
|
sdkJson?: Spec;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
export type
|
|
52
|
+
export type SDKJSONFilesLoaderFn = (opts: SDKJSONFilesLoaderParams) => Promise<SDKJSONFilesLoaderResult[]>;
|
|
53
53
|
|
|
54
54
|
async function readSpecFromFile(filePath: string) {
|
|
55
55
|
const txt = await readFile(filePath, 'utf8');
|
|
@@ -57,7 +57,7 @@ async function readSpecFromFile(filePath: string) {
|
|
|
57
57
|
return json;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export async function loadAllSpecs(specLoaderResultsPromise: Promise<
|
|
60
|
+
export async function loadAllSpecs(specLoaderResultsPromise: Promise<SDKJSONFilesLoaderResult[]>) {
|
|
61
61
|
const specLoaderResults = await specLoaderResultsPromise;
|
|
62
62
|
const specs = await Promise.all(
|
|
63
63
|
specLoaderResults.map(async (result) => {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { StlSidebarEntry } from '@stainless-api/docs-ui/components';
|
|
2
2
|
import { SidebarEntry } from '../pagination/util';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import { FunctionIcon } from '@stainless-api/ui-primitives/icons';
|
|
6
|
-
import { BracesIcon } from 'lucide-react';
|
|
4
|
+
import { getHttpMethod } from '@stainless-api/ui-primitives';
|
|
7
5
|
|
|
8
6
|
function getIcon(entry: SidebarEntry): ReactNode | undefined {
|
|
9
7
|
if (entry.type !== 'link') {
|
|
@@ -11,25 +9,34 @@ function getIcon(entry: SidebarEntry): ReactNode | undefined {
|
|
|
11
9
|
}
|
|
12
10
|
const methodAttr = entry.attrs['data-stldocs-method'];
|
|
13
11
|
const httpMethod = getHttpMethod(methodAttr);
|
|
12
|
+
const classes = `stl-ui-badge stl-ui-badge--size-sm stl-sidebar-icon`;
|
|
13
|
+
|
|
14
14
|
if (httpMethod) {
|
|
15
|
-
|
|
15
|
+
const methodClass = `stl-ui-badge--http-${httpMethod.toLowerCase()}`;
|
|
16
|
+
return (
|
|
17
|
+
<span className={`${classes} stl-ui-badge--http ${methodClass}`} role="img" aria-label={httpMethod} />
|
|
18
|
+
);
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
// special handling for the webhooks resource overview page
|
|
19
22
|
if (entry.attrs['data-stldocs-overview'] === 'webhooks') {
|
|
20
23
|
return (
|
|
21
|
-
<
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
+
<span
|
|
25
|
+
className={`${classes} stl-ui-badge--intent-info stl-sidebar-icon--braces`}
|
|
26
|
+
role="img"
|
|
27
|
+
aria-label="Webhook"
|
|
28
|
+
/>
|
|
24
29
|
);
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
// Support empty string as method to show generic "Function" badge
|
|
28
33
|
else if (methodAttr === '') {
|
|
29
34
|
return (
|
|
30
|
-
<
|
|
31
|
-
{
|
|
32
|
-
|
|
35
|
+
<span
|
|
36
|
+
className={`${classes} stl-ui-badge--intent-info stl-sidebar-icon--function`}
|
|
37
|
+
role="img"
|
|
38
|
+
aria-label="Method"
|
|
39
|
+
/>
|
|
33
40
|
);
|
|
34
41
|
}
|
|
35
42
|
return undefined;
|