polen 0.11.0-next.17 → 0.11.0-next.19

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 (307) hide show
  1. package/build/api/builder/ssg/generate.d.ts.map +1 -1
  2. package/build/api/builder/ssg/generate.js +5 -5
  3. package/build/api/builder/ssg/generate.js.map +1 -1
  4. package/build/api/builder/ssg/page-generator.worker.js +13 -3
  5. package/build/api/builder/ssg/page-generator.worker.js.map +1 -1
  6. package/build/api/config/input.d.ts +88 -3
  7. package/build/api/config/input.d.ts.map +1 -1
  8. package/build/api/config/normalized.d.ts +92 -7
  9. package/build/api/config/normalized.d.ts.map +1 -1
  10. package/build/api/config/normalized.js +11 -3
  11. package/build/api/config/normalized.js.map +1 -1
  12. package/build/api/config-template/template.js +2 -2
  13. package/build/api/config-template/template.js.map +1 -1
  14. package/build/api/content/sidebar.d.ts.map +1 -1
  15. package/build/api/content/sidebar.js +2 -1
  16. package/build/api/content/sidebar.js.map +1 -1
  17. package/build/api/errors.d.ts +278 -0
  18. package/build/api/errors.d.ts.map +1 -0
  19. package/build/api/errors.js +153 -0
  20. package/build/api/errors.js.map +1 -0
  21. package/build/api/examples/config.d.ts +366 -3
  22. package/build/api/examples/config.d.ts.map +1 -1
  23. package/build/api/examples/config.js +25 -3
  24. package/build/api/examples/config.js.map +1 -1
  25. package/build/api/examples/diagnostic/diagnostic.d.ts +1 -1
  26. package/build/api/examples/diagnostic/validation-error.d.ts +3 -2
  27. package/build/api/examples/diagnostic/validation-error.d.ts.map +1 -1
  28. package/build/api/examples/diagnostic/validation-error.js +9 -3
  29. package/build/api/examples/diagnostic/validation-error.js.map +1 -1
  30. package/build/api/examples/diagnostic/validator.d.ts.map +1 -1
  31. package/build/api/examples/diagnostic/validator.js +115 -68
  32. package/build/api/examples/diagnostic/validator.js.map +1 -1
  33. package/build/api/examples/filter.d.ts.map +1 -1
  34. package/build/api/examples/filter.js +9 -6
  35. package/build/api/examples/filter.js.map +1 -1
  36. package/build/api/examples/scanner.d.ts.map +1 -1
  37. package/build/api/examples/scanner.js +89 -103
  38. package/build/api/examples/scanner.js.map +1 -1
  39. package/build/api/examples/type-usage-indexer.d.ts.map +1 -1
  40. package/build/api/examples/type-usage-indexer.js +17 -30
  41. package/build/api/examples/type-usage-indexer.js.map +1 -1
  42. package/build/api/iso/schema/routing.d.ts.map +1 -1
  43. package/build/api/iso/schema/routing.js +8 -8
  44. package/build/api/iso/schema/routing.js.map +1 -1
  45. package/build/api/iso/schema/validation.d.ts.map +1 -1
  46. package/build/api/iso/schema/validation.js +3 -2
  47. package/build/api/iso/schema/validation.js.map +1 -1
  48. package/build/api/schema/input-source/$$.d.ts +1 -0
  49. package/build/api/schema/input-source/$$.d.ts.map +1 -1
  50. package/build/api/schema/input-source/$$.js +1 -0
  51. package/build/api/schema/input-source/$$.js.map +1 -1
  52. package/build/api/schema/input-source/errors.d.ts +36 -0
  53. package/build/api/schema/input-source/errors.d.ts.map +1 -0
  54. package/build/api/schema/input-source/errors.js +17 -0
  55. package/build/api/schema/input-source/errors.js.map +1 -0
  56. package/build/api/schema/input-source/input-source.d.ts +1 -7
  57. package/build/api/schema/input-source/input-source.d.ts.map +1 -1
  58. package/build/api/schema/input-source/input-source.js +0 -6
  59. package/build/api/schema/input-source/input-source.js.map +1 -1
  60. package/build/api/schema/input-sources/directory.d.ts.map +1 -1
  61. package/build/api/schema/input-sources/directory.js +19 -6
  62. package/build/api/schema/input-sources/directory.js.map +1 -1
  63. package/build/api/schema/input-sources/file.d.ts.map +1 -1
  64. package/build/api/schema/input-sources/file.js +15 -4
  65. package/build/api/schema/input-sources/file.js.map +1 -1
  66. package/build/api/schema/input-sources/introspection-file.d.ts.map +1 -1
  67. package/build/api/schema/input-sources/introspection-file.js +28 -6
  68. package/build/api/schema/input-sources/introspection-file.js.map +1 -1
  69. package/build/api/schema/input-sources/introspection.d.ts.map +1 -1
  70. package/build/api/schema/input-sources/introspection.js +35 -7
  71. package/build/api/schema/input-sources/introspection.js.map +1 -1
  72. package/build/api/schema/input-sources/memory.d.ts.map +1 -1
  73. package/build/api/schema/input-sources/memory.js +15 -3
  74. package/build/api/schema/input-sources/memory.js.map +1 -1
  75. package/build/api/schema/input-sources/versioned-directory.d.ts.map +1 -1
  76. package/build/api/schema/input-sources/versioned-directory.js +23 -7
  77. package/build/api/schema/input-sources/versioned-directory.js.map +1 -1
  78. package/build/api/schema/load.d.ts +1 -1
  79. package/build/api/schema/load.d.ts.map +1 -1
  80. package/build/api/schema/load.js.map +1 -1
  81. package/build/cli/commands/hero-image.d.ts +1 -2
  82. package/build/cli/commands/hero-image.d.ts.map +1 -1
  83. package/build/cli/index.d.ts +1 -1
  84. package/build/lib/catalog/catalog.d.ts +43 -3
  85. package/build/lib/catalog/catalog.d.ts.map +1 -1
  86. package/build/lib/catalog/catalog.js +67 -5
  87. package/build/lib/catalog/catalog.js.map +1 -1
  88. package/build/lib/catalog/versioned.d.ts +11 -1
  89. package/build/lib/catalog/versioned.d.ts.map +1 -1
  90. package/build/lib/catalog/versioned.js +23 -5
  91. package/build/lib/catalog/versioned.js.map +1 -1
  92. package/build/lib/document/document.d.ts +55 -5
  93. package/build/lib/document/document.d.ts.map +1 -1
  94. package/build/lib/document/document.js +96 -2
  95. package/build/lib/document/document.js.map +1 -1
  96. package/build/lib/document/versioned.d.ts +2 -2
  97. package/build/lib/document/versioned.d.ts.map +1 -1
  98. package/build/lib/document/versioned.js +7 -7
  99. package/build/lib/document/versioned.js.map +1 -1
  100. package/build/lib/lifecycles/lifecycles.d.ts +5 -4
  101. package/build/lib/lifecycles/lifecycles.d.ts.map +1 -1
  102. package/build/lib/lifecycles/lifecycles.js +14 -12
  103. package/build/lib/lifecycles/lifecycles.js.map +1 -1
  104. package/build/lib/version-coverage/$$.d.ts +2 -0
  105. package/build/lib/version-coverage/$$.d.ts.map +1 -0
  106. package/build/lib/version-coverage/$$.js +2 -0
  107. package/build/lib/version-coverage/$$.js.map +1 -0
  108. package/build/lib/version-coverage/$.d.ts.map +1 -0
  109. package/build/lib/version-coverage/$.js.map +1 -0
  110. package/build/lib/{version-selection/version-selection.d.ts → version-coverage/version-coverage.d.ts} +1 -1
  111. package/build/lib/version-coverage/version-coverage.d.ts.map +1 -0
  112. package/build/lib/{version-selection/version-selection.js → version-coverage/version-coverage.js} +2 -2
  113. package/build/lib/version-coverage/version-coverage.js.map +1 -0
  114. package/build/template/components/GraphQLDocument.d.ts +1 -1
  115. package/build/template/components/GraphQLDocument.d.ts.map +1 -1
  116. package/build/template/components/GraphQLDocument.js +10 -39
  117. package/build/template/components/GraphQLDocument.js.map +1 -1
  118. package/build/template/components/GraphQLInteractive/lib/parser.d.ts +28 -0
  119. package/build/template/components/GraphQLInteractive/lib/parser.d.ts.map +1 -1
  120. package/build/template/components/GraphQLInteractive/lib/parser.js +60 -27
  121. package/build/template/components/GraphQLInteractive/lib/parser.js.map +1 -1
  122. package/build/template/components/ReferenceVersionPicker.d.ts +9 -0
  123. package/build/template/components/ReferenceVersionPicker.d.ts.map +1 -0
  124. package/build/template/components/ReferenceVersionPicker.js +79 -0
  125. package/build/template/components/ReferenceVersionPicker.js.map +1 -0
  126. package/build/template/components/VersionCoveragePicker.d.ts +1 -1
  127. package/build/template/components/VersionCoveragePicker.d.ts.map +1 -1
  128. package/build/template/components/VersionCoveragePicker.js +4 -6
  129. package/build/template/components/VersionCoveragePicker.js.map +1 -1
  130. package/build/template/components/VersionPicker.d.ts +8 -3
  131. package/build/template/components/VersionPicker.d.ts.map +1 -1
  132. package/build/template/components/VersionPicker.js +12 -77
  133. package/build/template/components/VersionPicker.js.map +1 -1
  134. package/build/template/components/home/QuickStart.d.ts.map +1 -1
  135. package/build/template/components/home/QuickStart.js +8 -4
  136. package/build/template/components/home/QuickStart.js.map +1 -1
  137. package/build/template/hooks/use-highlighted.d.ts.map +1 -1
  138. package/build/template/hooks/use-highlighted.js +19 -13
  139. package/build/template/hooks/use-highlighted.js.map +1 -1
  140. package/build/template/lib/fetch-text.d.ts +18 -0
  141. package/build/template/lib/fetch-text.d.ts.map +1 -1
  142. package/build/template/lib/fetch-text.js +32 -4
  143. package/build/template/lib/fetch-text.js.map +1 -1
  144. package/build/template/routes/changelog/ChangelogBody.d.ts +6 -0
  145. package/build/template/routes/changelog/ChangelogBody.d.ts.map +1 -0
  146. package/build/template/{components/Changelog/Changelog.js → routes/changelog/ChangelogBody.js} +8 -58
  147. package/build/template/routes/changelog/ChangelogBody.js.map +1 -0
  148. package/build/template/routes/changelog/ChangelogSidebar.d.ts +7 -0
  149. package/build/template/routes/changelog/ChangelogSidebar.d.ts.map +1 -0
  150. package/build/template/routes/changelog/ChangelogSidebar.js +46 -0
  151. package/build/template/routes/changelog/ChangelogSidebar.js.map +1 -0
  152. package/build/template/routes/changelog/ChangelogSidebarItem.d.ts +11 -0
  153. package/build/template/routes/changelog/ChangelogSidebarItem.d.ts.map +1 -0
  154. package/build/template/routes/changelog/ChangelogSidebarItem.js +35 -0
  155. package/build/template/routes/changelog/ChangelogSidebarItem.js.map +1 -0
  156. package/build/template/routes/changelog/_.d.ts +3264 -0
  157. package/build/template/routes/changelog/_.d.ts.map +1 -0
  158. package/build/template/routes/changelog/_.js +111 -0
  159. package/build/template/routes/changelog/_.js.map +1 -0
  160. package/build/template/routes/changelog/utils.d.ts +3 -0
  161. package/build/template/routes/changelog/utils.d.ts.map +1 -0
  162. package/build/template/routes/changelog/utils.js +11 -0
  163. package/build/template/routes/changelog/utils.js.map +1 -0
  164. package/build/template/routes/examples/name.d.ts.map +1 -1
  165. package/build/template/routes/examples/name.js +4 -2
  166. package/build/template/routes/examples/name.js.map +1 -1
  167. package/build/template/routes/reference.js +2 -2
  168. package/build/template/routes/reference.js.map +1 -1
  169. package/build/template/routes/root.js +1 -1
  170. package/build/template/routes/root.js.map +1 -1
  171. package/build/template/stores/toast.d.ts.map +1 -1
  172. package/build/template/stores/toast.js +5 -3
  173. package/build/template/stores/toast.js.map +1 -1
  174. package/build/template/theme/swiss-sharp.css +14 -14
  175. package/build/vite/plugins/schemas.d.ts +1 -2
  176. package/build/vite/plugins/schemas.d.ts.map +1 -1
  177. package/build/vite/plugins/schemas.js +0 -1
  178. package/build/vite/plugins/schemas.js.map +1 -1
  179. package/package.json +7 -7
  180. package/src/api/builder/ssg/generate.ts +10 -5
  181. package/src/api/builder/ssg/page-generator.worker.ts +18 -3
  182. package/src/api/config/normalized.ts +12 -3
  183. package/src/api/config-template/template.ts +2 -2
  184. package/src/api/content/sidebar.ts +3 -3
  185. package/src/api/errors.ts +227 -0
  186. package/src/api/examples/config.test.ts +10 -0
  187. package/src/api/examples/config.ts +33 -4
  188. package/src/api/examples/diagnostic/validation-error.ts +9 -3
  189. package/src/api/examples/diagnostic/validator.test.ts +30 -0
  190. package/src/api/examples/diagnostic/validator.ts +148 -103
  191. package/src/api/examples/filter.ts +9 -6
  192. package/src/api/examples/scanner.ts +136 -117
  193. package/src/api/examples/type-usage-indexer.ts +24 -36
  194. package/src/api/iso/schema/routing.ts +10 -10
  195. package/src/api/iso/schema/validation.ts +3 -2
  196. package/src/api/schema/input-source/$$.ts +1 -0
  197. package/src/api/schema/input-source/errors.ts +26 -0
  198. package/src/api/schema/input-source/input-source.ts +1 -22
  199. package/src/api/schema/input-sources/directory.ts +20 -15
  200. package/src/api/schema/input-sources/file.ts +17 -4
  201. package/src/api/schema/input-sources/introspection-file.ts +30 -15
  202. package/src/api/schema/input-sources/introspection.ts +38 -7
  203. package/src/api/schema/input-sources/memory.ts +19 -3
  204. package/src/api/schema/input-sources/versioned-directory.ts +25 -27
  205. package/src/api/schema/load.ts +2 -1
  206. package/src/lib/catalog/catalog.ts +89 -6
  207. package/src/lib/catalog/versioned.ts +26 -5
  208. package/src/lib/document/document.ts +135 -2
  209. package/src/lib/document/versioned.ts +8 -8
  210. package/src/lib/lifecycles/lifecycles.ts +32 -27
  211. package/src/lib/version-coverage/$$.ts +1 -0
  212. package/src/lib/{version-selection/version-selection.ts → version-coverage/version-coverage.ts} +1 -1
  213. package/src/template/components/GraphQLDocument.tsx +11 -69
  214. package/src/template/components/GraphQLInteractive/lib/parser.ts +81 -29
  215. package/src/template/components/ReferenceVersionPicker.tsx +107 -0
  216. package/src/template/components/VersionCoveragePicker.tsx +4 -5
  217. package/src/template/components/VersionPicker.tsx +32 -98
  218. package/src/template/components/home/QuickStart.tsx +16 -7
  219. package/src/template/hooks/use-highlighted.ts +31 -19
  220. package/src/template/lib/fetch-text.ts +45 -4
  221. package/src/template/{components/Changelog/Changelog.tsx → routes/changelog/ChangelogBody.tsx} +7 -64
  222. package/src/template/routes/changelog/ChangelogSidebar.tsx +80 -0
  223. package/src/template/routes/changelog/ChangelogSidebarItem.tsx +68 -0
  224. package/src/template/routes/changelog/_.tsx +129 -0
  225. package/src/template/routes/changelog/utils.ts +13 -0
  226. package/src/template/routes/examples/name.tsx +4 -2
  227. package/src/template/routes/reference.tsx +2 -2
  228. package/src/template/routes/root.tsx +1 -1
  229. package/src/template/stores/toast.ts +6 -3
  230. package/src/template/theme/swiss-sharp.css +14 -14
  231. package/src/vite/plugins/schemas.ts +0 -1
  232. package/build/lib/graph/$$.d.ts +0 -2
  233. package/build/lib/graph/$$.d.ts.map +0 -1
  234. package/build/lib/graph/$$.js +0 -2
  235. package/build/lib/graph/$$.js.map +0 -1
  236. package/build/lib/graph/$.d.ts +0 -2
  237. package/build/lib/graph/$.d.ts.map +0 -1
  238. package/build/lib/graph/$.js +0 -2
  239. package/build/lib/graph/$.js.map +0 -1
  240. package/build/lib/graph/graph.d.ts +0 -127
  241. package/build/lib/graph/graph.d.ts.map +0 -1
  242. package/build/lib/graph/graph.js +0 -152
  243. package/build/lib/graph/graph.js.map +0 -1
  244. package/build/lib/mask/$$.d.ts +0 -3
  245. package/build/lib/mask/$$.d.ts.map +0 -1
  246. package/build/lib/mask/$$.js +0 -3
  247. package/build/lib/mask/$$.js.map +0 -1
  248. package/build/lib/mask/$.d.ts +0 -2
  249. package/build/lib/mask/$.d.ts.map +0 -1
  250. package/build/lib/mask/$.js +0 -2
  251. package/build/lib/mask/$.js.map +0 -1
  252. package/build/lib/mask/apply.d.ts +0 -86
  253. package/build/lib/mask/apply.d.ts.map +0 -1
  254. package/build/lib/mask/apply.js +0 -86
  255. package/build/lib/mask/apply.js.map +0 -1
  256. package/build/lib/mask/mask.d.ts +0 -124
  257. package/build/lib/mask/mask.d.ts.map +0 -1
  258. package/build/lib/mask/mask.js +0 -137
  259. package/build/lib/mask/mask.js.map +0 -1
  260. package/build/lib/mask/mask.test-d.d.ts +0 -2
  261. package/build/lib/mask/mask.test-d.d.ts.map +0 -1
  262. package/build/lib/mask/mask.test-d.js +0 -102
  263. package/build/lib/mask/mask.test-d.js.map +0 -1
  264. package/build/lib/version-selection/$$.d.ts +0 -2
  265. package/build/lib/version-selection/$$.d.ts.map +0 -1
  266. package/build/lib/version-selection/$$.js +0 -2
  267. package/build/lib/version-selection/$$.js.map +0 -1
  268. package/build/lib/version-selection/$.d.ts.map +0 -1
  269. package/build/lib/version-selection/$.js.map +0 -1
  270. package/build/lib/version-selection/version-selection.d.ts.map +0 -1
  271. package/build/lib/version-selection/version-selection.js.map +0 -1
  272. package/build/sandbox.d.ts +0 -2
  273. package/build/sandbox.d.ts.map +0 -1
  274. package/build/sandbox.js +0 -17
  275. package/build/sandbox.js.map +0 -1
  276. package/build/template/components/Changelog/Changelog.d.ts +0 -8
  277. package/build/template/components/Changelog/Changelog.d.ts.map +0 -1
  278. package/build/template/components/Changelog/Changelog.js.map +0 -1
  279. package/build/template/components/Changelog/ChangelogVersionPicker.d.ts +0 -8
  280. package/build/template/components/Changelog/ChangelogVersionPicker.d.ts.map +0 -1
  281. package/build/template/components/Changelog/ChangelogVersionPicker.js +0 -16
  282. package/build/template/components/Changelog/ChangelogVersionPicker.js.map +0 -1
  283. package/build/template/components/SimpleVersionPicker.d.ts +0 -15
  284. package/build/template/components/SimpleVersionPicker.d.ts.map +0 -1
  285. package/build/template/components/SimpleVersionPicker.js +0 -15
  286. package/build/template/components/SimpleVersionPicker.js.map +0 -1
  287. package/build/template/routes/changelog.d.ts +0 -1635
  288. package/build/template/routes/changelog.d.ts.map +0 -1
  289. package/build/template/routes/changelog.js +0 -168
  290. package/build/template/routes/changelog.js.map +0 -1
  291. package/src/lib/graph/$$.ts +0 -1
  292. package/src/lib/graph/$.ts +0 -1
  293. package/src/lib/graph/graph.ts +0 -197
  294. package/src/lib/mask/$$.ts +0 -2
  295. package/src/lib/mask/$.test.ts +0 -226
  296. package/src/lib/mask/$.ts +0 -1
  297. package/src/lib/mask/apply.ts +0 -134
  298. package/src/lib/mask/mask.test-d.ts +0 -156
  299. package/src/lib/mask/mask.ts +0 -244
  300. package/src/lib/version-selection/$$.ts +0 -1
  301. package/src/sandbox.ts +0 -15
  302. package/src/template/components/Changelog/ChangelogVersionPicker.tsx +0 -36
  303. package/src/template/components/SimpleVersionPicker.tsx +0 -48
  304. package/src/template/routes/changelog.tsx +0 -267
  305. /package/build/lib/{version-selection → version-coverage}/$.d.ts +0 -0
  306. /package/build/lib/{version-selection → version-coverage}/$.js +0 -0
  307. /package/src/lib/{version-selection → version-coverage}/$.ts +0 -0
