@stainless-api/docs 0.1.0-beta.9 → 0.1.0-beta.91

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 (142) hide show
  1. package/CHANGELOG.md +757 -0
  2. package/eslint-suppressions.json +32 -0
  3. package/locals.d.ts +17 -0
  4. package/package.json +49 -40
  5. package/playground-virtual-modules.d.ts +96 -0
  6. package/plugin/assets/languages/cli.svg +14 -0
  7. package/plugin/assets/languages/csharp.svg +1 -0
  8. package/plugin/buildAlgoliaIndex.ts +38 -11
  9. package/plugin/components/MethodDescription.tsx +54 -0
  10. package/plugin/components/RequestBuilder/ParamEditor.tsx +55 -0
  11. package/plugin/components/RequestBuilder/SnippetStainlessIsland.tsx +107 -0
  12. package/plugin/components/RequestBuilder/index.tsx +31 -0
  13. package/plugin/components/RequestBuilder/props.ts +9 -0
  14. package/plugin/components/RequestBuilder/spec-helpers.ts +50 -0
  15. package/plugin/components/RequestBuilder/styles.css +67 -0
  16. package/plugin/components/SDKSelect.astro +20 -104
  17. package/plugin/components/SnippetCode.tsx +111 -66
  18. package/plugin/components/StainlessIslands.tsx +126 -0
  19. package/plugin/components/search/SearchAlgolia.astro +45 -28
  20. package/plugin/components/search/SearchIsland.tsx +47 -29
  21. package/plugin/generateAPIReferenceLink.ts +2 -2
  22. package/plugin/globalJs/ai-dropdown-options.ts +243 -0
  23. package/plugin/globalJs/code-snippets.ts +15 -8
  24. package/plugin/globalJs/copy.ts +94 -17
  25. package/plugin/globalJs/create-playground.shim.ts +3 -0
  26. package/plugin/globalJs/method-descriptions.ts +33 -0
  27. package/plugin/globalJs/navigation.ts +10 -29
  28. package/plugin/globalJs/playground-data.shim.ts +1 -0
  29. package/plugin/globalJs/playground-data.ts +14 -0
  30. package/plugin/helpers/generateDocsRoutes.ts +27 -0
  31. package/plugin/helpers/getDocsLanguages.ts +9 -0
  32. package/plugin/index.ts +292 -116
  33. package/plugin/languages.ts +7 -2
  34. package/plugin/loadPluginConfig.ts +155 -79
  35. package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
  36. package/plugin/react/Routing.tsx +204 -132
  37. package/plugin/referencePlaceholderUtils.ts +18 -15
  38. package/plugin/replaceSidebarPlaceholderMiddleware.ts +38 -34
  39. package/plugin/routes/Docs.astro +65 -117
  40. package/plugin/routes/DocsStatic.astro +7 -4
  41. package/plugin/routes/Overview.astro +20 -24
  42. package/plugin/routes/markdown.ts +12 -11
  43. package/plugin/{cms → sidebar-utils}/sidebar-builder.ts +30 -54
  44. package/plugin/specs/fetchSpecSSR.ts +21 -0
  45. package/plugin/specs/generateSpec.ts +50 -0
  46. package/plugin/specs/index.ts +238 -0
  47. package/plugin/{cms → specs}/worker.ts +82 -5
  48. package/plugin/vendor/preview.worker.docs.js +22142 -18005
  49. package/plugin/vendor/templates/go.md +1 -1
  50. package/plugin/vendor/templates/python.md +1 -1
  51. package/resolveSrcFile.ts +10 -0
  52. package/scripts/vendor_deps.ts +5 -5
  53. package/shared/getProsePages.ts +42 -0
  54. package/shared/getSharedLogger.ts +15 -0
  55. package/shared/terminalUtils.ts +3 -0
  56. package/shared/virtualModule.ts +54 -1
  57. package/src/content.config.ts +9 -0
  58. package/stl-docs/components/AIDropdown.tsx +63 -0
  59. package/stl-docs/components/AiChatIsland.tsx +14 -0
  60. package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
  61. package/stl-docs/components/Head.astro +20 -0
  62. package/stl-docs/components/Header.astro +6 -8
  63. package/stl-docs/components/PageFrame.astro +18 -0
  64. package/stl-docs/components/PageTitle.astro +82 -0
  65. package/stl-docs/components/TableOfContents.astro +34 -0
  66. package/stl-docs/components/ThemeProvider.astro +36 -0
  67. package/stl-docs/components/ThemeSelect.astro +84 -139
  68. package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
  69. package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
  70. package/stl-docs/components/headers/StackedHeader.astro +29 -24
  71. package/stl-docs/components/icons/chat-gpt.tsx +2 -2
  72. package/stl-docs/components/icons/cursor.tsx +10 -0
  73. package/stl-docs/components/icons/gemini.tsx +19 -0
  74. package/stl-docs/components/icons/markdown.tsx +1 -1
  75. package/stl-docs/components/index.ts +1 -0
  76. package/stl-docs/components/mintlify-compat/Accordion.astro +7 -5
  77. package/stl-docs/components/mintlify-compat/AccordionGroup.astro +7 -3
  78. package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
  79. package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
  80. package/stl-docs/components/mintlify-compat/callouts/Callout.astro +1 -1
  81. package/stl-docs/components/mintlify-compat/callouts/Check.astro +1 -1
  82. package/stl-docs/components/mintlify-compat/callouts/Danger.astro +1 -1
  83. package/stl-docs/components/mintlify-compat/callouts/Info.astro +1 -1
  84. package/stl-docs/components/mintlify-compat/callouts/Note.astro +1 -1
  85. package/stl-docs/components/mintlify-compat/callouts/Tip.astro +1 -1
  86. package/stl-docs/components/mintlify-compat/callouts/Warning.astro +1 -1
  87. package/stl-docs/components/mintlify-compat/card.css +33 -35
  88. package/stl-docs/components/mintlify-compat/index.ts +2 -4
  89. package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -70
  90. package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
  91. package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
  92. package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
  93. package/stl-docs/components/pagination/HomeLink.astro +10 -0
  94. package/stl-docs/components/pagination/Pagination.astro +175 -0
  95. package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
  96. package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
  97. package/stl-docs/components/pagination/util.ts +71 -0
  98. package/stl-docs/components/scripts.ts +1 -0
  99. package/stl-docs/components/sidebars/BaseSidebar.astro +9 -2
  100. package/stl-docs/components/sidebars/SidebarWithComponents.tsx +10 -0
  101. package/stl-docs/components/sidebars/convertAstroSidebarToStl.tsx +62 -0
  102. package/stl-docs/disableCalloutSyntax.ts +36 -0
  103. package/stl-docs/fonts.ts +186 -0
  104. package/stl-docs/index.ts +153 -50
  105. package/stl-docs/loadStlDocsConfig.ts +51 -7
  106. package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +61 -0
  107. package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +41 -0
  108. package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
  109. package/stl-docs/proseSearchIndexing.ts +606 -0
  110. package/stl-docs/tabsMiddleware.ts +13 -4
  111. package/styles/code.css +128 -136
  112. package/styles/links.css +11 -48
  113. package/styles/method-descriptions.css +36 -0
  114. package/styles/overrides.css +49 -57
  115. package/styles/page.css +100 -59
  116. package/styles/sdk_select.css +9 -7
  117. package/styles/search.css +57 -69
  118. package/styles/sidebar.css +26 -156
  119. package/styles/{variables.css → sl-variables.css} +3 -2
  120. package/styles/stldocs-variables.css +6 -0
  121. package/styles/toc.css +41 -34
  122. package/theme.css +11 -11
  123. package/tsconfig.json +2 -5
  124. package/virtual-module.d.ts +47 -7
  125. package/components/variables.css +0 -135
  126. package/plugin/cms/client.ts +0 -62
  127. package/plugin/cms/server.ts +0 -268
  128. package/plugin/globalJs/ai-dropdown.ts +0 -57
  129. package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -58
  130. package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -55
  131. package/stl-docs/components/mintlify-compat/Step.astro +0 -58
  132. package/stl-docs/components/mintlify-compat/Steps.astro +0 -17
  133. package/styles/fonts.css +0 -68
  134. /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
  135. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
  136. /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
  137. /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
  138. /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
  139. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
  140. /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
  141. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
  142. /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
