polen 0.11.0-next.1 → 0.11.0-next.11

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 (215) hide show
  1. package/build/api/api.d.ts +2 -1
  2. package/build/api/api.d.ts.map +1 -1
  3. package/build/api/api.js +5 -1
  4. package/build/api/api.js.map +1 -1
  5. package/build/api/config/configurator.d.ts +35 -23
  6. package/build/api/config/configurator.d.ts.map +1 -1
  7. package/build/api/config/configurator.js +0 -6
  8. package/build/api/config/configurator.js.map +1 -1
  9. package/build/api/config/merge.d.ts.map +1 -1
  10. package/build/api/config/merge.js +0 -11
  11. package/build/api/config/merge.js.map +1 -1
  12. package/build/api/content/metadata.d.ts +8 -2
  13. package/build/api/content/metadata.d.ts.map +1 -1
  14. package/build/api/content/metadata.js +1 -1
  15. package/build/api/content/metadata.js.map +1 -1
  16. package/build/api/iso/$$.d.ts +2 -0
  17. package/build/api/iso/$$.d.ts.map +1 -0
  18. package/build/api/iso/$$.js +2 -0
  19. package/build/api/iso/$$.js.map +1 -0
  20. package/build/api/iso/$.d.ts +2 -0
  21. package/build/api/iso/$.d.ts.map +1 -0
  22. package/build/api/iso/$.js +2 -0
  23. package/build/api/iso/$.js.map +1 -0
  24. package/build/api/iso/schema/$$.d.ts +4 -0
  25. package/build/api/iso/schema/$$.d.ts.map +1 -0
  26. package/build/api/iso/schema/$$.js +3 -0
  27. package/build/api/iso/schema/$$.js.map +1 -0
  28. package/build/api/iso/schema/$.d.ts +2 -0
  29. package/build/api/iso/schema/$.d.ts.map +1 -0
  30. package/build/api/iso/schema/$.js +2 -0
  31. package/build/api/iso/schema/$.js.map +1 -0
  32. package/build/api/iso/schema/constants.d.ts +25 -0
  33. package/build/api/iso/schema/constants.d.ts.map +1 -0
  34. package/build/api/iso/schema/constants.js +42 -0
  35. package/build/api/iso/schema/constants.js.map +1 -0
  36. package/build/api/iso/schema/routing.d.ts +22 -0
  37. package/build/api/iso/schema/routing.d.ts.map +1 -0
  38. package/build/api/iso/schema/routing.js +39 -0
  39. package/build/api/iso/schema/routing.js.map +1 -0
  40. package/build/api/iso.d.ts +2 -0
  41. package/build/api/iso.d.ts.map +1 -0
  42. package/build/api/iso.js +2 -0
  43. package/build/api/iso.js.map +1 -0
  44. package/build/api/schema/data-sources/data-sources.d.ts +1 -0
  45. package/build/api/schema/data-sources/data-sources.d.ts.map +1 -1
  46. package/build/api/schema/data-sources/data-sources.js +1 -0
  47. package/build/api/schema/data-sources/data-sources.js.map +1 -1
  48. package/build/api/schema/data-sources/introspection/introspection.d.ts +83 -0
  49. package/build/api/schema/data-sources/introspection/introspection.d.ts.map +1 -0
  50. package/build/api/schema/data-sources/introspection/introspection.js +110 -0
  51. package/build/api/schema/data-sources/introspection/introspection.js.map +1 -0
  52. package/build/api/schema/metadata.d.ts +11 -3
  53. package/build/api/schema/metadata.d.ts.map +1 -1
  54. package/build/api/schema/metadata.js +1 -1
  55. package/build/api/schema/metadata.js.map +1 -1
  56. package/build/api/schema/read.d.ts +83 -9
  57. package/build/api/schema/read.d.ts.map +1 -1
  58. package/build/api/schema/read.js +15 -6
  59. package/build/api/schema/read.js.map +1 -1
  60. package/build/api/schema/schema.d.ts +3 -25
  61. package/build/api/schema/schema.d.ts.map +1 -1
  62. package/build/api/schema/schema.js +5 -42
  63. package/build/api/schema/schema.js.map +1 -1
  64. package/build/api/schema-source/schema-source.d.ts +1 -1
  65. package/build/api/schema-source/schema-source.d.ts.map +1 -1
  66. package/build/api/schema-source/schema-source.js.map +1 -1
  67. package/build/api/static/manifest.d.ts +1 -2
  68. package/build/api/static/manifest.d.ts.map +1 -1
  69. package/build/api/static/manifest.js +1 -1
  70. package/build/api/static/manifest.js.map +1 -1
  71. package/build/api/vite/plugins/build.d.ts.map +1 -1
  72. package/build/api/vite/plugins/build.js +3 -0
  73. package/build/api/vite/plugins/build.js.map +1 -1
  74. package/build/api/vite/plugins/core.d.ts.map +1 -1
  75. package/build/api/vite/plugins/core.js +11 -14
  76. package/build/api/vite/plugins/core.js.map +1 -1
  77. package/build/api/vite/plugins/main.d.ts.map +1 -1
  78. package/build/api/vite/plugins/main.js +1 -8
  79. package/build/api/vite/plugins/main.js.map +1 -1
  80. package/build/api/vite/plugins/schema-assets.d.ts.map +1 -1
  81. package/build/api/vite/plugins/schema-assets.js +52 -11
  82. package/build/api/vite/plugins/schema-assets.js.map +1 -1
  83. package/build/cli/commands/open.js +1 -1
  84. package/build/cli/commands/open.js.map +1 -1
  85. package/build/lib/grafaid/schema/schema.d.ts +1 -1
  86. package/build/lib/grafaid/schema/schema.d.ts.map +1 -1
  87. package/build/lib/grafaid/schema/schema.js +1 -1
  88. package/build/lib/grafaid/schema/schema.js.map +1 -1
  89. package/build/lib/kit-temp.js +2 -2
  90. package/build/lib/kit-temp.js.map +1 -1
  91. package/build/lib/react-router-aid/react-router-aid.d.ts +5 -3
  92. package/build/lib/react-router-aid/react-router-aid.d.ts.map +1 -1
  93. package/build/lib/react-router-aid/react-router-aid.js +7 -4
  94. package/build/lib/react-router-aid/react-router-aid.js.map +1 -1
  95. package/build/template/components/GraphQLInteractive/lib/parser.d.ts.map +1 -1
  96. package/build/template/components/GraphQLInteractive/lib/parser.js +32 -10
  97. package/build/template/components/GraphQLInteractive/lib/parser.js.map +1 -1
  98. package/build/template/components/HamburgerMenu.d.ts +1 -0
  99. package/build/template/components/HamburgerMenu.d.ts.map +1 -1
  100. package/build/template/components/HamburgerMenu.js +2 -2
  101. package/build/template/components/HamburgerMenu.js.map +1 -1
  102. package/build/template/components/ReferenceLink.d.ts.map +1 -1
  103. package/build/template/components/ReferenceLink.js +2 -4
  104. package/build/template/components/ReferenceLink.js.map +1 -1
  105. package/build/template/components/VersionSelector.d.ts +3 -2
  106. package/build/template/components/VersionSelector.d.ts.map +1 -1
  107. package/build/template/components/VersionSelector.js +7 -15
  108. package/build/template/components/VersionSelector.js.map +1 -1
  109. package/build/template/components/sidebar/Sidebar.d.ts +3 -2
  110. package/build/template/components/sidebar/Sidebar.d.ts.map +1 -1
  111. package/build/template/components/sidebar/Sidebar.js +7 -6
  112. package/build/template/components/sidebar/Sidebar.js.map +1 -1
  113. package/build/template/components/sidebar/SidebarContext.d.ts +6 -0
  114. package/build/template/components/sidebar/SidebarContext.d.ts.map +1 -0
  115. package/build/template/components/sidebar/SidebarContext.js +3 -0
  116. package/build/template/components/sidebar/SidebarContext.js.map +1 -0
  117. package/build/template/components/sidebar/SidebarItem.d.ts.map +1 -1
  118. package/build/template/components/sidebar/SidebarItem.js +11 -4
  119. package/build/template/components/sidebar/SidebarItem.js.map +1 -1
  120. package/build/template/hooks/useVersionPath.d.ts.map +1 -1
  121. package/build/template/hooks/useVersionPath.js +3 -1
  122. package/build/template/hooks/useVersionPath.js.map +1 -1
  123. package/build/template/layouts/SidebarLayout.d.ts +3 -2
  124. package/build/template/layouts/SidebarLayout.d.ts.map +1 -1
  125. package/build/template/layouts/SidebarLayout.js +2 -2
  126. package/build/template/layouts/SidebarLayout.js.map +1 -1
  127. package/build/template/routes/changelog.js +2 -2
  128. package/build/template/routes/changelog.js.map +1 -1
  129. package/build/template/routes/index.js +2 -2
  130. package/build/template/routes/index.js.map +1 -1
  131. package/build/template/routes/pages.js +2 -2
  132. package/build/template/routes/pages.js.map +1 -1
  133. package/build/template/routes/reference.d.ts +27 -4
  134. package/build/template/routes/reference.d.ts.map +1 -1
  135. package/build/template/routes/reference.js +82 -24
  136. package/build/template/routes/reference.js.map +1 -1
  137. package/build/template/routes/root.js +3 -3
  138. package/build/template/routes/root.js.map +1 -1
  139. package/build/template/server/ssg/get-route-paths.d.ts.map +1 -1
  140. package/build/template/server/ssg/get-route-paths.js +81 -9
  141. package/build/template/server/ssg/get-route-paths.js.map +1 -1
  142. package/build/template/sources/schema-source.d.ts +1 -1
  143. package/build/template/sources/schema-source.d.ts.map +1 -1
  144. package/build/template/sources/schema-source.js +2 -1
  145. package/build/template/sources/schema-source.js.map +1 -1
  146. package/package.json +19 -17
  147. package/src/api/api.ts +7 -1
  148. package/src/api/config/configurator.ts +35 -30
  149. package/src/api/config/merge.ts +0 -16
  150. package/src/api/content/metadata.ts +1 -1
  151. package/src/api/iso/$$.ts +1 -0
  152. package/src/api/iso/$.ts +1 -0
  153. package/src/api/iso/schema/$$.ts +5 -0
  154. package/src/api/iso/schema/$.ts +1 -0
  155. package/src/api/iso/schema/constants.ts +49 -0
  156. package/src/api/iso/schema/routing.ts +53 -0
  157. package/src/api/iso.ts +1 -0
  158. package/src/api/schema/data-sources/data-sources.ts +1 -0
  159. package/src/api/schema/data-sources/introspection/introspection.ts +213 -0
  160. package/src/api/schema/metadata.ts +1 -1
  161. package/src/api/schema/read.ts +107 -16
  162. package/src/api/schema/schema.ts +6 -53
  163. package/src/api/schema-source/schema-source.ts +3 -3
  164. package/src/api/static/manifest.ts +1 -1
  165. package/src/api/vite/plugins/build.ts +3 -0
  166. package/src/api/vite/plugins/core.ts +11 -14
  167. package/src/api/vite/plugins/main.ts +1 -9
  168. package/src/api/vite/plugins/schema-assets.ts +59 -12
  169. package/src/cli/commands/open.ts +1 -1
  170. package/src/lib/grafaid/schema/schema.ts +1 -0
  171. package/src/lib/kit-temp.ts +2 -2
  172. package/src/lib/mask/$.test.ts +3 -3
  173. package/src/lib/react-router-aid/react-router-aid.ts +12 -6
  174. package/src/template/components/GraphQLInteractive/lib/parser.ts +32 -16
  175. package/src/template/components/HamburgerMenu.tsx +3 -1
  176. package/src/template/components/ReferenceLink.tsx +7 -4
  177. package/src/template/components/VersionSelector.tsx +10 -18
  178. package/src/template/components/sidebar/Sidebar.tsx +20 -16
  179. package/src/template/components/sidebar/SidebarContext.tsx +7 -0
  180. package/src/template/components/sidebar/SidebarItem.tsx +11 -4
  181. package/src/template/hooks/useVersionPath.ts +3 -1
  182. package/src/template/layouts/SidebarLayout.tsx +5 -3
  183. package/src/template/routes/changelog.tsx +2 -2
  184. package/src/template/routes/index.tsx +2 -2
  185. package/src/template/routes/pages.tsx +2 -2
  186. package/src/template/routes/reference.tsx +90 -25
  187. package/src/template/routes/root.tsx +3 -3
  188. package/src/template/server/ssg/get-route-paths.test.ts +145 -0
  189. package/src/template/server/ssg/get-route-paths.ts +80 -9
  190. package/src/template/sources/schema-source.ts +2 -1
  191. package/build/template/lib/schema-utils/constants.d.ts +0 -5
  192. package/build/template/lib/schema-utils/constants.d.ts.map +0 -1
  193. package/build/template/lib/schema-utils/constants.js +0 -5
  194. package/build/template/lib/schema-utils/constants.js.map +0 -1
  195. package/build/template/routes/reference.$type.$field.d.ts +0 -5
  196. package/build/template/routes/reference.$type.$field.d.ts.map +0 -1
  197. package/build/template/routes/reference.$type.$field.js +0 -31
  198. package/build/template/routes/reference.$type.$field.js.map +0 -1
  199. package/build/template/routes/reference.$type.d.ts +0 -9
  200. package/build/template/routes/reference.$type.d.ts.map +0 -1
  201. package/build/template/routes/reference.$type.js +0 -25
  202. package/build/template/routes/reference.$type.js.map +0 -1
  203. package/build/template/routes/reference.version.$version.$type.$field.d.ts +0 -6
  204. package/build/template/routes/reference.version.$version.$type.$field.d.ts.map +0 -1
  205. package/build/template/routes/reference.version.$version.$type.$field.js +0 -32
  206. package/build/template/routes/reference.version.$version.$type.$field.js.map +0 -1
  207. package/build/template/routes/reference.version.$version.$type.d.ts +0 -11
  208. package/build/template/routes/reference.version.$version.$type.d.ts.map +0 -1
  209. package/build/template/routes/reference.version.$version.$type.js +0 -26
  210. package/build/template/routes/reference.version.$version.$type.js.map +0 -1
  211. package/src/template/lib/schema-utils/constants.ts +0 -4
  212. package/src/template/routes/reference.$type.$field.tsx +0 -34
  213. package/src/template/routes/reference.$type.tsx +0 -29
  214. package/src/template/routes/reference.version.$version.$type.$field.tsx +0 -35
  215. package/src/template/routes/reference.version.$version.$type.tsx +0 -30
