@stainless-api/docs-ui 0.1.0-beta.14 → 0.1.0-beta.15

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.
Files changed (168) hide show
  1. package/dist/breadcrumbs-Z-hEqjcp.d.ts +19 -0
  2. package/dist/chunk-Bp6m_JJh.js +13 -0
  3. package/dist/component-generics-DzI21jRn.js +35 -0
  4. package/dist/component-generics-q5Dqiu2D.d.ts +30 -0
  5. package/dist/components/breadcrumbs.d.ts +2 -0
  6. package/dist/components/breadcrumbs.js +16 -0
  7. package/dist/components/chat.d.ts +14 -0
  8. package/dist/components/chat.js +144 -0
  9. package/dist/components/dropdown.d.ts +2 -0
  10. package/dist/components/dropdown.js +4 -0
  11. package/dist/components/icons.d.ts +50 -0
  12. package/dist/components/icons.js +3 -0
  13. package/dist/components/index.d.ts +12 -0
  14. package/dist/components/index.js +16 -0
  15. package/dist/components/method.d.ts +2 -0
  16. package/dist/components/method.js +16 -0
  17. package/dist/components/overview.d.ts +2 -0
  18. package/dist/components/overview.js +16 -0
  19. package/dist/components/primitives.d.ts +2 -0
  20. package/dist/components/primitives.js +16 -0
  21. package/dist/components/properties.d.ts +2 -0
  22. package/dist/components/properties.js +16 -0
  23. package/dist/components/scripts/dropdown.d.ts +12 -0
  24. package/dist/components/scripts/dropdown.js +50 -0
  25. package/dist/components/sdk.d.ts +3 -0
  26. package/dist/components/sdk.js +16 -0
  27. package/dist/components/sidebar.d.ts +2 -0
  28. package/dist/components/sidebar.js +16 -0
  29. package/dist/components/snippets.d.ts +4 -0
  30. package/dist/components/snippets.js +16 -0
  31. package/dist/contexts/component-generics.d.ts +2 -0
  32. package/dist/contexts/component-generics.js +3 -0
  33. package/dist/contexts/component-types.d.ts +18 -0
  34. package/dist/contexts/component-types.js +1 -0
  35. package/dist/contexts/component.d.ts +31 -0
  36. package/dist/contexts/component.js +16 -0
  37. package/dist/contexts/docs.d.ts +2 -0
  38. package/dist/contexts/docs.js +3 -0
  39. package/dist/contexts/index.d.ts +20 -0
  40. package/dist/contexts/index.js +16 -0
  41. package/dist/contexts/markdown.d.ts +2 -0
  42. package/dist/contexts/markdown.js +4 -0
  43. package/dist/contexts/navigation.d.ts +3 -0
  44. package/dist/contexts/navigation.js +3 -0
  45. package/dist/contexts/search.d.ts +4 -0
  46. package/dist/contexts/search.js +16 -0
  47. package/dist/contexts/use-components.d.ts +16 -0
  48. package/dist/contexts/use-components.js +4 -0
  49. package/dist/contexts-DRxRO-xO.js +3747 -0
  50. package/dist/docs-Dh8kE1va.js +50 -0
  51. package/dist/docs-EUy-wfbA.d.ts +43 -0
  52. package/dist/dropdown-B7VyGMOw.d.ts +43 -0
  53. package/dist/dropdown-DtgAi6lb.js +62 -0
  54. package/dist/icons-DdKM-01E.js +753 -0
  55. package/dist/index-AicgPYKB.d.ts +239 -0
  56. package/dist/index-BhwLhiWk.d.ts +14 -0
  57. package/dist/index-YnpUtXLB.d.ts +16 -0
  58. package/dist/index.d.ts +22 -0
  59. package/dist/index.js +5276 -5873
  60. package/dist/languages/go.d.ts +13 -0
  61. package/dist/languages/go.js +16 -0
  62. package/dist/languages/http.d.ts +13 -0
  63. package/dist/languages/http.js +16 -0
  64. package/dist/languages/index.d.ts +13 -0
  65. package/dist/languages/index.js +16 -0
  66. package/dist/languages/java.d.ts +13 -0
  67. package/dist/languages/java.js +16 -0
  68. package/dist/languages/python.d.ts +13 -0
  69. package/dist/languages/python.js +16 -0
  70. package/dist/languages/ruby.d.ts +13 -0
  71. package/dist/languages/ruby.js +16 -0
  72. package/dist/languages/typescript.d.ts +13 -0
  73. package/dist/languages/typescript.js +16 -0
  74. package/dist/markdown/index.d.ts +11 -0
  75. package/dist/markdown/index.js +16 -0
  76. package/dist/markdown/md.d.ts +15 -0
  77. package/dist/markdown/md.js +3 -0
  78. package/dist/markdown/utils.d.ts +4 -0
  79. package/dist/markdown/utils.js +3 -0
  80. package/dist/markdown-BXfX1D7C.js +42 -0
  81. package/dist/markdown-nFyAEX_K.d.ts +22 -0
  82. package/dist/mcp.js +1720 -2298
  83. package/dist/md-Dg8aOyMA.js +41 -0
  84. package/dist/method-DpsVuzZW.d.ts +71 -0
  85. package/dist/navigation-aoYZ_tl4.js +24 -0
  86. package/dist/navigation-nyXBY-75.d.ts +29 -0
  87. package/dist/overview-C8e-6jGr.d.ts +38 -0
  88. package/dist/pagefind-ChrPfuVv.js +15 -0
  89. package/dist/primitives-DWz23_Ub.d.ts +99 -0
  90. package/dist/properties-CF71V58d.d.ts +46 -0
  91. package/dist/routing-DQjbRxdJ.js +189 -0
  92. package/dist/routing-qc0V00-j.d.ts +51 -0
  93. package/dist/routing.d.ts +2 -0
  94. package/dist/sdk-Zg3Rggk3.d.ts +118 -0
  95. package/dist/search/index.d.ts +26 -0
  96. package/dist/search/index.js +332 -0
  97. package/dist/search/providers/algolia.d.ts +23 -0
  98. package/dist/search/providers/algolia.js +16 -0
  99. package/dist/search/providers/fuse.d.ts +17 -0
  100. package/dist/search/providers/fuse.js +31 -0
  101. package/dist/search/providers/pagefind.d.ts +7 -0
  102. package/dist/search/providers/pagefind.js +3 -0
  103. package/dist/search/providers/walker.d.ts +8 -0
  104. package/dist/search/providers/walker.js +32 -0
  105. package/dist/search/types.d.ts +3 -0
  106. package/dist/search/types.js +3 -0
  107. package/dist/search-B6loAGmB.d.ts +21 -0
  108. package/dist/sidebar-C8KirYjg.d.ts +35 -0
  109. package/dist/snippets-EUzM4fRO.d.ts +45 -0
  110. package/dist/style-pN9hCoec.d.ts +181 -0
  111. package/dist/style-rYbbxIR_.js +182 -0
  112. package/dist/style.d.ts +2 -0
  113. package/dist/style.js +3 -0
  114. package/dist/styles/main.css +742 -748
  115. package/dist/styles/primitives.css +435 -428
  116. package/dist/styles/resets.css +33 -41
  117. package/dist/styles/search.css +247 -248
  118. package/dist/styles/sidebar.css +58 -60
  119. package/dist/styles/snippets.css +86 -88
  120. package/dist/styles/variables.css +86 -90
  121. package/dist/types-CTBDtD34.d.ts +82 -0
  122. package/dist/types-DFN4M1Sp.js +34 -0
  123. package/dist/use-components-D9E85p5x.js +7 -0
  124. package/dist/utils-BHwvUDKn.js +30 -0
  125. package/dist/utils-CJfFBNgT.js +32 -0
  126. package/dist/utils-DQhEbvUC.d.ts +20 -0
  127. package/dist/utils-nDazhti8.d.ts +11 -0
  128. package/dist/utils.d.ts +2 -0
  129. package/dist/utils.js +4 -0
  130. package/package.json +13 -7
  131. package/src/components/breadcrumbs.tsx +1 -1
  132. package/src/components/chat.tsx +18 -15
  133. package/src/components/method.tsx +8 -9
  134. package/src/components/overview.tsx +26 -12
  135. package/src/components/primitives.tsx +36 -19
  136. package/src/components/properties.tsx +4 -2
  137. package/src/components/scripts/dropdown.ts +1 -1
  138. package/src/components/sdk.tsx +25 -20
  139. package/src/components/sidebar.tsx +3 -3
  140. package/src/components/snippets.tsx +26 -9
  141. package/src/contexts/component-generics.tsx +10 -15
  142. package/src/contexts/docs.tsx +15 -4
  143. package/src/contexts/index.tsx +8 -5
  144. package/src/contexts/markdown.tsx +7 -6
  145. package/src/contexts/search.tsx +4 -5
  146. package/src/hooks/use-strict-context.tsx +16 -0
  147. package/src/languages/go.tsx +3 -3
  148. package/src/languages/http.tsx +31 -23
  149. package/src/languages/index.ts +7 -7
  150. package/src/languages/java.tsx +4 -4
  151. package/src/languages/python.tsx +12 -9
  152. package/src/languages/ruby.tsx +20 -13
  153. package/src/languages/typescript.tsx +18 -12
  154. package/src/markdown/index.ts +17 -12
  155. package/src/markdown/utils.ts +6 -3
  156. package/src/routing.ts +9 -9
  157. package/src/search/form.tsx +26 -24
  158. package/src/search/indexer.ts +17 -15
  159. package/src/search/mcp.ts +8 -8
  160. package/src/search/printer.tsx +1 -1
  161. package/src/search/providers/algolia.ts +5 -5
  162. package/src/search/providers/fuse.ts +4 -4
  163. package/src/search/providers/pagefind.ts +1 -1
  164. package/src/search/providers/walker.ts +5 -3
  165. package/src/search/results.tsx +7 -6
  166. package/src/search/types.ts +2 -2
  167. package/src/styles/main.css +2 -1
  168. package/src/utils.ts +9 -8
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type * as TSAST from '~/lib/json-spec-v2/TSAST';
2
+ import { TSAST } from '@stainless/sdk-json';
3
3
  import { useDeclaration, useLanguage, useLanguageComponents, useSpec } from '../contexts';
