polen 0.11.0-next.18 → 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 (123) hide show
  1. package/build/api/errors.d.ts +278 -0
  2. package/build/api/errors.d.ts.map +1 -0
  3. package/build/api/errors.js +153 -0
  4. package/build/api/errors.js.map +1 -0
  5. package/build/api/schema/input-source/$$.d.ts +1 -0
  6. package/build/api/schema/input-source/$$.d.ts.map +1 -1
  7. package/build/api/schema/input-source/$$.js +1 -0
  8. package/build/api/schema/input-source/$$.js.map +1 -1
  9. package/build/api/schema/input-source/errors.d.ts +36 -0
  10. package/build/api/schema/input-source/errors.d.ts.map +1 -0
  11. package/build/api/schema/input-source/errors.js +17 -0
  12. package/build/api/schema/input-source/errors.js.map +1 -0
  13. package/build/api/schema/input-source/input-source.d.ts +1 -7
  14. package/build/api/schema/input-source/input-source.d.ts.map +1 -1
  15. package/build/api/schema/input-source/input-source.js +0 -6
  16. package/build/api/schema/input-source/input-source.js.map +1 -1
  17. package/build/api/schema/input-sources/directory.d.ts.map +1 -1
  18. package/build/api/schema/input-sources/directory.js +17 -4
  19. package/build/api/schema/input-sources/directory.js.map +1 -1
  20. package/build/api/schema/input-sources/file.d.ts.map +1 -1
  21. package/build/api/schema/input-sources/file.js +15 -4
  22. package/build/api/schema/input-sources/file.js.map +1 -1
  23. package/build/api/schema/input-sources/introspection-file.d.ts.map +1 -1
  24. package/build/api/schema/input-sources/introspection-file.js +28 -6
  25. package/build/api/schema/input-sources/introspection-file.js.map +1 -1
  26. package/build/api/schema/input-sources/introspection.d.ts.map +1 -1
  27. package/build/api/schema/input-sources/introspection.js +35 -7
  28. package/build/api/schema/input-sources/introspection.js.map +1 -1
  29. package/build/api/schema/input-sources/memory.d.ts.map +1 -1
  30. package/build/api/schema/input-sources/memory.js +15 -3
  31. package/build/api/schema/input-sources/memory.js.map +1 -1
  32. package/build/api/schema/input-sources/versioned-directory.js +20 -4
  33. package/build/api/schema/input-sources/versioned-directory.js.map +1 -1
  34. package/build/api/schema/load.d.ts +1 -1
  35. package/build/api/schema/load.d.ts.map +1 -1
  36. package/build/api/schema/load.js +1 -1
  37. package/build/api/schema/load.js.map +1 -1
  38. package/build/cli/commands/hero-image.d.ts +1 -2
  39. package/build/cli/commands/hero-image.d.ts.map +1 -1
  40. package/build/cli/index.d.ts +1 -1
  41. package/build/template/components/ReferenceVersionPicker.d.ts +9 -0
  42. package/build/template/components/ReferenceVersionPicker.d.ts.map +1 -0
  43. package/build/template/components/ReferenceVersionPicker.js +79 -0
  44. package/build/template/components/ReferenceVersionPicker.js.map +1 -0
  45. package/build/template/components/VersionPicker.d.ts +8 -3
  46. package/build/template/components/VersionPicker.d.ts.map +1 -1
  47. package/build/template/components/VersionPicker.js +12 -77
  48. package/build/template/components/VersionPicker.js.map +1 -1
  49. package/build/template/routes/changelog/ChangelogBody.d.ts +6 -0
  50. package/build/template/routes/changelog/ChangelogBody.d.ts.map +1 -0
  51. package/build/template/{components/Changelog/Changelog.js → routes/changelog/ChangelogBody.js} +8 -58
  52. package/build/template/routes/changelog/ChangelogBody.js.map +1 -0
  53. package/build/template/routes/changelog/ChangelogSidebar.d.ts +7 -0
  54. package/build/template/routes/changelog/ChangelogSidebar.d.ts.map +1 -0
  55. package/build/template/routes/changelog/ChangelogSidebar.js +46 -0
  56. package/build/template/routes/changelog/ChangelogSidebar.js.map +1 -0
  57. package/build/template/routes/changelog/ChangelogSidebarItem.d.ts +11 -0
  58. package/build/template/routes/changelog/ChangelogSidebarItem.d.ts.map +1 -0
  59. package/build/template/routes/changelog/ChangelogSidebarItem.js +35 -0
  60. package/build/template/routes/changelog/ChangelogSidebarItem.js.map +1 -0
  61. package/build/template/routes/changelog/_.d.ts +3264 -0
  62. package/build/template/routes/changelog/_.d.ts.map +1 -0
  63. package/build/template/routes/changelog/_.js +111 -0
  64. package/build/template/routes/changelog/_.js.map +1 -0
  65. package/build/template/routes/changelog/utils.d.ts +3 -0
  66. package/build/template/routes/changelog/utils.d.ts.map +1 -0
  67. package/build/template/routes/changelog/utils.js +11 -0
  68. package/build/template/routes/changelog/utils.js.map +1 -0
  69. package/build/template/routes/reference.js +2 -2
  70. package/build/template/routes/reference.js.map +1 -1
  71. package/build/template/routes/root.js +1 -1
  72. package/build/template/routes/root.js.map +1 -1
  73. package/build/template/theme/swiss-sharp.css +14 -14
  74. package/build/vite/plugins/schemas.d.ts +1 -2
  75. package/build/vite/plugins/schemas.d.ts.map +1 -1
  76. package/build/vite/plugins/schemas.js +0 -1
  77. package/build/vite/plugins/schemas.js.map +1 -1
  78. package/package.json +1 -1
  79. package/src/api/errors.ts +227 -0
  80. package/src/api/schema/input-source/$$.ts +1 -0
  81. package/src/api/schema/input-source/errors.ts +26 -0
  82. package/src/api/schema/input-source/input-source.ts +1 -22
  83. package/src/api/schema/input-sources/directory.ts +18 -13
  84. package/src/api/schema/input-sources/file.ts +17 -4
  85. package/src/api/schema/input-sources/introspection-file.ts +30 -15
  86. package/src/api/schema/input-sources/introspection.ts +38 -7
  87. package/src/api/schema/input-sources/memory.ts +19 -3
  88. package/src/api/schema/input-sources/versioned-directory.ts +20 -20
  89. package/src/api/schema/load.ts +3 -2
  90. package/src/template/components/ReferenceVersionPicker.tsx +107 -0
  91. package/src/template/components/VersionPicker.tsx +32 -98
  92. package/src/template/{components/Changelog/Changelog.tsx → routes/changelog/ChangelogBody.tsx} +7 -64
  93. package/src/template/routes/changelog/ChangelogSidebar.tsx +80 -0
  94. package/src/template/routes/changelog/ChangelogSidebarItem.tsx +68 -0
  95. package/src/template/routes/changelog/_.tsx +129 -0
  96. package/src/template/routes/changelog/utils.ts +13 -0
  97. package/src/template/routes/reference.tsx +2 -2
  98. package/src/template/routes/root.tsx +1 -1
  99. package/src/template/theme/swiss-sharp.css +14 -14
  100. package/src/vite/plugins/schemas.ts +0 -1
  101. package/build/sandbox.d.ts +0 -2
  102. package/build/sandbox.d.ts.map +0 -1
  103. package/build/sandbox.js +0 -17
  104. package/build/sandbox.js.map +0 -1
  105. package/build/template/components/Changelog/Changelog.d.ts +0 -8
  106. package/build/template/components/Changelog/Changelog.d.ts.map +0 -1
  107. package/build/template/components/Changelog/Changelog.js.map +0 -1
  108. package/build/template/components/Changelog/ChangelogVersionPicker.d.ts +0 -8
  109. package/build/template/components/Changelog/ChangelogVersionPicker.d.ts.map +0 -1
  110. package/build/template/components/Changelog/ChangelogVersionPicker.js +0 -16
  111. package/build/template/components/Changelog/ChangelogVersionPicker.js.map +0 -1
  112. package/build/template/components/SimpleVersionPicker.d.ts +0 -15
  113. package/build/template/components/SimpleVersionPicker.d.ts.map +0 -1
  114. package/build/template/components/SimpleVersionPicker.js +0 -15
  115. package/build/template/components/SimpleVersionPicker.js.map +0 -1
  116. package/build/template/routes/changelog.d.ts +0 -1635
  117. package/build/template/routes/changelog.d.ts.map +0 -1
  118. package/build/template/routes/changelog.js +0 -168
  119. package/build/template/routes/changelog.js.map +0 -1
  120. package/src/sandbox.ts +0 -15
  121. package/src/template/components/Changelog/ChangelogVersionPicker.tsx +0 -36
  122. package/src/template/components/SimpleVersionPicker.tsx +0 -48
  123. package/src/template/routes/changelog.tsx +0 -267