@@ -1,10 +1,13 @@
1
1
  import type { GraphqlChangeset } from '#lib/graphql-changeset/index'
2
2
 
3
- export * as DataSources from './data-sources/data-sources.js'
4
-
5
- export * from './read.js'
3
+ // Re-export everything from isomorphic layer
4
+ export * from '../iso/schema/constants.js'
5
+ export * as Routing from '../iso/schema/routing.js'
6
6
 
7
+ // Server-only exports
8
+ export * as DataSources from './data-sources/data-sources.js'
7
9
  export * from './metadata.js'
10
+ export * from './read.js'
8
11
 
9
12
  export type ChangeSets = GraphqlChangeset.ChangeSet[]
10
13
 
@@ -17,53 +20,3 @@ export interface ChangelogData {
17
20
  changes: GraphqlChangeset.ChangeSet['changes']
18
21
  date: string
19
22
  }
20
-
21
- /**
22
- * Constants for schema versioning
23
- */
24
-
25
- /**
26
- * The version identifier for the latest schema
27
- */
28
- export const VERSION_LATEST = `latest`
29
-
30
- /**
31
- * Fallback version name when date parsing fails
32
- */
33
- export const VERSION_UNKNOWN_FALLBACK = `unknown`
34
-
35
- /**
36
- * Convert a date to a version string in YYYY-MM-DD format
37
- */
38
- export const dateToVersionString = (date: Date): string => {
39
- return date.toLocaleDateString('en-CA')
40
- }
41
-
42
- /**
43
- * Determine if a version at the given index should have a changelog file.
44
- * Only non-oldest versions get changelog files.
45
- */
46
- export const shouldVersionHaveChangelog = (versionIndex: number, totalVersions: number): boolean => {
47
- return versionIndex < totalVersions - 1
48
- }
49
-
50
- /**
51
- * Convert a version string back to a Date
52
- */
53
- export const versionStringToDate = (version: string): Date => {
54
- if (version === VERSION_LATEST) {
55
- return new Date()
56
- }
57
-
58
- // Use modern date parsing - the version string should be in YYYY-MM-DD format
59
- // which is ISO 8601 compatible
60
- const parsedDate = new Date(version + 'T00:00:00Z')
61
-
62
- // Check if the date is valid
63
- if (!isNaN(parsedDate.getTime())) {
64
- return parsedDate
65
- }
66
-
67
- // Throw error for invalid dates instead of silently defaulting
68
- throw new Error(`Invalid version string: ${version}`)
69
- }
@@ -157,13 +157,13 @@ export const createSchemaSource = (config: SchemaSourceConfig) => {
157
157
  },
