@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
@@ -0,0 +1,32 @@
1
+ {
2
+ "plugin/buildAlgoliaIndex.ts": {
3
+ "@typescript-eslint/no-explicit-any": {
4
+ "count": 2
5
+ }
6
+ },
7
+ "plugin/components/SnippetCode.tsx": {
8
+ "@typescript-eslint/no-explicit-any": {
9
+ "count": 1
10
+ }
11
+ },
12
+ "plugin/globalJs/copy.ts": {
13
+ "@typescript-eslint/no-explicit-any": {
14
+ "count": 3
15
+ }
16
+ },
17
+ "plugin/index.ts": {
18
+ "@typescript-eslint/no-explicit-any": {
19
+ "count": 1
20
+ }
21
+ },
22
+ "plugin/languages.ts": {
23
+ "@typescript-eslint/no-explicit-any": {
24
+ "count": 1
25
+ }
26
+ },
27
+ "plugin/specs/worker.ts": {
28
+ "@typescript-eslint/no-explicit-any": {
29
+ "count": 3
30
+ }
31
+ }
32
+ }
package/locals.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ type SidebarEntry = App.Locals['starlightRoute']['sidebar'][number];
2
+
3
+ /**
4
+ * Extending Astro’s `App.Locals` interface
5
+ */
6
+ declare namespace App {
7
+ interface Locals {
8
+ _stlStarlightPage?: {
9
+ skipRenderingStarlightTitle?: boolean;
10
+ hasMarkdownRoute?: boolean;
11
+ fullSidebar?: SidebarEntry[];
12
+ };
13
+
14
+ stainlessProject?: string;
15
+ language?: import('@stainless-api/docs-ui/routing').DocsLanguage;
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/docs",
3
- "version": "0.1.0-beta.9",
3
+ "version": "0.1.0-beta.91",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -9,24 +9,18 @@
9
9
  "exports": {
10
10
  ".": "./stl-docs/index.ts",
11
11
  "./plugin": "./plugin/index.ts",
12
- "./OverviewRoute": "./plugin/routes/Overview.astro",
13
- "./DocsRoute": "./plugin/routes/Docs.astro",
14
- "./DocsStaticRoute": "./plugin/routes/DocsStatic.astro",
15
- "./MarkdownRoute": "./plugin/routes/markdown.ts",
16
- "./Search": "./plugin/components/search/Search.astro",
17
- "./replaceSidebarPlaceholderMiddleware": "./plugin/replaceSidebarPlaceholderMiddleware.ts",
18
12
  "./plugin/middleware": "./plugin/middlewareBuilder/stlStarlightMiddleware.ts",
19
13
  "./plugin/MiddlewareTypes": "./plugin/middlewareBuilder/stainlessMiddleware.d.ts",
20
- "./Header": "./stl-docs/components/Header.astro",
21
- "./ThemeSelect": "./stl-docs/components/ThemeSelect.astro",
22
- "./BaseSidebar": "./stl-docs/components/sidebars/BaseSidebar.astro",
23
- "./SDKSelectSidebar": "./stl-docs/components/sidebars/SDKSelectSidebar.astro",
24
- "./ContentPanel": "./stl-docs/components/content-panel/ContentPanel.astro",
25
- "./tabsMiddleware": "./stl-docs/tabsMiddleware.ts",
14
+ "./plugin/languages": "./plugin/languages.ts",
26
15
  "./stainless-docs/mintlify-compat": "./stl-docs/components/mintlify-compat/index.ts",
27
- "./theme": "./theme.css",
28
16
  "./mintlify-compat.css": "./styles/mintlify-compat.css",
29
- "./font-imports": "./styles/fonts.css"
17
+ "./components": "./stl-docs/components/index.ts",
18
+ "./components/scripts": "./stl-docs/components/scripts.ts",
19
+ "./docs-config": "./stl-docs/loadStlDocsConfig.ts",
20
+ "./specs/fetchSpecSSR": "./plugin/specs/fetchSpecSSR.ts",
21
+ "./generate-docs-routes": "./plugin/helpers/generateDocsRoutes.ts",
22
+ "./components/Head": "./stl-docs/components/Head.astro",
23
+ "./components/ContentBreadcrumbs": "./stl-docs/components/ContentBreadcrumbs.tsx"
30
24
  },
31
25
  "keywords": [],
32
26
  "author": "",
@@ -35,41 +29,56 @@
35
29
  "node": ">=18.17.1"
36
30
  },
37
31
  "peerDependencies": {
38
- "@astrojs/starlight": ">=0.34.0",
39
- "astro": ">=5.5.0"
32
+ "@astrojs/starlight": ">=0.37.5",
33
+ "astro": ">=5.15.3",
34
+ "react": ">=19.0.0",
35
+ "react-dom": ">=19.0.0",
36
+ "vite": ">=6.2.1"
40
37
  },
41
38
  "dependencies": {
42
- "@astrojs/markdown-remark": "^6.3.2",
43
- "@astrojs/react": "^4.3.1",
44
- "@stainless-api/sdk": "0.1.0-alpha.12",
39
+ "@astrojs/markdown-remark": "^6.3.10",
40
+ "@astrojs/react": "^4.4.2",
41
+ "@stainless-api/sdk": "0.1.0-alpha.19",
42
+ "astro-expressive-code": "^0.41.6",
45
43
  "cheerio": "^1.1.2",
46
44
  "clsx": "^2.1.1",
47
- "dotenv": "17.2.2",
48
- "get-port": "^7.1.0",
49
- "highlight.js": "^11.11.1",
50
- "lucide-react": "^0.544.0",
51
- "marked": "^16.0.0",
52
- "react": "^19.1.1",
53
- "react-dom": "^19.1.1",
45
+ "dotenv": "17.2.3",
46
+ "lucide-react": "^0.562.0",
47
+ "marked": "^17.0.1",
48
+ "node-html-parser": "^7.0.1",
49
+ "rehype-parse": "^9.0.1",
50
+ "rehype-remark": "^10.0.1",
51
+ "remark-gfm": "^4.0.1",
54
52
  "remark-github-alerts": "^0.1.1",
55
- "shiki": "^3.9.2",
53
+ "remark-stringify": "^11.0.0",
54
+ "shiki": "^3.22.0",
55
+ "unified": "^11.0.5",
56
+ "vite-plugin-prebundle-workers": "^0.2.0",
56
57
  "web-worker": "^1.5.0",
57
- "yaml": "^2.8.0",
58
- "@stainless-api/docs-ui": "0.1.0-beta.7",
59
- "@stainless-api/ui-primitives": "0.1.0-beta.8"
58
+ "yaml": "^2.8.2",
59
+ "@stainless-api/docs-search": "0.1.0-beta.21",
60
+ "@stainless-api/docs-ui": "0.1.0-beta.68",
61
+ "@stainless-api/ui-primitives": "0.1.0-beta.47"
60
62
  },
61
63
  "devDependencies": {
62
- "@markdoc/markdoc": "^0.5.2",
63
- "@types/node": "^24.4.0",
64
- "@types/react": "^19.1.13",
65
- "@types/react-dom": "^19.1.9",
66
- "tsx": "^4.20.3",
67
- "zod": "^4.0.0",
68
- "@stainless/eslint-config": "0.0.0"
64
+ "@astrojs/check": "^0.9.6",
65
+ "@markdoc/markdoc": "^0.5.4",
66
+ "@types/node": "24.10.9",
67
+ "@types/react": "19.2.10",
68
+ "@types/react-dom": "^19.2.3",
69
+ "react": "^19.2.4",
70
+ "react-dom": "^19.2.4",
71
+ "tsx": "^4.21.0",
72
+ "typescript": "5.9.3",
73
+ "vite": "^6.4.1",
74
+ "zod": "^4.3.5",
75
+ "@stainless/eslint-config": "0.1.0-beta.1",
76
+ "@stainless/sdk-json": "^0.1.0-beta.4"
69
77
  },
70
78
  "scripts": {
71
- "vendor-deps": "pnpm tsx scripts/vendor_deps.ts",
79
+ "vendor-deps": "tsx scripts/vendor_deps.ts",
72
80
  "lint": "eslint . --max-warnings 0",
73
- "sync": "astro sync"
81
+ "sync": "astro sync",
82
+ "check:types": "astro check"
74
83
  }
75
84
  }