@@ -1,87 +1,75 @@
1
1
  ---
2
- import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
3
- import { cmsClient } from "../cms/client";
4
-
5
- import "@stainless-api/docs-ui/src/styles/resets.css";
6
- import "@stainless-api/docs-ui/src/styles/primitives.css";
7
- import "@stainless-api/docs-ui/src/styles/main.css";
8
- import "@stainless-api/docs-ui/src/styles/snippets.css";
9
- // TODO: fix variables.css import
10
- // import "./variables.css";
11
-
2
+ import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
3
+ import { getReadmeContent, buildPageNavigation, RenderSpec, astroMarkdownRender } from '../react/Routing';
4
+ import { getResourceFromSpec } from '@stainless-api/docs-ui/utils';
5
+ import { parseStainlessPath } from '@stainless-api/docs-ui/routing';
12
6
  import {
13
- getReadmeContent,
14
- generateDocsRoutes,
15
- buildPageNavigation,
16
- RenderSpec,
17
- astroMarkdownRender,
18
- } from "../react/Routing";
19
- import { getResourceFromSpec } from "@stainless-api/docs-ui/src/utils";
20
- import { BASE_PATH, CONTENT_PANEL_LAYOUT,MIDDLEWARE } from "virtual:stl-starlight-virtual-module";
7
+ CONTENT_PANEL_LAYOUT,
8
+ MIDDLEWARE,
9
+ EXPERIMENTAL_REQUEST_BUILDER,
10
+ } from 'virtual:stl-starlight-virtual-module';
11
+ import { generateDocsRoutes } from '../helpers/generateDocsRoutes';
12
+ import { StainlessIslands } from '../components/StainlessIslands';
13
+ import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
21
14
 