158
158
 
159
159
  writeAllAssets: async (
160
- schemaData: Awaited<ReturnType<typeof Schema.readOrThrow>>,
160
+ schemaData: Awaited<ReturnType<typeof Schema.readOrThrow>>['data'],
161
161
  metadata: Schema.SchemaMetadata,
162
162
  ) => {
163
163
  if (!schemaData) return
164
164
 
165
165
  // Write schema and changelog files
166
- for (const [index, version] of schemaData.entries()) {
166
+ for (const [index, version] of schemaData!.entries()) {
167
167
  const versionName = index === 0 ? Schema.VERSION_LATEST : Schema.dateToVersionString(version.date)
168
168
 
169
169
  // Write schema file
@@ -173,7 +173,7 @@ export const createSchemaSource = (config: SchemaSourceConfig) => {
173
173
  )
174
174
 
175
175
  // Write changelog file (except for the oldest/last version)
176
- if (Schema.shouldVersionHaveChangelog(index, schemaData.length)) {
176
+ if (Schema.shouldVersionHaveChangelog(index, schemaData!.length)) {
177
177
  const changelogData = {
178
178
  changes: version.changes,
179
179
  date: version.date.toISOString(),
@@ -5,7 +5,7 @@ export const PolenBuildManifestSchema = z.object({
5
5
  type: z.enum([`ssg`, `ssr`]),
6
6
  version: z.string(),
7
7
  basePath: z.string(),
8
- }).loose()
8
+ })
9
9
 
10
10
  export type PolenBuildManifest = z.infer<typeof PolenBuildManifestSchema>
11
11
 
@@ -75,6 +75,9 @@ export const Build = (config: Config.Config): Vite.Plugin[] => {
75
75
  // @see https://github.com/vitejs/vite/issues/20098
76
76
  ssr: {
77
77
  noExternal: true,
78
+ // Exclude lightningcss from bundling due to native bindings
79
+ // @see https://github.com/parcel-bundler/lightningcss/issues/701
80
+ external: ['lightningcss'],
78
81
  },
79
82
  environments: {
80
83
  ssr: {
@@ -1,22 +1,18 @@
1
1
  import type { Config } from '#api/config/index'
2
2
  import { Content } from '#api/content/$'
3
3
  import { createNavbar } from '#api/content/navbar'
4
+ import { Api } from '#api/index'
4
5
  import { VitePluginSelfContainedMode } from '#cli/_/self-contained-mode'
5
- import { Hono } from '#dep/hono/index'
6
6
  import type { ReactRouter } from '#dep/react-router/index'
7
7
  import type { Vite } from '#dep/vite/index'
8
8
  import { VitePluginJson } from '#lib/vite-plugin-json/index'
9
9
  import { ViteVirtual } from '#lib/vite-virtual/index'
10
10
  import { debugPolen } from '#singletons/debug'
11
11
  import { superjson } from '#singletons/superjson'
12
- import * as HonoNodeServer from '@hono/node-server'
13
- import { serveStatic } from '@hono/node-server/serve-static'
14
12
  import { Json, Str } from '@wollybeard/kit'
15
- import * as NodePath from 'node:path'
16
13
  import type { ProjectData } from '../../../project-data.js'
17
14
  import { SchemaAugmentation } from '../../schema-augmentation/index.js'
18
15
  import { Schema } from '../../schema/index.js'
19
- import { createLogger } from '../logger.js'
20
16
  import { polenVirtual } from '../vi.js'
21
17
  import { Pages } from './pages.js'
22
18
  import { SchemaAssets } from './schema-assets.js'
@@ -35,15 +31,15 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
35
31
 
36
32
  const readSchema = async () => {
37
33
  if (schemaCache === null) {
38
- const schema = await Schema.readOrThrow({
34
+ const schemaResult = await Schema.readOrThrow({
39
35
  ...config.schema,
40
36
  projectRoot: config.paths.project.rootDir,
41
37
  })
42
38
  // todo: augmentations scoped to a version
43
- schema?.forEach(version => {
39
+ schemaResult.data?.forEach(version => {
44
40
  SchemaAugmentation.apply(version.after, config.schemaAugmentations)
45
41
  })
46
- schemaCache = schema
42
+ schemaCache = schemaResult
47
43
  }
48
44
  return schemaCache
49
45
  }
@@ -166,8 +162,8 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
166
162
  const debug = debugPolen.sub(`module-project-schema`)
167
163
  debug(`load`, { id: viProjectSchema.id })
168
164
 
169
- const schema = await readSchema()
170
- return superjson.stringify(schema)
165
+ const schemaResult = await readSchema()
166
+ return superjson.stringify(schemaResult.data)
171
167
  },
172
168
  },
173
169
  {
@@ -191,18 +187,19 @@ export const Core = (config: Config.Config): Vite.PluginOption[] => {
191
187
 
192
188
  debug(`load`, { id: viProjectData.id })
193
189
 
194
- const schema = await readSchema()
190
+ const schemaResult = await readSchema()
195
191
 
196
192
  const navbar = []
197
193
 
198
194
  // ━ Schema presence causes adding some navbar items
199
- if (schema) {
195
+ if (schemaResult.data) {
200
196
  // IMPORTANT: Always ensure paths start with '/' for React Router compatibility.
201
197
  // Without the leading slash, React Router treats paths as relative, which causes
202
198
  // hydration mismatches between SSR (where base path is prepended) and client
203
199
  // (where basename is configured). This ensures consistent behavior.
204
- navbar.push({ pathExp: `/reference`, title: `Reference` })
205
- if (schema.length > 1) {
200
+ const referencePath = Api.Schema.Routing.createReferenceBasePath()
201
+ navbar.push({ pathExp: referencePath, title: `Reference` })
202
+ if (schemaResult.data.length > 1) {
206
203
  navbar.push({ pathExp: `/changelog`, title: `Changelog` })
207
204
  }
208
205
  }
@@ -2,9 +2,8 @@ import type { Config } from '#api/config/index'
2
2
  import type { Vite } from '#dep/vite/index'
3
3
  import { vitePluginSsrCss } from '@hiogawa/vite-plugin-ssr-css'
4
4
  import ViteReact from '@vitejs/plugin-react-oxc'
5
- import { Arr, Path } from '@wollybeard/kit'
5
+ import { Path } from '@wollybeard/kit'
6
6
  import Inspect from 'vite-plugin-inspect'
7
- import Restart from 'vite-plugin-restart'
8
7
  import { Branding } from './branding.js'
9
8
  import { Build } from './build.js'
10
9
  import { Core } from './core.js'
@@ -26,13 +25,6 @@ export const Main = (
26
25
  plugins.push(plugin)
27
26
  }
28
27
 
29
- if (Arr.isntEmpty(config.watch.also)) {
30
- const plugin = Restart({
31
- restart: config.watch.also,
32
- })
33
- plugins.push(plugin)
34
- }
35
-
36
28
  plugins.push(
37
29
  ViteReact(),
38
30
  vitePluginSsrCss({
@@ -9,6 +9,7 @@ import { debugPolen } from '#singletons/debug'
9
9
  import { Cache } from '@wollybeard/kit'
10
10
  import * as NodeFs from 'node:fs/promises'
11
11
  import * as NodePath from 'node:path'
12
+ import type { NonEmptyChangeSets } from '../../schema/schema.js'
12
13
  import { polenVirtual } from '../vi.js'
13
14
 
14
15
  export const viProjectSchemaMetadata = polenVirtual([`project`, `schema-metadata`])
@@ -35,27 +36,28 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
35
36
 
36
37
  // Helper to load and process schema data
37
38
  const loadAndProcessSchemaData = Cache.memoize(async () => {
38
- const schemaData = await Schema.readOrThrow({
39
+ const schemaResult = await Schema.readOrThrow({
39
40
  ...config.schema,
40
41
  projectRoot: config.paths.project.rootDir,
41
42
  })
42
43
 
43
- if (!schemaData) {
44
+ if (!schemaResult.data) {
44
45
  const metadata: Schema.SchemaMetadata = { hasSchema: false, versions: [] }
45
46
  return {
46
47
  schemaData: null,
47
48
  metadata,
49
+ source: schemaResult.source,
48
50
  }
49
51
  }
50
52
 
51
53
  // Apply augmentations
52
- schemaData.forEach(version => {
54
+ schemaResult.data.forEach(version => {
53
55
  SchemaAugmentation.apply(version.after, config.schemaAugmentations)
54
56
  })
55
57
 
56
58
  // Build metadata
57
59
  const versionStrings: string[] = []
58
- for (const [index, version] of schemaData.entries()) {
60
+ for (const [index, version] of schemaResult.data.entries()) {
59
61
  const versionName = index === 0 ? Schema.VERSION_LATEST : Schema.dateToVersionString(version.date)
60
62
  versionStrings.push(versionName)
61
63
  }
@@ -65,11 +67,12 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
65
67
  versions: versionStrings,
66
68
  }
67
69
 
68
- debug(`schemaDataLoaded`, { versionCount: schemaData.length })
70
+ debug(`schemaDataLoaded`, { versionCount: schemaResult.data.length })
69
71
 
70
72
  return {
71
- schemaData,
73
+ schemaData: schemaResult.data,
72
74
  metadata,
75
+ source: schemaResult.source,
73
76
  }
74
77
  })
75
78
 
@@ -102,10 +105,10 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
102
105
 
103
106
  // Helper to write assets using schema-source API
104
107
  const writeDevAssets = async (
105
- schemaData: Awaited<ReturnType<typeof Schema.readOrThrow>>,
108
+ schemaData: NonEmptyChangeSets,
106
109
  metadata: Schema.SchemaMetadata,
107
110
  ) => {
108
- if (!schemaData) return
111
+ // schemaData is now guaranteed to be non-null NonEmptyChangeSets
109
112
 
110
113
  const devAssetsDir = config.paths.framework.devAssets.schemas
111
114
  await NodeFs.mkdir(devAssetsDir, { recursive: true })
@@ -149,6 +152,13 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
149
152
  debug(`watchingSchemaFile`, { path: config.schema.dataSources.file.path })
150
153
  }
151
154
 
155
+ if (config.schema?.dataSources?.introspection?.url) {
156
+ // Watch the introspection file if introspection is configured
157
+ const introspectionFilePath = NodePath.join(config.paths.project.rootDir, `schema.introspection.json`)
158
+ server.watcher.add(introspectionFilePath)
159
+ debug(`watchingIntrospectionFile`, { path: introspectionFilePath })
160
+ }
161
+
152
162
  // Handle file removal
153
163
  server.watcher.on('unlink', async (file) => {
154
164
  const isSchemaFile = config.schema && (() => {
@@ -172,6 +182,15 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
172
182
  if (absoluteFile.startsWith(absoluteSchemaDir + NodePath.sep)) return true
173
183
  }
174
184
 
185
+ // Check if file is the introspection file
186
+ if (config.schema.dataSources?.introspection?.url) {
187
+ const absoluteIntrospectionFile = NodePath.resolve(
188
+ config.paths.project.rootDir,
189
+ `schema.introspection.json`,
190
+ )
191
+ if (absoluteFile === absoluteIntrospectionFile) return true
192
+ }
193
+
175
194
  return false
176
195
  })()
177
196
 
@@ -181,14 +200,33 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
181
200
  try {
182
201
  // Clear cache and regenerate
183
202
  loadAndProcessSchemaData.clear()
184
- const { schemaData, metadata } = await loadAndProcessSchemaData()
185
-
186
- if (schemaData) {
203
+ const { schemaData, metadata, source } = await loadAndProcessSchemaData()
204
+
205
+ // If file was deleted but can be recreated, attempt recreation
206
+ if (!schemaData && source.reCreate) {
207
+ debug(`attemptingSchemaRecreation`, { sourceType: source.type })
208
+ try {
209
+ const recreatedData = await source.reCreate()
210
+ if (recreatedData) {
211
+ // Clear cache again and reload after recreation
212
+ loadAndProcessSchemaData.clear()
213
+ const reloadResult = await loadAndProcessSchemaData()
214
+ if (reloadResult.schemaData) {
215
+ await writeDevAssets(reloadResult.schemaData, reloadResult.metadata)
216
+ debug(`hmr:schemaRecreatedAndWritten`, { versionCount: reloadResult.schemaData.length })
217
+ }
218
+ } else {
219
+ debug(`hmr:schemaRecreationFailed`, { reason: 'reCreate returned null' })
220
+ }
221
+ } catch (recreationError) {
222
+ debug(`hmr:schemaRecreationFailed`, { error: recreationError })
223
+ }
224
+ } else if (schemaData) {
187
225
  // Write new assets without the removed file
188
226
  await writeDevAssets(schemaData, metadata)
189
227
  debug(`hmr:schemaAssetsUpdatedAfterRemoval`, { versionCount: schemaData.length })
190
228
  } else {
191
- // No schema data - clear all assets
229
+ // No schema data and cannot recreate - clear all assets
192
230
  const schemaSource = createDevSchemaSource({ hasSchema: false, versions: [] })
193
231
  await schemaSource.clearAllAssets()
194
232
  debug(`hmr:allAssetsCleared`, {})
@@ -274,6 +312,15 @@ export const SchemaAssets = (config: Config.Config): Vite.Plugin => {
274
312
  if (absoluteFile.startsWith(absoluteSchemaDir + NodePath.sep)) return true
275
313
  }
276
314
 
315
+ // Check if file is the introspection file
316
+ if (config.schema.dataSources?.introspection?.url) {
317
+ const absoluteIntrospectionFile = NodePath.resolve(
318
+ config.paths.project.rootDir,
319
+ `schema.introspection.json`,
320
+ )
321
+ if (absoluteFile === absoluteIntrospectionFile) return true
322
+ }
323
+
277
324
  return false
278
325
  })()
279
326
  if (isSchemaFile) {
@@ -132,7 +132,7 @@ const wrapCache = <fn extends Fn.AnyAnyAsync>(fn: fn): fn => {
132
132
 
133
133
  // todo: use a proper validation, e.g. zod, better yet: allow to specify the validation in molt itself
134
134
  const parseHeaders = (headersJsonEncoded: string): Record<string, string> => {
135
- const headersJson = Json.codec.deserialize(headersJsonEncoded)
135
+ const headersJson = Json.codec.decode(headersJsonEncoded)
136
136
  if (!Rec.is(headersJson)) {
137
137
  console.log(`--introspection-headers must be a JSON object.`)
138
138
  process.exit(1)
@@ -4,6 +4,7 @@ export {
4
4
  buildASTSchema as fromAST,
5
5
  buildClientSchema as fromIntrospectionQuery,
6
6
  GraphQLSchema as Schema,
7
+ introspectionFromSchema as toIntrospectionQuery,
7
8
  printSchema as print,
8
9
  } from 'graphql'
9
10
 
@@ -105,9 +105,9 @@ export const objPolicyFilter = <
105
105
  const result: any = mode === `deny` ? { ...obj } : {}
106
106
 
107
107
  if (mode === `allow`) {
108
- // For allow mode, only add specified keys
108
+ // For allow mode, only add specified keys that are own properties
109
109
  for (const key of keys) {
110
- if (key in obj) {
110
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
111
111
  // @ts-expect-error
112
112
  result[key] = obj[key]
113
113
  }
@@ -113,9 +113,9 @@ describe('property-based tests', () => {
113
113
  // Result contains only keys that were in both mask and object
114
114
  expect(resultKeys.every(key => keys.includes(key))).toBe(true)
115
115
 
116
- // All requested keys that exist in obj are in result
116
+ // All requested keys that are own properties of obj are in result
117
117
  keys.forEach(key => {
118
- if (key in obj) {
118
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
119
119
  expect(result).toHaveProperty(key, (obj as any)[key])
120
120
  }
121
121
  })
@@ -169,7 +169,7 @@ describe('property-based tests', () => {
169
169
  const result = Mask.apply(obj as any, Mask.create(keys))
170
170
 
171
171
  keys.forEach(key => {
172
- if (key in obj) {
172
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
173
173
  expect(result).toHaveProperty(key)
174
174
  expect((result as any)[key]).toBe((obj as any)[key])
175
175
  }
@@ -1,4 +1,5 @@
1
1
  import type { ReactRouter } from '#dep/react-router/index'
2
+ import type { React } from '#dep/react/index'
2
3
  import type { Http } from '@wollybeard/kit'
3
4
 
4
5
  export * from './get-paths-patterns.js'
@@ -18,23 +19,28 @@ export interface RouteHandle {
18
19
  statusCode?: Http.Status.Code.All
19
20
  }
20
21
 
21
- export const createRoute = <routeObject extends RouteObject>(
22
+ export const route = <routeObject extends RouteObject>(
22
23
  routeObject: routeObject,
23
24
  ): routeObject => {
24
25
  return {
25
- id: routeObject.path,
26
26
  ...routeObject,
27
27
  }
28
28
  }
29
29
 
30
- export type RouteObjectIndexInput = Omit<RouteObjectIndex, `index` | `children`>
30
+ export type RouteObjectIndexInput = RouteObjectIndexInputConfig | React.ComponentType
31
+ export type RouteObjectIndexInputConfig = Omit<RouteObjectIndex, `index` | `children`>
31
32
 
32
- export const createRouteIndex = (
33
- indexRouteObjectInput: RouteObjectIndexInput,
33
+ export const routeIndex = (
34
+ input: RouteObjectIndexInput,
34
35
  ): RouteObjectIndex => {
36
+ const routeConfig: RouteObjectIndexInputConfig = isComponentType(input) ? { Component: input } : input
35
37
  return {
36
- ...indexRouteObjectInput,
38
+ ...routeConfig,
37
39
  index: true,
38
40
  children: undefined,
39
41
  }
40
42
  }
43
+
44
+ const isComponentType = (value: unknown): value is React.ComponentType => {
45
+ return typeof value === 'function'
46
+ }
@@ -5,6 +5,7 @@
5
5
  * analysis to create unified tokens for interactive code blocks.
6
6
  */
7
7
 
8
+ import { Api } from '#api/iso'
8
9
  import type { CodeAnnotation } from 'codehike/code'
9
10
  import {
10
11
  getNamedType,
@@ -14,7 +15,6 @@ import {
14
15
  GraphQLInputObjectType,
15
16
  GraphQLInterfaceType,
16
17
  GraphQLObjectType,
17
- type GraphQLOutputType,
18
18
  GraphQLScalarType,
19
19
  type GraphQLSchema,
20
20
  GraphQLUnionType,
@@ -24,12 +24,7 @@ import {
24
24
  import graphqlWasmUrl from 'tree-sitter-graphql-grammar-wasm/grammar.wasm?url'
25
25
  import * as WebTreeSitter from 'web-tree-sitter'
26
26
  import treeSitterWasmUrl from 'web-tree-sitter/tree-sitter.wasm?url'
27
- import {
28
- isKeywordNodeType,
29
- isLiteralNodeType,
30
- isPunctuationNodeType,
31
- type TreeSitterGraphQLNodeType,
32
- } from './graphql-node-types.js'
27
+ import { isKeywordNodeType, isPunctuationNodeType, type TreeSitterGraphQLNodeType } from './graphql-node-types.js'
33
28
  import type { SemanticNode } from './semantic-nodes.js'
34
29
  import {
35
30
  isArgument,
@@ -263,42 +258,63 @@ class UnifiedToken implements GraphQLToken {
263
258
 
264
259
  // Arguments - use #<field>__<argument> pattern
265
260
  if (isArgument(this.semantic)) {
266
- return `/reference/${this.semantic.parentType.name}#${this.semantic.parentField.name}__${this.semantic.argumentDef.name}`
261
+ const basePath = Api.Schema.Routing.createReferencePath({
262
+ type: this.semantic.parentType.name,
263
+ })
264
+ return `${basePath}#${this.semantic.parentField.name}__${this.semantic.argumentDef.name}`
267
265
  }
268
266
 
269
267
  // Output fields - use hash links since field routes aren't connected yet
270
268
  if (isOutputField(this.semantic)) {
271
- return `/reference/${this.semantic.parentType.name}#${this.semantic.fieldDef.name}`
269
+ const basePath = Api.Schema.Routing.createReferencePath({
270
+ type: this.semantic.parentType.name,
271
+ })
272
+ return `${basePath}#${this.semantic.fieldDef.name}`
272
273
  }
273
274
 
274
275
  // Input fields - use hash links since field routes aren't connected yet
275
276
  if (isInputField(this.semantic)) {
276
- return `/reference/${this.semantic.parentType.name}#${this.semantic.fieldDef.name}`
277
+ const basePath = Api.Schema.Routing.createReferencePath({
278
+ type: this.semantic.parentType.name,
279
+ })
280
+ return `${basePath}#${this.semantic.fieldDef.name}`
277
281
  }
278
282
 
279
283
  // Type references - use :type pattern
280
284
  if (this.semantic instanceof GraphQLObjectType) {
281
- return `/reference/${this.semantic.name}`
285
+ return Api.Schema.Routing.createReferencePath({
286
+ type: this.semantic.name,
287
+ })
282
288
  }
283
289
 
284
290
  if (this.semantic instanceof GraphQLScalarType) {
285
- return `/reference/${this.semantic.name}`
291
+ return Api.Schema.Routing.createReferencePath({
292
+ type: this.semantic.name,
293
+ })
286
294
  }
287
295
 
288
296
  if (this.semantic instanceof GraphQLInterfaceType) {
289
- return `/reference/${this.semantic.name}`
297
+ return Api.Schema.Routing.createReferencePath({
298
+ type: this.semantic.name,
299
+ })
290
300
  }
291
301
 
292
302
  if (this.semantic instanceof GraphQLUnionType) {
293
- return `/reference/${this.semantic.name}`
303
+ return Api.Schema.Routing.createReferencePath({
304
+ type: this.semantic.name,
305
+ })
294
306
  }
295
307
 
296
308
  if (this.semantic instanceof GraphQLEnumType) {
297
- return `/reference/${this.semantic.name}`
309
+ return Api.Schema.Routing.createReferencePath({
310
+ type: this.semantic.name,
311
+ })
298
312
  }
299
313
 
300
314
  if (this.semantic instanceof GraphQLInputObjectType) {
301
- return `/reference/${this.semantic.name}`
315
+ return Api.Schema.Routing.createReferencePath({
316
+ type: this.semantic.name,
317
+ })
302
318
  }
303
319
 
304
320
  return null
@@ -9,6 +9,7 @@ export interface HamburgerMenuProps {
9
9
  onToggle: () => void
10
10
  onClose: () => void
11
11
  sidebarData: Content.Item[]
12
+ basePath?: string
12
13
  }
13
14
 
14
15
  export const HamburgerMenu: React.FC<HamburgerMenuProps> = ({
@@ -16,6 +17,7 @@ export const HamburgerMenu: React.FC<HamburgerMenuProps> = ({
16
17
  onToggle,
17
18
  onClose,
18
19
  sidebarData,
20
+ basePath,
19
21
  }) => {
20
22
  // Prevent body scroll when mobile menu is open
21
23
  useEffect(() => {
@@ -87,7 +89,7 @@ export const HamburgerMenu: React.FC<HamburgerMenuProps> = ({
87
89
  <Cross2Icon width='18' height='18' />
88
90
  </IconButton>
89
91
  </Flex>
90
- <Sidebar data={sidebarData} />
92
+ <Sidebar data={sidebarData} basePath={basePath} />
91
93
  </Box>
92
94
  </>
93
95
  )}
@@ -1,3 +1,4 @@
1
+ import { Api } from '#api/iso'
1
2
  import type { ReactNode } from 'react'
2
3
  import { useVersionPath } from '../hooks/useVersionPath.js'
3
4
  import { Link } from './Link.js'
@@ -21,10 +22,12 @@ interface Props {
21
22
  export const ReferenceLink = ({ type, field, children }: Props) => {
22
23
  const versionPath = useVersionPath()
23
24
 
24
- let path = `/reference/${versionPath}${type}`
25
- if (field) {
26
- path += `/${field}`
27
- }
25
+ const path = Api.Schema.Routing.joinSegmentsAndPaths(
26
+ Api.Schema.Routing.segmentLiterals.reference,
27
+ versionPath,
28
+ type,
29
+ field,
30
+ )
28
31
 
29
32
  return (
30
33
  <Link to={path}>
@@ -1,13 +1,14 @@
1
+ import { Api } from '#api/iso'
2
+ import type { React } from '#dep/react/index'
1
3
  import { Select } from '@radix-ui/themes'
2
4
  import { useNavigate, useParams } from 'react-router'
3
- import { VERSION_LATEST } from '../lib/schema-utils/constants.js'
4
5
 
5
- interface VersionSelectorProps {
6
+ interface Props {
6
7
  availableVersions: string[]
7
8
  currentVersion: string
8
9
  }
9
10
 
10
- export const VersionSelector = ({ availableVersions, currentVersion }: VersionSelectorProps) => {
11
+ export const VersionSelector: React.FC<Props> = ({ availableVersions, currentVersion }) => {
11
12
  const navigate = useNavigate()
12
13
  const params = useParams()
13
14
 
@@ -17,20 +18,11 @@ export const VersionSelector = ({ availableVersions, currentVersion }: VersionSe
17
18
  }
18
19
 
19
20
  const handleVersionChange = (newVersion: string) => {
20
- // Build new path preserving the current type/field if any
21
- const currentType = params[`type`]
22
- const currentField = params[`field`]
23
-
24
- let newPath = `/reference`
25
- if (newVersion !== VERSION_LATEST) {
26
- newPath += `/version/${newVersion}`
27
- }
28
- if (currentType) {
29
- newPath += `/${currentType}`
30
- if (currentField) {
31
- newPath += `/${currentField}`
32
- }
33
- }
21
+ const newPath = Api.Schema.Routing.createReferencePath({
22
+ version: newVersion,
23
+ type: params[`type`],
24
+ field: params[`field`],
25
+ })
34
26
 
35
27
  navigate(newPath)
36
28
  }
@@ -41,7 +33,7 @@ export const VersionSelector = ({ availableVersions, currentVersion }: VersionSe
41
33
  <Select.Content>
42
34
  {availableVersions.map(version => (
43
35
  <Select.Item key={version} value={version}>
44
- {version === VERSION_LATEST ? `Latest` : version}
36
+ {version === Api.Schema.VERSION_LATEST ? `Latest` : version}
45
37
  </Select.Item>
46
38
  ))}
47
39
  </Select.Content>