@stainless-api/docs 1.0.0-beta.141 → 1.0.0-beta.143
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 +21 -0
- package/package.json +4 -4
- package/plugin/index.ts +2 -1
- package/plugin/loadPluginConfig.ts +4 -4
- package/plugin/react/Routing.tsx +0 -1
- package/plugin/specs/{defaultSpecLoader.ts → defaultSDKJSONLoader.ts} +30 -21
- package/plugin/specs/fetchSpecSSR.ts +10 -14
- package/plugin/specs/fileSystemSDKJSONLoader.ts +126 -0
- package/plugin/specs/utils.ts +19 -5
- package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +17 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @stainless-api/docs
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.143
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d358f02: Bugfix
|
|
8
|
+
- d358f02: Bug fixes + new API to override package versions etc.
|
|
9
|
+
|
|
10
|
+
## 1.0.0-beta.142
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 28bb924: updated API for SDKJSON
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 65c8fa0: Uses CSS for sidebar http icons instead of inline svg
|
|
19
|
+
- Updated dependencies [65c8fa0]
|
|
20
|
+
- Updated dependencies [28bb924]
|
|
21
|
+
- @stainless-api/docs-ui@1.0.0-beta.98
|
|
22
|
+
- @stainless-api/docs-search@1.0.0-beta.52
|
|
23
|
+
|
|
3
24
|
## 1.0.0-beta.141
|
|
4
25
|
|
|
5
26
|
### 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.143",
|
|
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 { fileSystemSDKJSONLoader } from './specs/fileSystemSDKJSONLoader';
|
|
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 {
|
|
10
|
-
import {
|
|
9
|
+
import { defaultSDKJSONLoader } 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 ?? defaultSDKJSONLoader,
|
|
290
290
|
branch: partial.versions?.[0]?.branch ?? 'main',
|
|
291
291
|
};
|
|
292
292
|
|
package/plugin/react/Routing.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams } from './utils';
|
|
3
|
+
import { sdkJSONCacheReaderWriter } from './utils';
|
|
3
4
|
import Stainless, { APIError } from '@stainless-api/sdk';
|
|
4
|
-
import { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
5
|
+
import { DocsLanguage, isSupportedLanguage } from '@stainless-api/docs-ui/routing';
|
|
5
6
|
import { bold } from '../../shared/terminalUtils';
|
|
6
|
-
import { mkdir, readdir, readFile, rm
|
|
7
|
+
import { mkdir, readdir, readFile, rm } from 'fs/promises';
|
|
7
8
|
import { generateSpecFromStrings, previewWorkerCode } from '@stainless/sdk-json/spec';
|
|
8
|
-
import { Spec
|
|
9
|
+
import { Spec } from '@stainless/sdk-json';
|
|
9
10
|
import crypto from 'crypto';
|
|
10
11
|
|
|
11
12
|
function resolvePath(inputPath: string) {
|
|
@@ -44,7 +45,7 @@ function redactApiKey(apiKey: string) {
|
|
|
44
45
|
.join('');
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
async function loadInputs({ apiKey, logger, stainlessProject, branch }:
|
|
48
|
+
async function loadInputs({ apiKey, logger, stainlessProject, branch }: SDKJSONFilesLoaderParams) {
|
|
48
49
|
const localFilePaths = getLocalFilePaths();
|
|
49
50
|
|
|
50
51
|
if (localFilePaths) {
|
|
@@ -115,13 +116,11 @@ async function loadInputs({ apiKey, logger, stainlessProject, branch }: SpecLoad
|
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return JSON.parse(fileContents) as T;
|
|
122
|
-
} catch {
|
|
123
|
-
return null;
|
|
119
|
+
function getLanguagesFromSDKJSON(spec: Spec) {
|
|
120
|
+
if (spec.docs?.languages) {
|
|
121
|
+
return spec.docs.languages;
|
|
124
122
|
}
|
|
123
|
+
return Object.keys(spec.decls).filter(isSupportedLanguage);
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
async function cleanupDirectory(directory: string, filesToKeep: string[]) {
|
|
@@ -133,12 +132,12 @@ async function cleanupDirectory(directory: string, filesToKeep: string[]) {
|
|
|
133
132
|
};
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
export const
|
|
135
|
+
export const defaultSDKJSONLoader: SDKJSONFilesLoaderFn = async (params) => {
|
|
137
136
|
const { createCodegenDir } = params;
|
|
138
137
|
|
|
139
138
|
const inputs = await loadInputs(params);
|
|
140
139
|
|
|
141
|
-
const specsDirectory = path.join(createCodegenDir().pathname, '
|
|
140
|
+
const specsDirectory = path.join(createCodegenDir().pathname, 'sdk_json_cache');
|
|
142
141
|
await mkdir(specsDirectory, { recursive: true });
|
|
143
142
|
|
|
144
143
|
const fileName =
|
|
@@ -150,20 +149,28 @@ export const defaultSpecLoader: SpecLoaderFn = async (params) => {
|
|
|
150
149
|
|
|
151
150
|
const filePath = path.join(specsDirectory, fileName);
|
|
152
151
|
|
|
153
|
-
const cachedSpec = await
|
|
152
|
+
const cachedSpec = await (async () => {
|
|
153
|
+
try {
|
|
154
|
+
return await sdkJSONCacheReaderWriter.readFile(filePath);
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
})();
|
|
159
|
+
|
|
154
160
|
// skip generation since we already have a cached spec
|
|
155
161
|
if (cachedSpec) {
|
|
162
|
+
const languages = getLanguagesFromSDKJSON(cachedSpec);
|
|
156
163
|
params.logger.info(`Loaded cached spec: ${fileName}`);
|
|
157
164
|
return [
|
|
158
165
|
{
|
|
159
166
|
filePath,
|
|
160
|
-
languages
|
|
161
|
-
sdkJson: cachedSpec
|
|
167
|
+
languages,
|
|
168
|
+
sdkJson: cachedSpec,
|
|
162
169
|
},
|
|
163
170
|
];
|
|
164
171
|
}
|
|
165
172
|
|
|
166
|
-
const
|
|
173
|
+
const { sdkJson } = await generateSpecFromStrings({
|
|
167
174
|
oasStr: inputs.oasStr,
|
|
168
175
|
configStr: inputs.configStr,
|
|
169
176
|
languageOverrides: {
|
|
@@ -174,9 +181,11 @@ export const defaultSpecLoader: SpecLoaderFn = async (params) => {
|
|
|
174
181
|
stainlessProject: params.stainlessProject,
|
|
175
182
|
});
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
params.logger.info(`Generated: ${fileName}`);
|
|
184
|
+
const languages = getLanguagesFromSDKJSON(sdkJson);
|
|
179
185
|
|
|
186
|
+
await sdkJSONCacheReaderWriter.writeFile(filePath, sdkJson);
|
|
187
|
+
|
|
188
|
+
params.logger.info(`Generated: ${fileName}`);
|
|
180
189
|
const { deletedCount } = await cleanupDirectory(specsDirectory, [fileName]);
|
|
181
190
|
if (deletedCount > 0) {
|
|
182
191
|
params.logger.info(`Cleaned up ${deletedCount} unused spec file(s)`);
|
|
@@ -185,8 +194,8 @@ export const defaultSpecLoader: SpecLoaderFn = async (params) => {
|
|
|
185
194
|
return [
|
|
186
195
|
{
|
|
187
196
|
filePath,
|
|
188
|
-
languages
|
|
189
|
-
sdkJson
|
|
197
|
+
languages,
|
|
198
|
+
sdkJson,
|
|
190
199
|
},
|
|
191
200
|
];
|
|
192
201
|
};
|
|
@@ -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,126 @@
|
|
|
1
|
+
import { Spec, SpecLanguage } from '@stainless/sdk-json';
|
|
2
|
+
import { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams, sdkJSONCacheReaderWriter } from './utils';
|
|
3
|
+
import { mkdir, readFile } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { generateSpecFromStrings } from '@stainless/sdk-json/spec';
|
|
6
|
+
|
|
7
|
+
interface GenerateSDKJSONOptions {
|
|
8
|
+
/** Raw OpenAPI spec contents (JSON or YAML). */
|
|
9
|
+
spec: string;
|
|
10
|
+
/** Raw Stainless config contents (YAML). */
|
|
11
|
+
config: string;
|
|
12
|
+
/** Language to build the SDK JSON spec for. */
|
|
13
|
+
language: SpecLanguage;
|
|
14
|
+
/** The name of the project. */
|
|
15
|
+
stainlessProject: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type GenerateSDKJSONFn<T> = (options: GenerateSDKJSONOptions) => Promise<{ spec: T }>;
|
|
19
|
+
|
|
20
|
+
type NonHttpSpecLanguage = Exclude<SpecLanguage, 'http'>;
|
|
21
|
+
|
|
22
|
+
type LibraryInformationOverride = Partial<{
|
|
23
|
+
[key in NonHttpSpecLanguage]: {
|
|
24
|
+
repo_url?: string;
|
|
25
|
+
code_url?: string;
|
|
26
|
+
version?: string;
|
|
27
|
+
install?: string;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
|
|
31
|
+
type FileSystemSpecLoaderParams<T> = {
|
|
32
|
+
/**
|
|
33
|
+
* The path to the OpenAPI spec file.
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
specPath: string;
|
|
37
|
+
/**
|
|
38
|
+
* The path to your Stainless config file.
|
|
39
|
+
*/
|
|
40
|
+
configFilePath: string;
|
|
41
|
+
/**
|
|
42
|
+
* The function used to generate your SDKJSON.
|
|
43
|
+
*/
|
|
44
|
+
generateSDKJSON?: GenerateSDKJSONFn<T>;
|
|
45
|
+
/**
|
|
46
|
+
* The languages for which you want to render documentation.
|
|
47
|
+
*/
|
|
48
|
+
languages: SpecLanguage[];
|
|
49
|
+
/**
|
|
50
|
+
* A key:value map of languages to overrides. Used to manually set things like the install command or SDK version.
|
|
51
|
+
*/
|
|
52
|
+
override?: LibraryInformationOverride;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const defaultGenerateSDKJSON: GenerateSDKJSONFn<Spec> = async ({
|
|
56
|
+
config,
|
|
57
|
+
spec,
|
|
58
|
+
language,
|
|
59
|
+
stainlessProject,
|
|
60
|
+
}) => {
|
|
61
|
+
const { sdkJson } = await generateSpecFromStrings({
|
|
62
|
+
oasStr: spec,
|
|
63
|
+
configStr: config,
|
|
64
|
+
languageOverrides: {
|
|
65
|
+
mode: 'only',
|
|
66
|
+
list: [language],
|
|
67
|
+
},
|
|
68
|
+
versionInfo: null,
|
|
69
|
+
stainlessProject,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return { spec: sdkJson };
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export function fileSystemSDKJSONLoader<T>({
|
|
76
|
+
specPath,
|
|
77
|
+
configFilePath,
|
|
78
|
+
generateSDKJSON,
|
|
79
|
+
languages,
|
|
80
|
+
override,
|
|
81
|
+
}: FileSystemSpecLoaderParams<T>): SDKJSONFilesLoaderFn {
|
|
82
|
+
const generateFn = generateSDKJSON ?? defaultGenerateSDKJSON;
|
|
83
|
+
return async function fileSystemSpecLoader(opts: SDKJSONFilesLoaderParams) {
|
|
84
|
+
const { createCodegenDir, logger } = opts;
|
|
85
|
+
const [spec, config] = await Promise.all([readFile(specPath, 'utf8'), readFile(configFilePath, 'utf8')]);
|
|
86
|
+
|
|
87
|
+
const specsDirectory = path.join(createCodegenDir().pathname, 'fs_spec_loader_specs');
|
|
88
|
+
await mkdir(specsDirectory, { recursive: true });
|
|
89
|
+
|
|
90
|
+
const r = languages.map(async (language) => {
|
|
91
|
+
const generateResult = await generateFn({
|
|
92
|
+
spec,
|
|
93
|
+
config,
|
|
94
|
+
language,
|
|
95
|
+
stainlessProject: opts.stainlessProject,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// type casting here is a little weird
|
|
99
|
+
// it prevents type errors from slightly incompatible SDKJSON types (since generateSDKJSON comes from the user)
|
|
100
|
+
const sdkJson = generateResult.spec as unknown as Spec;
|
|
101
|
+
|
|
102
|
+
if (override && language !== 'http' && override[language]) {
|
|
103
|
+
sdkJson.metadata[language] = {
|
|
104
|
+
...sdkJson.metadata[language],
|
|
105
|
+
...override[language],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const filePath = path.join(specsDirectory, `${language}.json`);
|
|
110
|
+
|
|
111
|
+
await sdkJSONCacheReaderWriter.writeFile(filePath, sdkJson);
|
|
112
|
+
|
|
113
|
+
logger.info(`Loaded SDKJSON for ${language} to ${filePath}`);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
filePath: filePath,
|
|
117
|
+
languages: [language],
|
|
118
|
+
sdkJson,
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const results = await Promise.all(r);
|
|
123
|
+
|
|
124
|
+
return results;
|
|
125
|
+
};
|
|
126
|
+
}
|
package/plugin/specs/utils.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Spec } from '@stainless/sdk-json';
|
|
2
|
-
import { readFile } from 'fs/promises';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
3
|
import { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
4
4
|
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) => {
|
|
@@ -84,3 +84,17 @@ export function flatSpecsList(specs: LoadedSpecs) {
|
|
|
84
84
|
)
|
|
85
85
|
.flat();
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
function typedReaderWriter<T>() {
|
|
89
|
+
return {
|
|
90
|
+
async readFile(filePath: string) {
|
|
91
|
+
const fileContents = await readFile(filePath, 'utf8');
|
|
92
|
+
return JSON.parse(fileContents) as T;
|
|
93
|
+
},
|
|
94
|
+
async writeFile(filePath: string, data: T) {
|
|
95
|
+
await writeFile(filePath, JSON.stringify(data), 'utf8');
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const sdkJSONCacheReaderWriter = typedReaderWriter<Spec>();
|
|
@@ -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;
|