15
+ const spec = await getSDKJSONInSSR();
22
16
 
23
- const spec = await cmsClient.getSpec();
24
- const routes = generateDocsRoutes(spec);
17
+ export type Props = Awaited<ReturnType<typeof generateDocsRoutes>>[number]['props'] | Record<string, never>;
25
18
 
26
- const route = routes.find((r) => r.params.slug === Astro.params.slug);
19
+ const props =
20
+ 'language' in Astro.props
21
+ ? // In prod, we pass the props down to this page
22
+ Astro.props
23
+ : // In the dev server, we skip the DocsStatic wrapper so we need to find the props ourselves
24
+ generateDocsRoutes(spec).find((r) => r.params.slug === Astro.params.slug)?.props;
25
+ if (!props) throw new Error(`Could not find a route for slug '${Astro.params.slug}'`);
27
26
 
28
- if (!route) {
29
- throw new Error("No such route");
30
- }
27
+ // PageTitle override will skip rendering the default Starlight title
28
+ Astro.locals._stlStarlightPage = {
29
+ skipRenderingStarlightTitle: props.kind === 'readme' ? false : true,
30
+ };
31
31
 
32
- const readmeContent = await getReadmeContent(spec, route.props.language);
33
- const readme =
34
- route.props.kind === "readme"
35
- ? await astroMarkdownRender(readmeContent ?? "")
36
- : null;
32
+ const readmeContent = await getReadmeContent(spec, props.language);
33
+ const readme = props.kind === 'readme' ? await astroMarkdownRender(readmeContent ?? '') : null;
37
34
 
38
- const resource = route.props.stainlessPath
39
- ? getResourceFromSpec(route.props.stainlessPath, spec)
40
- : null;
35
+ const resource = props.stainlessPath ? getResourceFromSpec(props.stainlessPath, spec) : null;
41
36
 
42
37
  const pageNav =
43
- route.props.kind === "resource" && resource
38
+ props.kind === 'resource' && resource
44
39
  ? buildPageNavigation(resource)
45
- : route.props.kind === "readme" && readme?.metadata
40
+ : props.kind === 'readme' && readme?.metadata
46
41
  ? readme?.metadata.headings
47
42
  : [];
48
43
 
49
- const props = route.props;
44
+ Astro.locals.language = props.language;
50
45
 
46
+ // Use first heading in README as page title
51
47
  if (readme) {
52
48
  const repo = spec.metadata?.[props.language]?.code_url;
53
- readme.code = readme.code.replace(
54
- /<a href="(?!(?:https?:\/\/|\/\/))([^"]+)"/g,
55
- `<a href="${repo}/$1"`);
56
- props.title = readme.metadata.headings[0].text ?? "Overview";
49
+ readme.code = readme.code.replace(/<a href="(?!(?:https?:\/\/|\/\/))([^"]+)"/g, `<a href="${repo}/$1"`);
50
+ props.title = readme.metadata.headings[0]!.text ?? 'Overview';
57
51
  }
58
52
 
53
+ // use summary for the page title of method pages
54
+ if (props.kind === 'http_method' && props.stainlessPath) {
55
+ const parsed = parseStainlessPath(props.stainlessPath);
56
+ const resource = getResourceFromSpec(props.stainlessPath, spec);
57
+ if (parsed?.method && resource?.methods[parsed.method]) {
58
+ const method = resource.methods[parsed.method];
59
+ props.title = method?.summary ?? method?.title ?? props.title;
60
+ }
61
+ }
59
62
  ---
60
63
 
61
-
62
64
  <StarlightPage
63
65
  headings={pageNav}
64
66
  frontmatter={{
65
- title: props?.title,
66
- head: [
67
- {
68
- tag: "link",
69
- attrs: {
70
- rel: "alternate",
71
- type: "text/markdown",
72
- href: `${BASE_PATH}/${Astro.params.slug}.md`
73
- }
74
- }
75
- ],
67
+ title: props.title,
76
68
  pagefind: false,
77
- tableOfContents: ["resource", "readme"].includes(props.kind)
78
- ? { maxHeadingLevel: 6 }
79
- : false,
80
- // @ts-ignore
81
- stainlessStarlight: {
82
- basePath: BASE_PATH,
83
- ...props,
84
- },
69
+ tableOfContents:
70
+ props.kind === 'readme' || (props.kind === 'resource' && props.language !== 'terraform')
71
+ ? { maxHeadingLevel: 6 }
72
+ : false,
85
73
  }}
