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,154 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Client-side coordination for navigating to a schema property row from a
5
+ * response example line (or a copied property link). Left-hand schema rows live
6
+ * inside collapsed Base UI accordions; because those panels are kept mounted,
7
+ * the target element is always in the DOM. Each {@link Disclosure} registers its
8
+ * panel element and an `open()` callback here, so navigation can reveal every
9
+ * collapsed ancestor of a target before scrolling to it.
10
+ */
11
+
12
+ type Registration = {
13
+ panel: HTMLElement
14
+ open: () => void
15
+ }
16
+
17
+ const disclosures = new Set<Registration>()
18
+
19
+ /** Registers a disclosure panel so it can be auto-opened during navigation. */
20
+ export function registerDisclosure(panel: HTMLElement, open: () => void): () => void {
21
+ const registration: Registration = { panel, open }
22
+ disclosures.add(registration)
23
+ return () => {
24
+ disclosures.delete(registration)
25
+ }
26
+ }
27
+
28
+ /**
29
+ * A code sample's anchor registration: `has(id)` reports whether the sample
30
+ * renders a line/span anchored to `id` (a response example line, or a request
31
+ * sample path/query parameter), and `select(id)` reveals it — switching to the
32
+ * owning response tab and/or expanding collapsed query parameters as needed.
33
+ */
34
+ type SampleRegistration = {
35
+ has: (id: string) => boolean
36
+ select: (id: string) => void
37
+ }
38
+
39
+ const sampleRegistrations = new Set<SampleRegistration>()
40
+ const sampleListeners = new Set<() => void>()
41
+
42
+ /**
43
+ * Registers a code sample's anchors so a left-hand "Example" click can (a) tell
44
+ * whether a matching right-hand line exists ({@link hasSampleLine}) and (b)
45
+ * reveal it ({@link revealSampleLine}) by switching response tabs / expanding
46
+ * collapsed query parameters first.
47
+ */
48
+ export function registerSampleAnchors(registration: SampleRegistration): () => void {
49
+ sampleRegistrations.add(registration)
50
+ for (const listener of sampleListeners) listener()
51
+ return () => {
52
+ sampleRegistrations.delete(registration)
53
+ for (const listener of sampleListeners) listener()
54
+ }
55
+ }
56
+
57
+ /** Whether any registered code sample renders a line/span anchored to `id`. */
58
+ export function hasSampleLine(id: string): boolean {
59
+ for (const registration of sampleRegistrations) if (registration.has(id)) return true
60
+ return false
61
+ }
62
+
63
+ /**
64
+ * Subscribes to sample-anchor registration changes (for `useSyncExternalStore`
65
+ * so a left-hand "Example" can reactively gain its clickable affordance once the
66
+ * sibling code sample has mounted and registered).
67
+ */
68
+ export function subscribeSampleAnchors(listener: () => void): () => void {
69
+ sampleListeners.add(listener)
70
+ return () => {
71
+ sampleListeners.delete(listener)
72
+ }
73
+ }
74
+
75
+ function nextFrame(): Promise<void> {
76
+ return new Promise((resolve) => requestAnimationFrame(() => resolve()))
77
+ }
78
+
79
+ /**
80
+ * Reveals and scrolls to the element with the given id, opening any registered
81
+ * disclosure panels that contain it first. Returns `false` if no such element
82
+ * exists.
83
+ */
84
+ export async function revealAnchor(
85
+ id: string,
86
+ options: { updateHash?: boolean; behavior?: ScrollBehavior } = {},
87
+ ): Promise<boolean> {
88
+ const target = document.getElementById(id)
89
+ if (!target) return false
90
+
91
+ for (const disclosure of disclosures) if (disclosure.panel.contains(target)) disclosure.open()
92
+
93
+ // Let controlled accordions commit their open state (mount/reveal) before
94
+ // measuring scroll position.
95
+ await nextFrame()
96
+ await nextFrame()
97
+
98
+ const resolved = document.getElementById(id)
99
+ if (!resolved) return false
100
+
101
+ resolved.scrollIntoView({ block: 'start', behavior: options.behavior ?? 'smooth' })
102
+ if (options.updateHash !== false) history.pushState(null, '', `#${id}`)
103
+ flash(resolved)
104
+ return true
105
+ }
106
+
107
+ /**
108
+ * The reverse of {@link revealAnchor}: from a left-hand schema/parameter row,
109
+ * reveal and flash the matching line in the right-hand code sample (a response
110
+ * example line, or a request-sample path/query parameter). Switches to the
111
+ * owning response tab and/or expands collapsed query parameters first. Returns
112
+ * `false` when no matching line exists (e.g. request-body properties, which the
113
+ * samples don't anchor).
114
+ */
115
+ export async function revealSampleLine(id: string): Promise<boolean> {
116
+ // Reveal the line in the right-hand panel (switch response tab / expand query
117
+ // params) before querying for it (no-op when it is already visible).
118
+ for (const registration of sampleRegistrations)
119
+ if (registration.has(id)) {
120
+ registration.select(id)
121
+ break
122
+ }
123
+
124
+ // Let the tab switch / expansion commit before querying for the line.
125
+ await nextFrame()
126
+ await nextFrame()
127
+
128
+ const selector = `[data-v-openapi-sample] [data-anchor="${cssEscape(id)}"]`
129
+ const target = document.querySelector<HTMLElement>(selector)
130
+ if (!target) return false
131
+
132
+ target.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
133
+ flash(target)
134
+ return true
135
+ }
136
+
137
+ /** Escapes a string for safe use in a CSS attribute selector. */
138
+ function cssEscape(value: string): string {
139
+ if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') return CSS.escape(value)
140
+ return value.replace(/["\\]/g, '\\$&')
141
+ }
142
+
143
+ /**
144
+ * Briefly highlights an element. Mirrors the `:target` flash used when clicking
145
+ * an anchor link, which `history.pushState` cannot trigger (and which never
146
+ * re-fires when navigating to the same id twice). Toggling a data attribute —
147
+ * with a forced reflow in between — restarts the CSS animation every time.
148
+ */
149
+ function flash(element: HTMLElement): void {
150
+ element.removeAttribute('data-v-openapi-flash')
151
+ // Force a reflow so the animation restarts even if the attribute persists.
152
+ void element.offsetWidth
153
+ element.setAttribute('data-v-openapi-flash', '')
154
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Client-side persistence for the OpenAPI playground's authentication.
3
+ *
4
+ * The source of truth is Scalar's own auth UI inside the "Try" modal: whenever
5
+ * the consumer edits credentials there, the
6
+ * {@link file://./Playground.client.tsx playground provider} captures Scalar's
7
+ * exported auth state and persists it here (keyed per spec mount). Every other
8
+ * playground instance — on other pages of the same section, or after a reload —
9
+ * reads it back and loads it into its Scalar store, so a credential entered once
10
+ * in any "Try" applies everywhere.
11
+ *
12
+ * The persisted value is an opaque JSON string (Scalar's `auth.export()` /
13
+ * `auth.load()` shape); we never interpret it. The value lives in
14
+ * `localStorage` so it survives reloads, and everything is guarded for SSR (no
15
+ * `window`) and degrades to a no-op when storage is unavailable (private mode,
16
+ * blocked cookies).
17
+ */
18
+
19
+ const prefix = 'vocs:openapi-auth:'
20
+ const eventName = 'vocs:openapi-auth-change'
21
+
22
+ function storageKey(mount: string) {
23
+ return prefix + (mount || '/')
24
+ }
25
+
26
+ /** Read the persisted auth blob for a mount (`null` when none/SSR). */
27
+ export function read(mount: string): string | null {
28
+ if (typeof window === 'undefined') return null
29
+ try {
30
+ return window.localStorage.getItem(storageKey(mount))
31
+ } catch {
32
+ return null
33
+ }
34
+ }
35
+
36
+ /** Persist the auth blob for a mount and notify listeners (this tab + others). */
37
+ export function write(mount: string, value: string | null): void {
38
+ if (typeof window === 'undefined') return
39
+ try {
40
+ if (value) window.localStorage.setItem(storageKey(mount), value)
41
+ else window.localStorage.removeItem(storageKey(mount))
42
+ } catch {}
43
+ // `storage` events only fire in *other* tabs, so dispatch our own for the
44
+ // current document (other playground instances on the page listen for it).
45
+ try {
46
+ window.dispatchEvent(new CustomEvent(eventName, { detail: { mount } }))
47
+ } catch {}
48
+ }
49
+
50
+ /**
51
+ * Subscribe to auth changes for a mount. Fires on same-tab writes (via the
52
+ * custom event) and cross-tab writes (via the native `storage` event). Returns
53
+ * an unsubscribe function.
54
+ */
55
+ export function subscribe(mount: string, callback: () => void): () => void {
56
+ if (typeof window === 'undefined') return () => {}
57
+ const onCustom = (event: Event) => {
58
+ if ((event as CustomEvent<{ mount?: string }>).detail?.mount === mount) callback()
59
+ }
60
+ const onStorage = (event: StorageEvent) => {
61
+ if (event.key === storageKey(mount)) callback()
62
+ }
63
+ window.addEventListener(eventName, onCustom)
64
+ window.addEventListener('storage', onStorage)
65
+ return () => {
66
+ window.removeEventListener(eventName, onCustom)
67
+ window.removeEventListener('storage', onStorage)
68
+ }
69
+ }
@@ -5,6 +5,8 @@ import { useSidebar } from './useSidebar.js'
5
5
 
6
6
  export type LayoutState = {
7
7
  layout: 'full' | 'minimal' | 'blank'
8
+ /** Content width: `default` (centered, readable) or `full` (full-bleed). */
9
+ contentWidth: 'default' | 'full'
8
10
  showAskAi: boolean
9
11
  showLogo: boolean
10
12
  showOutline: boolean
@@ -21,9 +23,11 @@ export function useLayout(): LayoutState {
21
23
 
22
24
  const layout = frontmatter?.layout ?? 'full'
23
25
  const outline = frontmatter?.outline
26
+ const contentWidth = frontmatter?.content?.width ?? 'default'
24
27
 
25
28
  return {
26
29
  layout,
30
+ contentWidth,
27
31
  get showSidebar() {
28
32
  if (frontmatter?.showSidebar !== undefined) return frontmatter.showSidebar
29
33
  if (sidebar.items.length === 0) return false
@@ -1,10 +1,29 @@
1
- import { ImageResponse } from '@takumi-rs/image-response/wasm'
2
- // @ts-expect-error
3
- import wasm from '@takumi-rs/wasm/takumi_wasm_bg.wasm?url'
4
-
1
+ /// <reference types="vite/client" />
5
2
  import * as Config from '../internal/config.js'
6
- // @ts-expect-error
7
- import font from './fonts/geist.woff2?arraybuffer'
3
+
4
+ export { compose, openApi } from './openapi/handler.js'
5
+
6
+ /**
7
+ * Loads the Vite-only OG assets (takumi wasm + font) via a Vite
8
+ * `import.meta.glob` trampoline.
9
+ *
10
+ * Vite implements `import.meta.glob` and rewrites it into a dynamic import of
11
+ * `./og-assets`, processing its `?url`/`?arraybuffer` asset imports normally.
12
+ * Bundlers that don't implement the macro (esbuild/Wrangler) leave the call
13
+ * untouched and never follow `./og-assets`, so importing the `vocs/server`
14
+ * barrel for `Handler.openApi` stays edge-safe. The glob is only evaluated when
15
+ * `og().fetch` actually runs, so the indirection costs non-Vite consumers
16
+ * nothing unless they call `Handler.og`.
17
+ */
18
+ async function loadOgAssets(): Promise<typeof import('./og-assets.js')> {
19
+ const modules = import.meta.glob('./og-assets.{js,ts}')
20
+ const load = modules['./og-assets.js'] ?? modules['./og-assets.ts']
21
+ if (!load)
22
+ throw new Error(
23
+ '[vocs] `Handler.og` requires the Vocs/Vite build pipeline (the OG image assets are Vite transforms).',
24
+ )
25
+ return (await load()) as typeof import('./og-assets.js')
26
+ }
8
27
 
9
28
  type Handler = {
10
29
  fetch: (request: Request) => Promise<Response>
@@ -35,6 +54,12 @@ type Handler = {
35
54
  export function og(render: (props: og.Props) => React.JSX.Element): Handler {
36
55
  return {
37
56
  fetch: async (request) => {
57
+ // Loaded lazily via a Vite glob trampoline (see `loadOgAssets`) so plain
58
+ // Node/edge consumers of `vocs/server` — e.g. `Handler.openApi` — can
59
+ // import the namespace without their bundler following the Vite-only
60
+ // takumi/font asset imports.
61
+ const { ImageResponse, wasm, font } = await loadOgAssets()
62
+
38
63
  const url = new URL(request.url)
39
64
  const config = await Config.resolve({ server: true })
40
65
 
@@ -0,0 +1,14 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ // Vite-only asset module. These specifiers (`?url`, `?arraybuffer`) are Vite
4
+ // transforms, so this file is loaded indirectly via `import.meta.glob` in
5
+ // `handlers.ts` rather than imported directly. That keeps non-Vite bundlers
6
+ // (esbuild/Wrangler) from following these asset imports when they only import
7
+ // the `vocs/server` barrel for `Handler.openApi`.
8
+
9
+ export { ImageResponse } from '@takumi-rs/image-response/wasm'
10
+
11
+ import wasm from '@takumi-rs/wasm/takumi_wasm_bg.wasm?url'
12
+ import font from './fonts/geist.woff2?arraybuffer'
13
+
14
+ export { font, wasm }