@stainless-api/docs 0.1.0-beta.117 → 0.1.0-beta.119

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,29 @@
1
1
  # @stainless-api/docs
2
2
 
3
+ ## 0.1.0-beta.119
4
+
5
+ ### Patch Changes
6
+
7
+ - 403c097: Export additional components
8
+ - Updated dependencies [848cff4]
9
+ - Updated dependencies [ea2b90c]
10
+ - @stainless-api/ui-primitives@0.1.0-beta.50
11
+ - @stainless-api/docs-ui@0.1.0-beta.86
12
+ - @stainless-api/docs-search@0.1.0-beta.39
13
+
14
+ ## 0.1.0-beta.118
15
+
16
+ ### Minor Changes
17
+
18
+ - 9599de4: Updates preview worker to improve response snippets
19
+
20
+ ### Patch Changes
21
+
22
+ - 7901fd4: fix astro scoping for language-block style?
23
+ - Updated dependencies [93a3767]
24
+ - @stainless-api/docs-ui@0.1.0-beta.85
25
+ - @stainless-api/docs-search@0.1.0-beta.38
26
+
3
27
  ## 0.1.0-beta.117
4
28
 
5
29
  ### Patch Changes
@@ -4,14 +4,39 @@
4
4
  "count": 1
5
5
  }
6
6
  },
7
+ "plugin/components/StainlessIslands.tsx": {
8
+ "@typescript-eslint/no-unsafe-assignment": {
9
+ "count": 1
10
+ },
11
+ "@typescript-eslint/no-unsafe-member-access": {
12
+ "count": 2
13
+ }
14
+ },
15
+ "plugin/generateAPIReferenceLink.ts": {
16
+ "@typescript-eslint/no-unsafe-assignment": {
17
+ "count": 2
18
+ }
19
+ },
7
20
  "plugin/globalJs/copy.ts": {
8
21
  "@typescript-eslint/no-explicit-any": {
22
+ "count": 4
23
+ },
24
+ "@typescript-eslint/no-floating-promises": {
25
+ "count": 1
26
+ },
27
+ "@typescript-eslint/no-unsafe-assignment": {
28
+ "count": 2
29
+ },
30
+ "@typescript-eslint/no-unsafe-member-access": {
9
31
  "count": 3
10
32
  }
11
33
  },
12
34
  "plugin/index.ts": {
13
35
  "@typescript-eslint/no-explicit-any": {
14
36
  "count": 1
37
+ },
38
+ "@typescript-eslint/no-unsafe-assignment": {
39
+ "count": 1
15
40
  }
16
41
  },
17
42
  "plugin/languages.ts": {
@@ -19,9 +44,52 @@
19
44
  "count": 1
20
45
  }
21
46
  },
47
+ "plugin/referencePlaceholderUtils.ts": {
48
+ "@typescript-eslint/no-unsafe-assignment": {
49
+ "count": 1
50
+ }
51
+ },
52
+ "plugin/specs/generateSpec.ts": {
53
+ "@typescript-eslint/no-unsafe-assignment": {
54
+ "count": 2
55
+ }
56
+ },
22
57
  "plugin/specs/worker.ts": {
23
58
  "@typescript-eslint/no-explicit-any": {
24
59
  "count": 3
60
+ },
61
+ "@typescript-eslint/no-unsafe-argument": {
62
+ "count": 1
63
+ },
64
+ "@typescript-eslint/no-unsafe-assignment": {
65
+ "count": 7
66
+ },
67
+ "@typescript-eslint/no-unsafe-member-access": {
68
+ "count": 4
69
+ },
70
+ "@typescript-eslint/no-unsafe-return": {
71
+ "count": 1
72
+ },
73
+ "@typescript-eslint/prefer-promise-reject-errors": {
74
+ "count": 4
75
+ }
76
+ },
77
+ "stl-docs/components/sidebars/convertAstroSidebarToStl.tsx": {
78
+ "@typescript-eslint/no-unsafe-argument": {
79
+ "count": 1
80
+ },
81
+ "@typescript-eslint/no-unsafe-assignment": {
82
+ "count": 1
83
+ }
84
+ },
85
+ "stl-docs/proseDocSync.ts": {
86
+ "@typescript-eslint/restrict-template-expressions": {
87
+ "count": 4
88
+ }
89
+ },
90
+ "stl-docs/proseSearchIndexing.ts": {
91
+ "@typescript-eslint/restrict-template-expressions": {
92
+ "count": 1
25
93
  }
26
94
  }