@@ -1,4 +1,5 @@
1
1
  import { InputSource } from '#api/schema/input-source/$'
2
+ import type { InputSourceError } from '#api/schema/input-source/errors'
2
3
  import type { Catalog } from '#lib/catalog/$'
3
4
  import type { PlatformError } from '@effect/platform/Error'
4
5
  import type { FileSystem } from '@effect/platform/FileSystem'
@@ -7,28 +8,6 @@ import { Effect } from 'effect'
7
8
 
8
9
  type Options = object
9
10
 
10
- // ============================================================================
11
- // Error Types
12
- // ============================================================================
13
-
14
- export interface InputSourceError {
15
- readonly _tag: 'InputSourceError'
16
- readonly source: string
17
- readonly message: string
18
- readonly cause?: unknown
19
- }
20
-
21
- export const InputSourceError = (
22
- source: string,
23
- message: string,
24
- cause?: unknown,
25
- ): InputSourceError => ({
26
- _tag: 'InputSourceError',
27
- source,
28
- message,
29
- cause,
30
- })
31
-
32
11
  // ============================================================================
33
12
  // Effect-based InputSource
34
13
  // ============================================================================
@@ -1,4 +1,5 @@
1
1
  import { InputSource } from '#api/schema/input-source/$'
2
+ import { InputSourceError } from '#api/schema/input-source/errors'
2
3
  import { Catalog } from '#lib/catalog/$'