86
74
  >
87
75
  {
@@ -96,76 +84,36 @@ if (readme) {
96
84
  contentPanelLayout={CONTENT_PANEL_LAYOUT}
97
85
  transformRequestSnippet={MIDDLEWARE.transformRequestSnippet}
98
86
  />
99
-
100
- <style is:inline>
101
- #stldocs-snippet-title {
102
- display: flex;
103
- gap: 5px;
104
- }
105
-
106
- .stldocs-snippet-code:not(.stldocs-snippet-response .stldocs-snippet-code) {
107
- padding: 0 !important;
108
-
109
- .astro-code {
110
- padding: 1rem;
111
- }
112
- }
113
-
114
-
115
- [data-has-sidebar]:not([data-has-toc]) .sl-container {
116
- max-width: 1428px;
117
- }
118
-
119
- .content-panel:nth-of-type(1) {
120
- display: none;
121
- }
122
- .content-panel:nth-of-type(2) .stl-page-nav-container {
123
- display: none;
124
- }
125
-
126
- .content-panel:nth-of-type(2) .stldocs-root .stl-page-nav-container {
127
- display: flex;
128
- }
129
- </style>
130
87
  </div>
131
88
  ) : (
132
89
  <>
133
90
  <Fragment set:html={readme?.code} />
134
- <style is:inline>
135
- .sl-markdown-content h1:first-of-type {
136
- display: none;
137
- }
138
-
139
- .sl-markdown-content img {
140
- display: inline-block;
141
- vertical-align: text-bottom;
142
- }
91
+ <style
92
+ is:inline
93
+ set:text={`
94
+ .sl-markdown-content h1:first-of-type {
95
+ display: none;
96
+ }
143
97
 
144
- .sl-markdown-content .octicon {
145
- margin-right: 0.2rem;
146
- overflow: visible !important;
147
- -webkit-mask: var(--oct-icon) no-repeat;
148
- mask: var(--oct-icon) no-repeat;
149
- -webkit-mask-size: 100% 100%;
150
- mask-size: 100% 100%;
151
- background-color: currentColor;
152
- color: inherit;
153
- display: inline-block;
154
- vertical-align: text-bottom;
155
- width: 1em;
156
- height: 1em;
157
- }
98
+ .sl-markdown-content img {
99
+ display: inline-block;
100
+ vertical-align: text-bottom;
101
+ }
158
102
 
159
- .sl-markdown-content code {
160
- white-space: pre-wrap;
161
- }
162
- </style>
103
+ .sl-markdown-content code {
104
+ white-space: pre-wrap;
105
+ }
106
+ `}
107
+ />
163
108
  </>
164
109
  )
165
110
  }
166
111
  </StarlightPage>
167
112
 
113
+ {EXPERIMENTAL_REQUEST_BUILDER && <StainlessIslands client:load />}
114
+
168
115
  <script src="../globalJs/navigation.ts"></script>
169
116
  <script src="../globalJs/copy.ts"></script>
170
117
  <script src="../globalJs/tooltip.ts"></script>
171
118
  <script src="../globalJs/code-snippets.ts"></script>
119
+ <script src="../globalJs/method-descriptions.ts"></script>
@@ -1,14 +1,17 @@
1
1
  ---
2
2
  import type { GetStaticPaths } from 'astro';
3
3
  import Docs from './Docs.astro';
4
- import { cmsClient } from '../cms/client';
5
- import { generateDocsRoutes } from '../react/Routing';
4
+ import { generateDocsRoutes } from '../helpers/generateDocsRoutes';
5
+ import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
6
6
 
7
7
  export const getStaticPaths = (async () => {
8
- const spec = await cmsClient.getSpec();
8
+ const spec = await getSDKJSONInSSR();
9
9
  const routes = generateDocsRoutes(spec);
10
10
  return routes;
11
11
  }) satisfies GetStaticPaths;
12
+
13
+ export type Props = Awaited<ReturnType<typeof getStaticPaths>>[number]['props'];
14
+ const props = Astro.props;
12
15
  ---
13
16
 
14
- <Docs />
17
+ <Docs {...props} />
@@ -1,24 +1,22 @@
1
1
  ---
2
2
  import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