27
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/docs",
3
- "version": "0.1.0-beta.117",
3
+ "version": "0.1.0-beta.119",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,13 +14,18 @@
14
14
  "./plugin/languages": "./plugin/languages.ts",
15
15
  "./stainless-docs/mintlify-compat": "./stl-docs/components/mintlify-compat/index.ts",
16
16
  "./mintlify-compat.css": "./styles/mintlify-compat.css",
17
- "./components": "./stl-docs/components/index.ts",
18
- "./components/scripts": "./stl-docs/components/scripts.ts",
19
17
  "./docs-config": "./stl-docs/loadStlDocsConfig.ts",
20
18
  "./specs/fetchSpecSSR": "./plugin/specs/fetchSpecSSR.ts",
21
19
  "./generate-docs-routes": "./plugin/helpers/generateDocsRoutes.ts",
20
+ "./components": "./stl-docs/components/index.ts",
21
+ "./components/scripts": "./stl-docs/components/scripts.ts",
22
22
  "./components/Head": "./stl-docs/components/Head.astro",
23
- "./components/ContentBreadcrumbs": "./stl-docs/components/ContentBreadcrumbs.tsx"
23
+ "./components/PageFrame": "./stl-docs/components/PageFrame.astro",
24
+ "./components/PageTitle": "./stl-docs/components/PageTitle.astro",
25
+ "./components/ContentBreadcrumbs": "./stl-docs/components/ContentBreadcrumbs.tsx",
26
+ "./components/AIDropdown": "./stl-docs/components/AIDropdown.tsx",
27
+ "./components/Footer": "./stl-docs/components/Footer.astro",
28
+ "./components/Pagination": "./stl-docs/components/pagination/Pagination.astro"
24
29
  },
25
30
  "keywords": [],
26
31
  "author": "",
@@ -36,15 +41,15 @@
36
41
  "vite": ">=7.3.1"
37
42
  },
38
43
  "dependencies": {
39
- "@astrojs/markdown-remark": "^7.0.0",
40
- "@astrojs/react": "^5.0.0",
41
- "@stainless-api/sdk": "0.1.0-alpha.19",
42
- "astro-expressive-code": "^0.41.6",
44
+ "@astrojs/markdown-remark": "^7.0.1",
45
+ "@astrojs/react": "^5.0.1",
46
+ "@stainless-api/sdk": "0.5.0",
47
+ "astro-expressive-code": "^0.41.7",
43
48
  "cheerio": "^1.2.0",
44
49
  "clsx": "^2.1.1",
45
50
  "dotenv": "17.3.1",
46
51
  "lucide-react": "^0.574.0",
47
- "marked": "^17.0.3",
52
+ "marked": "^17.0.4",
48
53
  "node-html-parser": "^7.0.2",
49
54
  "rehype-parse": "^9.0.1",
50
55
  "rehype-remark": "^10.0.1",
@@ -56,14 +61,14 @@
56
61
  "vite-plugin-prebundle-workers": "^0.2.0",
57
62
  "web-worker": "^1.5.0",
58
63
  "yaml": "^2.8.2",
59
- "@stainless-api/docs-search": "0.1.0-beta.37",
60
- "@stainless-api/docs-ui": "0.1.0-beta.84",
61
- "@stainless-api/ui-primitives": "0.1.0-beta.49"
64
+ "@stainless-api/docs-search": "0.1.0-beta.39",
65
+ "@stainless-api/docs-ui": "0.1.0-beta.86",
66
+ "@stainless-api/ui-primitives": "0.1.0-beta.50"
62
67
  },