@@ -0,0 +1,107 @@
1
+ import { Api } from '#api/iso'
2
+ import type { React } from '#dep/react/index'
3
+ import { Version } from '#lib/version/$'
4
+ import { HashMap, Option } from 'effect'
5
+ import { useNavigate } from 'react-router'
6
+ import { schemasCatalog } from 'virtual:polen/project/schemas'
7
+ import { useReferencePath } from '../hooks/useReferencePath.js'
8
+ import { Stores } from '../stores/$.js'
9
+ import { tryWithToast } from '../utils/try-with-toast.js'
10
+ import { VersionPicker } from './VersionPicker.js'
11
+
12
+ interface Props {
13
+ data: readonly Version.Version[]
14
+ current: Version.Version
15
+ }
16
+
17
+ export const ReferenceVersionPicker: React.FC<Props> = ({ data, current }) => {
18
+ const navigate = useNavigate()
19
+ const currentPath = useReferencePath()
20
+
21
+ const handleVersionChange = async (version: Version.Version) => {
22
+ const newVersion = Version.encodeSync(version)
23
+ const error = await tryWithToast(async () => {
24
+ // Get the full catalog to find the target schema
25
+ if (!schemasCatalog) {
26
+ throw new Error('No catalog available')
27
+ }
28
+ const catalog = schemasCatalog
29
+
30
+ // This component is only used for versioned catalogs
31
+ if (catalog._tag !== 'CatalogVersioned') {
32
+ throw new Error('VersionPicker used with non-versioned catalog')
33
+ }
34
+
35
+ // Find the schema for the target version
36
+ // Note: newVersion is a string that we need to parse
37
+ const targetSchemaOption = Option.map(
38
+ HashMap.findFirst(catalog.entries, (_, key) => Version.encodeSync(key) === newVersion),
39
+ ([, value]) => value,
40
+ )
41
+
42
+ if (Option.isNone(targetSchemaOption)) {
43
+ throw new Error(`Version ${newVersion} not found`)
44
+ }
45
+
46
+ const targetSchema = Option.getOrThrow(targetSchemaOption)
47
+
48
+ // Find fallback path if needed
49
+ const fallbackPath = Api.Schema.Validation.findFallbackPath(targetSchema.definition, currentPath)
50
+ // Get redirect description if path changed
51
+ const redirectDescription = Api.Schema.Validation.getRedirectDescription(
52
+ targetSchema.definition,
53
+ currentPath,
54
+ fallbackPath,
55
+ newVersion,
56
+ )
57
+ // Create the new path - parse newVersion string to Version type
58
+ const newPath = Api.Schema.Routing.createReferencePath({
59
+ version: Version.fromString(newVersion),
60
+ type: fallbackPath.type || '',
61
+ field: fallbackPath.field || '',
62
+ })
63
+ // Show toast notification if schema location redirect will occur
64
+ if (redirectDescription) {
65
+ Stores.Toast.store.info(redirectDescription, {
66
+ duration: 160_000,
67
+ actions: [
68
+ {
69
+ label: 'Go back',
70
+ onClick() {
71
+ navigate(-1)
72
+ },
73
+ },
74
+ {
75
+ label: 'View changelog',
76
+ onClick() {
77
+ // Navigate to changelog page
78
+ navigate('/changelog')
79
+ },
80
+ },
81
+ ],
82
+ })
83
+ }
84
+
85
+ navigate(newPath)
86
+ }, 'Failed to switch version')
87
+
88
+ // Fallback logic if error occurred
89
+ if (error) {
90
+ // Fallback to simple navigation if schema loading fails
91
+ const newPath = Api.Schema.Routing.createReferencePath({
92
+ version: Version.fromString(newVersion),
93
+ type: currentPath.type || '',
94
+ field: currentPath.field || '',
95
+ })
96
+ navigate(newPath)
97
+ }
98
+ }
99
+
100
+ return (
101
+ <VersionPicker
102
+ versions={data}
103
+ currentVersion={current}
104
+ onVersionChange={handleVersionChange}
105
+ />
106
+ )
107
+ }
@@ -1,6 +1,6 @@
1
1
  import { Catalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
- import { VersionCoverage } from '#lib/version-selection/$'
3
+ import { VersionCoverage } from '#lib/version-coverage'
4
4
  import { Select } from '@radix-ui/themes'
5
5
  import { HashMap } from 'effect'
6
6
  import type { FC } from 'react'
@@ -30,12 +30,11 @@ export const VersionCoveragePicker: FC<Props> = ({
30
30
  <Select.Root
31
31
  value={VersionCoverage.toLabel(current)}
32
32
  onValueChange={(label) => {
33
- // Find selection by label and pick first version from it
33
+ // Find the full version coverage by label and pass it entirely
34
34
  const selection = options.find(s => VersionCoverage.toLabel(s) === label)
35
35
  if (selection) {
36
- const versions = VersionCoverage.toVersions(selection)
37
- const version = versions[0]
38
- if (version) onChange(version)
36
+ // Pass the entire VersionCoverage, not just the first version
37
+ onChange(selection)
39
38
  }
40
39
  }}
41
40
  >
@@ -1,108 +1,42 @@
1
- import { Api } from '#api/iso'
2
- import type { React } from '#dep/react/index'
3
- import { Catalog } from '#lib/catalog/$'
4
1
  import { Version } from '#lib/version/$'
5
- import { HashMap, Option } from 'effect'
6
- import { useNavigate } from 'react-router'
7
- import { schemasCatalog } from 'virtual:polen/project/schemas'
8
- import { useReferencePath } from '../hooks/useReferencePath.js'
9
- import { Stores } from '../stores/$.js'
10
- import { tryWithToast } from '../utils/try-with-toast.js'
11
- import { SimpleVersionPicker } from './SimpleVersionPicker.js'
2
+ import { Select } from '@radix-ui/themes'
3
+ import type * as React from 'react'
12
4
 
13
5
  interface Props {
14
- data: readonly Version.Version[]
15
- current: Version.Version
6
+ versions: readonly Version.Version[]
7
+ currentVersion: Version.Version
8
+ onVersionChange: (version: Version.Version) => void
16
9
  }
17
10
 
18
- export const VersionPicker: React.FC<Props> = ({ data, current }) => {
19
- const navigate = useNavigate()
20
- const currentPath = useReferencePath()
21
-
22
- const handleVersionChange = async (version: Version.Version) => {
23
- const newVersion = Version.encodeSync(version)
24
- const error = await tryWithToast(async () => {
25
- // Get the full catalog to find the target schema
26
- if (!schemasCatalog) {
27
- throw new Error('No catalog available')
28
- }
29
- const catalog = schemasCatalog
30
-
31
- // This component is only used for versioned catalogs
32
- if (catalog._tag !== 'CatalogVersioned') {
33
- throw new Error('VersionPicker used with non-versioned catalog')
34
- }
35
-
36
- // Find the schema for the target version
37
- // Note: newVersion is a string that we need to parse
38
- const targetSchemaOption = Option.map(
39
- HashMap.findFirst(catalog.entries, (_, key) => Version.encodeSync(key) === newVersion),
40
- ([, value]) => value,
41
- )
42
-
43
- if (Option.isNone(targetSchemaOption)) {
44
- throw new Error(`Version ${newVersion} not found`)
45
- }
46
-
47
- const targetSchema = Option.getOrThrow(targetSchemaOption)
48
-
49
- // Find fallback path if needed
50
- const fallbackPath = Api.Schema.Validation.findFallbackPath(targetSchema.definition, currentPath)
51
- // Get redirect description if path changed
52
- const redirectDescription = Api.Schema.Validation.getRedirectDescription(
53
- targetSchema.definition,
54
- currentPath,
55
- fallbackPath,
56
- newVersion,
57
- )
58
- // Create the new path - parse newVersion string to Version type
59
- const newPath = Api.Schema.Routing.createReferencePath({
60
- version: Version.fromString(newVersion),
61
- type: fallbackPath.type || '',
62
- field: fallbackPath.field || '',
63
- })
64
- // Show toast notification if schema location redirect will occur
65
- if (redirectDescription) {
66
- Stores.Toast.store.info(redirectDescription, {
67
- duration: 160_000,
68
- actions: [
69
- {
70
- label: 'Go back',
71
- onClick() {
72
- navigate(-1)
73
- },
74
- },
75
- {
76
- label: 'View changelog',
77
- onClick() {
78
- // Navigate to changelog page
79
- navigate('/changelog')
80
- },
81
- },
82
- ],
83
- })
84
- }
85
-
86
- navigate(newPath)
87
- }, 'Failed to switch version')
88
-
89
- // Fallback logic if error occurred
90
- if (error) {
91
- // Fallback to simple navigation if schema loading fails
92
- const newPath = Api.Schema.Routing.createReferencePath({
93
- version: Version.fromString(newVersion),
94
- type: currentPath.type || '',
95
- field: currentPath.field || '',
96
- })
97
- navigate(newPath)
98
- }
11
+ /**
12
+ * A generic version picker component that can be used for any versioned content.
13
+ * This is a controlled component - parent manages the state.
14
+ */
15
+ export const VersionPicker: React.FC<Props> = ({
16
+ versions,
17
+ currentVersion,
18
+ onVersionChange,
19
+ }) => {
20
+ // Don't show selector if only one version
21
+ if (versions.length <= 1) {
22
+ return null
99
23
  }
100
24
 
101
25
  return (
102
- <SimpleVersionPicker
103
- versions={data}
104
- currentVersion={current}
105
- onVersionChange={handleVersionChange}
106
- />
26
+ <Select.Root
27
+ value={Version.encodeSync(currentVersion)}
28
+ onValueChange={(versionEncoded) => onVersionChange(Version.fromString(versionEncoded))}
29
+ >
30
+ <Select.Trigger style={{ minWidth: '120px' }}>
31
+ Version {Version.encodeSync(currentVersion)}
32
+ </Select.Trigger>
33
+ <Select.Content position='popper' sideOffset={5}>
34
+ {versions.map(version => (
35
+ <Select.Item key={Version.encodeSync(version)} value={Version.encodeSync(version)}>
36
+ Version {Version.encodeSync(version)}
37
+ </Select.Item>
38
+ ))}
39
+ </Select.Content>
40
+ </Select.Root>
107
41
  )
108
42
  }
@@ -1,5 +1,6 @@
1
1
  import { Box, Card, Heading, Section, Tabs, Text } from '@radix-ui/themes'
2
2
  import { highlight } from 'codehike/code'
3
+ import { Effect } from 'effect'
3
4
  import * as React from 'react'
4
5
  import { CodeBlock } from '../CodeBlock.js'
5
6
 
@@ -73,14 +74,22 @@ export const QuickStartSection: React.FC<Props> = ({ examples = defaultExamples
73
74
 
74
75
  React.useEffect(() => {
75
76
  const highlightExamples = async () => {
76
- const highlighted = await Promise.all(
77
- examples.map(async (example) => ({
78
- label: example.label,
79
- codeblock: await highlight(
80
- { value: example.code, lang: example.language, meta: '' },
81
- { theme: 'github-light' },
77
+ const highlighted = await Effect.runPromise(
78
+ Effect.all(
79
+ examples.map((example) =>
80
+ Effect.tryPromise({
81
+ try: async () => ({
82
+ label: example.label,
83
+ codeblock: await highlight(
84
+ { value: example.code, lang: example.language, meta: '' },
85
+ { theme: 'github-light' },
86
+ ),
87
+ }),
88
+ catch: (error) => new Error(`Failed to highlight ${example.label}: ${error}`),
89
+ })
82
90
  ),
83
- })),
91
+ { concurrency: 'unbounded' },
92
+ ),
84
93
  )
85
94
  setHighlightedExamples(highlighted)
86
95
  }
@@ -1,5 +1,6 @@
1
1
  import type { HighlightedCode } from 'codehike/code'
2
2
  import { highlight } from 'codehike/code'
3
+ import { Duration, Effect } from 'effect'
3
4
  import * as React from 'react'
4
5
 
5
6
  /**
@@ -29,26 +30,37 @@ export const useHighlighted = (
29
30
  const [highlightedCode, setHighlightedCode] = React.useState<HighlightedCode | null>(null)
30
31
 
31
32
  React.useEffect(() => {
32
- const highlightContent = async () => {
33
- // Add a timeout to detect if highlight is hanging
34
- const timeoutPromise = new Promise((_, reject) => {
35
- setTimeout(() => reject(new Error('Highlight timeout after 5 seconds')), 5000)
36
- })
37
-
38
- const highlightPromise = highlight(
39
- {
40
- value: content,
41
- lang: config.lang,
42
- meta: metaString,
43
- },
44
- {
45
- theme: 'github-light',
46
- },
47
- )
33
+ const HIGHLIGHT_TIMEOUT = Duration.seconds(5)
48
34
 
49
- const highlighted = await Promise.race([highlightPromise, timeoutPromise])
50
-
51
- setHighlightedCode(highlighted as any)
35
+ const highlightContent = async () => {
36
+ try {
37
+ const highlighted = await Effect.runPromise(
38
+ Effect.tryPromise({
39
+ try: () =>
40
+ highlight(
41
+ {
42
+ value: content,
43
+ lang: config.lang,
44
+ meta: metaString,
45
+ },
46
+ {
47
+ theme: 'github-light',
48
+ },
49
+ ),
50
+ catch: (error) => new Error(`Highlight failed: ${error}`),
51
+ }).pipe(
52
+ Effect.timeout(HIGHLIGHT_TIMEOUT),
53
+ Effect.catchTag(
54
+ 'TimeoutException',
55
+ () => Effect.fail(new Error(`Highlight timeout after ${Duration.toSeconds(HIGHLIGHT_TIMEOUT)} seconds`)),
56
+ ),
57
+ ),
58
+ )
59
+ setHighlightedCode(highlighted)
60
+ } catch (error) {
61
+ console.error('Failed to highlight code:', error)
62
+ setHighlightedCode(null)
63
+ }
52
64
  }
53
65
  highlightContent()
54
66
  }, [content, config.lang, config.interactive])
@@ -1,13 +1,54 @@
1
+ import { Either } from 'effect'
2
+
3
+ /**
4
+ * Error type for fetch failures
5
+ */
6
+ export interface FetchError {
7
+ readonly _tag: 'FetchError'
8
+ readonly url: string
9
+ readonly status: number
10
+ readonly statusText: string
11
+ readonly message: string
12
+ }
13
+
14
+ const makeFetchError = (url: string, status: number, statusText: string): FetchError => ({
15
+ _tag: 'FetchError',
16
+ url,
17
+ status,
18
+ statusText,
19
+ message: `Failed to fetch: ${url} (${status} ${statusText})`,
20
+ })
21
+
1
22
  /**
2
23
  * Fetch text content from a URL
3
24
  * @param url - The URL to fetch from
25
+ * @returns Either with text content on right or FetchError on left
26
+ */
27
+ export const fetchTextEither = async (url: string): Promise<Either.Either<string, FetchError>> => {
28
+ try {
29
+ const response = await fetch(url)
30
+ if (!response.ok) {
31
+ return Either.left(makeFetchError(url, response.status, response.statusText))
32
+ }
33
+ const text = await response.text()
34
+ return Either.right(text)
35
+ } catch (error) {
36
+ // Network errors or other exceptions
37
+ return Either.left(makeFetchError(url, 0, 'Network Error'))
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Fetch text content from a URL (legacy throwing version)
43
+ * @param url - The URL to fetch from
4
44
  * @returns Promise that resolves to the text content
5
45
  * @throws Error if the request fails
46
+ * @deprecated Use fetchTextEither for better error handling
6
47
  */
7
48
  export const fetchText = async (url: string): Promise<string> => {
8
- const response = await fetch(url)
9
- if (!response.ok) {
10
- throw new Error(`Failed to fetch: ${url} (${response.status} ${response.statusText})`)
49
+ const result = await fetchTextEither(url)
50
+ if (Either.isLeft(result)) {
51
+ throw new Error(result.left.message)
11
52
  }
12
- return response.text()
53
+ return result.right
13
54
  }
@@ -1,75 +1,18 @@
1
1
  import { Catalog } from '#lib/catalog/$'
2
2
  import { Change } from '#lib/change/$'
3
- import { DateOnly } from '#lib/date-only/$'
4
3
  import { Revision } from '#lib/revision/$'
5
4
  import { Schema } from '#lib/schema/$'
6
- import { Version } from '#lib/version/$'
7
- import { HashMap, Option } from 'effect'
8
5
  const CRITICALITY_LEVELS = ['BREAKING', 'DANGEROUS', 'NON_BREAKING'] as const
9
6
  import type { CriticalityLevel } from '@graphql-inspector/core'
10
7
  import { Box, Heading } from '@radix-ui/themes'
11
- import React, { useEffect } from 'react'
8
+ import React from 'react'
12
9
  import { useMemo } from 'react'
13
- import { useNavigate, useParams } from 'react-router'
14
- import { ComponentDispatch } from '../ComponentDispatch.js'
15
- import { CriticalitySection } from './CriticalitySection.js'
16
- import * as Group from './groups/index.js'
17
-
18
- export const renderDate = (dateOnly: DateOnly.DateOnly) => {
19
- const date = DateOnly.toDate(dateOnly)
20
- const year = date.getUTCFullYear()
21
- return `${year} ${
22
- date.toLocaleString('default', {
23
- month: 'long',
24
- day: 'numeric',
25
- timeZone: 'UTC',
26
- })
27
- }`
28
- }
29
-
30
- export const Changelog: React.FC<{ catalog: Catalog.Catalog }> = ({ catalog }) => {
31
- const params = useParams()
32
- const navigate = useNavigate()
33
- const urlVersion = params['version']
34
-
35
- // Redirect to latest version if versioned catalog and no version specified
36
- useEffect(() => {
37
- if (urlVersion) return
38
- if (Catalog.Unversioned.is(catalog)) return
39
- const latestSchema = Catalog.Versioned.getLatestOrThrow(catalog)
40
- const latestVersion = Version.encodeSync(latestSchema.version)
41
- navigate(`/changelog/version/${latestVersion}`, { replace: true })
42
- }, [catalog, urlVersion, navigate])
43
-
44
- // Get revisions and corresponding schema based on catalog type and URL params
45
- const { revisions, schema } = useMemo(() => {
46
- if (Catalog.Unversioned.is(catalog)) {
47
- return {
48
- revisions: catalog.schema.revisions,
49
- schema: catalog.schema,
50
- }
51
- } else {
52
- // For versioned catalogs, always show specific version (never all)
53
- if (urlVersion) {
54
- const entryOption = Option.map(
55
- HashMap.findFirst(catalog.entries, (_, key) => Version.encodeSync(key) === urlVersion),
56
- ([, value]) => value,
57
- )
58
- return Option.match(entryOption, {
59
- onNone: () => ({ revisions: [], schema: null }),
60
- onSome: (entry) => ({ revisions: entry.revisions, schema: entry }),
61
- })
62
- }
63
- // This shouldn't happen due to redirect above, but return empty as fallback
64
- return { revisions: [], schema: null }
65
- }
66
- }, [catalog, urlVersion])
67
-
68
- // Don't render anything while redirecting
69
- if (Catalog.Versioned.is(catalog) && !urlVersion) {
70
- return null
71
- }
10
+ import { CriticalitySection } from '../../components/Changelog/CriticalitySection.js'
11
+ import * as Group from '../../components/Changelog/groups/index.js'
12
+ import { ComponentDispatch } from '../../components/ComponentDispatch.js'
13
+ import { renderDate } from './utils.js'
72
14
 
15
+ export const ChangelogBody: React.FC<{ schema: Schema.Schema }> = ({ schema }) => {
73
16
  return (
74
17
  <Box>
75
18
  {/* Title bar - always shown */}
@@ -77,7 +20,7 @@ export const Changelog: React.FC<{ catalog: Catalog.Catalog }> = ({ catalog }) =
77
20
  Changelog
78
21
  </Heading>
79
22
 
80
- {revisions.map(revision => <Changeset key={revision.date} revision={revision} schema={schema} />)}
23
+ {schema.revisions.map(revision => <Changeset key={revision.date} revision={revision} schema={schema} />)}
81
24
  </Box>
82
25
  )
83
26
  }
@@ -0,0 +1,80 @@
1
+ import { Catalog } from '#lib/catalog/$'
2
+ import { Schema } from '#lib/schema/$'
3
+ import { Swiss } from '#lib/swiss/$'
4
+ import { Version } from '#lib/version'
5
+ import { Box, Text } from '@radix-ui/themes'
6
+ import { useEffect, useState } from 'react'
7
+ import { useNavigate, useParams } from 'react-router'
8
+ import { VersionPicker } from '../../components/VersionPicker.js'
9
+ import { ChangelogSidebarItem } from './ChangelogSidebarItem.js'
10
+
11
+ export const ChangelogSidebar: React.FC<{
12
+ catalog: Catalog.Catalog
13
+ schema: Schema.Schema
14
+ }> = ({ catalog, schema }) => {
15
+ {
16
+ const navigate = useNavigate()
17
+
18
+ // Get revisions for the current version (for sidebar)
19
+ const revisions = schema.revisions
20
+
21
+ const [activeRevision, setActiveRevision] = useState<string | null>(null)
22
+ // Track active revision based on URL hash
23
+ useEffect(() => {
24
+ const handleHashChange = () => {
25
+ const hash = window.location.hash.slice(1)
26
+ setActiveRevision(hash || null)
27
+ }
28
+
29
+ // Set initial active revision
30
+ handleHashChange()
31
+
32
+ // Listen for hash changes
33
+ window.addEventListener('hashchange', handleHashChange)
34
+
35
+ // Listen for pushState/replaceState (custom event we'll dispatch)
36
+ window.addEventListener('pushstate', handleHashChange)
37
+
38
+ return () => {
39
+ window.removeEventListener('hashchange', handleHashChange)
40
+ window.removeEventListener('pushstate', handleHashChange)
41
+ }
42
+ }, [])
43
+
44
+ return (
45
+ <Swiss.Item
46
+ cols={3}
47
+ style={{
48
+ position: 'sticky',
49
+ top: '2rem',
50
+ height: 'fit-content',
51
+ minWidth: '250px',
52
+ maxHeight: 'calc(100vh - 4rem)',
53
+ overflowY: 'auto',
54
+ }}
55
+ >
56
+ {Catalog.Versioned.is(catalog) && Schema.Versioned.is(schema) && (
57
+ <Box mb='3'>
58
+ <VersionPicker
59
+ versions={Catalog.Versioned.getVersions(catalog)}
60
+ currentVersion={schema.version}
61
+ onVersionChange={(newVersion) => {
62
+ navigate(`/changelog/version/${Version.encodeSync(newVersion)}`)
63
+ }}
64
+ />
65
+ </Box>
66
+ )}
67
+ <Text size='2' weight='medium' mb='3' style={{ display: 'block' }}>
68
+ Revisions
69
+ </Text>
70
+ {revisions.map((revision) => (
71
+ <ChangelogSidebarItem
72
+ key={revision.date}
73
+ revision={revision}
74
+ isActive={activeRevision === revision.date}
75
+ />
76
+ ))}
77
+ </Swiss.Item>
78
+ )
79
+ }
80
+ }
@@ -0,0 +1,68 @@
1
+ import { Change } from '#lib/change'
2
+ import { Revision } from '#lib/revision'
3
+ import { Box, Flex, Text } from '@radix-ui/themes'
4
+ import { renderDate } from './utils.js'
5
+
6
+ export const ChangelogSidebarItem: React.FC<{
7
+ revision: Revision.Revision
8
+ isActive: boolean
9
+ }> = ({ revision, isActive }) => {
10
+ const counts = calculateCounts(revision)
11
+
12
+ return (
13
+ <Box mb='2'>
14
+ <a
15
+ href={`#${revision.date}`}
16
+ style={{
17
+ textDecoration: 'none',
18
+ display: 'flex',
19
+ alignItems: 'center',
20
+ justifyContent: 'space-between',
21
+ padding: '0.5rem 0.75rem',
22
+ borderRadius: '4px',
23
+ backgroundColor: isActive ? 'var(--gray-a3)' : 'transparent',
24
+ color: 'inherit',
25
+ transition: 'background-color 0.2s',
26
+ }}
27
+ onClick={(e) => {
28
+ e.preventDefault()
29
+ // Update URL hash
30
+ window.history.pushState(null, '', `#${revision.date}`)
31
+ // Dispatch custom event for pushState
32
+ window.dispatchEvent(new Event('pushstate'))
33
+ // Smooth scroll to element
34
+ document.getElementById(revision.date)?.scrollIntoView({ behavior: 'smooth' })
35
+ }}
36
+ >
37
+ <Text size='2' weight={isActive ? 'medium' : 'regular'}>
38
+ {renderDate(revision.date)}
39
+ </Text>
40
+ <Flex gap='2' align='center'>
41
+ {counts.breaking > 0 && (
42
+ <Text size='1' weight='medium' style={{ color: '#ef4444' }}>
43
+ {counts.breaking}
44
+ </Text>
45
+ )}
46
+ {counts.dangerous > 0 && (
47
+ <Text size='1' weight='medium' style={{ color: '#f59e0b' }}>
48
+ {counts.dangerous}
49
+ </Text>
50
+ )}
51
+ {counts.safe > 0 && (
52
+ <Text size='1' weight='medium' style={{ color: '#10b981' }}>
53
+ {counts.safe}
54
+ </Text>
55
+ )}
56
+ </Flex>
57
+ </a>
58
+ </Box>
59
+ )
60
+ }
61
+
62
+ export const calculateCounts = (revision: Revision.Revision) => {
63
+ return {
64
+ breaking: revision.changes.filter(Change.isBreaking).length,
65
+ dangerous: revision.changes.filter(Change.isDangerous).length,
66
+ safe: revision.changes.filter(Change.isSafe).length,
67
+ }
68
+ }