3
- import { BASE_PATH, EXCLUDE_LANGUAGES } from 'virtual:stl-starlight-virtual-module';
4
- import { cmsClient } from '../cms/client';
5
- import type { DocsLanguage } from '@stainless-api/docs-ui/src/routing';
6
-
7
- import '@stainless-api/docs-ui/src/styles/resets.css';
8
- import '@stainless-api/docs-ui/src/styles/primitives.css';
9
- import '@stainless-api/docs-ui/src/styles/main.css';
10
- import '@stainless-api/docs-ui/src/styles/snippets.css';
11
- // TODO: fix variables.css import
12
- // import '../components/variables.css';
3
+ import { EXCLUDE_LANGUAGES } from 'virtual:stl-starlight-virtual-module';
4
+ import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
13
5
  import { RenderLibraries, RenderSpecOverview, type SpecMetadata } from '../react/Routing';
6
+ import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
14
7
 
15
- const spec = await cmsClient.getSpec();
8
+ const spec = await getSDKJSONInSSR();
16
9
 
17
10
  const languages: DocsLanguage[] = spec.docs!.languages ?? ['http'];
18
- const metadata = languages
11
+ const metadata: SpecMetadata = languages
19
12
  .filter((language) => !['http', 'terraform'].includes(language) && spec.metadata[language])
20
13
  .filter((language) => !EXCLUDE_LANGUAGES.includes(language))
21
- .map((language) => [language, spec.metadata[language]]) as SpecMetadata;
14
+ .map<SpecMetadata[number]>((language) => [language, spec.metadata[language]!]);
15
+
16
+ // PageTitle override will skip rendering the default Starlight title
17
+ Astro.locals._stlStarlightPage = {
18
+ hasMarkdownRoute: false,
19
+ };
22
20
  ---
23
21
 
24
22
  <StarlightPage
@@ -26,22 +24,20 @@ const metadata = languages
26
24
  title: 'API Reference',
27
25
  pagefind: false,
28
26
  tableOfContents: false,
29
- stainlessStarlight: {
30
- basePath: BASE_PATH,
31
- language: 'http',
32
- },
33
27
  }}
34
28
  >
35
- <h3>Libraries</h3>
29
+ <div class="stl-overview">
30
+ <h3>Libraries</h3>
36
31
 
37
- <div class="stldocs-root language-blocks stl-ui-not-prose">
38
- <RenderLibraries metadata={metadata} />
39
- </div>
32
+ <div class="stldocs-root language-blocks stl-ui-not-prose not-content">
33
+ <RenderLibraries metadata={metadata} />
34
+ </div>
40
35
 
41
- <h3>API Overview</h3>
36
+ <h3>API Overview</h3>
42
37
 
43
- <div class="stldocs-root api-overview stl-ui-not-prose">
44
- <RenderSpecOverview spec={spec} language="http" />
38
+ <div class="stldocs-root api-overview stl-ui-not-prose">
39
+ <RenderSpecOverview spec={spec} language="http" />
40
+ </div>
45
41
  </div>
46
42
  </StarlightPage>
47
43
 
@@ -1,13 +1,14 @@
1
1
  import type { APIRoute, GetStaticPaths } from 'astro';
2
- import { cmsClient } from '../cms/client';
3
- import { generateDocsRoutes, getReadmeContent } from '../react/Routing';
4
- import { getResourceFromSpec } from '@stainless-api/docs-ui/src/utils';
2
+ import { getReadmeContent } from '../react/Routing';
3
+ import { getResourceFromSpec } from '@stainless-api/docs-ui/utils';
5
4
 
6
- import { renderMarkdown } from '@stainless-api/docs-ui/src/markdown';
5
+ import { renderMarkdown } from '@stainless-api/docs-ui/markdown';
7
6
 
8
- import { parseStainlessPath, type DocsLanguage } from '@stainless-api/docs-ui/src/routing';
9
- import type { EnvironmentType } from '@stainless-api/docs-ui/src/markdown/utils';
7
+ import { parseStainlessPath, type DocsLanguage } from '@stainless-api/docs-ui/routing';
8
+ import type { EnvironmentType } from '@stainless-api/docs-ui/markdown/utils';
10
9
  import { PROPERTY_SETTINGS, MIDDLEWARE } from 'virtual:stl-starlight-virtual-module';
10
+ import { generateDocsRoutes } from '../helpers/generateDocsRoutes';
11
+ import { getSDKJSONInSSR } from '../specs/fetchSpecSSR';
11
12
 