@@ -0,0 +1,96 @@
1
+ declare module 'virtual:stl-playground/typescript.json' {
2
+ const data: {
3
+ links: [string, string][];
4
+ files: [string, string][];
5
+ } | null;
6
+ export { data as default };
7
+ }
8
+ declare module 'virtual:stl-playground/python.json' {
9
+ const data: { files: Record<string, string>; wheel: string } | null;
10
+ export { data as default };
11
+ }
12
+ declare module 'virtual:stl-playground/auth.json' {
13
+ const data:
14
+ | ({
15
+ type: 'http_bearer' | 'query' | 'header' | 'oauth2' | 'http_basic' | 'http_digest';
16
+ description?: string;
17
+ name: string;
18
+ title: string;
19
+ header: string | undefined;
20
+ example: string | undefined;
21
+ } & {
22
+ opts: {
23
+ name: string;
24
+ type: 'string' | 'number' | 'boolean' | 'null' | 'integer';
25
+ nullable: boolean;
26
+ description?: string | undefined;
27
+ example?: unknown;
28
+ default?: unknown;
29
+ read_env?: string | undefined;
30
+ auth?:
31
+ | {
32
+ security_scheme: string;
33
+ role?: 'value' | 'password' | 'username' | 'client_id' | 'client_secret' | undefined;
34
+ }
35
+ | undefined;
36
+ }[];
37
+ })[]
38
+ | null;
39
+ export { data as default };
40
+ }
41
+ declare module 'virtual:stl-playground/data' {
42
+ import type { Config } from 'virtual:stl-playground/create';
43
+ declare const data: Config;
44
+ export { data as default };
45
+ }
46
+ declare module 'virtual:stl-playground/create' {
47
+ export type PlaygroundLanguage = 'python' | 'typescript' | 'http';
48
+ export type Config = {
49
+ wheelUrl: string;
50
+ pyTypes: {
51
+ files: Record<string, string>;
52
+ wheel: string;
53
+ } | null;
54
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ HIGHLIGHT_THEMES: any;
56
+ tsTypes: {
57
+ links: [string, string][];
58
+ files: [string, string][];
59
+ } | null;
60
+ authData:
61
+ | ({
62
+ type: 'http_bearer' | 'query' | 'header' | 'oauth2' | 'http_basic' | 'http_digest';
63
+ description?: string;
64
+ name: string;
65
+ title: string;
66
+ header: string | undefined;
67
+ example: string | undefined;
68
+ } & {
69
+ opts: {
70
+ name: string;
71
+ type: 'string' | 'number' | 'boolean' | 'null' | 'integer';
72
+ nullable: boolean;
73
+ description?: string | undefined;
74
+ example?: unknown;
75
+ default?: unknown;
76
+ read_env?: string | undefined;
77
+ auth?:
78
+ | {
79
+ security_scheme: string;
80
+ role?: 'value' | 'password' | 'username' | 'client_id' | 'client_secret' | undefined;
81
+ }
82
+ | undefined;
83
+ }[];
84
+ })[]
85
+ | null;
86
+ };
87
+ export function createPlayground(
88
+ props: {
89
+ lang: PlaygroundLanguage;
90
+ doc: string;
91
+ /** div.stl-snippet-request-container */
92
+ container: HTMLElement;
93
+ onLanguageSelect: (value: string) => void;
94
+ } & Config,
95
+ ): () => Promise<void>;
96
+ }
@@ -0,0 +1,14 @@
1
+ <svg
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ viewBox="0 0 20 20"
4
+ width="24"
5
+ height="24"
6
+ fill="nopne"
7
+ >
8
+ <path
9
+ fill-rule="evenodd"
10
+ d="M3.25 3A2.25 2.25 0 0 0 1 5.25v9.5A2.25 2.25 0 0 0 3.25 17h13.5A2.25 2.25 0 0 0 19 14.75v-9.5A2.25 2.25 0 0 0 16.75 3zm.943 8.752a.75.75 0 0 1 .055-1.06L6.128 9l-1.88-1.693a.75.75 0 1 1 1.004-1.114l2.5 2.25a.75.75 0 0 1 0 1.114l-2.5 2.25a.75.75 0 0 1-1.06-.055M9.75 10.25a.75.75 0 0 0 0 1.5h2.5a.75.75 0 0 0 0-1.5z"
11
+ clip-rule="evenodd"
12
+ fill="#a2a1a1"
13
+ />
14
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><defs><linearGradient id="a-_r_1_" x1="46.77" x2="69.91" y1="86.46" y2="126.73" gradientTransform="matrix(8.78996,0,0,8.78996,-233.98,-518.97)" gradientUnits="userSpaceOnUse"><stop stop-color="#927be5"></stop><stop offset="1" stop-color="#512bd4"></stop></linearGradient><filter id="b-_r_1_" width="42.84" height="39.14" x="44.63" y="91.89" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset></feOffset><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix><feBlend in2="BackgroundImageFix" result="effect1_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="1"></feOffset><feGaussianBlur stdDeviation="2.5"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix><feBlend in2="effect1_dropShadow_2037_2800" result="effect2_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="4"></feOffset><feGaussianBlur stdDeviation="2"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.09 0"></feColorMatrix><feBlend in2="effect2_dropShadow_2037_2800" result="effect3_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="9"></feOffset><feGaussianBlur stdDeviation="2.5"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"></feColorMatrix><feBlend in2="effect3_dropShadow_2037_2800" result="effect4_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="15"></feOffset><feGaussianBlur stdDeviation="3"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.01 0"></feColorMatrix><feBlend in2="effect4_dropShadow_2037_2800" result="effect5_dropShadow_2037_2800"></feBlend><feBlend in="SourceGraphic" in2="effect5_dropShadow_2037_2800" result="shape"></feBlend></filter></defs><path fill="url(#a-_r_1_)" d="M135.73 285.85v173.93a60.2 60.2 0 0 0 30.13 52.17l150.62 86.97a60.2 60.2 0 0 0 60.25 0l150.62-86.97a60.2 60.2 0 0 0 30.13-52.17V285.85a60.2 60.2 0 0 0-30.13-52.18l-150.62-86.95a60.2 60.2 0 0 0-60.25 0l-150.62 86.95a60.3 60.3 0 0 0-30.13 52.18" transform="scale(0.44288615) matrix(0.1,0,0,0.1,-7.57,-10.19)"></path><path fill="#fff" d="M54.06 98.03v6.86a1.7 1.7 0 0 0 1.71 1.7 1.7 1.7 0 0 0 1.71-1.7 1.71 1.71 0 1 1 3.43 0 5.14 5.14 0 1 1-10.28 0v-6.86a5.14 5.14 0 1 1 10.28 0 1.71 1.71 0 1 1-3.43 0 1.71 1.71 0 1 0-3.42 0zm27.41 6.86a1.7 1.7 0 0 1-1.71 1.7h-1.71v1.72c0 .46-.18.9-.5 1.21a1.7 1.7 0 0 1-2.43 0 1.7 1.7 0 0 1-.5-1.2v-1.72h-3.43v1.71a1.7 1.7 0 0 1-1.71 1.72 1.7 1.7 0 0 1-1.72-1.72v-1.71h-1.71a1.71 1.71 0 1 1 0-3.43h1.71v-3.43h-1.71a1.71 1.71 0 1 1 0-3.42h1.71V94.6a1.71 1.71 0 1 1 3.43 0v1.72h3.43V94.6a1.71 1.71 0 1 1 3.43 0v1.72h1.7c.46 0 .9.18 1.22.5a1.7 1.7 0 0 1 0 2.42 1.7 1.7 0 0 1-1.21.5h-1.71v3.43h1.7a1.7 1.7 0 0 1 1.72 1.71m-6.85-5.14h-3.43v3.42h3.43z" filter="url(#b-_r_1_)" style="mix-blend-mode: screen;" transform="scale(0.44288615) matrix(0.879,0,0,0.879,-30.96,-62.09)"></path></svg>
@@ -1,10 +1,10 @@
1
1
  import Markdoc from '@markdoc/markdoc';
2
2
  import Stainless from '@stainless-api/sdk';
3
- import { createSDKJSON, parseInputs, transformOAS } from './cms/worker';
4
- import type * as SDKJSON from '~/lib/json-spec-v2/types';
5
- import { Languages } from '@stainless-api/docs-ui/src/routing';
6
- import { buildIndex } from '@stainless-api/docs-ui/src/search/providers/algolia';
7
- import type { VersionUserConfig } from './loadPluginConfig';
3
+ import { createSDKJSON, parseInputs, transformOAS } from './specs/worker';
4
+ import type * as SDKJSON from '@stainless/sdk-json';
5
+ import { Languages } from '@stainless-api/docs-ui/routing';
6
+ import { buildIndex } from '@stainless-api/docs-search/providers/algolia';
7
+ import type { AstroIntegrationLogger } from 'astro';
8
8
 
9
9
  const markdocConfig = {
10
10
  nodes: {
@@ -20,11 +20,38 @@ function renderMarkdown(content?: string) {
20
20
  return Markdoc.renderers.html(transformed);
21
21
  }
22
22
 
23
- export async function buildAlgoliaIndex({ version, apiKey }: { version: VersionUserConfig; apiKey: string }) {
23
+ export async function buildAlgoliaIndex({
24
+ stainlessProject,
25
+ branch,
26
+ apiKey,
27
+ logger,
28
+ }: {
29
+ stainlessProject: string;
30
+ branch: string;
31
+ apiKey: string;
32
+ logger?: AstroIntegrationLogger;
33
+ }) {
34
+ function warnLog(message: string) {
35
+ if (logger) {
36
+ logger.warn(message);
37
+ } else {
38
+ console.warn(message);
39
+ }
40
+ }
41
+
42
+ function infoLog(message: string) {
43
+ if (logger) {
44
+ logger.info(message);
45
+ } else {
46
+ console.log(message);
47
+ }
48
+ }
49
+
50
+ // TODO: this is all redundant with the spec code and should be DRYed
24
51
  const client = new Stainless({ apiKey });
25
52
  const configs = await client.projects.configs.retrieve({
26
- project: version.stainlessProject,
27
- branch: version.branch,
53
+ project: stainlessProject,
54
+ branch,
28
55
  include: 'openapi',
29
56
  });
30
57
 
@@ -42,7 +69,6 @@ export async function buildAlgoliaIndex({ version, apiKey }: { version: VersionU
42
69
  const languages =
43
70
  config.docs?.languages ??
44
71
  (Object.entries(config.targets)
45
- // @ts-expect-error we don't have the actual Stainless config type here
46
72
  .filter(([name, target]) => Languages.includes(name) && !target.skip)
47
73
  .map(([name]) => name) as SDKJSON.SpecLanguage[]);
48
74
 
@@ -50,6 +76,7 @@ export async function buildAlgoliaIndex({ version, apiKey }: { version: VersionU
50
76
  oas: transformedOAS,
51
77
  config,
52
78
  languages,
79
+ projectName: stainlessProject,
53
80
  });
54
81
 
55
82
  const {
@@ -64,9 +91,9 @@ export async function buildAlgoliaIndex({ version, apiKey }: { version: VersionU
64
91
  !indexName && 'PUBLIC_ALGOLIA_INDEX',
65
92
  !algoliaWriteKey && 'PRIVATE_ALGOLIA_WRITE_KEY',
66
93
  ].filter(Boolean);
67
- console.warn(`⚠️ Skipping Algolia indexing due to missing environment variables: ${missing.join(', ')}`);
94
+ warnLog(`Skipping Algolia indexing due to missing environment variables: ${missing.join(', ')}`);
68
95
  return;
69
96
  }
70
97
  await buildIndex(appId, indexName, algoliaWriteKey, sdkJson, renderMarkdown);
71
- console.log('Indexing complete.');
98
+ infoLog('Indexing complete.');
72
99
  }
@@ -0,0 +1,54 @@
1
+ import { MethodDescriptionProps } from '@stainless-api/docs-ui/components';
2
+ import { useComponents } from '@stainless-api/docs-ui/contexts/use-components';
3
+ import style from '@stainless-api/docs-ui/style';
4
+ import { Button } from '@stainless-api/ui-primitives';
5
+
6
+ function shouldCollapseDescription(description: string) {
7
+ const MIN_CHARS = 400;
8
+ const MIN_LINES = 6;
9
+
10
+ const lineCount = description.split('\n').length;
11
+
12
+ if (description.length >= MIN_CHARS) return true;
13
+ if (lineCount >= MIN_LINES) return true;
14
+
15
+ // Markdown structure often means longer content
16
+ if (/#\s/.test(description)) return true; // has headings
17
+ if (/```/.test(description)) return true; // has code blocks
18
+ if (/^\s*[-*]\s+/m.test(description)) return true; // has lists
19
+
20
+ return false;
21
+ }
22
+
23
+ export function MethodDescription({ description }: MethodDescriptionProps) {
24
+ const { Markdown } = useComponents();
25
+
26
+ if (description) {
27
+ // Attempt to determine if we should make the description collapsible initially
28
+ // or not. If we get this right, there will be no FOUC.
29
+ const collapsible = shouldCollapseDescription(description);
30
+
31
+ return (
32
+ <div className="stl-method-description">
33
+ <div
34
+ className={style.MethodDescription}
35
+ data-stldocs-property-group="method-description"
36
+ data-collapsed={collapsible ? 'true' : 'false'}
37
+ >
38
+ <Markdown content={description} />
39
+ </div>
40
+ <div className="stl-method-description-overflow-wrapper">
41
+ <Button
42
+ type="button"
43
+ data-method-description-toggle
44
+ size="sm"
45
+ variant="ghost"
46
+ hidden={!collapsible}
47
+ >
48
+ Show more
49
+ </Button>
50
+ </div>
51
+ </div>
52
+ );
53
+ }
54
+ }
@@ -0,0 +1,55 @@
1
+ import { useMemo } from 'react';
2
+ import { Button } from '@stainless-api/ui-primitives';
3
+ import type { Param } from './spec-helpers';
4
+ import { InfoIcon } from 'lucide-react';
5
+ import { Input } from '@stainless-api/docs-ui/components';
6
+
7
+ function setHighlight(stainlessPath: string, highlighted: boolean) {
8
+ const ele = document.getElementById(stainlessPath);
9
+ if (!ele) return;
10
+ ele.classList.toggle('stldocs-property-highlighted', highlighted);
11
+ if (highlighted) {
12
+ if (location.hash) {
13
+ const prevScroll = document.documentElement.scrollTop;
14
+ location.hash = '';
15
+ document.documentElement.scrollTop = prevScroll;
16
+ }
17
+ if (document.body.clientWidth >= 1280) {
18
+ ele.scrollIntoView({
19
+ behavior: 'smooth',
20
+ });
21
+ }
22
+ }
23
+ }
24
+
25
+ function htmlToText(html: string) {
26
+ const template = document.createElement('template');
27
+ template.innerHTML = html;
28
+ return template.content.textContent;
29
+ }
30
+
31
+ export function ParamEditor({ param }: { param: Param }) {
32
+ const type = useMemo(() => htmlToText(param.type), [param.type]);
33
+
34
+ return (
35
+ <label className="request-builder-param">
36
+ <Button
37
+ className="request-builder-param-info-button"
38
+ variant="ghost"
39
+ href={`#${encodeURIComponent(param.stainlessPath)}`}
40
+ >
41
+ <Button.Icon icon={InfoIcon} size={16} />
42
+ </Button>
43
+
44
+ <span className="request-builder-param-label">{param.key}</span>
45
+ <span className="request-builder-param-colon">:</span>
46
+
47
+ <Input
48
+ className="request-builder-param-value"
49
+ onFocus={() => setHighlight(param.stainlessPath, true)}
50
+ onBlur={() => setHighlight(param.stainlessPath, false)}
51
+ placeholder={type}
52
+ />
53
+ </label>
54
+ );
55
+ }
@@ -0,0 +1,107 @@
1
+ import { useState, useMemo, useEffect, useId, useSyncExternalStore, Activity, Fragment } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+ import { Button } from '@stainless-api/ui-primitives';
4
+ import { PlayIcon, RotateCcw } from 'lucide-react';
5
+ import { SnippetStainlessIslandPropsSchema } from './props';
6
+ import { ParamEditor } from './ParamEditor';
7
+ import './styles.css';
8
+
9
+ function useRequiredChild<T extends Element = Element>(
10
+ parent: Element | null,
11
+ selector: string,
12
+ ): React.RefObject<T> {
13
+ const elementRef = useMemo(() => {
14
+ const el = parent?.querySelector<T>(selector);
15
+ return el ? { current: el } : null;
16
+ }, [parent, selector]);
17
+ if (!elementRef) throw new Error(`Required child not found: ${selector}`);
18
+ return elementRef;
19
+ }
20
+
21
+ function useSetVisibility(elementRef: React.RefObject<HTMLElement>, visible: boolean) {
22
+ useEffect(() => {
23
+ elementRef.current.style.display = visible ? '' : 'none';
24
+ }, [elementRef, visible]);
25
+ }
26
+
27
+ export default function SnippetStainlessIsland({ parent }: { parent: HTMLElement }) {
28
+ const [expanded, setExpanded] = useState(false);
29
+
30
+ const trigger = useRequiredChild<HTMLButtonElement>(parent, '.try-it-footer .try-it-button');
31
+ const codeContainer = useRequiredChild<HTMLElement>(parent, '.stldocs-snippet-code');
32
+ const exampleContainer = useRequiredChild<HTMLElement>(parent, '.stldocs-snippet-multi-response');
33
+ useSetVisibility(codeContainer, !expanded);
34
+ useSetVisibility(exampleContainer, !expanded);
35
+ useSetVisibility(trigger, !expanded);
36
+ // Attach click handler to trigger
37
+ useEffect(() => {
38
+ if (!trigger.current) return;
39
+ const ac = new AbortController();
40
+ trigger.current.addEventListener('click', () => setExpanded(true), { signal: ac.signal });
41
+ return () => ac.abort();
42
+ });
43
+
44
+ const requestBuilderContainer = useRequiredChild<HTMLElement>(parent, '.request-builder-container');
45
+ const requestBuilderFooter = useRequiredChild<HTMLElement>(parent, '.request-builder-footer');
46
+ const requestBuilderResponse = useRequiredChild<HTMLElement>(parent, '.request-builder-response');
47
+ const requestBuilderProps = useRequiredChild<HTMLTemplateElement>(parent, '.request-builder-props').current;
48
+ const serializedProps = useSyncExternalStore(
49
+ (cb) => {
50
+ const mutationObserver = new MutationObserver(() => cb());
51
+ mutationObserver.observe(requestBuilderProps, { childList: true });
52
+ return () => mutationObserver.disconnect();
53
+ },
54
+ () => requestBuilderProps.content.textContent,
55
+ );
56
+ const deserializedProps = SnippetStainlessIslandPropsSchema.parse(JSON.parse(serializedProps));
57
+ const groupedParams = Map.groupBy(deserializedProps.params, (p) => p.location);
58
+
59
+ const formId = `request-builder-form-${useId()}`;
60
+
61
+ return (
62
+ <>
63
+ {createPortal(
64
+ <Activity mode={expanded ? 'visible' : 'hidden'}>
65
+ <form
66
+ onSubmit={(e) => {
67
+ alert('TODO: Submit button clicked');
68
+ e.preventDefault();
69
+ }}
70
+ id={formId}
71
+ >
72
+ {[...groupedParams.entries()].map(([location, params]) => (
73
+ <Fragment key={location}>
74
+ <h4>{location} parameters</h4>
75
+ {params.map((e) => (
76
+ <ParamEditor param={e} key={e.location + e.key} />
77
+ ))}
78
+ </Fragment>
79
+ ))}
80
+ </form>
81
+ </Activity>,
82
+ requestBuilderContainer.current,
83
+ )}
84
+
85
+ {createPortal(
86
+ <Activity mode={expanded ? 'visible' : 'hidden'}>
87
+ <Button variant="ghost" border={true} onClick={() => setExpanded(false)}>
88
+ <Button.Icon icon={RotateCcw} />
89
+ </Button>
90
+
91
+ <Button variant="success" className="send-button" type="submit" form={formId}>
92
+ <Button.Label>Send</Button.Label>
93
+ <Button.Icon icon={PlayIcon} />
94
+ </Button>
95
+ </Activity>,
96
+ requestBuilderFooter.current,
97
+ )}
98
+
99
+ {createPortal(
100
+ <Activity mode={expanded ? 'visible' : 'hidden'}>
101
+ <div>{/* TODO */}</div>
102
+ </Activity>,
103
+ requestBuilderResponse.current,
104
+ )}
105
+ </>
106
+ );
107
+ }
@@ -0,0 +1,31 @@
1
+ import { ReactNode } from 'react';
2
+ import * as SDKJSON from '@stainless/sdk-json';
3
+ import { useSpec } from '@stainless-api/docs-ui/contexts';
4
+ import { extractParams } from './spec-helpers';
5
+ import type { SnippetStainlessIslandProps } from './props';
6
+
7
+ /** Load and process the spec on the server side to avoid inflating client bundle */
8
+ export function RequestBuilder({
9
+ className,
10
+ children,
11
+ method,
12
+ }: {
13
+ className: string;
14
+ children: ReactNode;
15
+ method: SDKJSON.Method;
16
+ }) {
17
+ const spec = useSpec();
18
+ if (!spec) throw new Error('Spec is required for RequestBuilder');
19
+ const params = spec && extractParams(spec, method);
20
+ const [httpMethod, path] = method.endpoint.split(' ') as [string, string];
21
+
22
+ return (
23
+ <stl-island component="SnippetStainlessIsland" className={className}>
24
+ {/* Pass state down to the client component. TODO: we need a better solution for this */}
25
+ <template className="request-builder-props">
26
+ {JSON.stringify({ method: httpMethod, path, params } satisfies SnippetStainlessIslandProps)}
27
+ </template>
28
+ {children}
29
+ </stl-island>
30
+ );
31
+ }
@@ -0,0 +1,9 @@
1
+ import z from 'zod';
2
+ import { ParamSchema } from './spec-helpers';
3
+
4
+ export const SnippetStainlessIslandPropsSchema = z.object({
5
+ method: z.string(),
6
+ path: z.string(),
7
+ params: z.array(ParamSchema),
8
+ });
9
+ export type SnippetStainlessIslandProps = z.infer<typeof SnippetStainlessIslandPropsSchema>;