vocs 2.0.17 → 2.1.2

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 (306) hide show
  1. package/dist/config.d.ts +1 -0
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +1 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/globals.d.ts +16 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal/config.d.ts +28 -0
  11. package/dist/internal/config.d.ts.map +1 -1
  12. package/dist/internal/config.js +10 -2
  13. package/dist/internal/config.js.map +1 -1
  14. package/dist/internal/llms.d.ts +21 -2
  15. package/dist/internal/llms.d.ts.map +1 -1
  16. package/dist/internal/llms.js +41 -1
  17. package/dist/internal/llms.js.map +1 -1
  18. package/dist/internal/markdown-negotiation.d.ts +36 -0
  19. package/dist/internal/markdown-negotiation.d.ts.map +1 -0
  20. package/dist/internal/markdown-negotiation.js +81 -0
  21. package/dist/internal/markdown-negotiation.js.map +1 -0
  22. package/dist/internal/markdown.d.ts.map +1 -1
  23. package/dist/internal/markdown.js +5 -0
  24. package/dist/internal/markdown.js.map +1 -1
  25. package/dist/internal/openapi/anchors.d.ts +25 -0
  26. package/dist/internal/openapi/anchors.d.ts.map +1 -0
  27. package/dist/internal/openapi/anchors.js +37 -0
  28. package/dist/internal/openapi/anchors.js.map +1 -0
  29. package/dist/internal/openapi/app.d.ts +89 -0
  30. package/dist/internal/openapi/app.d.ts.map +1 -0
  31. package/dist/internal/openapi/app.js +62 -0
  32. package/dist/internal/openapi/app.js.map +1 -0
  33. package/dist/internal/openapi/index.d.ts +8 -0
  34. package/dist/internal/openapi/index.d.ts.map +1 -0
  35. package/dist/internal/openapi/index.js +5 -0
  36. package/dist/internal/openapi/index.js.map +1 -0
  37. package/dist/internal/openapi/markdown.d.ts +42 -0
  38. package/dist/internal/openapi/markdown.d.ts.map +1 -0
  39. package/dist/internal/openapi/markdown.js +235 -0
  40. package/dist/internal/openapi/markdown.js.map +1 -0
  41. package/dist/internal/openapi/openapi.d.ts +187 -0
  42. package/dist/internal/openapi/openapi.d.ts.map +1 -0
  43. package/dist/internal/openapi/openapi.js +44 -0
  44. package/dist/internal/openapi/openapi.js.map +1 -0
  45. package/dist/internal/openapi/openrpc.d.ts +90 -0
  46. package/dist/internal/openapi/openrpc.d.ts.map +1 -0
  47. package/dist/internal/openapi/openrpc.js +213 -0
  48. package/dist/internal/openapi/openrpc.js.map +1 -0
  49. package/dist/internal/openapi/parser.d.ts +181 -0
  50. package/dist/internal/openapi/parser.d.ts.map +1 -0
  51. package/dist/internal/openapi/parser.js +329 -0
  52. package/dist/internal/openapi/parser.js.map +1 -0
  53. package/dist/internal/openapi/registry.d.ts +36 -0
  54. package/dist/internal/openapi/registry.d.ts.map +1 -0
  55. package/dist/internal/openapi/registry.js +79 -0
  56. package/dist/internal/openapi/registry.js.map +1 -0
  57. package/dist/internal/openapi/sample.d.ts +115 -0
  58. package/dist/internal/openapi/sample.d.ts.map +1 -0
  59. package/dist/internal/openapi/sample.js +434 -0
  60. package/dist/internal/openapi/sample.js.map +1 -0
  61. package/dist/internal/openapi/search.d.ts +19 -0
  62. package/dist/internal/openapi/search.d.ts.map +1 -0
  63. package/dist/internal/openapi/search.js +98 -0
  64. package/dist/internal/openapi/search.js.map +1 -0
  65. package/dist/internal/openapi/sidebar.d.ts +30 -0
  66. package/dist/internal/openapi/sidebar.d.ts.map +1 -0
  67. package/dist/internal/openapi/sidebar.js +67 -0
  68. package/dist/internal/openapi/sidebar.js.map +1 -0
  69. package/dist/internal/openapi/union.d.ts +36 -0
  70. package/dist/internal/openapi/union.d.ts.map +1 -0
  71. package/dist/internal/openapi/union.js +69 -0
  72. package/dist/internal/openapi/union.js.map +1 -0
  73. package/dist/internal/search.d.ts.map +1 -1
  74. package/dist/internal/search.js +20 -0
  75. package/dist/internal/search.js.map +1 -1
  76. package/dist/internal/vite-plugins.d.ts +12 -0
  77. package/dist/internal/vite-plugins.d.ts.map +1 -1
  78. package/dist/internal/vite-plugins.js +102 -11
  79. package/dist/internal/vite-plugins.js.map +1 -1
  80. package/dist/react/Badge.d.ts +2 -3
  81. package/dist/react/Badge.d.ts.map +1 -1
  82. package/dist/react/Layout.client.d.ts.map +1 -1
  83. package/dist/react/Layout.client.js +2 -2
  84. package/dist/react/Layout.client.js.map +1 -1
  85. package/dist/react/OpenApi.d.ts +6 -0
  86. package/dist/react/OpenApi.d.ts.map +1 -0
  87. package/dist/react/OpenApi.js +6 -0
  88. package/dist/react/OpenApi.js.map +1 -0
  89. package/dist/react/internal/CodeToHtml.client.d.ts +53 -2
  90. package/dist/react/internal/CodeToHtml.client.d.ts.map +1 -1
  91. package/dist/react/internal/CodeToHtml.client.js +154 -21
  92. package/dist/react/internal/CodeToHtml.client.js.map +1 -1
  93. package/dist/react/internal/Sidebar.d.ts.map +1 -1
  94. package/dist/react/internal/Sidebar.js +99 -2
  95. package/dist/react/internal/Sidebar.js.map +1 -1
  96. package/dist/react/internal/openapi/CodeSample.client.d.ts +21 -0
  97. package/dist/react/internal/openapi/CodeSample.client.d.ts.map +1 -0
  98. package/dist/react/internal/openapi/CodeSample.client.js +134 -0
  99. package/dist/react/internal/openapi/CodeSample.client.js.map +1 -0
  100. package/dist/react/internal/openapi/CollapsibleChildren.client.d.ts +17 -0
  101. package/dist/react/internal/openapi/CollapsibleChildren.client.d.ts.map +1 -0
  102. package/dist/react/internal/openapi/CollapsibleChildren.client.js +18 -0
  103. package/dist/react/internal/openapi/CollapsibleChildren.client.js.map +1 -0
  104. package/dist/react/internal/openapi/Disclosure.client.d.ts +28 -0
  105. package/dist/react/internal/openapi/Disclosure.client.d.ts.map +1 -0
  106. package/dist/react/internal/openapi/Disclosure.client.js +38 -0
  107. package/dist/react/internal/openapi/Disclosure.client.js.map +1 -0
  108. package/dist/react/internal/openapi/Endpoints.d.ts +26 -0
  109. package/dist/react/internal/openapi/Endpoints.d.ts.map +1 -0
  110. package/dist/react/internal/openapi/Endpoints.js +33 -0
  111. package/dist/react/internal/openapi/Endpoints.js.map +1 -0
  112. package/dist/react/internal/openapi/EndpointsView.d.ts +24 -0
  113. package/dist/react/internal/openapi/EndpointsView.d.ts.map +1 -0
  114. package/dist/react/internal/openapi/EndpointsView.js +26 -0
  115. package/dist/react/internal/openapi/EndpointsView.js.map +1 -0
  116. package/dist/react/internal/openapi/EnumValues.client.d.ts +14 -0
  117. package/dist/react/internal/openapi/EnumValues.client.d.ts.map +1 -0
  118. package/dist/react/internal/openapi/EnumValues.client.js +20 -0
  119. package/dist/react/internal/openapi/EnumValues.client.js.map +1 -0
  120. package/dist/react/internal/openapi/HeadingAnchor.d.ts +15 -0
  121. package/dist/react/internal/openapi/HeadingAnchor.d.ts.map +1 -0
  122. package/dist/react/internal/openapi/HeadingAnchor.js +12 -0
  123. package/dist/react/internal/openapi/HeadingAnchor.js.map +1 -0
  124. package/dist/react/internal/openapi/OpenApiPage.d.ts +79 -0
  125. package/dist/react/internal/openapi/OpenApiPage.d.ts.map +1 -0
  126. package/dist/react/internal/openapi/OpenApiPage.js +72 -0
  127. package/dist/react/internal/openapi/OpenApiPage.js.map +1 -0
  128. package/dist/react/internal/openapi/Operation.d.ts +25 -0
  129. package/dist/react/internal/openapi/Operation.d.ts.map +1 -0
  130. package/dist/react/internal/openapi/Operation.js +101 -0
  131. package/dist/react/internal/openapi/Operation.js.map +1 -0
  132. package/dist/react/internal/openapi/Playground.client.d.ts +33 -0
  133. package/dist/react/internal/openapi/Playground.client.d.ts.map +1 -0
  134. package/dist/react/internal/openapi/Playground.client.js +170 -0
  135. package/dist/react/internal/openapi/Playground.client.js.map +1 -0
  136. package/dist/react/internal/openapi/PropertyExample.client.d.ts +17 -0
  137. package/dist/react/internal/openapi/PropertyExample.client.d.ts.map +1 -0
  138. package/dist/react/internal/openapi/PropertyExample.client.js +21 -0
  139. package/dist/react/internal/openapi/PropertyExample.client.js.map +1 -0
  140. package/dist/react/internal/openapi/Reference.d.ts +55 -0
  141. package/dist/react/internal/openapi/Reference.d.ts.map +1 -0
  142. package/dist/react/internal/openapi/Reference.js +42 -0
  143. package/dist/react/internal/openapi/Reference.js.map +1 -0
  144. package/dist/react/internal/openapi/Schema.d.ts +110 -0
  145. package/dist/react/internal/openapi/Schema.d.ts.map +1 -0
  146. package/dist/react/internal/openapi/Schema.js +239 -0
  147. package/dist/react/internal/openapi/Schema.js.map +1 -0
  148. package/dist/react/internal/openapi/SchemaUnion.client.d.ts +25 -0
  149. package/dist/react/internal/openapi/SchemaUnion.client.d.ts.map +1 -0
  150. package/dist/react/internal/openapi/SchemaUnion.client.js +48 -0
  151. package/dist/react/internal/openapi/SchemaUnion.client.js.map +1 -0
  152. package/dist/react/internal/openapi/anchor-navigation.client.d.ts +47 -0
  153. package/dist/react/internal/openapi/anchor-navigation.client.d.ts.map +1 -0
  154. package/dist/react/internal/openapi/anchor-navigation.client.js +120 -0
  155. package/dist/react/internal/openapi/anchor-navigation.client.js.map +1 -0
  156. package/dist/react/internal/openapi/auth.d.ts +28 -0
  157. package/dist/react/internal/openapi/auth.d.ts.map +1 -0
  158. package/dist/react/internal/openapi/auth.js +75 -0
  159. package/dist/react/internal/openapi/auth.js.map +1 -0
  160. package/dist/react/useLayout.d.ts +2 -0
  161. package/dist/react/useLayout.d.ts.map +1 -1
  162. package/dist/react/useLayout.js +2 -0
  163. package/dist/react/useLayout.js.map +1 -1
  164. package/dist/server/handlers.d.ts +1 -1
  165. package/dist/server/handlers.d.ts.map +1 -1
  166. package/dist/server/handlers.js +26 -5
  167. package/dist/server/handlers.js.map +1 -1
  168. package/dist/server/og-assets.d.ts +5 -0
  169. package/dist/server/og-assets.d.ts.map +1 -0
  170. package/dist/server/og-assets.js +11 -0
  171. package/dist/server/og-assets.js.map +1 -0
  172. package/dist/server/openapi/assets.d.ts +33 -0
  173. package/dist/server/openapi/assets.d.ts.map +1 -0
  174. package/dist/server/openapi/assets.generated.d.ts +9 -0
  175. package/dist/server/openapi/assets.generated.d.ts.map +1 -0
  176. package/dist/server/openapi/assets.generated.js +1091 -0
  177. package/dist/server/openapi/assets.generated.js.map +1 -0
  178. package/dist/server/openapi/assets.js +32 -0
  179. package/dist/server/openapi/assets.js.map +1 -0
  180. package/dist/server/openapi/handler.d.ts +103 -0
  181. package/dist/server/openapi/handler.d.ts.map +1 -0
  182. package/dist/server/openapi/handler.js +198 -0
  183. package/dist/server/openapi/handler.js.map +1 -0
  184. package/dist/server/openapi/handler.test.d.ts +2 -0
  185. package/dist/server/openapi/handler.test.d.ts.map +1 -0
  186. package/dist/server/openapi/handler.test.js +203 -0
  187. package/dist/server/openapi/handler.test.js.map +1 -0
  188. package/dist/server/openapi/html.d.ts +16 -0
  189. package/dist/server/openapi/html.d.ts.map +1 -0
  190. package/dist/server/openapi/html.js +75 -0
  191. package/dist/server/openapi/html.js.map +1 -0
  192. package/dist/server/openapi/pages.d.ts +33 -0
  193. package/dist/server/openapi/pages.d.ts.map +1 -0
  194. package/dist/server/openapi/pages.js +130 -0
  195. package/dist/server/openapi/pages.js.map +1 -0
  196. package/dist/server/openapi/pages.test.d.ts +2 -0
  197. package/dist/server/openapi/pages.test.d.ts.map +1 -0
  198. package/dist/server/openapi/pages.test.js +94 -0
  199. package/dist/server/openapi/pages.test.js.map +1 -0
  200. package/dist/server/openapi/state.d.ts +42 -0
  201. package/dist/server/openapi/state.d.ts.map +1 -0
  202. package/dist/server/openapi/state.js +101 -0
  203. package/dist/server/openapi/state.js.map +1 -0
  204. package/dist/styles/index.css +16 -0
  205. package/dist/styles/markdown.css +9 -7
  206. package/dist/styles/openapi-playground.css +80 -0
  207. package/dist/styles/openapi.css +660 -0
  208. package/dist/vite.d.ts.map +1 -1
  209. package/dist/vite.js +1 -0
  210. package/dist/vite.js.map +1 -1
  211. package/dist/waku/internal/middleware/md-router.d.ts +0 -4
  212. package/dist/waku/internal/middleware/md-router.d.ts.map +1 -1
  213. package/dist/waku/internal/middleware/md-router.js +3 -48
  214. package/dist/waku/internal/middleware/md-router.js.map +1 -1
  215. package/dist/waku/internal/patches/adapters/vercel-build-enhancer.js +1 -1
  216. package/dist/waku/internal/patches/adapters/vercel-build-enhancer.js.map +1 -1
  217. package/dist/waku/internal/patches/router.d.ts.map +1 -1
  218. package/dist/waku/internal/patches/router.js +114 -1
  219. package/dist/waku/internal/patches/router.js.map +1 -1
  220. package/package.json +5 -1
  221. package/src/config.ts +1 -0
  222. package/src/globals.d.ts +16 -0
  223. package/src/index.ts +1 -0
  224. package/src/internal/config.ts +40 -1
  225. package/src/internal/llms.ts +51 -1
  226. package/src/internal/markdown-negotiation.test.ts +42 -0
  227. package/src/internal/markdown-negotiation.ts +95 -0
  228. package/src/internal/markdown.ts +5 -0
  229. package/src/internal/openapi/anchors.ts +44 -0
  230. package/src/internal/openapi/app.ts +127 -0
  231. package/src/internal/openapi/index.ts +24 -0
  232. package/src/internal/openapi/markdown.test.ts +115 -0
  233. package/src/internal/openapi/markdown.ts +275 -0
  234. package/src/internal/openapi/openapi.ts +212 -0
  235. package/src/internal/openapi/openrpc.test.ts +239 -0
  236. package/src/internal/openapi/openrpc.ts +295 -0
  237. package/src/internal/openapi/parser.test.ts +203 -0
  238. package/src/internal/openapi/parser.ts +613 -0
  239. package/src/internal/openapi/registry.test.ts +89 -0
  240. package/src/internal/openapi/registry.ts +89 -0
  241. package/src/internal/openapi/sample.test.ts +283 -0
  242. package/src/internal/openapi/sample.ts +562 -0
  243. package/src/internal/openapi/search.test.ts +62 -0
  244. package/src/internal/openapi/search.ts +108 -0
  245. package/src/internal/openapi/sidebar.test.ts +131 -0
  246. package/src/internal/openapi/sidebar.ts +94 -0
  247. package/src/internal/openapi/union.test.ts +51 -0
  248. package/src/internal/openapi/union.ts +74 -0
  249. package/src/internal/search.ts +20 -0
  250. package/src/internal/test/virtual-config.stub.ts +14 -0
  251. package/src/internal/vite-plugins.ts +106 -11
  252. package/src/openapi-app/App.tsx +64 -0
  253. package/src/openapi-app/blocks.tsx +33 -0
  254. package/src/openapi-app/client.tsx +25 -0
  255. package/src/openapi-app/links.test.ts +84 -0
  256. package/src/openapi-app/links.ts +66 -0
  257. package/src/openapi-app/payload.ts +20 -0
  258. package/src/openapi-app/virtual/config.ts +7 -0
  259. package/src/openapi-app/virtual/group-icons.ts +2 -0
  260. package/src/openapi-app/virtual/langs.ts +6 -0
  261. package/src/openapi-app/virtual/openapi.ts +10 -0
  262. package/src/openapi-app/virtual/search-index.ts +21 -0
  263. package/src/openapi-app/virtual/slots.ts +4 -0
  264. package/src/openapi-app/virtual/user-styles.ts +2 -0
  265. package/src/openapi-app/waku.tsx +154 -0
  266. package/src/react/Badge.tsx +2 -3
  267. package/src/react/Layout.client.tsx +17 -4
  268. package/src/react/OpenApi.tsx +5 -0
  269. package/src/react/internal/CodeToHtml.client.tsx +283 -22
  270. package/src/react/internal/Sidebar.tsx +126 -22
  271. package/src/react/internal/openapi/CodeSample.client.tsx +294 -0
  272. package/src/react/internal/openapi/CollapsibleChildren.client.tsx +41 -0
  273. package/src/react/internal/openapi/Disclosure.client.tsx +67 -0
  274. package/src/react/internal/openapi/Endpoints.tsx +58 -0
  275. package/src/react/internal/openapi/EndpointsView.tsx +76 -0
  276. package/src/react/internal/openapi/EnumValues.client.tsx +49 -0
  277. package/src/react/internal/openapi/HeadingAnchor.tsx +28 -0
  278. package/src/react/internal/openapi/OpenApiPage.tsx +173 -0
  279. package/src/react/internal/openapi/Operation.test.tsx +101 -0
  280. package/src/react/internal/openapi/Operation.tsx +335 -0
  281. package/src/react/internal/openapi/Playground.client.tsx +234 -0
  282. package/src/react/internal/openapi/PropertyExample.client.tsx +55 -0
  283. package/src/react/internal/openapi/Reference.tsx +120 -0
  284. package/src/react/internal/openapi/Schema.tsx +467 -0
  285. package/src/react/internal/openapi/SchemaUnion.client.tsx +123 -0
  286. package/src/react/internal/openapi/anchor-navigation.client.ts +154 -0
  287. package/src/react/internal/openapi/auth.ts +69 -0
  288. package/src/react/useLayout.ts +4 -0
  289. package/src/server/handlers.ts +31 -6
  290. package/src/server/og-assets.ts +14 -0
  291. package/src/server/openapi/assets.generated.ts +1093 -0
  292. package/src/server/openapi/assets.ts +57 -0
  293. package/src/server/openapi/handler.test.ts +244 -0
  294. package/src/server/openapi/handler.ts +277 -0
  295. package/src/server/openapi/html.ts +84 -0
  296. package/src/server/openapi/pages.test.ts +111 -0
  297. package/src/server/openapi/pages.ts +153 -0
  298. package/src/server/openapi/state.ts +136 -0
  299. package/src/styles/index.css +16 -0
  300. package/src/styles/markdown.css +9 -7
  301. package/src/styles/openapi-playground.css +80 -0
  302. package/src/styles/openapi.css +660 -0
  303. package/src/vite.ts +1 -0
  304. package/src/waku/internal/middleware/md-router.ts +8 -52
  305. package/src/waku/internal/patches/adapters/vercel-build-enhancer.ts +1 -1
  306. package/src/waku/internal/patches/router.ts +131 -1