12
13
  type RouteProps = {
13
14
  stainlessPath: string;
@@ -16,17 +17,17 @@ type RouteProps = {
16
17
  };
17
18
 
18
19
  export const getStaticPaths = (async () => {
19
- const spec = await cmsClient.getSpec();
20
+ const spec = await getSDKJSONInSSR();
20
21
  return generateDocsRoutes(spec);
21
22
  }) satisfies GetStaticPaths;
22
23
 
23
24
  export const GET: APIRoute<RouteProps> = async ({ props }) => {
24
- const spec = await cmsClient.getSpec();
25
+ const spec = await getSDKJSONInSSR();
25
26
 
26
27
  if (props.kind === 'readme') {
27
28
  const readmeContent = await getReadmeContent(spec, props.language);
28
29
  return new Response(readmeContent, {
29
- headers: { 'Content-Type': 'text/markdown' },
30
+ headers: { 'Content-Type': 'text/plain' },
30
31
  });
31
32
  }
32
33
 
@@ -47,11 +48,11 @@ export const GET: APIRoute<RouteProps> = async ({ props }) => {
47
48
  },
48
49
  };
49
50
 
50
- const target = props.kind === 'http_method' && parsed?.method ? resource.methods[parsed.method] : resource;
51
+ const target = props.kind === 'http_method' && parsed?.method ? resource.methods[parsed.method]! : resource;
51
52
  const output = renderMarkdown(env, target);
52
53
 
53
54
  return new Response(output, {
54
- headers: { 'Content-Type': 'text/markdown' },
55
+ headers: { 'Content-Type': 'text/plain' },
55
56
  });
56
57
  };
57
58
 
@@ -1,5 +1,5 @@
1
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
2
- import { generateRoute, walkTree, type DocsLanguage } from '@stainless-api/docs-ui/src/routing';
1
+ import type * as SDKJSON from '@stainless/sdk-json';
2
+ import { generateRoute, walkTree, type DocsLanguage } from '@stainless-api/docs-ui/routing';
3
3
  import type { StarlightRouteData } from '@astrojs/starlight/route-data';
4
4
 
5
5
  function isResourceNonEmpty(resource: SDKJSON.Resource) {
@@ -119,23 +119,12 @@ export type GeneratedSidebarConfig = {
119
119
  ) => ReferenceSidebarConfigItem[] | void;
120
120
  };
121
121
 