3
4
  import { Change } from '#lib/change/$'
4
5
  import { DateOnly } from '#lib/date-only/$'
@@ -178,7 +179,7 @@ export const loader = InputSource.createEffect({
178
179
 
179
180
  const read = (
180
181
  revisionInputs: { date: DateOnly.DateOnly; filePath: string }[],
181
- ): Effect.Effect<Schema.Unversioned.Unversioned, InputSource.InputSourceError | PlatformError, FileSystem> =>
182
+ ): Effect.Effect<Schema.Unversioned.Unversioned, InputSourceError | PlatformError, FileSystem> =>
182
183
  Effect.gen(function*() {
183
184
  const revisionInputsLoaded = yield* Effect.all(
184
185
  Arr.map(revisionInputs, (revisionInput) =>
@@ -187,20 +188,20 @@ const read = (
187
188
  const content = yield* fs.readFileString(revisionInput.filePath)
188
189
  const ast = yield* Grafaid.Schema.AST.parse(content).pipe(
189
190
  Effect.mapError((error) =>
190
- InputSource.InputSourceError(
191
- 'directory',
192
- `Failed to parse schema file ${revisionInput.filePath}: ${error}`,
193
- error,
194
- )
191
+ new InputSourceError({
192
+ source: 'directory',
193
+ message: `Failed to parse schema file ${revisionInput.filePath}: ${error}`,
194
+ cause: error,
195
+ })
195
196
  ),
196
197
  )
197
198
  const schema = yield* Grafaid.Schema.fromAST(ast).pipe(
198
199
  Effect.mapError((error) =>
199
- InputSource.InputSourceError(
200
- 'directory',
201
- `Failed to build schema from ${revisionInput.filePath}: ${error}`,
202
- error,
203
- )
200
+ new InputSourceError({
201
+ source: 'directory',
202
+ message: `Failed to build schema from ${revisionInput.filePath}: ${error}`,
203
+ cause: error,
204
+ })
204
205
  ),
205
206
  )
206
207
 
@@ -230,7 +231,11 @@ const read = (
230
231
 
231
232
  const changes = yield* Change.calcChangeset({ before, after }).pipe(
232
233
  Effect.mapError((error) =>
233
- InputSource.InputSourceError('directory', `Failed to calculate changeset: ${error}`, error)
234
+ new InputSourceError({
235
+ source: 'directory',
236
+ message: `Failed to calculate changeset: ${error}`,
237
+ cause: error,
238
+ })
234
239
  ),
235
240
  )
236
241
 
@@ -245,7 +250,7 @@ const read = (
245
250
  // Get the latest schema (first in the array after sorting newest first)
246
251
  const latestSchemaData = revisionInputsSorted[0]?.schema
247
252
  if (!latestSchemaData) {
248
- return yield* Effect.fail(InputSource.InputSourceError('directory', 'No schema files found'))
253
+ return yield* Effect.fail(new InputSourceError({ source: 'directory', message: 'No schema files found' }))
249
254
  }
250
255
 
251
256
  // Create unversioned schema with full revisions
@@ -5,7 +5,6 @@ import { DateOnly } from '#lib/date-only/$'
5
5
  import { Grafaid } from '#lib/grafaid'
6
6
  import { Revision } from '#lib/revision/$'
7
7
  import { Schema } from '#lib/schema/$'
8
- import { PlatformError } from '@effect/platform/Error'
9
8
  import { FileSystem } from '@effect/platform/FileSystem'
10
9
  import { Path } from '@wollybeard/kit'
11
10
  import { Effect } from 'effect'
@@ -76,18 +75,32 @@ export const loader = InputSource.createEffect({
76
75
 
77
76
  const ast = yield* Grafaid.Schema.AST.parse(content).pipe(
78
77
  Effect.mapError((error) =>
79
- InputSource.InputSourceError('file', `Failed to parse schema file: ${error}`, error)
78
+ new InputSource.InputSourceError({
79
+ source: 'file',
80
+ message: `Failed to parse schema file: ${error}`,
81
+ cause: error,
82
+ })
80
83
  ),
81
84
  )
82
85
  const after = yield* Grafaid.Schema.fromAST(ast).pipe(
83
- Effect.mapError((error) => InputSource.InputSourceError('file', `Failed to build schema: ${error}`, error)),
86
+ Effect.mapError((error) =>
87
+ new InputSource.InputSourceError({
88
+ source: 'file',
89
+ message: `Failed to build schema: ${error}`,
90
+ cause: error,
91
+ })
92
+ ),
84
93
  )
85
94
 
86
95
  const date = new Date()
87
96
  const before = Grafaid.Schema.empty
88
97
  const changes = yield* Change.calcChangeset({ before, after }).pipe(
89
98
  Effect.mapError((error) =>
90
- InputSource.InputSourceError('file', `Failed to calculate changeset: ${error}`, error)
99
+ new InputSource.InputSourceError({
100
+ source: 'file',
101
+ message: `Failed to calculate changeset: ${error}`,
102
+ cause: error,
103
+ })
91
104
  ),
92
105
  )
93
106
 
@@ -80,7 +80,11 @@ export const read = (
80
80
 
81
81
  const introspectionFileContent = yield* fs.readFileString(config.path).pipe(
82
82
  Effect.mapError((error) =>
83
- InputSource.InputSourceError('introspectionFile', `Failed to read file ${config.path}: ${error}`, error)
83
+ new InputSource.InputSourceError({
84
+ source: 'introspectionFile',
85
+ message: `Failed to read file ${config.path}: ${error}`,
86
+ cause: error,
87
+ })
84
88
  ),
85
89
  )
86
90
 
@@ -90,16 +94,20 @@ export const read = (
90
94
  try: () => Json.codec.decode(introspectionFileContent),
91
95
  catch: (error) => {
92
96
  if (error instanceof SyntaxError) {
93
- return InputSource.InputSourceError(
94
- 'introspectionFile',
95
- `Invalid JSON in ${config.path}: ${error.message}`,
96
- error,
97
+ return new InputSource.InputSourceError(
98
+ {
99
+ source: 'introspectionFile',
100
+ message: `Invalid JSON in ${config.path}: ${error.message}`,
101
+ cause: error,
102
+ },
97
103
  )
98
104
  }
99
- return InputSource.InputSourceError(
100
- 'introspectionFile',
101
- `Failed to parse JSON in ${config.path}: ${error}`,
102
- error,
105
+ return new InputSource.InputSourceError(
106
+ {
107
+ source: 'introspectionFile',
108
+ message: `Failed to parse JSON in ${config.path}: ${error}`,
109
+ cause: error,
110
+ },
103
111
  )
104
112
  },
105
113
  })
@@ -107,7 +115,10 @@ export const read = (
107
115
  // Validate introspection data structure before passing to fromIntrospectionQuery
108
116
  if (!introspectionData || typeof introspectionData !== 'object') {
109
117
  return yield* Effect.fail(
110
- InputSource.InputSourceError('introspectionFile', 'Introspection data must be a valid JSON object'),
118
+ new InputSource.InputSourceError({
119
+ source: 'introspectionFile',
120
+ message: 'Introspection data must be a valid JSON object',
121
+ }),
111
122
  )
112
123
  }
113
124
 
@@ -115,10 +126,10 @@ export const read = (
115
126
  // It will provide more specific GraphQL-related error messages
116
127
  if (!('data' in introspectionData)) {
117
128
  return yield* Effect.fail(
118
- InputSource.InputSourceError(
119
- 'introspectionFile',
120
- 'Introspection data missing required "data" property (expected GraphQL introspection result format)',
121
- ),
129
+ new InputSource.InputSourceError({
130
+ source: 'introspectionFile',
131
+ message: 'Introspection data missing required "data" property (expected GraphQL introspection result format)',
132
+ }),
122
133
  )
123
134
  }
124
135
 
@@ -144,7 +155,11 @@ const createCatalogFromSchema = (
144
155
  after,
145
156
  }).pipe(
146
157
  Effect.mapError((error) =>
147
- InputSource.InputSourceError('introspectionFile', `Failed to calculate changeset: ${error}`, error)
158
+ new InputSource.InputSourceError({
159
+ source: 'introspectionFile',
160
+ message: `Failed to calculate changeset: ${error}`,
161
+ cause: error,
162
+ })
148
163
  ),
149
164
  )
150
165
 
@@ -150,7 +150,12 @@ export const loader = InputSource.createEffect({
150
150
  // Try to read from cache
151
151
  const cacheEntry = yield* Effect.tryPromise({
152
152
  try: () => readCache(cachePath),
153
- catch: (error) => InputSource.InputSourceError('introspection', `Failed to read cache: ${error}`, error),
153
+ catch: (error) =>
154
+ new InputSource.InputSourceError({
155
+ source: 'introspection',
156
+ message: `Failed to read cache: ${error}`,
157
+ cause: error,
158
+ }),
154
159
  })
155
160
 
156
161
  let schema: Grafaid.Schema.Schema
@@ -162,7 +167,11 @@ export const loader = InputSource.createEffect({
162
167
  // Fetch fresh introspection
163
168
  schema = yield* fetchIntrospection(options).pipe(
164
169
  Effect.mapError((error) =>
165
- InputSource.InputSourceError('introspection', `Failed to fetch introspection: ${error}`, error)
170
+ new InputSource.InputSourceError({
171
+ source: 'introspection',
172
+ message: `Failed to fetch introspection: ${error}`,
173
+ cause: error,
174
+ })
166
175
  ),
167
176
  )
168
177
 
@@ -176,13 +185,22 @@ export const loader = InputSource.createEffect({
176
185
 
177
186
  yield* Effect.tryPromise({
178
187
  try: () => writeCache(cachePath, newCacheEntry),
179
- catch: (error) => InputSource.InputSourceError('introspection', `Failed to write cache: ${error}`, error),
188
+ catch: (error) =>
189
+ new InputSource.InputSourceError({
190
+ source: 'introspection',
191
+ message: `Failed to write cache: ${error}`,
192
+ cause: error,
193
+ }),
180
194
  })
181
195
  }
182
196
 
183
197
  return yield* createCatalogFromSchema(schema).pipe(
184
198
  Effect.mapError((error) =>
185
- InputSource.InputSourceError('introspection', `Failed to create catalog: ${error}`, error)
199
+ new InputSource.InputSourceError({
200
+ source: 'introspection',
201
+ message: `Failed to create catalog: ${error}`,
202
+ cause: error,
203
+ })
186
204
  ),
187
205
  )
188
206
  }),
@@ -196,7 +214,11 @@ export const loader = InputSource.createEffect({
196
214
  // Force fresh introspection
197
215
  const schema = yield* fetchIntrospection(options).pipe(
198
216
  Effect.mapError((error) =>
199
- InputSource.InputSourceError('introspection', `Failed to fetch introspection: ${error}`, error)
217
+ new InputSource.InputSourceError({
218
+ source: 'introspection',
219
+ message: `Failed to fetch introspection: ${error}`,
220
+ cause: error,
221
+ })
200
222
  ),
201
223
  )
202
224
 
@@ -210,12 +232,21 @@ export const loader = InputSource.createEffect({
210
232
 
211
233
  yield* Effect.tryPromise({
212
234
  try: () => writeCache(cachePath, newCacheEntry),
213
- catch: (error) => InputSource.InputSourceError('introspection', `Failed to write cache: ${error}`, error),
235
+ catch: (error) =>
236
+ new InputSource.InputSourceError({
237
+ source: 'introspection',
238
+ message: `Failed to write cache: ${error}`,
239
+ cause: error,
240
+ }),
214
241
  })
215
242
 
216
243
  return yield* createCatalogFromSchema(schema).pipe(
217
244
  Effect.mapError((error) =>
218
- InputSource.InputSourceError('introspection', `Failed to create catalog: ${error}`, error)
245
+ new InputSource.InputSourceError({
246
+ source: 'introspection',
247
+ message: `Failed to create catalog: ${error}`,
248
+ cause: error,
249
+ })
219
250
  ),
220
251
  )
221
252
  }),
@@ -122,10 +122,22 @@ const parseSchema = (value: string | GraphQLSchema): Effect.Effect<GraphQLSchema
122
122
  Effect.gen(function*() {
123
123
  if (typeof value === 'string') {
124
124
  const ast = yield* Grafaid.Schema.AST.parse(value).pipe(
125
- Effect.mapError((error) => InputSource.InputSourceError('memory', `Failed to parse schema: ${error}`, error)),
125
+ Effect.mapError((error) =>
126
+ new InputSource.InputSourceError({
127
+ source: 'memory',
128
+ message: `Failed to parse schema: ${error}`,
129
+ cause: error,
130
+ })
131
+ ),
126
132
  )
127
133
  return yield* Grafaid.Schema.fromAST(ast).pipe(
128
- Effect.mapError((error) => InputSource.InputSourceError('memory', `Failed to build schema: ${error}`, error)),
134
+ Effect.mapError((error) =>
135
+ new InputSource.InputSourceError({
136
+ source: 'memory',
137
+ message: `Failed to build schema: ${error}`,
138
+ cause: error,
139
+ })
140
+ ),
129
141
  )
130
142
  }
131
143
  return value // Already a GraphQLSchema
@@ -186,7 +198,11 @@ export const read = (
186
198
 
187
199
  changes = yield* Change.calcChangeset({ before, after }).pipe(
188
200
  Effect.mapError((error) =>
189
- InputSource.InputSourceError('memory', `Failed to calculate changeset: ${error}`, error)
201
+ new InputSource.InputSourceError({
202
+ source: 'memory',
203
+ message: `Failed to calculate changeset: ${error}`,
204
+ cause: error,
205
+ })
190
206
  ),
191
207
  )
192
208
  }
@@ -203,20 +203,20 @@ export const readOrThrow = (
203
203
  const content = yield* fs.readFileString(filePath)
204
204
  const ast = yield* Grafaid.Schema.AST.parse(content).pipe(
205
205
  Effect.mapError((error) =>
206
- InputSource.InputSourceError(
207
- 'versionedDirectory',
208
- `Failed to parse schema from ${filePath}: ${error}`,
209
- error,
210
- )
206
+ new InputSource.InputSourceError({
207
+ source: 'versionedDirectory',
208
+ message: `Failed to parse schema from ${filePath}: ${error}`,
209
+ cause: error,
210
+ })
211
211
  ),
212
212
  )
213
213
  const schema = yield* Grafaid.Schema.fromAST(ast).pipe(
214
214
  Effect.mapError((error) =>
215
- InputSource.InputSourceError(
216
- 'versionedDirectory',
217
- `Failed to build schema from ${filePath}: ${error}`,
218
- error,
219
- )
215
+ new InputSource.InputSourceError({
216
+ source: 'versionedDirectory',
217
+ message: `Failed to build schema from ${filePath}: ${error}`,
218
+ cause: error,
219
+ })
220
220
  ),
221
221
  )
222
222
 
@@ -285,11 +285,11 @@ export const readOrThrow = (
285
285
 
286
286
  const changes = yield* Change.calcChangeset({ before, after }).pipe(
287
287
  Effect.mapError((error) =>
288
- InputSource.InputSourceError(
289
- 'versionedDirectory',
290
- `Failed to calculate changeset for ${version.name}: ${error}`,
291
- error,
292
- )
288
+ new InputSource.InputSourceError({
289
+ source: 'versionedDirectory',
290
+ message: `Failed to calculate changeset for ${version.name}: ${error}`,
291
+ cause: error,
292
+ })
293
293
  ),
294
294
  )
295
295
 
@@ -330,11 +330,11 @@ export const readOrThrow = (
330
330
 
331
331
  const changes = yield* Change.calcChangeset({ before, after }).pipe(
332
332
  Effect.mapError((error) =>
333
- InputSource.InputSourceError(
334
- 'versionedDirectory',
335
- `Failed to calculate parent changeset: ${error}`,
336
- error,
337
- )
333
+ new InputSource.InputSourceError({
334
+ source: 'versionedDirectory',
335
+ message: `Failed to calculate parent changeset: ${error}`,
336
+ cause: error,
337
+ })
338
338
  ),
339
339
  )
340
340
 
@@ -1,13 +1,14 @@
1
1
  import type { Config } from '#api/config/normalized'
2
2
  import { Augmentations } from '#api/schema/augmentations/$'
3
- import type { EffectInputSource, InputSource, InputSourceError } from '#api/schema/input-source/input-source'
3
+ import type { InputSourceError } from '#api/schema/input-source/errors'
4
+ import type { EffectInputSource, InputSource } from '#api/schema/input-source/input-source'
4
5
  import * as InputSourceLoader from '#api/schema/input-source/load'
5
6
  import { InputSources } from '#api/schema/input-sources/$'
6
7
  import { Catalog } from '#lib/catalog/$'
7
8
  import type { PlatformError } from '@effect/platform/Error'
8
9
  import type { FileSystem } from '@effect/platform/FileSystem'
9
10
  import { Arr } from '@wollybeard/kit'
10
- import { Array, Effect, Option } from 'effect'
11
+ import { Effect } from 'effect'
11
12
 
12
13
  // For now, we'll need a type that accepts both promise and effect sources
13
14
  type AnyInputSource = InputSource | EffectInputSource
@@ -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
+ }