63
68
  "devDependencies": {
64
- "@astrojs/check": "^0.9.7",
65
- "@markdoc/markdoc": "^0.5.4",
66
- "@types/node": "24.10.13",
69
+ "@astrojs/check": "^0.9.8",
70
+ "@markdoc/markdoc": "^0.5.6",
71
+ "@types/node": "24.12.0",
67
72
  "@types/react": "19.2.14",
68
73
  "@types/react-dom": "^19.2.3",
69
74
  "react": "^19.2.4",
@@ -140,7 +140,7 @@ function condensedShikiHtmlFull(docHtml: string, language: string, ranges: [numb
140
140
  out.push('<span class="line ellipsis">…\n</span>');
141
141
  didPushEllipsis = true;
142
142
  }
143
- out.push($.html(lineEl)!);
143
+ out.push($.html(lineEl));
144
144
  });
145
145
 
146
146
  $code.html(out.join(''));
@@ -37,8 +37,12 @@ async function createMarkdownRenderer(): Promise<MarkdownContext> {
37
37
  ...Markdoc.nodes.fence,
38
38
  transform(node, config) {
39
39
  const attributes = node.transformAttributes(config);
40
+ if (typeof node.attributes.language !== 'string' || typeof node.attributes.content !== 'string') {
41
+ throw new Error('Expected language and content to be strings');
42
+ }
40
43
  const lang = node.attributes.language === 'node' ? 'typescript' : node.attributes.language;
41
44
  const code = highlighter.codeToTokens(node.attributes.content, {
45
+ // @ts-expect-error - TODO: narrowing
42
46
  lang,
43
47
  theme: 'github-dark',
44
48
  });
@@ -63,6 +67,7 @@ async function createMarkdownRenderer(): Promise<MarkdownContext> {
63
67
  transform(node, config) {
64
68
  const children = node.transformChildren(config);
65
69
  const attrs = node.transformAttributes(config);
70
+ if (typeof attrs['href'] !== 'string') throw new Error('Expected href to be a string');
66
71
  const href = attrs['href'].replace('docs://BASE_PATH', RESOLVED_API_REFERENCE_PATH);
67
72
  return new Markdoc.Tag(this.render, { ...attrs, href }, children);
68
73
  },
@@ -142,7 +142,9 @@ const aiDropdownOptions: DropdownOption[][] = [
142
142
  .then((response) => response.text())
143
143
  .then((text) => new Blob([text], { type: 'text/plain' })),
144
144
  });
145
- navigator.clipboard.write([text]);
145
+ navigator.clipboard.write([text]).catch(() => {
146
+ console.error('Failed to copy to clipboard using ClipboardItem');
147
+ });
146
148
  } else {
147
149
  // NOTE: Firefox has support for ClipboardItem and navigator.clipboard.write,
148
150
  // but those are behind `dom.events.asyncClipboard.clipboardItem` preference.
@@ -150,7 +152,10 @@ const aiDropdownOptions: DropdownOption[][] = [
150
152
  // Clipboard API being used async in a Promise.
151
153
  fetch(markdownUrl)
152
154
  .then((response) => response.text())
153
- .then((text) => navigator.clipboard.writeText(text));
155
+ .then((text) => navigator.clipboard.writeText(text))
156
+ .catch(() => {
157
+ console.error('Failed to copy to clipboard');
158
+ });
154
159
  }
155
160
  },
156
161
  icon: 'copy',
@@ -13,7 +13,7 @@ document.addEventListener(getPageLoadEvent(), () => {
13
13
  const panelId = (tab as HTMLButtonElement).dataset.snippetResponseTabId;
14
14
 
15
15
  if (!panelId) {
16
- console.error(`No panel found for tab: ${tab}`);
16
+ console.error(`No panel found for tab: ${tab.outerHTML}`);
17
17
  return;
18
18
  }
19
19
  document
@@ -29,8 +29,8 @@ document.addEventListener(getPageLoadEvent(), () => {
29
29
  document.getElementById('stl-snippet-expand-button')?.addEventListener('click', (e) => {
30
30
  const btn = e.currentTarget as HTMLButtonElement;
31
31
 
32
- const collapsedDiv = document.querySelector('.stl-snippet-code-is-collapsed') as HTMLElement | null;
33
- const expandedDiv = document.querySelector('.stl-snippet-code-is-expanded') as HTMLElement | null;
32
+ const collapsedDiv = document.querySelector('.stl-snippet-code-is-collapsed');
33
+ const expandedDiv = document.querySelector('.stl-snippet-code-is-expanded');
34
34
 
35
35
  // We need to use javascript for height animations due to having dynamic heights based on snippet size.
36
36
  const animateHeight = (el: HTMLElement, expand: boolean) => {
@@ -71,7 +71,7 @@ document.addEventListener(getPageLoadEvent(), () => {
71
71
  el.style.height = `${endHeight}px`;
72
72
  };
73
73
 
74
- if (collapsedDiv) {
74
+ if (collapsedDiv instanceof HTMLElement) {
75
75
  if (collapsedDiv) {
76
76
  collapsedDiv.querySelector('.shiki')?.setAttribute('style', `counter-reset: codeblock-line 0`);
77
77
  }
@@ -80,7 +80,7 @@ document.addEventListener(getPageLoadEvent(), () => {
80
80
  return;
81
81
  }
82
82
 
83
- if (expandedDiv) {
83
+ if (expandedDiv instanceof HTMLElement) {
84
84
  const dataSnippetExpandedOffset = expandedDiv?.dataset.snippetExpandedOffset;
85
85
  if (dataSnippetExpandedOffset) {
86
86
  const offset = parseInt(dataSnippetExpandedOffset, 10);
@@ -22,36 +22,44 @@ function getContent(button: HTMLElement, full: boolean) {
22
22
  contentCopy.querySelectorAll('.leading-ws').forEach((el) => el.remove());
23
23
  }
24
24
 
25
- return contentCopy.textContent!;
25
+ return contentCopy.textContent;
26
26
  }
27
27
 
28
- const preloadPlayground = async (event: Event) => {
28
+ const preloadPlayground = (event: Event) => {
29
29
  const playButton = (event.target as HTMLElement).closest('[data-stldocs-snippet-play]') as HTMLElement;
30
30
  if (playButton) {
31
31
  loadPlayground(playButton);
32
32
  }
33
33
  };
34
34
  addEventListener('mouseover', preloadPlayground);
35
- addEventListener('click', async (event) => {
36
- const copyButton = (event.target as HTMLElement).closest('[data-stldocs-snippet-copy]') as HTMLElement;
35
+ addEventListener('click', (event) => {
36
+ if (!(event.target instanceof HTMLElement)) return;
37
+ const copyButton = event.target.closest('[data-stldocs-snippet-copy]');
38
+ if (!(copyButton instanceof HTMLElement)) return;
39
+
37
40
  if (copyButton) {
38
41
  const iconElement = copyButton.querySelector('.stldocs-icon') as SVGElement;
39
42
  clearTimeout(copyButton.dataset.__stldocsCopyTimeout);
40
- try {
41
- await navigator.clipboard.writeText(getContent(copyButton, false));
42
- iconElement.innerHTML = checkIcon;
43
- } catch {
44
- iconElement.innerHTML = circleAlertIcon;
45
- }
46
- copyButton.dataset.__stldocsCopyTimeout =
47
- setTimeout(() => {
48
- iconElement.innerHTML = copyIcon;
49
- }, 1000) + '';
43
+ navigator.clipboard
44
+ .writeText(getContent(copyButton, false))
45
+ .then(() => {
46
+ iconElement.innerHTML = checkIcon;
47
+ })
48
+ .catch(() => {
49
+ iconElement.innerHTML = circleAlertIcon;
50
+ })
51
+ .finally(() => {
52
+ copyButton.dataset.__stldocsCopyTimeout = setTimeout(() => {
53
+ iconElement.innerHTML = copyIcon;
54
+ }).toString();
55
+ });
50
56
  }
51
57
 
52
- const playButton = (event.target as HTMLElement).closest('[data-stldocs-snippet-play]') as HTMLElement;
53
- if (playButton) {
54
- showPlayground(playButton);
58
+ const playButton = event.target.closest('[data-stldocs-snippet-play]');
59
+ if (playButton instanceof HTMLElement) {
60
+ showPlayground(playButton).catch(() => {
61
+ console.error('Failed to load playground');
62
+ });
55
63
  }
56
64
  });
57
65
 
@@ -87,7 +95,6 @@ function loadPlayground(playButton: HTMLElement) {
87
95
  const { createPlayground } = await import('virtual:stl-playground/create');
88
96
  const { default: playgroundData } = await import('virtual:stl-playground/data');
89
97
  return createPlayground({
90
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
98
  lang: language as any,
92
99
  doc: (language === 'python' ? 'from rich import print\n' : '') + code.trimEnd(),
93
100
  container,
@@ -109,7 +116,10 @@ function loadPlayground(playButton: HTMLElement) {
109
116
  document.addEventListener(getPageLoadEvent(), () => {
110
117
  if (new URL(location.href).searchParams.has('play')) {
111
118
  document.querySelectorAll('[data-stldocs-snippet-play]').forEach((e) => {
112
- showPlayground(e as HTMLElement);
119
+ if (e instanceof HTMLElement)
120
+ showPlayground(e).catch(() => {
121
+ console.error('Failed to load playground');
122
+ });
113
123
  });
114
124
  }
115
125
  });
@@ -27,7 +27,9 @@ document.addEventListener(getPageLoadEvent(), () => {
27
27
  root: rootElement,
28
28
  onSelect: (value) => {
29
29
  const originalLanguage = rootElement.dataset.currentValue;
30
- navigate(updateSelectedLanguage(RESOLVED_API_REFERENCE_PATH, originalLanguage, value));
30
+ navigate(updateSelectedLanguage(RESOLVED_API_REFERENCE_PATH, originalLanguage, value)).catch((e) => {
31
+ console.error('Failed to navigate to selected language', e);
32
+ });
31
33
  },
32
34
  });
33
35
  });
@@ -53,7 +55,7 @@ document.addEventListener('click', (event) => {
53
55
  if (!target) return;
54
56
 
55
57
  target.querySelectorAll('details').forEach((details) => {
56
- const el = details as HTMLDetailsElement;
58
+ const el = details;
57
59
  const initial = el.dataset.stldocsExpanderInitialState;
58
60
  el.open = initial === 'true' ? true : !state;
59
61
  });
package/plugin/index.ts CHANGED
@@ -89,14 +89,12 @@ export function generateAPIReferenceItems(
89
89
  return makePlaceholderItems(id);
90
90
  }
91
91
 
92
- async function stlStarlightAstroIntegration(
93
- pluginConfig: NormalizedStainlessStarlightConfig,
94
- ): Promise<AstroIntegration> {
92
+ function stlStarlightAstroIntegration(pluginConfig: NormalizedStainlessStarlightConfig): AstroIntegration {
95
93
  const virtualId = `virtual:stl-starlight-virtual-module`;
96
94
  // The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
97
95
  const resolvedId = `\0${virtualId}`;
98
96
  let playgroundsBase: string | undefined;
99
- let buildPlaygrounds;
97
+ let buildPlaygrounds: (args: unknown) => Promise<void> | undefined;
100
98
  let astroBase = '/';
101
99
 
102
100
  let specLoader: SpecLoader | undefined;
@@ -125,7 +123,7 @@ async function stlStarlightAstroIntegration(
125
123
 
126
124
  const langs = specComposite.getLanguages();
127
125
 
128
- await buildPlaygrounds!({
126
+ return buildPlaygrounds?.({
129
127
  spec,
130
128
  langs,
131
129
  auth,
@@ -133,6 +131,8 @@ async function stlStarlightAstroIntegration(
133
131
  reportError(message: string) {
134
132
  (reportError ?? console.error)(message);
135
133
  },
134
+ })?.catch(() => {
135
+ console.error('Failed to build playgrounds');
136
136
  });
137
137
  })());
138
138
  }
@@ -396,7 +396,7 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
396
396
  return {
397
397
  name: 'stl-starlight',
398
398
  hooks: {
399
- 'config:setup': async ({
399
+ 'config:setup': ({
400
400
  addIntegration,
401
401
  updateConfig,
402
402
  addRouteMiddleware,
@@ -456,7 +456,7 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
456
456
  }
457
457
  }
458
458
 
459
- addIntegration(await stlStarlightAstroIntegration(config));
459
+ addIntegration(stlStarlightAstroIntegration(config));
460
460
 
461
461
  const expressiveCodeConfig =
462
462
  typeof starlightConfig.expressiveCode === 'object' ? starlightConfig.expressiveCode : {};
@@ -342,7 +342,7 @@ export function RenderSpec({
342
342
 
343
343
  return (
344
344
  <DocsProvider
345
- spec={spec as SDKJSON.Spec}
345
+ spec={spec}
346
346
  language={language ?? 'node'}
347
347
  settings={{
348
348
  contentPanelLayout,
@@ -356,7 +356,7 @@ export function RenderSpec({
356
356
  <div className="stldocs-root stl-ui-not-prose">
357
357
  <div className="stl-page-nav-container">
358
358
  <SDKBreadcrumbs
359
- spec={spec as SDKJSON.Spec}
359
+ spec={spec}
360
360
  currentPath={currentPath}
361
361
  basePath={RESOLVED_API_REFERENCE_PATH}
362
362
  config={BREADCRUMB_CONFIG}
@@ -32,7 +32,7 @@ function markCurrentItems(sidebar: SidebarEntry[], currentSlug: string) {
32
32
  return mutableSidebarInstance;
33
33
  }
34
34
 
35
- export const onRequest = defineRouteMiddleware(async (context) => {
35
+ export const onRequest = defineRouteMiddleware((context) => {
36
36
  // if using content collection schema, use: context.locals.starlightRoute.entry.data.stainlessStarlight
37
37
  // this worked without collections but relied on hijacking starlightRoute: context.props.frontmatter.stainlessStarlight
38
38
  const slug = path.posix.join(import.meta.env.BASE_URL ?? '', `/${context.locals.starlightRoute.id}`); // same as .slug but not deprecated
@@ -68,7 +68,7 @@ Astro.locals._stlStarlightPage = {
68
68
  gap: 1rem;
69
69
  margin-top: 2rem;
70
70
 
71
- .stldocs-language-block {
71
+ > * {
72
72
  width: 0;
73
73
  flex: 1 1 350px;
74
74
  }
@@ -93,13 +93,18 @@ export async function startSpecLoader(
93
93
  const specs = await pluginConfig.api.loadSpecs();
94
94
 
95
95
  // not awaited since it's just cleanup
96
- specCache.cleanupUnusedFiles().then((result) => {
97
- if (result.deletedCount > 0) {
98
- logger.info(`Cleaned up ${result.deletedCount} unused spec files`);
99
- } else {
100
- logger.debug(`No unused spec files to clean up`);
101
- }
102
- });
96
+ specCache
97
+ .cleanupUnusedFiles()
98
+ .then((result) => {
99
+ if (result.deletedCount > 0) {
100
+ logger.info(`Cleaned up ${result.deletedCount} unused spec files`);
101
+ } else {
102
+ logger.debug(`No unused spec files to clean up`);
103
+ }
104
+ })
105
+ .catch(() => {
106
+ logger.warn(`Failed to clean up unused spec files`);
107
+ });
103
108
 
104
109
  return {
105
110
  specComposite: new SpecComposite(specs),
@@ -7,7 +7,9 @@ import Stainless, { APIError } from '@stainless-api/sdk';
7
7
  import { GenerateSpecRawInputs } from './generateSpec';
8
8
 
9
9
  export type SpecInputResolver = {
10
- resolve: (context: { apiKey: LoadedApiKey | null }) => Promise<GenerateSpecRawInputs>;
10
+ resolve: (context: {
11
+ apiKey: LoadedApiKey | null;
12
+ }) => GenerateSpecRawInputs | Promise<GenerateSpecRawInputs>;
11
13
  printError: (error: Error, logger: AstroIntegrationLogger) => void;
12
14
  };
13
15
 
@@ -123,7 +125,7 @@ function fromStrings({
123
125
  stainlessProject: string;
124
126
  }): SpecInputResolver {
125
127
  return {
126
- async resolve() {
128
+ resolve() {
127
129
  return {
128
130
  oasStr,
129
131
  configStr,