122
- function countKeys(obj?: Record<string, any>) {
123
- let o = obj ?? {};
124
- return Object.keys(o).length;
122
+ function countKeys(obj?: Record<string, unknown>) {
123
+ return Object.keys(obj ?? {}).length;
125
124
  }
126
125
 
127
- function getMethodDeclForLanguage(entry: SDKJSON.Method, spec: SDKJSON.Spec, language: DocsLanguage) {
128
- const decls = spec.decls[language] ?? {};
129
- const decl = decls[entry.stainlessPath];
130
- if (decl !== undefined) {
131
- if ('ident' in decl) {
132
- return decl;
133
- }
134
- }
135
- return null;
136
- }
137
-
138
- type MethodDecl = Exclude<ReturnType<typeof getMethodDeclForLanguage>, null>;
126
+ type HasIdent<T> = T extends { ident: unknown } ? T : never;
127
+ type MethodDecl = HasIdent<SDKJSON.LanguageDeclNodes[SDKJSON.SpecLanguage]>;
139
128
 
140
129
  function makeAPIOverviewPage(): UserSidebarAPIOverviewPage {
141
130
  return {
@@ -166,7 +155,7 @@ function pullOutSharedModelsResource(resources: SDKJSON.Resource[]): {
166
155
  }
167
156
 
168
157
  export class SidebarConfigItemsBuilder {
169
- private getMethodDeclForLanguage(entry: SDKJSON.Method) {
158
+ private getMethodDeclForLanguage(entry: SDKJSON.Method): MethodDecl | null {
170
159
  const decls = this.spec.decls[this.language] ?? {};
171
160
  const decl = decls[entry.stainlessPath];
172
161
  if (decl !== undefined) {
@@ -177,10 +166,14 @@ export class SidebarConfigItemsBuilder {
177
166
  return null;
178
167
  }
179
168
 
169
+ private isWebhookResource(resource: SDKJSON.Resource): boolean {
170
+ return resource.stainlessPath === '(resource) webhooks';
171
+ }
172
+
180
173
  private toResourceOverviewPage(entry: SDKJSON.Resource): UserSidebarResourceOverviewPage {
181
174
  return {
182
175
  kind: 'resource_overview_page',
183
- label: 'Overview',
176
+ label: this.isWebhookResource(entry) ? 'Events' : 'Overview',
184
177
  key: entry.configRef,
185
178
  badge: undefined,
186
179
  metadata: {
@@ -208,16 +201,10 @@ export class SidebarConfigItemsBuilder {
208
201
  };
209
202
  }
210
203
 
211
- private sortByLabel<T extends UserSidebarConfigItem>(items: T[]) {
212
- // sorts in place
213
- items.sort((a, b) => {
214
- return a.label.localeCompare(b.label);
215
- });
216
- }
217
-
218
204
  private generateResourceGroup(resource: SDKJSON.Resource, collapsed: boolean): ReferenceSidebarGroup {
219
205
  const entries: ReferenceSidebarConfigItem[] = [];
220
- if (!this.options?.excludeResourceOverviewPages) {
206
+ // even if we aren't generating resource overview pages, we want to generate them for webhooks
207
+ if (!this.options?.excludeResourceOverviewPages || this.isWebhookResource(resource)) {
221
208
  entries.push(this.toResourceOverviewPage(resource));
222
209
  }
223
210
  const methods = Object.values(resource.methods ?? {});
@@ -228,7 +215,6 @@ export class SidebarConfigItemsBuilder {
228
215
  methodPages.push(this.toMethodPage(m, langDecl));
229
216
  }
230
217
  }
231
- this.sortByLabel(methodPages);
232
218
  entries.push(...methodPages);
233
219
 
234
220
  const subresources = Object.values(resource.subresources ?? {});
@@ -238,7 +224,6 @@ export class SidebarConfigItemsBuilder {
238
224
  subresourceGroups.push(this.generateResourceGroup(sub, true));
239
225
  }
240
226
  }
241
- this.sortByLabel(subresourceGroups);
242
227
  entries.push(...subresourceGroups);
243
228
 
244
229
  return {
@@ -253,7 +238,7 @@ export class SidebarConfigItemsBuilder {
253
238
 
254
239
  public generateItems(): ReferenceSidebarConfigItem[] {
255
240
  const resourceMap = this.spec.resources;
256
- let { resources, sharedModelsResource } = pullOutSharedModelsResource(Object.values(resourceMap ?? {}));
241
+ const { resources, sharedModelsResource } = pullOutSharedModelsResource(Object.values(resourceMap ?? {}));
257
242
 
258
243
  const entries: ReferenceSidebarConfigItem[] = resources.filter(isResourceNonEmpty).map((r) => {
259
244
  return this.generateResourceGroup(r, false);
@@ -276,22 +261,11 @@ export class SidebarConfigItemsBuilder {
276
261
  ) {}
277
262
  }
278
263
 
279
- export function walkSidebarConfigItems(
280
- sidebar: ReferenceSidebarConfigItem[],
281
- fn: (item: ReferenceSidebarConfigItem) => void,
282
- ) {
283
- for (const item of sidebar) {
284
- fn(item);
285
- if (item.kind === 'group') {
286
- walkSidebarConfigItems(item.entries, fn);
287
- }
288
- }
289
- }
290
-
291
264
  type SidebarEntry = StarlightRouteData['sidebar'][number];
292
265
 
293
266
  // This allows us to be a bit more forgiving to the user.
294
267
  // As long as they don't modify the key, we can still find the item.
268
+
295
269
  function getResourceOrMethod(spec: SDKJSON.Spec, endpointOrConfigRef: string) {
296
270
  for (const entry of walkTree(spec, false)) {
297
271
  if (entry.data.kind === 'resource' && entry.data.configRef === endpointOrConfigRef) {
@@ -304,7 +278,7 @@ function getResourceOrMethod(spec: SDKJSON.Spec, endpointOrConfigRef: string) {
304
278
  return null;
305
279
  }
306
280
 
307
- export function forceGenerateRoute({
281
+ function forceGenerateRoute({
308
282
  basePath,
309
283
  stainlessPath,
310
284
  language,
@@ -325,19 +299,17 @@ export type BuildSidebarParams = {
325
299
  currentSlug: string;
326
300
  };
327
301
 
328
- type ToStarlightSidebarParams = BuildSidebarParams & {
302
+ type ToStarlightSidebarParams = {
303
+ basePath: string;
329
304
  spec: SDKJSON.Spec;
330
305
  entries: ReferenceSidebarConfigItem[];
331
- currentStainlessPath: string;
332
306
  currentLanguage: DocsLanguage;
333
307
  };
334
308
 
335
309
  export function toStarlightSidebar({
336
310
  basePath,
337
- currentSlug,
338
311
  spec,
339
312
  entries,
340
- currentStainlessPath,
341
313
  currentLanguage,
342
314
  }: ToStarlightSidebarParams): SidebarEntry[] {
343
315
  const starlightEntries: SidebarEntry[] = [];
@@ -350,7 +322,7 @@ export function toStarlightSidebar({
350
322
  type: 'link',
351
323
  href: readmeSlug,
352
324
  label: entry.label,
353
- isCurrent: currentSlug === readmeSlug,
325
+ isCurrent: false,
354
326
  badge: entry.badge,
355
327
  attrs: {
356
328
  'data-stldocs-overview': 'readme',
@@ -369,14 +341,12 @@ export function toStarlightSidebar({
369
341
  language: currentLanguage,
370
342
  });
371
343
 
372
- const isCurrent = resourceOrMethod.data.stainlessPath === currentStainlessPath;
373
-
374
344
  if (resourceOrMethod.data.kind === 'http_method') {
375
345
  starlightEntries.push({
376
346
  type: 'link',
377
347
  href: route,
378
348
  label: entry.label,
379
- isCurrent,
349
+ isCurrent: false,
380
350
  badge: entry.badge,
381
351
  attrs: {
382
352
  'data-stldocs-method': resourceOrMethod.data.httpMethod,
@@ -387,7 +357,7 @@ export function toStarlightSidebar({
387
357
  type: 'link',
388
358
  href: route,
389
359
  label: entry.label,
390
- isCurrent,
360
+ isCurrent: false,
391
361
  badge: entry.badge,
392
362
  attrs: {
393
363
  // TODO: @Ryan: is data.name unique? This is what we used before so I'm not changing, but I am curious.
@@ -398,14 +368,20 @@ export function toStarlightSidebar({
398
368
  throw new Error(`Unknown entry kind ${JSON.stringify(entry)}`);
399
369
  }
400
370
  } else if (entry.kind === 'group') {
371
+ // Skip pushing the group if if the resource it represents is not available in the current language.
372
+ // This occurs when SDK generation for the current language is skipped in the Stainless config for that resource.
373
+ if (entry.resourceGroupKey) {
374
+ const resourceOrMethod = getResourceOrMethod(spec, entry.resourceGroupKey);
375
+ if (resourceOrMethod?.data?.kind === 'resource' && !resourceOrMethod?.data?.[currentLanguage]) {
376
+ continue;
377
+ }
378
+ }
401
379
  starlightEntries.push({
402
380
  type: 'group',
403
381
  label: entry.label,
404
382
  entries: toStarlightSidebar({
405
383
  basePath,
406
- currentSlug,
407
384
  spec,
408
- currentStainlessPath,
409
385
  entries: entry.entries,
410
386
  currentLanguage,
411
387
  }),
@@ -0,0 +1,21 @@
1
+ import { readFile } from 'fs/promises';
2
+
3
+ import { specPath } from 'virtual:stainless-sdk-json-manifest';
4
+ import { SpecWithAuth } from './generateSpec';
5
+
6
+ let cachedSpecWithAuth: SpecWithAuth | null = null;
7
+
8
+ async function getSpecWithAuthInSSR() {
9
+ if (cachedSpecWithAuth) {
10
+ return cachedSpecWithAuth;
11
+ }
12
+ const specStr = await readFile(specPath, 'utf8');
13
+ const json = JSON.parse(specStr) as SpecWithAuth;
14
+ cachedSpecWithAuth = json;
15
+ return json;
16
+ }
17
+
18
+ export async function getSDKJSONInSSR() {
19
+ const specWithAuth = await getSpecWithAuthInSSR();
20
+ return specWithAuth.data;
21
+ }
@@ -0,0 +1,50 @@
1
+ import type * as SDKJSON from '@stainless/sdk-json';
2
+ import { Languages } from '@stainless-api/docs-ui/routing';
3
+ import { createSDKJSON, ParsedConfig, parseInputs, transformOAS } from './worker';
4
+
5
+ function addAuthToSpec(spec: SDKJSON.Spec, config: ParsedConfig) {
6
+ const opts = Object.entries(config.client_settings.opts).map(([k, v]) => ({ name: k, ...v }));
7
+ return {
8
+ data: spec,
9
+ auth: spec.security_schemes.map((scheme) => ({
10
+ ...scheme,
11
+ opts: opts.filter((opt) => opt.auth?.security_scheme === scheme.name),
12
+ })),
13
+ };
14
+ }
15
+
16
+ export type SpecWithAuth = ReturnType<typeof addAuthToSpec>;
17
+
18
+ export async function generateSpecFromStrings({
19
+ oasStr,
20
+ configStr,
21
+ projectName,
22
+ }: {
23
+ oasStr: string;
24
+ configStr: string;
25
+ projectName: string;
26
+ }) {
27
+ const { oas, config } = await parseInputs({
28
+ oas: oasStr,
29
+ config: configStr,
30
+ });
31
+
32
+ const transformedOAS = await transformOAS({ oas, config });
33
+
34
+ const languages =
35
+ config.docs?.languages ??
36
+ (Object.entries(config.targets)
37
+ .filter(([name, target]) => Languages.includes(name) && !target.skip)
38
+ .map(([name]) => name) as SDKJSON.SpecLanguage[]);
39
+
40
+ const sdkJson = await createSDKJSON({
41
+ oas: transformedOAS,
42
+ config,
43
+ languages,
44
+ projectName,
45
+ });
46
+
47
+ const specWithAuth = addAuthToSpec(sdkJson, config);
48
+
49
+ return specWithAuth;
50
+ }