4
4
  import { useComponents } from '../contexts/use-components';
5
5
  import style from '../style';
@@ -13,7 +13,7 @@ const ComplexTypes: Record<string, string> = {
13
13
  TSTypeArray: 'array',
14
14
  };
15
15
 
16
- const constStyle = {
16
+ const constStyle: Record<string, string> = {
17
17
  string: style.LiteralString,
18
18
  number: style.LiteralNumeric,
19
19
  boolean: style.LiteralBoolean,
@@ -66,17 +66,23 @@ function TypeParams({ params }: { params?: TSAST.TSTypeParameter[] }) {
66
66
  function TypePreview({ path }: { path: string }) {
67
67
  const spec = useSpec();
68
68
  const language = useLanguage();
69
- const decl = useDeclaration(path);
69
+ const decl = useDeclaration(path, false);
70
70
  const { Join } = useComponents();
71
71
 
72
- if (!(decl && 'children' in decl && decl.children.length > 0) || decl['type']?.['kind'] === 'TSTypeUnion')
72
+ if (
73
+ !(decl && 'children' in decl && decl.children && decl.children.length > 0) ||
74
+ (decl && 'type' in decl && 'kind' in decl['type'] && decl['type']['kind'] === 'TSTypeUnion')
75
+ )
73
76
  return;
74
77
 
75
- const items = decl.children.map((prop, key) => (
76
- <span key={key} className={style.TypePropertyName}>
77
- <span className={style.TextIdentifier}>{spec?.decls?.[language]?.[prop]?.['key']}</span>
78
- </span>
79
- ));
78
+ const items = decl.children.map((prop, key) => {
79
+ const p = spec?.decls?.[language]?.[prop];
80
+ return (
81
+ <span key={key} className={style.TypePropertyName}>
82
+ <span className={style.TextIdentifier}>{p && 'key' in p ? p['key'] : null}</span>
83
+ </span>
84
+ );
85
+ });
80
86
 
81
87
  return (
82
88
  <span className={style.TypePreview} data-stldocs-type-preview="properties">
@@ -146,7 +152,7 @@ export function Type({ type }: TypeProps) {
146
152
 
147
153
  return (
148
154
  <span className={style.Type}>
149
- <SDKReference stainlessPath={type.$ref}>{name}</SDKReference>
155
+ <SDKReference stainlessPath={type.$ref!}>{name}</SDKReference>
150
156
  {params && params.length > 0 && (
151
157
  <>
152
158
  <span className={style.TypeBracket}>{'<'}</span>
@@ -156,7 +162,7 @@ export function Type({ type }: TypeProps) {
156
162
  <span className={style.TypeBracket}>{'>'}</span>
157
163
  </>
158
164
  )}
159
- <TypePreview path={type.$ref} />
165
+ <TypePreview path={type.$ref!} />
160
166
  </span>
161
167
  );
162
168
  }
@@ -274,7 +280,7 @@ export function MethodSignature({ decl }: MethodSignatureProps) {
274
280
 
275
281
  export type PropertyProps = {
276
282
  decl: TSAST.TSDeclaration;
277
- children?: PropertyFn;
283
+ children: PropertyFn;
278
284
  };
279
285
 
280
286
  export function Property({ decl, children }: PropertyProps) {
@@ -2,7 +2,7 @@ import Markdoc from '@markdoc/markdoc';
2
2
  import * as md from './md';
3
3
  import { EnvironmentType, getDecl, getSnippet, stripMarkup } from './utils';
4
4
  import * as printer from '../search/printer';
5
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
5
+ import type * as SDKJSON from '@stainless/sdk-json';
6
6
  import type { Node } from '@markdoc/markdoc';
7
7
 
8
8
  export function declaration(env: EnvironmentType, decl: SDKJSON.DeclarationNode) {
@@ -15,20 +15,20 @@ function renderChildren(env: EnvironmentType, children: SDKJSON.ID[], nesting: s
15
15
  }
16
16
 
17
17
  function renderDecl(env: EnvironmentType, path: string, nesting: string[] = []) {
18
- const decl = getDecl(env, path);
18
+ const decl = getDecl(env, path)!;
19
19
  const item = md.item(declaration(env, decl));
20
20
 
21
- const hasChildren = 'children' in decl && decl.children.length > 0;
22
- const showModelProps = !decl['modelPath'] || env.options.includeModelProperties;
21
+ const hasChildren = 'children' in decl && decl.children && decl.children.length > 0;
22
+ const showModelProps = !('modelPath' in decl && decl['modelPath']) || env.options.includeModelProperties;
23
23
 
24
24
  if ('docstring' in decl && decl.docstring) item.children.push(...md.parse(decl.docstring));
25
25
  if (hasChildren && showModelProps && !nesting.includes(path))
26
- item.push(renderChildren(env, decl.children, [...nesting, path]));
26
+ item.push(renderChildren(env, decl.children ?? [], [...nesting, path]));
27
27
 
28
28
  return item;
29
29
  }
30
30
 
31
- function renderMethod(env: EnvironmentType, method: SDKJSON.Method) {
31
+ function renderMethod(env: EnvironmentType, method: SDKJSON.Method): Node[] {
32
32
  const decl = getDecl(env, method.stainlessPath);
33
33
 
34
34
  if (!decl)
@@ -41,11 +41,11 @@ function renderMethod(env: EnvironmentType, method: SDKJSON.Method) {
41
41
  ];
42
42
 
43
43
  const signature = printer.methodSignature(env.language, decl);
44
- const [httpMethod, endpoint] = method.endpoint.split(' ');
44
+ const [httpMethod, endpoint] = method.endpoint.split(' ') as [string, string];
45
45
 
46
46
  const output = [
47
47
  md.heading(2, method.title),
48
- env.language === 'http' ? null : md.paragraph(md.code(stripMarkup(signature))),
48
+ ...(env.language === 'http' ? [] : [md.paragraph(md.code(stripMarkup(signature)))]),
49
49
  md.paragraph(md.strong(md.text(httpMethod)), md.text(' '), md.code(endpoint)),
50
50
  ];
51
51
 
@@ -54,7 +54,7 @@ function renderMethod(env: EnvironmentType, method: SDKJSON.Method) {
54
54
  if ('paramsChildren' in decl && Array.isArray(decl.paramsChildren) && decl.paramsChildren.length > 0)
55
55
  output.push(md.heading(3, 'Parameters'), renderChildren(env, decl.paramsChildren));
56
56
 
57
- if ('responseChildren' in decl && decl.responseChildren.length > 0)
57
+ if ('responseChildren' in decl && decl.responseChildren && decl.responseChildren.length > 0)
58
58
  output.push(md.heading(3, 'Returns'), renderChildren(env, decl.responseChildren));
59
59
 
60
60
  const snippet = getSnippet(env, method.stainlessPath);
@@ -67,7 +67,7 @@ function renderModel(env: EnvironmentType, model: SDKJSON.Model) {
67
67
  return [md.heading(3, model.title), md.list(renderDecl(env, `${model.stainlessPath} > (schema)`))];
68
68
  }
69
69
 
70
- function renderResource(env: EnvironmentType, resource: SDKJSON.Resource) {
70
+ function renderResource(env: EnvironmentType, resource: SDKJSON.Resource): Node[] {
71
71
  const methods = Object.values(resource.methods)
72
72
  .filter((method) => getDecl(env, method.stainlessPath))
73
73
  .flatMap((method) => renderMethod(env, method));
@@ -82,11 +82,16 @@ function renderResource(env: EnvironmentType, resource: SDKJSON.Resource) {
82
82
 
83
83
  if (!env.options.renderNestedResources) return doc;
84
84
 
85
- const children = Object.values(resource.subresources).map((resource) => renderResource(env, resource));
85
+ const children = Object.values(resource.subresources ?? {}).flatMap((resource) =>
86
+ renderResource(env, resource),
87
+ );
86
88
  return [...doc, ...children];
87
89
  }
88
90
 
89
- export function render(env: EnvironmentType, node: SDKJSON.Resource | SDKJSON.Method | SDKJSON.Model) {
91
+ export function render(
92
+ env: EnvironmentType,
93
+ node: SDKJSON.Resource | SDKJSON.Method | SDKJSON.Model,
94
+ ): Node[] {
90
95
  switch (node.kind) {
91
96
  case 'resource':
92
97
  return renderResource(env, node);
@@ -1,6 +1,6 @@
1
1
  import { Parser } from 'htmlparser2';
2
2
  import type { DocsLanguage } from '../routing';
3
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
3
+ import type * as SDKJSON from '@stainless/sdk-json';
4
4
  import type { TransformRequestSnippetFn } from '../components/sdk';
5
5
 
6
6
  export type EnvironmentType = {
@@ -19,7 +19,10 @@ export function getDecl(env: EnvironmentType, path: string) {
19
19
  const decl = env.spec?.decls?.[env.language]?.[path];
20
20
 
21
21
  if (decl?.kind?.endsWith('Reference')) {
22
- const refId = decl['type']['$ref'];
22
+ const refId =
23
+ 'type' in decl && typeof decl['type'] === 'object' && '$ref' in decl['type']
24
+ ? decl['type']['$ref']
25
+ : null;
23
26
  if (refId === path) return decl;
24
27
  if (refId) return getDecl(env, refId);
25
28
  }
@@ -28,7 +31,7 @@ export function getDecl(env: EnvironmentType, path: string) {
28
31
  }
29
32
 
30
33
  export function getSnippet(env: EnvironmentType, path: string) {
31
- let snippet = env.spec?.snippets?.[`${env.language}.default`]?.[path];
34
+ let snippet = env.spec?.snippets?.[`${env.language}.default` as SDKJSON.SnippetLanguage]?.[path];
32
35
  if (typeof snippet === 'string' && env.transforms?.transformRequestSnippet) {
33
36
  snippet = env.transforms.transformRequestSnippet({ snippet, language: env.language });
34
37
  }
package/src/routing.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
1
+ import type * as SDKJSON from '@stainless/sdk-json';
2
2
 
3
3
  export const Languages = [
4
4
  'http',
@@ -56,10 +56,10 @@ export type ParsedStainlessPath = ReturnType<typeof parseStainlessPath>;
56
56
  export function parseStainlessPath(stainlessPath: string) {
57
57
  const match = stainlessPath.match(StainlessPathPattern);
58
58
 
59
- if (!match) return null;
59
+ if (!match?.groups) return null;
60
60
 
61
61
  return {
62
- resource: match.groups.resource.split('.'),
62
+ resource: match.groups.resource?.split('.') ?? null,
63
63
  method: match.groups.method ?? null,
64
64
  model: match.groups.model ?? null,
65
65
  routable: match.groups.model ? match[1] : match[0],
@@ -72,7 +72,7 @@ export function trimStainlessPath(stainlessPath: string) {
72
72
 
73
73
  export function getResource(stainlessPath: string) {
74
74
  const parsed = parseStainlessPath(stainlessPath);
75
- return parsed?.resource[0];
75
+ return parsed?.resource?.[0];
76
76
  }
77
77
 
78
78
  export function parseRoute(
@@ -119,7 +119,7 @@ export function generateRoute(basePath: string, language: string, stainlessPath:
119
119
  const path = [basePath.endsWith('/') ? basePath.slice(0, -1) : basePath];
120
120
  if (language && language !== DefaultLanguage) path.push(language);
121
121
 
122
- const resources = parsedPath.resource.flatMap((name, index) => [
122
+ const resources = parsedPath.resource!.flatMap((name, index) => [
123
123
  index > 0 ? 'subresources' : 'resources',
124
124
  name,
125
125
  ]);
@@ -130,7 +130,7 @@ export function generateRoute(basePath: string, language: string, stainlessPath:
130
130
 
131
131
  if (parsedPath.method) path.push('methods', parsedPath.method);
132
132
 
133
- return stainlessPath.length > parsedPath.routable.length
133
+ return stainlessPath.length > parsedPath.routable!.length
134
134
  ? `${path.join('/')}#${encodeURIComponent(stainlessPath)}`
135
135
  : path.join('/');
136
136
  }
@@ -203,7 +203,7 @@ export function generateRouteList({
203
203
 
204
204
  type ResourceOrMethod = SDKJSON.Resource | SDKJSON.Method;
205
205
 
206
- export function findNavigationPath(items: ResourceOrMethod[], target: string) {
206
+ export function findNavigationPath(items: ResourceOrMethod[], target: string): string[] | undefined {
207
207
  for (const item of Object.values(items)) {
208
208
  if (item.stainlessPath === target) return [item.stainlessPath];
209
209
  if (item.kind === 'http_method') continue;
@@ -217,9 +217,9 @@ export function findNavigationPath(items: ResourceOrMethod[], target: string) {
217
217
  }
218
218
  }
219
219
 
220
- export function expandToElement(el: HTMLElement) {
220
+ export function expandToElement(el: HTMLElement | null) {
221
221
  while (el) {
222
- if (el.tagName === 'DETAILS') el['open'] = true;
222
+ if (el instanceof HTMLDetailsElement) el.open = true;
223
223
  el = el.parentElement;
224
224
  }
225
225
  }
@@ -14,36 +14,36 @@ export function SearchForm() {
14
14
  const language = useLanguage();
15
15
  const { onSelect, pageFind } = useSearchContext();
16
16
 
17
- const [results, setResults] = React.useState<ResultData>(null);
17
+ const [results, setResults] = React.useState<ResultData>(null!);
18
18
  const [filterKind, setFilterKind] = React.useState<QueryKindsType>('all');
19
19
  const [searchQuery, setSearchQuery] = React.useState<string>('');
20
20
  const inputRef = React.useRef<HTMLInputElement>(null);
21
21
 
22
- async function performSearch() {
23
- const guideLimit = filterKind === 'guide' ? 25 : 5;
24
- const kind = ['all', 'guide'].includes(filterKind) ? undefined : filterKind;
25
-
26
- const [guideResults, apiResults] = await Promise.all([
27
- pageFind ? guideSearch(pageFind, searchQuery, guideLimit) : [],
28
- search({ query: searchQuery, kind, language }),
29
- ]);
30
-
31
- setResults({
32
- items: filterKind === 'guide' ? guideResults : [...guideResults, ...apiResults.hits],
33
- counts: {
34
- ...apiResults.facets?.['kind'],
35
- guide: guideResults.length,
36
- all: apiResults.nbHits,
37
- },
38
- });
39
- }
40
-
41
22
  function clearInput() {
42
23
  setSearchQuery('');
43
24
  inputRef?.current?.focus();
44
25
  }
45
26
 
46
- React.useEffect(() => void performSearch(), [searchQuery, filterKind, language]);
27
+ React.useEffect(() => {
28
+ (async function performSearch() {
29
+ const guideLimit = filterKind === 'guide' ? 25 : 5;
30
+ const kind = ['all', 'guide'].includes(filterKind) ? undefined : filterKind;
31
+
32
+ const [guideResults, apiResults] = await Promise.all([
33
+ pageFind ? guideSearch(pageFind, searchQuery, guideLimit) : [],
34
+ search({ query: searchQuery, kind, language }),
35
+ ]);
36
+
37
+ setResults({
38
+ items: filterKind === 'guide' ? guideResults : [...guideResults, ...(apiResults?.hits ?? [])],
39
+ counts: {
40
+ ...apiResults?.facets?.['kind'],
41
+ guide: guideResults.length,
42
+ all: apiResults?.nbHits,
43
+ },
44
+ });
45
+ })();
46
+ }, [searchQuery, filterKind, language, pageFind, search]);
47
47
 
48
48
  return (
49
49
  <div className={style.SearchForm}>
@@ -72,7 +72,9 @@ export function SearchForm() {
72
72
  itemDelegate={(item) =>
73
73
  'kind' in item ? <SearchResult result={item} /> : <GuideResult result={item} />
74
74
  }
75
- onSelectListItem={(item) => onSelect?.(item['data']?.['url'] ?? item['stainlessPath'])}
75
+ onSelectListItem={(item) =>
76
+ onSelect?.((item as any)['data']?.['url'] ?? (item as any)['stainlessPath'])
77
+ }
76
78
  />
77
79
  </div>
78
80
  );
@@ -81,7 +83,7 @@ export function SearchForm() {
81
83
  export type SearchFilterProps = {
82
84
  results: ResultData;
83
85
  filterKind: QueryKindsType;
84
- onChange: (filterKind?: QueryKindsType) => void;
86
+ onChange: (filterKind: QueryKindsType) => void;
85
87
  };
86
88
 
87
89
  export function SearchFilter({ results, filterKind, onChange }: SearchFilterProps) {
@@ -111,7 +113,7 @@ export type SearchModalProps = {
111
113
  };
112
114
 
113
115
  export function SearchModal({ id, open: isOpen }: SearchModalProps) {
114
- const [open, setOpen] = React.useState<boolean>(isOpen);
116
+ const [open, setOpen] = React.useState<boolean>(isOpen ?? false);
115
117
 
116
118
  return (
117
119
  <div
@@ -1,6 +1,6 @@
1
1
  import { generateRoute, Languages, parseStainlessPath, walkTree } from '../routing';
2
2
  import * as printer from './printer';
3
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
3
+ import type * as SDKJSON from '@stainless/sdk-json';
4
4
  import type { IndexEntry } from './types';
5
5
  import { renderMarkdown } from '../markdown';
6
6
 
@@ -93,8 +93,8 @@ export function* generateChatIndex(spec: SDKJSON.Spec) {
93
93
  summary,
94
94
  description,
95
95
  stainlessPath,
96
- qualified: decl['qualified'],
97
- ident: decl['ident'],
96
+ qualified: 'qualified' in decl ? decl['qualified'] : undefined,
97
+ ident: 'ident' in decl ? decl['ident'] : undefined,
98
98
  content: chunk,
99
99
  url: generateRoute('docs://BASE_PATH', language, stainlessPath),
100
100
  };
@@ -105,7 +105,7 @@ export function* generateChatIndex(spec: SDKJSON.Spec) {
105
105
 
106
106
  export function* generateIndex(
107
107
  spec: SDKJSON.Spec,
108
- renderMarkdownFn?: (string?) => string | null,
108
+ renderMarkdownFn?: (_: string) => string | null,
109
109
  includeTypes?: boolean,
110
110
  ): Generator<IndexEntry> {
111
111
  const parentCrumbs: Record<string, string[]> = {};
@@ -113,8 +113,8 @@ export function* generateIndex(
113
113
  const { kind, name, title, stainlessPath } = data;
114
114
  const common = { name, title, stainlessPath };
115
115
 
116
- const parsedPath = parseStainlessPath(stainlessPath);
117
- const crumbs = getResourceNames(parsedPath.resource, spec.resources);
116
+ const parsedPath = parseStainlessPath(stainlessPath)!;
117
+ const crumbs = getResourceNames(parsedPath.resource!, spec.resources);
118
118
 
119
119
  switch (kind) {
120
120
  case 'resource':
@@ -144,7 +144,7 @@ export function* generateIndex(
144
144
  if (!found) continue;
145
145
 
146
146
  parentCrumbs[stainlessPath] = [...crumbs, title];
147
- const qualified = found['qualified'];
147
+ const qualified = 'qualified' in found ? found['qualified'] : undefined;
148
148
  const ident = qualified?.split('.')?.at(-1);
149
149
 
150
150
  yield {
@@ -153,7 +153,9 @@ export function* generateIndex(
153
153
  ident,
154
154
  qualified,
155
155
  language,
156
- description: renderMarkdownFn?.(data.description) ?? data.description,
156
+ description: data.description
157
+ ? (renderMarkdownFn?.(data.description) ?? data.description)
158
+ : undefined,
157
159
  endpoint: endpoint.slice(httpMethod.length).trim(),
158
160
  httpMethod,
159
161
  summary,
@@ -172,9 +174,9 @@ export function* generateIndex(
172
174
  parentCrumbs[stainlessPath] = [...crumbs, title];
173
175
  const schema = spec.decls[language]?.[`${stainlessPath} > (schema)`];
174
176
  const children =
175
- schema?.['children']
177
+ (schema && 'children' in schema ? schema?.['children'] : undefined)
176
178
  ?.map((childPath) => {
177
- const child = spec.decls?.[language]?.[childPath];
179
+ const child = spec.decls?.[language]?.[childPath] as any;
178
180
  return (
179
181
  child?.['ident'] ??
180
182
  child?.['name'] ??
@@ -192,7 +194,7 @@ export function* generateIndex(
192
194
  children,
193
195
  language,
194
196
  priority: 2,
195
- ident: schema?.['ident'],
197
+ ident: schema && 'ident' in schema ? schema?.['ident'] : undefined,
196
198
  ...common,
197
199
  };
198
200
  }
@@ -213,11 +215,11 @@ export function* generateIndex(
213
215
  case 'HttpDeclProperty':
214
216
  case 'TSDeclProperty':
215
217
  {
216
- const parsedPath = parseStainlessPath(decl.stainlessPath);
218
+ const parsedPath = parseStainlessPath(decl.stainlessPath)!;
217
219
  const type = includeTypes === false ? undefined : printer.typeName(language, decl.type);
218
- const name = decl['ident'] ?? decl['name'] ?? decl['key'];
220
+ const name: string = (decl as any)['ident'] ?? (decl as any)['name'] ?? (decl as any)['key'];
219
221
 
220
- const parent = parentCrumbs[parsedPath.routable];
222
+ const parent = parentCrumbs[parsedPath.routable!];
221
223
  // Filter out properties of non-routable response types
222
224
  if (parent === undefined) continue;
223
225
 
@@ -232,7 +234,7 @@ export function* generateIndex(
232
234
  name,
233
235
  stainlessPath: decl.stainlessPath,
234
236
  crumbs: [...parent, ...props],
235
- docstring: renderMarkdownFn?.(decl.docstring) ?? decl.docstring,
237
+ docstring: decl.docstring ? (renderMarkdownFn?.(decl.docstring) ?? decl.docstring) : undefined,
236
238
  type,
237
239
  language,
238
240
  priority: 3,
package/src/search/mcp.ts CHANGED
@@ -5,7 +5,7 @@ import { getResourceFromSpec } from '../utils';
5
5
  import { buildIndex, search as fuseSearch } from './providers/fuse';
6
6
  import type { IndexEntry, IndexMethod } from './types';
7
7
  import natural from 'natural';
8
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
8
+ import type * as SDKJSON from '@stainless/sdk-json';
9
9
 
10
10
  type Item = IndexEntry & IndexMethod;
11
11
 
@@ -20,12 +20,12 @@ export function consolidate(results: IndexEntry[]) {
20
20
  const methods = new Set<string>();
21
21
 
22
22
  for (const entry of results) {
23
- const parsed = parseStainlessPath(entry.stainlessPath);
24
- if (parsed.method) methods.add(parsed.routable);
25
- else resources.add(parsed.routable);
23
+ const parsed = parseStainlessPath(entry.stainlessPath)!;
24
+ if (parsed.method) methods.add(parsed.routable!);
25
+ else resources.add(parsed.routable!);
26
26
  }
27
27
 
28
- const filtered = Array.from(methods).filter((path) => !resources.has(path.split(' >').at(0)));
28
+ const filtered = Array.from(methods).filter((path) => !resources.has(path.split(' >').at(0)!));
29
29
  return [...resources, ...filtered];
30
30
  }
31
31
 
@@ -46,9 +46,9 @@ export function render(
46
46
 
47
47
  const paths = consolidate(items);
48
48
  const output = paths.map((entry) => {
49
- const parsed = parseStainlessPath(entry);
50
- const resource = getResourceFromSpec(parsed.resource, spec);
51
- const target = parsed.method ? resource.methods[parsed.method] : resource;
49
+ const parsed = parseStainlessPath(entry)!;
50
+ const resource = getResourceFromSpec(parsed.resource!, spec)!;
51
+ const target = parsed.method ? resource.methods[parsed.method]! : resource;
52
52
  const content = renderMarkdown(env, target);
53
53
  return [entry, content];
54
54
  });
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { renderToStaticMarkup } from 'react-dom/server';
3
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
3
+ import type * as SDKJSON from '@stainless/sdk-json';
4
4
  import type { DocsLanguage } from '../routing';
5
5
 
6
6
  import { DocsProvider, useLanguageComponents } from '../contexts';
@@ -1,7 +1,7 @@
1
1
  import { searchClient } from '@algolia/client-search';
2
2
  import { generateChatIndex, generateIndex } from '../indexer';
3
3
  import { SearchableAttributes, SearchableAttributesChat } from '../types';
4
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
4
+ import type * as SDKJSON from '@stainless/sdk-json';
5
5
  import type { ResultRecordType, SearchSettings, SearchParams, ResultType } from '../types';
6
6
 
7
7
  export async function buildIndex(
@@ -9,7 +9,7 @@ export async function buildIndex(
9
9
  indexName: string,
10
10
  writeKey: string,
11
11
  spec: SDKJSON.Spec,
12
- renderMarkdown: (string?) => string | null,
12
+ renderMarkdown: (_: string) => string | null,
13
13
  ): Promise<void> {
14
14
  if (!appId || !indexName || !writeKey) return;
15
15
  const objects = Array.from(generateIndex(spec, renderMarkdown));
@@ -22,7 +22,7 @@ export async function buildIndex(
22
22
  highlightPostTag: '</mark>',
23
23
  customRanking: ['asc(priority)'],
24
24
  attributesForFaceting: ['language', 'kind'],
25
- searchableAttributes: SearchableAttributes,
25
+ searchableAttributes: [...SearchableAttributes],
26
26
  },
27
27
  });
28
28
 
@@ -81,8 +81,8 @@ export async function search({
81
81
  ],
82
82
  });
83
83
 
84
- if ('hits' in results[0] && 'hits' in results[1]) {
84
+ if ('hits' in results[0]! && 'hits' in results[1]!) {
85
85
  const [{ nbHits, facets }, { hits }] = results;
86
- return { hits, nbHits, facets };
86
+ return { hits, nbHits: nbHits ?? 0, facets };
87
87
  }
88
88
  }
@@ -2,18 +2,18 @@ import Fuse, { FuseIndex } from 'fuse.js';
2
2
  import { DocsLanguage } from '../../routing';
3
3
  import { generateIndex } from '../indexer';
4
4
  import { IndexEntry, SearchableAttributes } from '../types';
5
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
5
+ import type * as SDKJSON from '@stainless/sdk-json';
6
6
 
7
7
  export type FuseIndexData = { content: IndexEntry[]; index: FuseIndex<IndexEntry> };
8
8
 
9
9
  export function buildIndex(spec: SDKJSON.Spec, language?: DocsLanguage): FuseIndexData {
10
- const idx = Array.from(generateIndex(spec, null, false));
10
+ const idx = Array.from(generateIndex(spec, undefined, false));
11
11
  const content = language ? idx.filter((entry) => entry.language === language) : idx;
12
- const index = Fuse.createIndex(SearchableAttributes, content);
12
+ const index = Fuse.createIndex([...SearchableAttributes], content);
13
13
  return { content, index };
14
14
  }
15
15
 
16
16
  export function search({ content, index }: FuseIndexData, query: string, limit: number = 100) {
17
- const fuse = new Fuse(content, { keys: SearchableAttributes }, index);
17
+ const fuse = new Fuse(content, { keys: [...SearchableAttributes] }, index);
18
18
  return fuse.search(query).slice(0, limit);
19
19
  }
@@ -13,5 +13,5 @@ export async function guideSearch(
13
13
  const index = await loadPagefind(loadPath);
14
14
  const response = await index.search(query);
15
15
  const items = limit ? response.results.slice(0, limit) : response.results;
16
- return Promise.all(items.map((result) => result.data().then((data) => ({ ...result, data }))));
16
+ return Promise.all(items.map((result: any) => result.data().then((data: any) => ({ ...result, data }))));
17
17
  }
@@ -1,17 +1,19 @@
1
1
  import { DocsLanguage } from '../../routing';
2
2
  import { generateIndex } from '../indexer';
3
3
  import { IndexEntry, SearchableAttributes } from '../types';
4
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
4
+ import type * as SDKJSON from '@stainless/sdk-json';
5
5
 
6
6
  export function buildIndex(spec: SDKJSON.Spec) {
7
- return generateIndex(spec, null, false);
7
+ return generateIndex(spec, undefined, false);
8
8
  }
9
9
 
10
10
  function* findEntryInIndex(index: Generator<IndexEntry>, language: string, query: string) {
11
11
  for (const entry of index) {
12
12
  if (entry.language !== language) continue;
13
13
  for (const attr of SearchableAttributes) {
14
- if (entry[attr] && typeof entry[attr] === 'string' && entry[attr].includes(query)) yield entry;
14
+ const attr_ = attr in entry ? (attr as keyof typeof entry) : null;
15
+ if (attr_ && entry[attr_] && typeof entry[attr_] === 'string' && entry[attr_].includes(query))
16
+ yield entry;
15
17
  }
16
18
  }
17
19
  }
@@ -125,11 +125,12 @@ export function SearchResultContent({ result }: SearchResultProps) {
125
125
  );
126
126
 
127
127
  case 'model': {
128
- const properties = result.children.map((child, index) => (
129
- <span key={index} className={style.TextIdentifier}>
130
- {child}
131
- </span>
132
- ));
128
+ const properties =
129
+ result.children?.map((child, index) => (
130
+ <span key={index} className={style.TextIdentifier}>
131
+ {child}
132
+ </span>
133
+ )) ?? [];
133
134
 
134
135
  return (
135
136
  <div className={style.Property} data-stldocs-language={language}>
@@ -168,7 +169,7 @@ export function SearchResultContent({ result }: SearchResultProps) {
168
169
  <Highlight result={result} name="name" />
169
170
  </span>
170
171
  <span className={style.PropertyTypeName}>
171
- <span dangerouslySetInnerHTML={{ __html: result.type }} />
172
+ <span dangerouslySetInnerHTML={{ __html: result.type ?? '' }} />
172
173
  </span>
173
174
  </div>
174
175
  {result.docstring && (
@@ -1,4 +1,4 @@
1
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
1
+ import type * as SDKJSON from '@stainless/sdk-json';
2
2
  import { DocsLanguage } from '../routing';
3
3
 
4
4
  export type SearchSettings = {
@@ -58,7 +58,7 @@ export const SearchableAttributes = [
58
58
  'summary',
59
59
  'description',
60
60
  'docstring',
61
- ];
61
+ ] as const;
62
62
 
63
63
  export const SearchableAttributesChat = [
64
64
  'title',
@@ -183,8 +183,9 @@
183
183
  color: var(--stldocs-color-text-tertiary);
184
184
  align-content: center;
185
185
  line-height: 120%;
186
- overflow-x: hidden;
186
+ overflow: hidden;
187
187
  text-overflow: ellipsis;
188
+ white-space: nowrap;
188
189
  }
189
190
  }
190
191