@@ -0,0 +1,234 @@
1
+ 'use client'
2
+
3
+ // Scalar's stylesheet, loaded with this client-only chunk (i.e. only on
4
+ // OpenAPI pages). It is largely unlayered, so it outranks Vocs's layered
5
+ // Tailwind and styles the modal without further layer wiring. During SSR this
6
+ // import is a no-op. A static import is used because Vite reliably injects CSS
7
+ // for static client imports, unlike dynamic `import('*.css')`.
8
+ import '@scalar/api-client/style.css'
9
+ // Maps Scalar's theme variables onto Vocs tokens (loaded after Scalar's CSS so
10
+ // the overrides win). Lives under `src/styles` so the build emits it to
11
+ // `dist/styles` (zile only copies CSS assets reachable from the `./styles/*`
12
+ // export glob; a colocated `./playground.css` would not be emitted).
13
+ import '../../../styles/openapi-playground.css'
14
+ import * as React from 'react'
15
+ import { createPortal } from 'react-dom'
16
+ import LucidePlay from '~icons/lucide/play'
17
+ import type { Ir } from '../../../internal/openapi/parser.js'
18
+ import { useColorScheme } from '../../useColorScheme.js'
19
+ import * as Auth from './auth.js'
20
+
21
+ type OpenFn = (operation: { method: string; path: string; example?: string | undefined }) => void
22
+
23
+ const PlaygroundContext = React.createContext<{ open: OpenFn; ready: boolean } | null>(null)
24
+
25
+ /**
26
+ * Mounts the Scalar API client modal once per spec and exposes an `open`
27
+ * function to its descendants. The modal is a Vue app loaded lazily on the
28
+ * client only (Scalar is untested under SSR), so nothing is imported during
29
+ * server rendering.
30
+ */
31
+ export function PlaygroundProvider(props: PlaygroundProvider.Props) {
32
+ const { client, children, mount: specMount = '/' } = props
33
+ const containerRef = React.useRef<HTMLDivElement>(null)
34
+ // biome-ignore lint/suspicious/noExplicitAny: Scalar's modal type lives in a client-only module.
35
+ const modalRef = React.useRef<any>(null)
36
+ // The Scalar workspace store backing the modal; kept so cross-page auth
37
+ // updates can be loaded into the live store without reopening the modal.
38
+ // biome-ignore lint/suspicious/noExplicitAny: client-only Scalar store instance.
39
+ const storeRef = React.useRef<any>(null)
40
+ const [ready, setReady] = React.useState(false)
41
+
42
+ React.useEffect(() => {
43
+ let cancelled = false
44
+ // biome-ignore lint/suspicious/noExplicitAny: client-only Scalar app instance.
45
+ let modal: any = null
46
+
47
+ async function mount() {
48
+ try {
49
+ const [{ createWorkspaceStore }, { createApiClientModal }] = await Promise.all([
50
+ import('@scalar/workspace-store/client'),
51
+ import('@scalar/api-client/modal'),
52
+ ])
53
+
54
+ // Register a plugin so we're notified whenever the consumer edits
55
+ // credentials in Scalar's "Try" auth UI. We mirror Scalar's exported
56
+ // auth state into localStorage so every other playground instance
57
+ // (other pages, future reloads) picks it up.
58
+ const store = createWorkspaceStore({
59
+ plugins: [
60
+ {
61
+ hooks: {
62
+ onWorkspaceStateChanges(event) {
63
+ if (event.type !== 'auth') return
64
+ const next = serializeAuth(store)
65
+ // Skip writes that match what's already stored — including the
66
+ // change fired by our own `auth.load()` below — to avoid a
67
+ // persist → subscribe → load → persist feedback loop.
68
+ if (next === Auth.read(specMount)) return
69
+ Auth.write(specMount, next)
70
+ },
71
+ },
72
+ },
73
+ ],
74
+ })
75
+ storeRef.current = store
76
+ await store.addDocument({
77
+ name: 'default',
78
+ ...('url' in client ? { url: client.url } : { document: client.content }),
79
+ })
80
+ if (cancelled) return
81
+
82
+ // Seed credentials captured from a previous "Try" session (this page's
83
+ // first mount, another page, or a prior visit).
84
+ loadStoredAuth(store, specMount)
85
+
86
+ modal = createApiClientModal({
87
+ el: containerRef.current,
88
+ workspaceStore: store,
89
+ })
90
+ modalRef.current = modal
91
+ setReady(true)
92
+ } catch (error) {
93
+ // Surface load failures without breaking the docs page.
94
+ console.error('[vocs] Failed to initialize the OpenAPI playground.', error)
95
+ }
96
+ }
97
+
98
+ mount()
99
+ return () => {
100
+ cancelled = true
101
+ try {
102
+ modal?.app?.unmount()
103
+ } catch {}
104
+ modalRef.current = null
105
+ storeRef.current = null
106
+ }
107
+ }, [client, specMount])
108
+
109
+ // When another playground instance (another page/tab) persists new
110
+ // credentials, load them into this live store so its "Try" stays in sync
111
+ // without reopening the modal.
112
+ React.useEffect(
113
+ () =>
114
+ Auth.subscribe(specMount, () => {
115
+ const store = storeRef.current
116
+ if (store) loadStoredAuth(store, specMount)
117
+ }),
118
+ [specMount],
119
+ )
120
+
121
+ const open = React.useCallback<OpenFn>((operation) => {
122
+ modalRef.current?.open({
123
+ method: operation.method.toLowerCase(),
124
+ path: operation.path,
125
+ // Preselect the JSON-RPC method's request example (expanded OpenRPC
126
+ // operations all share one path + verb, so the example disambiguates).
127
+ ...(operation.example ? { example: operation.example } : {}),
128
+ })
129
+ }, [])
130
+
131
+ const value = React.useMemo(() => ({ open, ready }), [open, ready])
132
+
133
+ // Render the Scalar host at `document.body` (client-only) so it sits outside
134
+ // Vocs's layout: a transformed/contained ancestor would otherwise break the
135
+ // modal's `position: fixed` overlay.
136
+ const [mounted, setMounted] = React.useState(false)
137
+ React.useEffect(() => setMounted(true), [])
138
+
139
+ // Scalar's `--scalar-*` theme variables are defined under `.light-mode` /
140
+ // `.dark-mode`; without one of those classes every `var(--scalar-*)` resolves
141
+ // to nothing. Mirror Vocs's active color scheme onto the host.
142
+ const colorScheme = useColorScheme()
143
+
144
+ return (
145
+ <PlaygroundContext.Provider value={value}>
146
+ {children}
147
+ {mounted &&
148
+ createPortal(
149
+ // Scalar scopes ~all of its CSS under `.scalar-app`/`.scalar-client`,
150
+ // so everything it renders must live inside an element with those
151
+ // classes. The dialog teleports (via @headlessui/vue) into
152
+ // `#headlessui-portal-root`; pre-creating that node here — inside the
153
+ // Scalar scope — makes Headless UI reuse it instead of appending a
154
+ // bare node to `<body>`, so the dialog inherits Scalar's styles.
155
+ <div
156
+ className={`scalar-app scalar-client ${colorScheme === 'dark' ? 'dark-mode' : 'light-mode'}`}
157
+ data-v-openapi-playground-root
158
+ >
159
+ <div ref={containerRef} />
160
+ <div id="headlessui-portal-root" />
161
+ </div>,
162
+ document.body,
163
+ )}
164
+ </PlaygroundContext.Provider>
165
+ )
166
+ }
167
+
168
+ export declare namespace PlaygroundProvider {
169
+ type Props = {
170
+ client: Ir['client']
171
+ children: React.ReactNode
172
+ /** Spec mount path; scopes the persisted auth (e.g. `/api`). */
173
+ mount?: string | undefined
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Serializes Scalar's exported auth state to a JSON string for persistence,
179
+ * or `null` when the store holds no credentials.
180
+ */
181
+ // biome-ignore lint/suspicious/noExplicitAny: client-only Scalar store instance.
182
+ function serializeAuth(store: any): string | null {
183
+ try {
184
+ const data = store.auth.export()
185
+ return data && Object.keys(data).length > 0 ? JSON.stringify(data) : null
186
+ } catch {
187
+ return null
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Loads the persisted auth blob for a mount into a Scalar store. Skips the load
193
+ * when the store already matches what's stored, so the change `auth.load()`
194
+ * fires doesn't churn or feed back into a persist loop.
195
+ */
196
+ // biome-ignore lint/suspicious/noExplicitAny: client-only Scalar store instance.
197
+ function loadStoredAuth(store: any, mount: string): void {
198
+ const saved = Auth.read(mount)
199
+ if (!saved || saved === serializeAuth(store)) return
200
+ try {
201
+ store.auth.load(JSON.parse(saved))
202
+ } catch {}
203
+ }
204
+
205
+ /**
206
+ * Button that opens the Scalar API client modal for a single operation. Renders
207
+ * a disabled placeholder until the modal finishes loading on the client.
208
+ */
209
+ export function TestRequestButton(props: TestRequestButton.Props) {
210
+ const { method, path, example } = props
211
+ const context = React.useContext(PlaygroundContext)
212
+
213
+ return (
214
+ <button
215
+ type="button"
216
+ data-v-openapi-action
217
+ data-v-openapi-test-request
218
+ disabled={!context?.ready}
219
+ onClick={() => context?.open({ method, path, example })}
220
+ >
221
+ <LucidePlay data-v-openapi-action-icon />
222
+ Try
223
+ </button>
224
+ )
225
+ }
226
+
227
+ export declare namespace TestRequestButton {
228
+ type Props = {
229
+ method: string
230
+ path: string
231
+ /** Name of the request example to preselect (JSON-RPC method name). */
232
+ example?: string | undefined
233
+ }
234
+ }
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+
3
+ import { useSyncExternalStore } from 'react'
4
+ import {
5
+ hasSampleLine,
6
+ revealSampleLine,
7
+ subscribeSampleAnchors,
8
+ } from './anchor-navigation.client.js'
9
+
10
+ /**
11
+ * A schema/parameter example value. When the sibling code sample renders a line
12
+ * for the same property — a response example line, or a request sample path/
13
+ * query parameter — the value becomes clickable and reveals (switching response
14
+ * tabs / expanding collapsed query params if needed) and flashes that right-hand
15
+ * line: the reverse of clicking a sample line to jump to this row.
16
+ */
17
+ export function PropertyExample(props: PropertyExample.Props) {
18
+ const { id, value } = props
19
+
20
+ // Re-evaluate once the sibling `CodeSample` mounts and registers its anchors,
21
+ // so the affordance appears even though both mount around the same time.
22
+ const clickable = useSyncExternalStore(
23
+ subscribeSampleAnchors,
24
+ () => Boolean(id) && hasSampleLine(id as string),
25
+ () => false,
26
+ )
27
+
28
+ return (
29
+ <div data-v-openapi-property-example data-clickable={clickable || undefined}>
30
+ <span data-v-openapi-property-example-label>Example</span>
31
+ {clickable ? (
32
+ <button
33
+ type="button"
34
+ data-v-openapi-property-example-value
35
+ onClick={() => {
36
+ void revealSampleLine(id as string)
37
+ }}
38
+ >
39
+ {value}
40
+ </button>
41
+ ) : (
42
+ <span data-v-openapi-property-example-value>{value}</span>
43
+ )}
44
+ </div>
45
+ )
46
+ }
47
+
48
+ export declare namespace PropertyExample {
49
+ type Props = {
50
+ /** The property/parameter row's anchor id, matched against sample lines. */
51
+ id?: string | undefined
52
+ /** Example value display string. */
53
+ value: string
54
+ }
55
+ }
@@ -0,0 +1,120 @@
1
+ import type { ReactNode } from 'react'
2
+ import * as Markdown from '../../../internal/markdown.js'
3
+ import type { Ir, IrGroup } from '../../../internal/openapi/parser.js'
4
+ import { HeadingAnchor } from './HeadingAnchor.js'
5
+ import { Operation } from './Operation.js'
6
+
7
+ /**
8
+ * Prop-driven OpenAPI renderers shared by the Vite/RSC site integration
9
+ * ({@link file://./OpenApiPage.tsx `OpenApiPage`}) and the standalone client
10
+ * app ({@link file://../../../standalone/openapi/App.client.tsx}).
11
+ *
12
+ * These render only the section content (the `data-v-openapi` tree). They have
13
+ * no dependency on the Waku `Layout`, the `virtual:vocs/openapi` module, or any
14
+ * router — the caller supplies the parsed {@link Ir} and wraps the tree in the
15
+ * appropriate layout/playground provider.
16
+ */
17
+
18
+ /**
19
+ * Renders trusted markdown from the spec (info/category descriptions) with the
20
+ * same typography as MDX content.
21
+ */
22
+ export function Prose(props: { markdown: string; attr?: string }) {
23
+ return (
24
+ <div
25
+ data-v-openapi-description={props.attr === 'description' ? '' : undefined}
26
+ data-v-content
27
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: server-rendered trusted spec content
28
+ dangerouslySetInnerHTML={{ __html: Markdown.toHtml(props.markdown) }}
29
+ />
30
+ )
31
+ }
32
+
33
+ /**
34
+ * Overview / landing page body. Renders the consumer override (or the
35
+ * auto-generated spec header). The domain/endpoint list is opt-in via
36
+ * `<OpenApi.Endpoints />`.
37
+ */
38
+ export function ReferenceOverview(props: ReferenceOverview.Props) {
39
+ const { ir, intro, endpoints } = props
40
+ return (
41
+ <div data-v-openapi data-v-openapi-landing>
42
+ {intro ? (
43
+ <div data-v-openapi-intro data-v-content>
44
+ {intro}
45
+ </div>
46
+ ) : (
47
+ <>
48
+ <header data-v-openapi-header>
49
+ <h1 data-v data-v-openapi-info-title>
50
+ {ir.info.title}
51
+ </h1>
52
+ {ir.info.description && <Prose markdown={ir.info.description} attr="description" />}
53
+ </header>
54
+ {endpoints}
55
+ </>
56
+ )}
57
+ </div>
58
+ )
59
+ }
60
+
61
+ export declare namespace ReferenceOverview {
62
+ type Props = {
63
+ ir: Ir
64
+ /** Consumer override rendered in place of the auto-generated header. */
65
+ intro?: ReactNode | undefined
66
+ /**
67
+ * Domain/endpoint list rendered below the auto-generated header (ignored
68
+ * when `intro` is set — overrides control their own content). The caller
69
+ * supplies the framework-specific list; the standalone handler passes it so
70
+ * its Introduction lists every endpoint by default.
71
+ */
72
+ endpoints?: ReactNode | undefined
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Single category page body: category header (or consumer override) followed by
78
+ * its operations. Does not mount the playground provider — the caller wraps this
79
+ * with `PlaygroundProvider` so a single Scalar modal is shared across the page.
80
+ */
81
+ export function ReferenceGroup(props: ReferenceGroup.Props) {
82
+ const { ir, group, intro } = props
83
+ return (
84
+ <div data-v-openapi>
85
+ {intro ? (
86
+ // The override keeps the `group.id` anchor so the sidebar "Overview"
87
+ // link and scroll-spy still resolve to this page.
88
+ <div data-v-openapi-intro data-v-content id={group.id}>
89
+ {intro}
90
+ </div>
91
+ ) : (
92
+ <header data-v-openapi-header>
93
+ <h1 data-v data-v-openapi-h1 id={group.id}>
94
+ {group.name}
95
+ <HeadingAnchor id={group.id} />
96
+ </h1>
97
+ {group.description && <Prose markdown={group.description} attr="description" />}
98
+ </header>
99
+ )}
100
+ {group.operations.map((operation, index) => (
101
+ <Operation
102
+ key={operation.id}
103
+ operation={operation}
104
+ server={ir.servers[0]?.url}
105
+ headingLevel={2}
106
+ separator={index > 0}
107
+ />
108
+ ))}
109
+ </div>
110
+ )
111
+ }
112
+
113
+ export declare namespace ReferenceGroup {
114
+ type Props = {
115
+ ir: Ir
116
+ group: IrGroup
117
+ /** Consumer override rendered in place of the auto-generated category header. */
118
+ intro?: ReactNode | undefined
119
+ }
120
+ }