@vexcms/core 0.0.19 → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/LICENSE +202 -0
  2. package/dist/.build +1 -0
  3. package/dist/access/buildChecks.d.ts +58 -0
  4. package/dist/access/buildChecks.d.ts.map +1 -0
  5. package/dist/access/canAccessAdminPanel.d.ts +53 -0
  6. package/dist/access/canAccessAdminPanel.d.ts.map +1 -0
  7. package/dist/access/compileConstraints.d.ts +155 -0
  8. package/dist/access/compileConstraints.d.ts.map +1 -0
  9. package/dist/access/config.d.ts +62 -0
  10. package/dist/access/config.d.ts.map +1 -0
  11. package/dist/access/constants.d.ts +95 -0
  12. package/dist/access/constants.d.ts.map +1 -0
  13. package/dist/access/constraintTypes.d.ts +337 -0
  14. package/dist/access/constraintTypes.d.ts.map +1 -0
  15. package/dist/access/createAccessQueryBuilder.d.ts +59 -0
  16. package/dist/access/createAccessQueryBuilder.d.ts.map +1 -0
  17. package/dist/access/createFilterConstraintBuilder.d.ts +26 -0
  18. package/dist/access/createFilterConstraintBuilder.d.ts.map +1 -0
  19. package/dist/access/createIndexConstraintBuilder.d.ts +40 -0
  20. package/dist/access/createIndexConstraintBuilder.d.ts.map +1 -0
  21. package/dist/access/hasPermission.d.ts +85 -0
  22. package/dist/access/hasPermission.d.ts.map +1 -0
  23. package/dist/access/index.d.ts +13 -0
  24. package/dist/access/index.d.ts.map +1 -0
  25. package/dist/access/pickQueryIndex.d.ts +42 -0
  26. package/dist/access/pickQueryIndex.d.ts.map +1 -0
  27. package/dist/access/resolveAccessRule.d.ts +85 -0
  28. package/dist/access/resolveAccessRule.d.ts.map +1 -0
  29. package/dist/access/types.d.ts +738 -0
  30. package/dist/access/types.d.ts.map +1 -0
  31. package/dist/access/validateAccessConstraints.d.ts +57 -0
  32. package/dist/access/validateAccessConstraints.d.ts.map +1 -0
  33. package/dist/api/client.d.ts +20 -0
  34. package/dist/api/client.d.ts.map +1 -0
  35. package/dist/api/client.js +117 -0
  36. package/dist/api/client.js.map +1 -0
  37. package/dist/api/convex.d.ts +296 -0
  38. package/dist/api/convex.d.ts.map +1 -0
  39. package/dist/api/create/client.d.ts +50 -0
  40. package/dist/api/create/client.d.ts.map +1 -0
  41. package/dist/api/create/server.d.ts +43 -0
  42. package/dist/api/create/server.d.ts.map +1 -0
  43. package/dist/api/depth.d.ts +39 -0
  44. package/dist/api/depth.d.ts.map +1 -0
  45. package/dist/api/find/client.d.ts +90 -0
  46. package/dist/api/find/client.d.ts.map +1 -0
  47. package/dist/api/find/server.d.ts +73 -0
  48. package/dist/api/find/server.d.ts.map +1 -0
  49. package/dist/api/get/client.d.ts +56 -0
  50. package/dist/api/get/client.d.ts.map +1 -0
  51. package/dist/api/get/server.d.ts +49 -0
  52. package/dist/api/get/server.d.ts.map +1 -0
  53. package/dist/api/globals/find.client.d.ts +20 -0
  54. package/dist/api/globals/find.client.d.ts.map +1 -0
  55. package/dist/api/globals/find.server.d.ts +29 -0
  56. package/dist/api/globals/find.server.d.ts.map +1 -0
  57. package/dist/api/globals/get.client.d.ts +46 -0
  58. package/dist/api/globals/get.client.d.ts.map +1 -0
  59. package/dist/api/globals/get.server.d.ts +55 -0
  60. package/dist/api/globals/get.server.d.ts.map +1 -0
  61. package/dist/api/globals/types.d.ts +65 -0
  62. package/dist/api/globals/types.d.ts.map +1 -0
  63. package/dist/api/globals/upsert.client.d.ts +24 -0
  64. package/dist/api/globals/upsert.client.d.ts.map +1 -0
  65. package/dist/api/globals/upsert.server.d.ts +47 -0
  66. package/dist/api/globals/upsert.server.d.ts.map +1 -0
  67. package/dist/api/populate.d.ts +23 -0
  68. package/dist/api/populate.d.ts.map +1 -0
  69. package/dist/api/remove/client.d.ts +58 -0
  70. package/dist/api/remove/client.d.ts.map +1 -0
  71. package/dist/api/remove/server.d.ts +65 -0
  72. package/dist/api/remove/server.d.ts.map +1 -0
  73. package/dist/api/search/client.d.ts +58 -0
  74. package/dist/api/search/client.d.ts.map +1 -0
  75. package/dist/api/search/server.d.ts +54 -0
  76. package/dist/api/search/server.d.ts.map +1 -0
  77. package/dist/api/server.d.ts +370 -0
  78. package/dist/api/server.d.ts.map +1 -0
  79. package/dist/api/server.js +33 -0
  80. package/dist/api/server.js.map +1 -0
  81. package/dist/api/types.d.ts +525 -0
  82. package/dist/api/types.d.ts.map +1 -0
  83. package/dist/api/update/client.d.ts +53 -0
  84. package/dist/api/update/client.d.ts.map +1 -0
  85. package/dist/api/update/server.d.ts +47 -0
  86. package/dist/api/update/server.d.ts.map +1 -0
  87. package/dist/api/utils.d.ts +57 -0
  88. package/dist/api/utils.d.ts.map +1 -0
  89. package/dist/auth/mergeCollections.d.ts +28 -0
  90. package/dist/auth/mergeCollections.d.ts.map +1 -0
  91. package/dist/auth/types.d.ts +84 -0
  92. package/dist/auth/types.d.ts.map +1 -0
  93. package/dist/chunk-2DU7JDEX.js +1877 -0
  94. package/dist/chunk-2DU7JDEX.js.map +1 -0
  95. package/dist/chunk-2IB2DCN7.js +75 -0
  96. package/dist/chunk-2IB2DCN7.js.map +1 -0
  97. package/dist/collections/config.d.ts +28 -0
  98. package/dist/collections/config.d.ts.map +1 -0
  99. package/dist/collections/constants.d.ts +27 -0
  100. package/dist/collections/constants.d.ts.map +1 -0
  101. package/dist/collections/index.d.ts +7 -0
  102. package/dist/collections/index.d.ts.map +1 -0
  103. package/dist/collections/indexFields.d.ts +20 -0
  104. package/dist/collections/indexFields.d.ts.map +1 -0
  105. package/dist/collections/interfaceGen.d.ts +59 -0
  106. package/dist/collections/interfaceGen.d.ts.map +1 -0
  107. package/dist/collections/internal/index.d.ts +2 -0
  108. package/dist/collections/internal/index.d.ts.map +1 -0
  109. package/dist/collections/types.d.ts +282 -0
  110. package/dist/collections/types.d.ts.map +1 -0
  111. package/dist/collections/utils.d.ts +71 -0
  112. package/dist/collections/utils.d.ts.map +1 -0
  113. package/dist/collections/validator.d.ts +73 -0
  114. package/dist/collections/validator.d.ts.map +1 -0
  115. package/dist/config/config.d.ts +43 -0
  116. package/dist/config/config.d.ts.map +1 -0
  117. package/dist/config/index.d.ts +5 -0
  118. package/dist/config/index.d.ts.map +1 -0
  119. package/dist/config/sanitizeConfig.d.ts +82 -0
  120. package/dist/config/sanitizeConfig.d.ts.map +1 -0
  121. package/dist/config/types.d.ts +316 -0
  122. package/dist/config/types.d.ts.map +1 -0
  123. package/dist/fields/array/config.d.ts +57 -0
  124. package/dist/fields/array/config.d.ts.map +1 -0
  125. package/dist/fields/array/index.d.ts +5 -0
  126. package/dist/fields/array/index.d.ts.map +1 -0
  127. package/dist/fields/array/inputSchema.d.ts +32 -0
  128. package/dist/fields/array/inputSchema.d.ts.map +1 -0
  129. package/dist/fields/array/types.d.ts +127 -0
  130. package/dist/fields/array/types.d.ts.map +1 -0
  131. package/dist/fields/array/validator.d.ts +30 -0
  132. package/dist/fields/array/validator.d.ts.map +1 -0
  133. package/dist/fields/baseTypes.d.ts +251 -0
  134. package/dist/fields/baseTypes.d.ts.map +1 -0
  135. package/dist/fields/blocks/config.d.ts +63 -0
  136. package/dist/fields/blocks/config.d.ts.map +1 -0
  137. package/dist/fields/blocks/index.d.ts +5 -0
  138. package/dist/fields/blocks/index.d.ts.map +1 -0
  139. package/dist/fields/blocks/inputSchema.d.ts +22 -0
  140. package/dist/fields/blocks/inputSchema.d.ts.map +1 -0
  141. package/dist/fields/blocks/types.d.ts +253 -0
  142. package/dist/fields/blocks/types.d.ts.map +1 -0
  143. package/dist/fields/blocks/validator.d.ts +32 -0
  144. package/dist/fields/blocks/validator.d.ts.map +1 -0
  145. package/dist/fields/checkbox/config.d.ts +46 -0
  146. package/dist/fields/checkbox/config.d.ts.map +1 -0
  147. package/dist/fields/checkbox/index.d.ts +5 -0
  148. package/dist/fields/checkbox/index.d.ts.map +1 -0
  149. package/dist/fields/checkbox/inputSchema.d.ts +27 -0
  150. package/dist/fields/checkbox/inputSchema.d.ts.map +1 -0
  151. package/dist/fields/checkbox/types.d.ts +67 -0
  152. package/dist/fields/checkbox/types.d.ts.map +1 -0
  153. package/dist/fields/checkbox/validator.d.ts +34 -0
  154. package/dist/fields/checkbox/validator.d.ts.map +1 -0
  155. package/dist/fields/color/config.d.ts +49 -0
  156. package/dist/fields/color/config.d.ts.map +1 -0
  157. package/dist/fields/color/convert.d.ts +72 -0
  158. package/dist/fields/color/convert.d.ts.map +1 -0
  159. package/dist/fields/color/formats.d.ts +38 -0
  160. package/dist/fields/color/formats.d.ts.map +1 -0
  161. package/dist/fields/color/index.d.ts +8 -0
  162. package/dist/fields/color/index.d.ts.map +1 -0
  163. package/dist/fields/color/inputSchema.d.ts +29 -0
  164. package/dist/fields/color/inputSchema.d.ts.map +1 -0
  165. package/dist/fields/color/types.d.ts +100 -0
  166. package/dist/fields/color/types.d.ts.map +1 -0
  167. package/dist/fields/color/utils.d.ts +100 -0
  168. package/dist/fields/color/utils.d.ts.map +1 -0
  169. package/dist/fields/color/validator.d.ts +27 -0
  170. package/dist/fields/color/validator.d.ts.map +1 -0
  171. package/dist/fields/constants.d.ts +108 -0
  172. package/dist/fields/constants.d.ts.map +1 -0
  173. package/dist/fields/date/config.d.ts +57 -0
  174. package/dist/fields/date/config.d.ts.map +1 -0
  175. package/dist/fields/date/index.d.ts +5 -0
  176. package/dist/fields/date/index.d.ts.map +1 -0
  177. package/dist/fields/date/inputSchema.d.ts +29 -0
  178. package/dist/fields/date/inputSchema.d.ts.map +1 -0
  179. package/dist/fields/date/types.d.ts +147 -0
  180. package/dist/fields/date/types.d.ts.map +1 -0
  181. package/dist/fields/date/validator.d.ts +34 -0
  182. package/dist/fields/date/validator.d.ts.map +1 -0
  183. package/dist/fields/group/config.d.ts +47 -0
  184. package/dist/fields/group/config.d.ts.map +1 -0
  185. package/dist/fields/group/index.d.ts +5 -0
  186. package/dist/fields/group/index.d.ts.map +1 -0
  187. package/dist/fields/group/inputSchema.d.ts +27 -0
  188. package/dist/fields/group/inputSchema.d.ts.map +1 -0
  189. package/dist/fields/group/types.d.ts +105 -0
  190. package/dist/fields/group/types.d.ts.map +1 -0
  191. package/dist/fields/group/validator.d.ts +41 -0
  192. package/dist/fields/group/validator.d.ts.map +1 -0
  193. package/dist/fields/index.d.ts +20 -0
  194. package/dist/fields/index.d.ts.map +1 -0
  195. package/dist/fields/inputSchemas/index.d.ts +23 -0
  196. package/dist/fields/inputSchemas/index.d.ts.map +1 -0
  197. package/dist/fields/inputSchemas/utils.d.ts +25 -0
  198. package/dist/fields/inputSchemas/utils.d.ts.map +1 -0
  199. package/dist/fields/interfaceGen.d.ts +15 -0
  200. package/dist/fields/interfaceGen.d.ts.map +1 -0
  201. package/dist/fields/number/config.d.ts +48 -0
  202. package/dist/fields/number/config.d.ts.map +1 -0
  203. package/dist/fields/number/index.d.ts +5 -0
  204. package/dist/fields/number/index.d.ts.map +1 -0
  205. package/dist/fields/number/inputSchema.d.ts +23 -0
  206. package/dist/fields/number/inputSchema.d.ts.map +1 -0
  207. package/dist/fields/number/types.d.ts +100 -0
  208. package/dist/fields/number/types.d.ts.map +1 -0
  209. package/dist/fields/number/validator.d.ts +39 -0
  210. package/dist/fields/number/validator.d.ts.map +1 -0
  211. package/dist/fields/relationship/config.d.ts +45 -0
  212. package/dist/fields/relationship/config.d.ts.map +1 -0
  213. package/dist/fields/relationship/index.d.ts +5 -0
  214. package/dist/fields/relationship/index.d.ts.map +1 -0
  215. package/dist/fields/relationship/inputSchema.d.ts +31 -0
  216. package/dist/fields/relationship/inputSchema.d.ts.map +1 -0
  217. package/dist/fields/relationship/types.d.ts +126 -0
  218. package/dist/fields/relationship/types.d.ts.map +1 -0
  219. package/dist/fields/relationship/validator.d.ts +27 -0
  220. package/dist/fields/relationship/validator.d.ts.map +1 -0
  221. package/dist/fields/select/config.d.ts +59 -0
  222. package/dist/fields/select/config.d.ts.map +1 -0
  223. package/dist/fields/select/index.d.ts +5 -0
  224. package/dist/fields/select/index.d.ts.map +1 -0
  225. package/dist/fields/select/inputSchema.d.ts +28 -0
  226. package/dist/fields/select/inputSchema.d.ts.map +1 -0
  227. package/dist/fields/select/types.d.ts +89 -0
  228. package/dist/fields/select/types.d.ts.map +1 -0
  229. package/dist/fields/select/validator.d.ts +31 -0
  230. package/dist/fields/select/validator.d.ts.map +1 -0
  231. package/dist/fields/text/config.d.ts +48 -0
  232. package/dist/fields/text/config.d.ts.map +1 -0
  233. package/dist/fields/text/index.d.ts +5 -0
  234. package/dist/fields/text/index.d.ts.map +1 -0
  235. package/dist/fields/text/inputSchema.d.ts +24 -0
  236. package/dist/fields/text/inputSchema.d.ts.map +1 -0
  237. package/dist/fields/text/types.d.ts +132 -0
  238. package/dist/fields/text/types.d.ts.map +1 -0
  239. package/dist/fields/text/validator.d.ts +39 -0
  240. package/dist/fields/text/validator.d.ts.map +1 -0
  241. package/dist/fields/types.d.ts +135 -0
  242. package/dist/fields/types.d.ts.map +1 -0
  243. package/dist/fields/upload/config.d.ts +24 -0
  244. package/dist/fields/upload/config.d.ts.map +1 -0
  245. package/dist/fields/upload/index.d.ts +5 -0
  246. package/dist/fields/upload/index.d.ts.map +1 -0
  247. package/dist/fields/upload/inputSchema.d.ts +17 -0
  248. package/dist/fields/upload/inputSchema.d.ts.map +1 -0
  249. package/dist/fields/upload/types.d.ts +78 -0
  250. package/dist/fields/upload/types.d.ts.map +1 -0
  251. package/dist/fields/upload/validator.d.ts +16 -0
  252. package/dist/fields/upload/validator.d.ts.map +1 -0
  253. package/dist/fields/url/config.d.ts +49 -0
  254. package/dist/fields/url/config.d.ts.map +1 -0
  255. package/dist/fields/url/index.d.ts +5 -0
  256. package/dist/fields/url/index.d.ts.map +1 -0
  257. package/dist/fields/url/inputSchema.d.ts +31 -0
  258. package/dist/fields/url/inputSchema.d.ts.map +1 -0
  259. package/dist/fields/url/types.d.ts +70 -0
  260. package/dist/fields/url/types.d.ts.map +1 -0
  261. package/dist/fields/url/validator.d.ts +37 -0
  262. package/dist/fields/url/validator.d.ts.map +1 -0
  263. package/dist/fields/utils.d.ts +47 -0
  264. package/dist/fields/utils.d.ts.map +1 -0
  265. package/dist/fields/validators/index.d.ts +23 -0
  266. package/dist/fields/validators/index.d.ts.map +1 -0
  267. package/dist/fields/validators/utils.d.ts +24 -0
  268. package/dist/fields/validators/utils.d.ts.map +1 -0
  269. package/dist/framework.d.ts +227 -0
  270. package/dist/framework.d.ts.map +1 -0
  271. package/dist/globals/config/config.d.ts +1 -0
  272. package/dist/globals/config/config.d.ts.map +1 -0
  273. package/dist/globals/config/types.d.ts +1 -0
  274. package/dist/globals/config/types.d.ts.map +1 -0
  275. package/dist/globals/config.d.ts +47 -0
  276. package/dist/globals/config.d.ts.map +1 -0
  277. package/dist/globals/index.d.ts +5 -0
  278. package/dist/globals/index.d.ts.map +1 -0
  279. package/dist/globals/interfaceGen.d.ts +33 -0
  280. package/dist/globals/interfaceGen.d.ts.map +1 -0
  281. package/dist/globals/types.d.ts +175 -0
  282. package/dist/globals/types.d.ts.map +1 -0
  283. package/dist/globals/utils.d.ts +37 -0
  284. package/dist/globals/utils.d.ts.map +1 -0
  285. package/dist/index.d.ts +15 -3165
  286. package/dist/index.d.ts.map +1 -0
  287. package/dist/index.js +2101 -3470
  288. package/dist/index.js.map +1 -1
  289. package/dist/media/api/index.d.ts +5 -0
  290. package/dist/media/api/index.d.ts.map +1 -0
  291. package/dist/media/api/mutations.d.ts +76 -0
  292. package/dist/media/api/mutations.d.ts.map +1 -0
  293. package/dist/media/api/queries.d.ts +28 -0
  294. package/dist/media/api/queries.d.ts.map +1 -0
  295. package/dist/media/api/server.d.ts +68 -0
  296. package/dist/media/api/server.d.ts.map +1 -0
  297. package/dist/media/api/types.d.ts +171 -0
  298. package/dist/media/api/types.d.ts.map +1 -0
  299. package/dist/media/config.d.ts +25 -0
  300. package/dist/media/config.d.ts.map +1 -0
  301. package/dist/media/index.d.ts +6 -0
  302. package/dist/media/index.d.ts.map +1 -0
  303. package/dist/media/types.d.ts +332 -0
  304. package/dist/media/types.d.ts.map +1 -0
  305. package/dist/media/utils.d.ts +35 -0
  306. package/dist/media/utils.d.ts.map +1 -0
  307. package/dist/media/validators.d.ts +61 -0
  308. package/dist/media/validators.d.ts.map +1 -0
  309. package/dist/schema/generateVexSchema.d.ts +36 -0
  310. package/dist/schema/generateVexSchema.d.ts.map +1 -0
  311. package/dist/schema/index.d.ts +3 -0
  312. package/dist/schema/index.d.ts.map +1 -0
  313. package/dist/schema/migrate.d.ts +73 -0
  314. package/dist/schema/migrate.d.ts.map +1 -0
  315. package/dist/types/generateVexTypes.d.ts +41 -0
  316. package/dist/types/generateVexTypes.d.ts.map +1 -0
  317. package/dist/types/generated.d.ts +382 -0
  318. package/dist/types/generated.d.ts.map +1 -0
  319. package/dist/types/index.d.ts +5 -0
  320. package/dist/types/index.d.ts.map +1 -0
  321. package/dist/utils.d.ts +57 -0
  322. package/dist/utils.d.ts.map +1 -0
  323. package/package.json +67 -24
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/media.ts","../src/errors/index.ts","../src/config/defineConfig.ts","../src/config/defineCollection.ts","../src/config/defineGlobal.ts","../src/access/defineAccess.ts","../src/access/hasPermission.ts","../src/access/checkAdminAccess.ts","../src/metadata/buildSiteMetadata.ts","../src/config/sanitizeConfig.ts","../src/config/isMediaCollection.ts","../src/config/findCollectionBySlug.ts","../src/fields/checkbox/config.ts","../src/utils.ts","../src/fields/checkbox/columnDef.ts","../src/valueTypes/processAdminOptions.ts","../src/fields/constants.ts","../src/fields/checkbox/schemaValueType.ts","../src/fields/number/config.ts","../src/fields/number/columnDef.ts","../src/fields/number/schemaValueType.ts","../src/fields/select/config.ts","../src/fields/select/columnDef.tsx","../src/fields/select/schemaValueType.ts","../src/fields/text/config.ts","../src/fields/text/columnDef.tsx","../src/fields/text/schemaValueType.ts","../src/fields/date/config.ts","../src/fields/date/columnDef.ts","../src/fields/date/schemaValueType.ts","../src/fields/imageUrl/config.ts","../src/fields/imageUrl/columnDef.tsx","../src/fields/imageUrl/schemaValueType.ts","../src/fields/relationship/config.ts","../src/fields/relationship/columnDef.ts","../src/fields/relationship/schemaValueType.ts","../src/fields/json/config.ts","../src/fields/json/columnDef.ts","../src/fields/json/schemaValueType.ts","../src/fields/object/config.ts","../src/fields/object/schemaValueType.ts","../src/fields/object/columnDef.ts","../src/fields/richtext/config.ts","../src/fields/richtext/schemaValueType.ts","../src/fields/richtext/columnDef.ts","../src/fields/media/config.ts","../src/fields/media/schemaValueType.ts","../src/fields/array/config.ts","../src/fields/array/columnDef.ts","../src/fields/array/schemaValueType.ts","../src/fields/blocks/config.ts","../src/fields/blocks/schemaValueType.ts","../src/fields/blocks/columnDef.ts","../src/fields/color/config.ts","../src/fields/color/schemaValueType.ts","../src/fields/color/columnDef.ts","../src/valueTypes/extract.ts","../src/valueTypes/indexes.ts","../src/valueTypes/searchIndexes.ts","../src/valueTypes/merge.ts","../src/valueTypes/slugs.ts","../src/valueTypes/generate.ts","../src/schema/extendTable.ts","../src/fields/media/columnDef.ts","../src/columns/generateColumns.ts","../src/formSchema/generateFormSchema.ts","../src/formSchema/generateFormDefaultValues.ts","../src/fields/ui/config.ts","../src/fields/tabs/config.ts","../src/types/fields.ts","../src/blocks/defineBlock.ts","../src/styles/presets.ts","../src/styles/blockStylesToTailwind.ts","../src/typeGen/slugToInterfaceName.ts","../src/typeGen/fieldToTypeString.ts","../src/typeGen/generateVexTypes.ts","../src/versioning/constants.ts","../src/versioning/extractUserFields.ts","../src/livePreview/resolvePreviewURL.ts","../src/livePreview/shouldReloadURL.ts","../src/livePreview/constants.ts","../src/convex/previewSnapshot.ts","../src/convex/vexQuery.ts","../src/convex/model/collections.ts","../src/valueTypes/generateCollectionQueries.ts","../src/migrations/diffSchema.ts","../src/migrations/planMigration.ts"],"sourcesContent":["import type { VexField } from \"./fields\";\nimport type { VexCollection, CollectionAdminConfig } from \"./collections\";\n\n/**\n * Interface that file storage plugins must implement.\n * Each method operates on the storage provider (e.g., Convex file storage, S3, Cloudinary).\n */\nexport interface FileStorageAdapter {\n /** Identifier for the storage provider (e.g., \"convex\", \"s3\", \"cloudinary\"). */\n readonly name: string;\n\n /**\n * The Convex value type string for the storageId field in media collections.\n * Determines the schema type at generation time.\n *\n * - Convex adapter: `'v.id(\"_storage\")'` — typed reference to Convex file storage\n * - Generic adapters: `'v.string()'` — plain string for external storage URLs/IDs\n */\n readonly storageIdValueType: string;\n\n /**\n * Get a presigned upload URL from the storage provider.\n * Called by the admin panel before uploading a file.\n *\n * @returns A URL string that accepts file uploads via PUT/POST.\n */\n getUploadUrl: () => Promise<string>;\n\n /**\n * Resolve a storage ID to an accessible URL.\n *\n * @param props.storageId - The storage provider's file identifier.\n * @returns A URL string for accessing the file, or null if the file doesn't exist.\n */\n getUrl: (props: { storageId: string }) => Promise<string | null>;\n\n /**\n * Delete a file from the storage provider.\n *\n * @param props.storageId - The storage provider's file identifier.\n */\n deleteFile: (props: { storageId: string }) => Promise<void>;\n}\n\n/**\n * Fields that are auto-injected into every media collection and cannot be overridden.\n */\nexport const LOCKED_MEDIA_FIELDS = [\n \"storageId\",\n \"filename\",\n \"mimeType\",\n \"size\",\n] as const;\nexport type LockedMediaField = (typeof LOCKED_MEDIA_FIELDS)[number];\n\n/**\n * Fields that are auto-injected but CAN be overridden by the user.\n */\nexport const OVERRIDABLE_MEDIA_FIELDS = [\n \"url\",\n \"alt\",\n \"width\",\n \"height\",\n] as const;\nexport type OverridableMediaField = (typeof OVERRIDABLE_MEDIA_FIELDS)[number];\n\n/**\n * Keys of all default media fields auto-injected by `defineConfig()`.\n * Used as extra autocomplete keys in `CollectionAdminConfig` so that\n * `useAsTitle`, `defaultColumns`, etc. suggest both user fields and preset fields.\n */\nexport type DefaultMediaFieldKeys =\n | LockedMediaField\n | OverridableMediaField;\n\n/**\n * A media collection definition. Users create these as plain objects.\n * Default media fields (storageId, filename, mimeType, size, url, alt, width, height)\n * are injected automatically by `defineConfig()`.\n *\n * The `fields` record contains ONLY user-defined additional fields or overrides\n * of overridable defaults (url, alt, width, height).\n */\nexport interface VexMediaCollection<\n TFields extends Record<string, VexField> = any,\n TSlug extends string = string,\n> {\n readonly slug: TSlug;\n fields?: TFields;\n tableName?: string;\n labels?: { singular?: string; plural?: string };\n admin?: CollectionAdminConfig<TFields, DefaultMediaFieldKeys>;\n}\n\n/**\n * Default media fields injected into every media collection by defineConfig().\n * Returns a fresh record each call to avoid mutation across collections.\n */\nexport function getDefaultMediaFields(): Record<string, VexField> {\n return {\n storageId: {\n type: \"text\",\n required: true,\n defaultValue: \"\",\n label: \"Storage ID\",\n admin: { hidden: true },\n },\n filename: {\n type: \"text\",\n required: true,\n defaultValue: \"\",\n label: \"Filename\",\n admin: { readOnly: true },\n },\n mimeType: {\n type: \"text\",\n required: true,\n defaultValue: \"\",\n label: \"MIME Type\",\n index: \"by_mimeType\",\n admin: { readOnly: true },\n },\n size: {\n type: \"number\",\n required: true,\n defaultValue: 0,\n label: \"File Size (bytes)\",\n admin: { readOnly: true },\n },\n url: {\n type: \"text\",\n required: true,\n defaultValue: \"\",\n label: \"URL\",\n admin: { readOnly: true },\n },\n alt: { type: \"text\", label: \"Alt Text\" },\n width: { type: \"number\", label: \"Width (px)\" },\n height: { type: \"number\", label: \"Height (px)\" },\n };\n}\n\n/**\n * The resolved media configuration on VexConfig.\n */\nexport interface MediaConfig {\n collections: VexCollection[];\n storageAdapter: FileStorageAdapter;\n}\n\n/**\n * Client-safe media configuration with non-serializable parts stripped.\n * Used when passing config across RSC serialization boundaries (e.g., to client components).\n */\nexport interface ClientMediaConfig {\n collections: VexCollection[];\n}\n\n/**\n * Input shape for the `media` field on VexConfigInput.\n */\nexport interface MediaConfigInput {\n collections: VexMediaCollection[];\n storageAdapter: FileStorageAdapter;\n}\n","/**\n * Base error class for all Vex CMS errors.\n * Provides consistent error formatting with a [vex] prefix.\n */\nexport class VexError extends Error {\n constructor(message: string) {\n super(`[vex] ${message}`);\n this.name = \"VexError\";\n }\n}\n\n/**\n * Thrown when a duplicate table slug is detected during schema generation.\n * Includes both registrations so the user can identify the conflict.\n */\nexport class VexSlugConflictError extends VexError {\n constructor(\n public readonly slug: string,\n public readonly existingSource: string,\n public readonly existingLocation: string,\n public readonly newSource: string,\n public readonly newLocation: string,\n ) {\n super(\n `Duplicate table slug \"${slug}\":\\n` +\n ` - ${existingSource}: ${existingLocation}\\n` +\n ` - ${newSource}: ${newLocation}\\n` +\n `Rename one of these to resolve the conflict.`,\n );\n this.name = \"VexSlugConflictError\";\n }\n}\n\n/**\n * Thrown when a field fails validation during schema generation.\n * For example: required field with no defaultValue, or wrong defaultValue type.\n */\nexport class VexFieldValidationError extends VexError {\n constructor(\n public readonly collectionSlug: string,\n public readonly fieldName: string,\n public readonly detail: string,\n ) {\n super(`Field \"${fieldName}\" in collection \"${collectionSlug}\": ${detail}`);\n this.name = \"VexFieldValidationError\";\n }\n}\n\n/**\n * Thrown when auth configuration is invalid.\n * For example: userCollection not found in collections.\n */\nexport class VexAuthConfigError extends VexError {\n constructor(detail: string) {\n super(`Auth configuration error: ${detail}`);\n this.name = \"VexAuthConfigError\";\n }\n}\n\n/**\n * Thrown when media configuration is invalid.\n */\nexport class VexMediaConfigError extends VexError {\n constructor(detail: string) {\n super(`Media configuration error: ${detail}`);\n this.name = \"VexMediaConfigError\";\n }\n}\n\n/**\n * Thrown when access configuration is invalid.\n * For example: orgCollection provided without userOrgField.\n */\nexport class VexAccessConfigError extends VexError {\n constructor(detail: string) {\n super(`Access configuration error: ${detail}`);\n this.name = \"VexAccessConfigError\";\n }\n}\n\n/**\n * Thrown by `hasPermission` when `throwOnDenied` is true and the user\n * does not have permission for the requested action.\n *\n * Contains structured context about the denied access attempt so callers\n * can log, surface to users, or handle programmatically.\n */\nexport class VexAccessError extends VexError {\n constructor(\n public readonly resource: string,\n public readonly action: string,\n public readonly field?: string,\n ) {\n const target = field\n ? `field \"${field}\" on resource \"${resource}\"`\n : `resource \"${resource}\"`;\n super(`Access denied: ${action} on ${target}`);\n this.name = \"VexAccessError\";\n }\n}\n\n/**\n * Thrown when a block definition is invalid.\n * For example: reserved field name used, duplicate block slug.\n */\nexport class VexBlockValidationError extends VexError {\n constructor(\n public readonly blockSlug: string,\n public readonly detail: string,\n ) {\n super(`Block \"${blockSlug}\": ${detail}`);\n this.name = \"VexBlockValidationError\";\n }\n}\n","import type { VexConfig, VexConfigInput, VexCollection } from \"../types\";\nimport type { VexMediaCollection } from \"../types/media\";\nimport { getDefaultMediaFields, LOCKED_MEDIA_FIELDS } from \"../types/media\";\nimport { VexMediaConfigError } from \"../errors\";\n\nexport const BASE_VEX_CONFIG: Omit<VexConfig, \"auth\"> = {\n basePath: \"/admin\",\n globals: [],\n collections: [],\n admin: {\n meta: {\n titleSuffix: \"| Admin\",\n favicon: \"/favicon.ico\",\n },\n user: \"users\",\n sidebar: {\n hideGlobals: false,\n },\n onboarding: {\n disabled: false,\n },\n },\n schema: {\n outputPath: \"/convex/vex.schema.ts\",\n typesOutputPath: \"/convex/vex.types.ts\",\n autoMigrate: true,\n autoRemove: false,\n },\n};\n\n/**\n * Resolve a VexMediaCollection into a VexCollection by injecting\n * default media fields. Locked fields cannot be overridden by the user.\n * Overridable fields (url, alt, width, height) can be customized.\n */\nfunction resolveMediaCollection(props: {\n mediaCollection: VexMediaCollection;\n}): VexCollection {\n const defaults = getDefaultMediaFields();\n\n // Merge user fields, skipping locked fields\n if (props.mediaCollection.fields) {\n for (const [fieldName, field] of Object.entries(props.mediaCollection.fields) as [string, any][]) {\n if ((LOCKED_MEDIA_FIELDS as readonly string[]).includes(fieldName)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[vex] Media collection \"${props.mediaCollection.slug}\": field \"${fieldName}\" is a system field and cannot be overridden`,\n );\n }\n continue;\n }\n defaults[fieldName] = field;\n }\n }\n\n // Build admin config with useAsTitle default\n const adminConfig: Record<string, unknown> = {\n ...props.mediaCollection.admin,\n useAsTitle: props.mediaCollection.admin?.useAsTitle ?? \"filename\",\n };\n\n return {\n slug: props.mediaCollection.slug,\n fields: defaults,\n tableName: props.mediaCollection.tableName,\n labels: props.mediaCollection.labels,\n admin: adminConfig as any,\n _isMedia: true,\n };\n}\n\nexport function defineConfig(vexConfig: VexConfigInput): VexConfig {\n // Execute plugins sequentially — each transforms the config for the next\n let resolvedInput = vexConfig;\n if (vexConfig.plugins && vexConfig.plugins.length > 0) {\n for (const plugin of vexConfig.plugins) {\n resolvedInput = plugin(resolvedInput);\n }\n }\n // Remove plugins from the resolved config (they've already been applied)\n const { plugins: _plugins, ...inputWithoutPlugins } = resolvedInput;\n\n const { media: mediaInput, ...restInput } = inputWithoutPlugins;\n const resolved = inputWithoutPlugins;\n const config: VexConfig = {\n ...BASE_VEX_CONFIG,\n ...restInput,\n admin: {\n ...BASE_VEX_CONFIG.admin,\n ...resolved.admin,\n meta: {\n ...BASE_VEX_CONFIG.admin.meta,\n ...resolved.admin?.meta,\n },\n sidebar: {\n ...BASE_VEX_CONFIG.admin.sidebar,\n ...resolved.admin?.sidebar,\n },\n onboarding: {\n ...BASE_VEX_CONFIG.admin.onboarding,\n ...resolved.admin?.onboarding,\n },\n livePreview: resolved.admin?.livePreview,\n },\n schema: {\n ...BASE_VEX_CONFIG.schema,\n ...resolved.schema,\n },\n access: resolved.access,\n breakpoints: resolved.breakpoints,\n };\n\n // Handle media config\n if (mediaInput) {\n if (mediaInput.collections.length === 0) {\n config.media = undefined;\n } else if (!mediaInput.storageAdapter) {\n throw new VexMediaConfigError(\n \"media.storageAdapter is required when media.collections is non-empty\",\n );\n } else {\n config.media = {\n collections: mediaInput.collections.map((mc) =>\n resolveMediaCollection({ mediaCollection: mc }),\n ),\n storageAdapter: mediaInput.storageAdapter,\n };\n }\n } else {\n config.media = undefined;\n }\n\n if (process.env.NODE_ENV !== \"production\") {\n // Validate collection slugs\n for (const collection of config.collections) {\n if (!/^[a-z][a-z0-9_]*$/.test(collection.slug)) {\n console.warn(\n `[vex] Collection slug \"${collection.slug}\" should be lowercase alphanumeric with underscores, starting with a letter`,\n );\n }\n if (collection.slug.startsWith(\"vex_\")) {\n console.warn(\n `[vex] Collection slug \"${collection.slug}\" uses reserved prefix \"vex_\"`,\n );\n }\n if (Object.keys(collection.fields).length === 0) {\n console.warn(`[vex] Collection \"${collection.slug}\" has no fields defined`);\n }\n }\n\n // Validate global slugs\n for (const global of config.globals) {\n if (!/^[a-z][a-z0-9_]*$/.test(global.slug)) {\n console.warn(\n `[vex] Global slug \"${global.slug}\" should be lowercase alphanumeric with underscores, starting with a letter`,\n );\n }\n if (global.slug.startsWith(\"vex_\")) {\n console.warn(`[vex] Global slug \"${global.slug}\" uses reserved prefix \"vex_\"`);\n }\n if (Object.keys(global.fields).length === 0) {\n console.warn(`[vex] Global \"${global.slug}\" has no fields defined`);\n }\n }\n\n // Check for duplicate slugs\n const slugs = config.collections.concat(config.globals as any[]).map((c) => c.slug);\n const duplicates = slugs.filter((slug, i) => slugs.indexOf(slug) !== i);\n if (duplicates.length > 0) {\n console.warn(\n `[vex] Duplicate collection slugs detected: ${duplicates.join(\", \")}`,\n );\n }\n }\n\n return config;\n}\n","import type { VexField, VexCollection } from \"../types\";\nimport type { VexAuthAdapter, AuthCollectionFieldKeys } from \"../types/auth\";\nimport type { CollectionAdminConfig, IndexConfig, SearchIndexConfig, VersionsConfig, VersioningFieldKeys } from \"../types/collections\";\nimport type { VexMediaCollection, DefaultMediaFieldKeys } from \"../types/media\";\n\n/**\n * Creates a VexCollection with full LSP autocomplete on field names,\n * `admin.useAsTitle`, `admin.defaultColumns`, index fields, etc.\n *\n * When `auth` is provided, auth field keys (e.g. \"email\", \"createdAt\") are\n * also included in autocomplete for admin config and indexes.\n *\n * @example\n * ```ts\n * // Without auth — autocomplete for own fields\n * export const posts = defineCollection({\n * slug: \"posts\",\n * fields: {\n * title: { type: \"text\", required: true },\n * status: { type: \"select\", options: [...] },\n * },\n * admin: { useAsTitle: \"title\" }, // autocomplete: \"title\" | \"status\"\n * });\n *\n * // With auth — autocomplete for own fields + auth fields\n * export const users = defineCollection({\n * slug: \"users\",\n * auth,\n * fields: {\n * name: { type: \"text\", required: true },\n * role: { type: \"select\", options: [...] },\n * },\n * admin: {\n * useAsTitle: \"name\", // autocomplete: \"name\" | \"role\" | \"email\" | \"createdAt\" | ...\n * defaultColumns: [\"name\", \"email\"], // same autocomplete\n * },\n * });\n * ```\n */\nexport function defineCollection<\n TFields extends Record<string, VexField>,\n TAuth extends VexAuthAdapter<any> | undefined = undefined,\n TSlug extends string = string,\n>(props: {\n readonly slug: TSlug;\n fields: TFields;\n auth?: TAuth;\n tableName?: string;\n labels?: { singular?: string; plural?: string };\n admin?: CollectionAdminConfig<\n TFields,\n VersioningFieldKeys | (TAuth extends VexAuthAdapter<any> ? AuthCollectionFieldKeys<TAuth, TSlug> : never)\n >;\n indexes?: IndexConfig<\n TFields,\n VersioningFieldKeys | (TAuth extends VexAuthAdapter<any> ? AuthCollectionFieldKeys<TAuth, TSlug> : never)\n >[];\n searchIndexes?: SearchIndexConfig<\n TFields,\n VersioningFieldKeys | (TAuth extends VexAuthAdapter<any> ? AuthCollectionFieldKeys<TAuth, TSlug> : never)\n >[];\n versions?: VersionsConfig;\n interfaceName?: string;\n}): VexCollection<\n TFields,\n VersioningFieldKeys | (TAuth extends VexAuthAdapter<any> ? AuthCollectionFieldKeys<TAuth, TSlug> : never),\n TSlug\n> {\n const { auth: _auth, ...rest } = props;\n return rest as VexCollection<\n TFields,\n VersioningFieldKeys | (TAuth extends VexAuthAdapter<any> ? AuthCollectionFieldKeys<TAuth, TSlug> : never),\n TSlug\n >;\n}\n\n/**\n * Creates a VexMediaCollection with full LSP autocomplete on field names\n * and `admin.useAsTitle`, `admin.defaultColumns`, etc.\n *\n * Default media fields (storageId, filename, mimeType, size, url, alt, width, height)\n * are injected automatically by `defineConfig()` — only define additional or\n * overridden fields here.\n *\n * @example\n * ```ts\n * export const media = defineMediaCollection({\n * slug: \"media\",\n * fields: {\n * caption: { type: \"text\" },\n * },\n * admin: { useAsTitle: \"filename\" }, // autocomplete: \"caption\" | default media field keys\n * });\n * ```\n */\nexport function defineMediaCollection<\n TFields extends Record<string, VexField> = Record<never, VexField>,\n TSlug extends string = string,\n>(props: {\n readonly slug: TSlug;\n fields?: TFields;\n tableName?: string;\n labels?: { singular?: string; plural?: string };\n admin?: CollectionAdminConfig<TFields, DefaultMediaFieldKeys>;\n}): VexMediaCollection<TFields, TSlug> {\n return props as VexMediaCollection<TFields, TSlug>;\n}\n","import type { VexField, VexGlobal, GlobalAdminConfig } from \"../types\";\nimport type { VersionsConfig } from \"../types/collections\";\n\n/**\n * Creates a VexGlobal with full LSP autocomplete on field names\n * and `admin.useAsTitle`, etc.\n *\n * A global is a singleton document — only one document exists per global.\n * The admin panel shows it as a single editable form, not a list.\n *\n * @example\n * ```ts\n * export const siteSettings = defineGlobal({\n * slug: \"site_settings\",\n * label: \"Site Settings\",\n * fields: {\n * siteName: text({ label: \"Site Name\", required: true }),\n * description: text({ label: \"Description\" }),\n * },\n * admin: { useAsTitle: \"siteName\" },\n * versions: { drafts: true },\n * });\n * ```\n */\nexport function defineGlobal<\n TFields extends Record<string, VexField>,\n TSlug extends string = string,\n>(props: {\n readonly slug: TSlug;\n fields: TFields;\n label?: string;\n tableName?: string;\n admin?: GlobalAdminConfig<TFields>;\n versions?: VersionsConfig;\n interfaceName?: string;\n}): VexGlobal<TFields, TSlug> {\n return props;\n}\n","import type {\n VexAccessConfig,\n VexAccessInputBase,\n VexAccessInputWithOrg,\n} from \"./types\";\nimport type { VexCollection } from \"../types\";\nimport { VexAccessConfigError } from \"../errors\";\n\n/**\n * Define access permissions for the Vex CMS admin panel.\n *\n * This is a builder function (like `defineCollection`) that provides full\n * TypeScript inference for roles, resource slugs, field keys, user type,\n * and organization type.\n *\n * The function validates configuration in non-production and returns a\n * `VexAccessConfig` for passing to `defineConfig({ access: ... })`.\n *\n * @returns A `VexAccessConfig` for passing to `defineConfig({ access: ... })`.\n */\n\n// Overload: with organization (must come first — more specific)\nexport function defineAccess<\n const TRoles extends readonly string[],\n const TResources extends readonly any[],\n const TUserCollection extends VexCollection<any, any, any>,\n TUser = undefined,\n const TOrgCollection extends VexCollection<any, any, any> = never,\n TOrg = undefined,\n>(\n props: VexAccessInputWithOrg<TRoles, TResources, TUserCollection, TUser, TOrgCollection, TOrg>,\n): VexAccessConfig;\n\n// Overload: without organization\nexport function defineAccess<\n const TRoles extends readonly string[],\n const TResources extends readonly any[],\n const TUserCollection extends VexCollection<any, any, any>,\n TUser = undefined,\n>(\n props: VexAccessInputBase<TRoles, TResources, TUserCollection, TUser> & {\n orgCollection?: never;\n orgType?: never;\n userOrgField?: never;\n },\n): VexAccessConfig;\n\n// Implementation\nexport function defineAccess(props: {\n roles: readonly string[];\n adminRoles?: readonly string[];\n resources?: readonly any[];\n userCollection: { slug: string; fields?: Record<string, any> };\n userType?: unknown;\n orgCollection?: { slug: string };\n orgType?: unknown;\n userOrgField?: string;\n permissions: Record<string, any>;\n}): VexAccessConfig {\n // Validate org config coupling\n if (props.orgCollection && !props.userOrgField) {\n throw new VexAccessConfigError(\"orgCollection requires userOrgField\");\n }\n if (props.userOrgField && !props.orgCollection) {\n throw new VexAccessConfigError(\"userOrgField requires orgCollection\");\n }\n\n // Default adminRoles to all roles if not specified\n const adminRoles = props.adminRoles ?? props.roles;\n\n if (process.env.NODE_ENV !== \"production\") {\n // Validate userCollection has a slug\n if (!props.userCollection?.slug) {\n console.warn(\"[vex] defineAccess: userCollection must have a slug\");\n }\n\n // Validate orgCollection has a slug if provided\n if (props.orgCollection && !props.orgCollection.slug) {\n console.warn(\"[vex] defineAccess: orgCollection must have a slug\");\n }\n\n // Validate that permission resource slugs match resources (if resources provided)\n if (props.resources) {\n const resourceSlugs = new Set(\n props.resources.map((r: any) => r.slug),\n );\n for (const role of Object.keys(props.permissions)) {\n const rolePerms = props.permissions[role];\n if (!rolePerms) continue;\n for (const slug of Object.keys(rolePerms)) {\n // \"admin\" is a built-in permission key for admin panel access, not a resource\n if (slug === \"admin\") continue;\n if (!resourceSlugs.has(slug)) {\n console.warn(\n `[vex] defineAccess: permission resource \"${slug}\" not found in resources`,\n );\n }\n }\n }\n }\n\n // Validate that permission role keys match roles array\n const rolesSet = new Set(props.roles);\n for (const role of Object.keys(props.permissions)) {\n if (!rolesSet.has(role)) {\n console.warn(\n `[vex] defineAccess: permission role \"${role}\" not in roles array`,\n );\n }\n }\n\n // Validate adminRoles are a subset of roles\n if (props.adminRoles) {\n const rolesSetForAdmin = new Set(props.roles);\n for (const adminRole of props.adminRoles) {\n if (!rolesSetForAdmin.has(adminRole)) {\n console.warn(\n `[vex] defineAccess: adminRole \"${adminRole}\" not found in roles array`,\n );\n }\n }\n }\n\n // Validate userOrgField exists in user collection fields\n if (props.userOrgField && props.userCollection?.fields) {\n if (!(props.userOrgField in props.userCollection.fields)) {\n console.warn(\n `[vex] defineAccess: userOrgField \"${props.userOrgField}\" not found in user collection fields`,\n );\n }\n }\n }\n\n return {\n roles: props.roles,\n adminRoles,\n userCollection: props.userCollection.slug,\n orgCollection: props.orgCollection?.slug,\n userOrgField: props.userOrgField,\n permissions: props.permissions,\n };\n}\n","import type { AccessAction, VexAccessConfig, PermissionCheck, FieldPermissionResult } from \"./types\";\nimport { VexAccessError } from \"../errors\";\n\n/**\n * The result of resolving field permissions for a resource action.\n * Maps each field key to whether the action is allowed on that field.\n */\nexport type ResolvedFieldPermissions = Record<string, boolean>;\n\n/**\n * Resolve a permission check value (boolean, mode object, or function)\n * into a result for the requested fields.\n *\n * When `fields` is provided, returns a `Record<field, boolean>` for those fields.\n * When `fields` is omitted, returns a single `boolean` for overall action access.\n *\n * @param props.check - The permission check value to resolve\n * @param props.fields - Specific fields to check. When omitted, returns overall boolean.\n * @param props.data - The document data (for dynamic checks)\n * @param props.user - The user object (for dynamic checks)\n * @param props.organization - Optional organization object (for dynamic checks)\n * @returns Field permission map when fields provided, boolean when omitted\n */\nexport function resolvePermissionCheck(props: {\n check: PermissionCheck<string, any, any, any> | undefined;\n fields?: string[];\n data: Record<string, any>;\n user: Record<string, any>;\n organization?: Record<string, any>;\n}): ResolvedFieldPermissions | boolean {\n // Permissive default for missing actions\n if (props.check === undefined) {\n if (props.fields === undefined || props.fields.length === 0) return true;\n return Object.fromEntries(props.fields.map((k) => [k, true]));\n }\n\n // Resolve function checks\n let resolved: FieldPermissionResult<string>;\n if (typeof props.check === \"function\") {\n const callbackProps: any = props.organization !== undefined\n ? { data: props.data, user: props.user, organization: props.organization }\n : { data: props.data, user: props.user };\n resolved = props.check(callbackProps);\n } else {\n resolved = props.check;\n }\n\n // Handle undefined function return as deny-all\n if (resolved === undefined) {\n if (props.fields === undefined) return false;\n return Object.fromEntries(props.fields.map((k) => [k, false]));\n }\n\n // Boolean result\n if (typeof resolved === \"boolean\") {\n if (props.fields === undefined) return resolved;\n return Object.fromEntries(props.fields.map((k) => [k, resolved as boolean]));\n }\n\n // Mode object result — need fields to check against\n if (props.fields === undefined) {\n // No specific fields requested — for mode objects, we can't give a single boolean\n // without knowing what fields exist. Default to true (allow mode with fields means\n // \"some fields allowed\", deny mode with fields means \"some fields denied\").\n // Callers wanting field-level granularity must pass fields.\n if (resolved.mode === \"allow\") return resolved.fields.length > 0;\n if (resolved.mode === \"deny\") return resolved.fields.length === 0;\n return true;\n }\n\n if (resolved.mode === \"allow\") {\n const allowSet = new Set(resolved.fields);\n return Object.fromEntries(\n props.fields.map((k) => [k, allowSet.has(k)]),\n );\n }\n\n // mode === \"deny\"\n const denySet = new Set(resolved.fields);\n return Object.fromEntries(\n props.fields.map((k) => [k, !denySet.has(k)]),\n );\n}\n\n/**\n * Merge field permission maps from multiple roles using OR logic.\n * If any role grants access to a field, that field is allowed.\n * Allow always wins over deny in cross-role merges.\n *\n * When all entries are booleans (no fields mode), merges with OR logic on booleans.\n *\n * @param props.results - Array of resolved permission results (one per role)\n * @param props.fields - The specific fields being checked (when field-level)\n * @returns Merged result: Record<string, boolean> when fields provided, boolean otherwise\n */\nexport function mergeRolePermissions(props: {\n results: (ResolvedFieldPermissions | boolean)[];\n fields?: string[];\n}): ResolvedFieldPermissions | boolean {\n if (props.results.length === 0) {\n if (props.fields === undefined) return true;\n return Object.fromEntries(props.fields.map((k) => [k, true]));\n }\n\n // No fields — merge booleans with OR\n if (props.fields === undefined || props.fields.length === 0) {\n return props.results.some((r) =>\n typeof r === \"boolean\" ? r : Object.values(r).some(Boolean),\n );\n }\n\n // With fields — merge field maps with OR\n return Object.fromEntries(\n props.fields.map((k) => [\n k,\n props.results.some((r) =>\n typeof r === \"boolean\" ? r : (r[k] === true),\n ),\n ]),\n );\n}\n\n/**\n * Check permissions for a user on a resource action.\n *\n * Without `fields` param → returns `boolean` (overall action access)\n * With `fields` param → returns `Record<string, boolean>` for those specific fields\n *\n * @param props.access - The VexAccessConfig from defineAccess\n * @param props.user - The user object\n * @param props.userRoles - The user's role(s) as a string array\n * @param props.resource - The resource slug (collection or global slug)\n * @param props.action - The CRUD action to check\n * @param props.data - Document data for dynamic permission checks. Defaults to `{}`.\n * @param props.organization - Optional organization object for org-aware permission checks.\n * @param props.fields - Specific fields to check. When provided, returns Record<string, boolean>.\n * @param props.throwOnDenied - When true, throws VexAccessError instead of returning false. Default: false.\n * @returns `boolean` when fields is omitted, `Record<string, boolean>` when fields is provided\n * @throws {VexAccessError} When `throwOnDenied` is true and access is denied\n */\nexport function hasPermission(props: {\n access: VexAccessConfig | undefined;\n user: Record<string, any>;\n userRoles: string[];\n resource: string;\n action: AccessAction;\n data?: Record<string, any>;\n organization?: Record<string, any>;\n fields?: string[];\n throwOnDenied?: boolean;\n}): ResolvedFieldPermissions | boolean {\n // Permissive default when no access config\n if (props.access === undefined) {\n if (props.fields === undefined) return true;\n return Object.fromEntries(props.fields.map((k) => [k, true]));\n }\n\n // Deny all when no roles\n if (props.userRoles.length === 0) {\n if (props.throwOnDenied) {\n throw new VexAccessError(props.resource, props.action);\n }\n if (props.fields === undefined) return false;\n return Object.fromEntries(props.fields.map((k) => [k, false]));\n }\n\n // Filter to only known roles\n const knownRolesSet = new Set(props.access.roles);\n const knownRoles = props.userRoles.filter((r) => knownRolesSet.has(r));\n\n // All roles unknown → deny all\n if (knownRoles.length === 0) {\n if (props.throwOnDenied) {\n throw new VexAccessError(props.resource, props.action);\n }\n if (props.fields === undefined) return false;\n return Object.fromEntries(props.fields.map((k) => [k, false]));\n }\n\n // Resolve permissions for each known role\n const results: (ResolvedFieldPermissions | boolean)[] = [];\n const data = props.data ?? {};\n\n for (const role of knownRoles) {\n const rolePerms = props.access.permissions[role];\n if (rolePerms === undefined) {\n // Role has no permissions object → skip (contributes nothing)\n continue;\n }\n\n const resourcePerms = rolePerms[props.resource];\n if (resourcePerms === undefined) {\n // Role has no entry for this resource → permissive default\n results.push(true);\n continue;\n }\n\n // Boolean shorthand at resource level: true = all actions allowed, false = all denied\n if (typeof resourcePerms === \"boolean\") {\n results.push(resourcePerms);\n continue;\n }\n\n const actionCheck = resourcePerms[props.action];\n results.push(\n resolvePermissionCheck({\n check: actionCheck,\n fields: props.fields,\n data,\n user: props.user,\n organization: props.organization,\n }),\n );\n }\n\n // Merge all role results with OR logic\n const merged = mergeRolePermissions({\n results,\n fields: props.fields,\n });\n\n // Handle throwOnDenied\n if (props.throwOnDenied) {\n if (typeof merged === \"boolean\") {\n if (!merged) {\n throw new VexAccessError(props.resource, props.action);\n }\n } else {\n const deniedField = Object.entries(merged).find(([, v]) => v === false);\n if (deniedField) {\n throw new VexAccessError(props.resource, props.action, deniedField[0]);\n }\n }\n }\n\n return merged;\n}\n","import type { VexAccessConfig } from \"./types\";\n\n/**\n * Check whether a user has access to the admin panel.\n *\n * Evaluates the `admin` permission on each of the user's roles.\n * If any role has `admin: true` (or a callback that returns true),\n * the user is granted access. Returns false if no role grants access\n * or if the access config is not defined.\n *\n * @param props.access - The VexAccessConfig from defineAccess\n * @param props.user - The user object (passed to dynamic permission callbacks)\n * @param props.userRoles - The user's role(s) as a string array\n * @param props.organization - Optional organization object (passed to callbacks if org support is configured)\n * @returns Whether the user can access the admin panel\n */\nexport function checkAdminAccess(props: {\n access: VexAccessConfig | undefined;\n user: Record<string, any>;\n userRoles: string[];\n organization?: Record<string, any>;\n}): boolean {\n // No access config — deny by default (admin should be explicitly granted)\n if (props.access === undefined) {\n return false;\n }\n\n // No roles — deny\n if (props.userRoles.length === 0) {\n return false;\n }\n\n const knownRolesSet = new Set(props.access.roles);\n\n for (const role of props.userRoles) {\n if (!knownRolesSet.has(role)) continue;\n\n const rolePerms = props.access.permissions[role];\n if (rolePerms === undefined) continue;\n\n const adminPerm = (rolePerms as Record<string, unknown>).admin;\n\n // Not specified — defaults to false\n if (adminPerm === undefined) continue;\n\n // Static boolean\n if (typeof adminPerm === \"boolean\") {\n if (adminPerm) return true;\n continue;\n }\n\n // Dynamic callback\n if (typeof adminPerm === \"function\") {\n const callbackProps: any = props.organization !== undefined\n ? { user: props.user, organization: props.organization }\n : { user: props.user };\n if (adminPerm(callbackProps)) return true;\n }\n }\n\n return false;\n}\n","/**\n * Framework-agnostic site metadata object.\n * Consumers (Next.js, TanStack Start, etc.) map this to their framework's metadata format.\n */\nexport interface SiteMetadata {\n title: string;\n description: string;\n ogImage?: string;\n twitterHandle?: string;\n}\n\n/**\n * Build site metadata by merging site-wide defaults with per-page overrides.\n *\n * Resolution order (per-page wins over site-wide):\n * - title: page.metaTitle → page.title → site.metaTitle → site.name → \"Untitled\"\n * - description: page.metaDescription → site.metaDescription → site.description → \"\"\n * - ogImage: page.ogImage → site.ogImage → undefined\n * - twitterHandle: site.twitterHandle → undefined\n *\n * @param props.site - Site settings fields (from globals)\n * @param props.page - Optional per-page overrides\n * @param props.titleSuffix - Optional suffix appended to title (e.g. \" | My Site\")\n * @returns Framework-agnostic metadata object\n */\nexport function buildSiteMetadata(props: {\n site: {\n name?: string;\n metaTitle?: string;\n metaDescription?: string;\n description?: string;\n ogImage?: string;\n twitterHandle?: string;\n };\n page?: {\n title?: string;\n metaTitle?: string;\n metaDescription?: string;\n ogImage?: string;\n };\n titleSuffix?: string;\n}): SiteMetadata {\n const title =\n props.page?.metaTitle ||\n props.page?.title ||\n props.site.metaTitle ||\n props.site.name ||\n \"Untitled\";\n\n const description =\n props.page?.metaDescription ||\n props.site.metaDescription ||\n props.site.description ||\n \"\";\n\n const ogImage = props.page?.ogImage || props.site.ogImage || undefined;\n\n const twitterHandle = props.site.twitterHandle || undefined;\n\n // Append title suffix if provided, unless:\n // - The title already ends with the suffix\n // - The title equals the site name (avoids \"My Site | My Site\" on home page)\n let finalTitle = title;\n if (\n props.titleSuffix &&\n !title.endsWith(props.titleSuffix) &&\n title !== props.site.name\n ) {\n finalTitle = title + props.titleSuffix;\n }\n\n return {\n title: finalTitle,\n description,\n ogImage,\n twitterHandle,\n };\n}\n","import type { VexConfig, ClientVexConfig } from \"../types\";\n\n/**\n * Strip non-serializable values from VexConfig for safe passage across\n * RSC / JSON serialization boundaries (e.g., server layout → client component).\n *\n * Currently strips:\n * - `media.storageAdapter` (contains async functions — only needed at CLI / schema-gen time)\n * - `admin.livePreview.url` function values on collections (replaced with `null`)\n *\n * This function is the single place to extend when new non-serializable\n * properties are added to VexConfig in the future.\n */\nexport function sanitizeConfigForClient(config: VexConfig): ClientVexConfig {\n const { media, access: _access, ...rest } = config;\n\n return {\n ...rest,\n collections: rest.collections.map((collection) => {\n if (!collection.admin?.livePreview) return collection;\n if (typeof collection.admin.livePreview.url === \"string\") return collection;\n\n // Strip function URL — replaced with null for RSC serialization.\n // The admin panel resolves function URLs at runtime via livePreviewConfigs prop.\n return {\n ...collection,\n admin: {\n ...collection.admin,\n livePreview: {\n ...collection.admin.livePreview,\n url: null as any,\n },\n },\n };\n }),\n media: media\n ? { collections: media.collections }\n : undefined,\n };\n}\n\n/**\n * Extracts a map of collection slug → original livePreview URL function for collections\n * that have function-based preview URLs. Pass this to admin components so they\n * can resolve preview URLs at runtime on the client.\n *\n * @returns Map of collection slug → { url } (only entries with function URLs)\n */\nexport function extractLivePreviewConfigs(config: VexConfig): Record<string, { url: (doc: { _id: string; [key: string]: any }) => string }> {\n const result: Record<string, { url: (doc: { _id: string; [key: string]: any }) => string }> = {};\n\n for (const collection of config.collections) {\n if (collection.admin?.livePreview && typeof collection.admin.livePreview.url === \"function\") {\n result[collection.slug] = { url: collection.admin.livePreview.url };\n }\n }\n\n return result;\n}\n","interface HasSlug {\n readonly slug: string;\n}\n\ninterface ConfigWithMedia {\n media?: {\n collections: HasSlug[];\n };\n}\n\n/**\n * Check whether a collection is a media collection.\n *\n * Compares the collection's slug against the slugs in `config.media.collections`.\n * Works with both `VexConfig` and `ClientVexConfig` (both have the `media?.collections` shape).\n *\n * @param props.collection - The collection to check\n * @param props.config - The Vex config (or client config) containing media configuration\n * @returns true if the collection's slug matches a media collection slug\n */\nexport function isMediaCollection(props: {\n collection: HasSlug;\n config: ConfigWithMedia;\n}): boolean {\n if (!props.config.media?.collections) return false;\n return props.config.media.collections.some(\n (mc) => mc.slug === props.collection.slug,\n );\n}\n","import type { VexField } from \"../types/fields\";\n\ninterface HasSlugAndFields {\n readonly slug: string;\n fields: Record<string, VexField>;\n}\n\ninterface ConfigShape {\n collections: HasSlugAndFields[];\n globals: HasSlugAndFields[];\n media?: {\n collections: HasSlugAndFields[];\n };\n}\n\nexport type CollectionKind = \"collection\" | \"media\" | \"global\";\n\nexport interface ResolvedCollectionMatch {\n slug: string;\n fields: Record<string, VexField>;\n kind: CollectionKind;\n}\n\n/**\n * Get all collections, media collections, and globals as a flat array.\n *\n * Each entry includes the `kind` discriminator so callers can switch on it.\n *\n * @param props.config - The resolved Vex config\n * @param props.excludeGlobals - Skip globals (default: false)\n */\nexport function getAllCollections(props: {\n config: ConfigShape;\n excludeGlobals?: boolean;\n}): ResolvedCollectionMatch[] {\n const { config, excludeGlobals = false } = props;\n const result: ResolvedCollectionMatch[] = [];\n\n for (const c of config.collections) {\n result.push({ slug: c.slug, fields: c.fields, kind: \"collection\" });\n }\n\n if (config.media?.collections) {\n for (const c of config.media.collections) {\n result.push({ slug: c.slug, fields: c.fields, kind: \"media\" });\n }\n }\n\n if (!excludeGlobals) {\n for (const g of config.globals) {\n result.push({ slug: g.slug, fields: g.fields, kind: \"global\" });\n }\n }\n\n return result;\n}\n\n/**\n * Find a collection, media collection, or global by slug across the entire config.\n *\n * Searches in order: collections → media collections → globals.\n * Returns the match with its fields and what kind it is, or null if not found.\n *\n * @param props.slug - The slug to search for\n * @param props.config - The resolved Vex config\n * @param props.excludeGlobals - Skip globals when searching (default: false)\n */\nexport function findCollectionBySlug(props: {\n slug: string;\n config: ConfigShape;\n excludeGlobals?: boolean;\n}): ResolvedCollectionMatch | null {\n return getAllCollections(props).find((c) => c.slug === props.slug) ?? null;\n}\n","import type { CheckboxFieldDef } from \"../../types\";\n\nexport function checkbox(options?: Omit<CheckboxFieldDef, \"type\">): CheckboxFieldDef {\n return {\n type: \"checkbox\",\n ...(options?.required && options?.defaultValue === undefined\n ? { defaultValue: false }\n : {}),\n ...options,\n };\n}\n","const MINOR_WORDS = new Set([\n \"a\",\n \"an\",\n \"and\",\n \"as\",\n // \"at\",\n \"but\",\n \"by\",\n \"for\",\n \"if\",\n \"in\",\n \"nor\",\n \"of\",\n \"on\",\n \"or\",\n \"so\",\n \"the\",\n \"to\",\n \"up\",\n \"yet\",\n]);\n\nexport function toTitleCase(input: string): string {\n const words = input\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .replace(/[_-]+/g, \" \")\n .trim()\n .split(/\\s+/);\n\n return words\n .map((word, i) => {\n const lower = word.toLowerCase();\n if (i > 0 && MINOR_WORDS.has(lower)) return lower;\n return lower.charAt(0).toUpperCase() + lower.slice(1);\n })\n .join(\" \");\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { CheckboxFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a checkbox (boolean) field.\n *\n * @param props.fieldKey - The field name (used as accessorKey)\n * @param props.field - The checkbox field definition\n * @returns A ColumnDef for the checkbox field\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: render \"Yes\" / \"No\" (React rendering with icons is handled by UI layer)\n */\nexport function checkboxColumnDef(props: {\n fieldKey: string;\n field: CheckboxFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n };\n}\n","import { VexFieldValidationError } from \"../errors\";\n\n/**\n * Validates a field's configuration and determines if it should be optional.\n * Called by each per-field valueType function before generating the valueType string.\n *\n * Checks:\n * 1. If required=true and defaultValue is undefined → throw VexFieldValidationError\n * 2. If defaultValue is provided, verify it matches the expected type → throw VexFieldValidationError\n *\n * @param props.field - The field to validate (only needs required and defaultValue)\n * @param props.collectionSlug - The collection slug (for error messages)\n * @param props.fieldName - The field name (for error messages)\n * @param props.expectedType - The expected typeof for defaultValue (e.g., \"string\", \"number\", \"boolean\")\n * @param props.valueType - The Convex value type string (e.g., \"v.string()\")\n * @param props.skipDefaultValidation - Skip defaultValue presence and type checks.\n */\nexport function processFieldValueTypeOptions(props: {\n field: { required?: boolean; defaultValue?: unknown };\n collectionSlug: string;\n fieldName: string;\n expectedType: string;\n valueType: string;\n skipDefaultValidation?: boolean;\n}): string {\n if (!props.field.required) {\n return `v.optional(${props.valueType})`;\n }\n\n if (!props.skipDefaultValidation) {\n if (props.field.defaultValue === undefined) {\n throw new VexFieldValidationError(\n props.collectionSlug,\n props.fieldName,\n \"No defaultValue Provided\",\n );\n }\n if (!(typeof props.field.defaultValue === props.expectedType)) {\n throw new VexFieldValidationError(\n props.collectionSlug,\n props.fieldName,\n `Invalid defaultValue Provided. Expected: ${props.expectedType}, Received: ${typeof props.field.defaultValue}`,\n );\n }\n }\n\n return props.valueType;\n}\n","export const TEXT_VALUETYPE = \"v.string()\" as const;\nexport const NUMBER_VALUETYPE = \"v.number()\" as const;\nexport const CHECKBOX_VALUETYPE = \"v.boolean()\" as const;\nexport const DATE_VALUETYPE = \"v.number()\" as const;\nexport const IMAGEURL_VALUETYPE = \"v.string()\" as const;\nexport const JSON_VALUETYPE = \"v.any()\" as const;\nexport const RICHTEXT_VALUETYPE = \"v.any()\" as const;\n\nexport type { Alignment } from \"../types/fields\";\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { CheckboxFieldDef } from \"../../types\";\nimport { CHECKBOX_VALUETYPE } from \"../constants\";\n\n/**\n * Converts checkbox field definition to a Convex value type string.\n *\n * @returns `\"v.boolean()\"` or `\"v.optional(v.boolean())\"`\n */\nexport function checkboxToValueTypeString(props: {\n field: CheckboxFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"boolean\",\n valueType: CHECKBOX_VALUETYPE,\n });\n}\n","import type { NumberFieldDef } from \"../../types\";\n\nexport function number(options?: Omit<NumberFieldDef, \"type\">): NumberFieldDef {\n return {\n type: \"number\",\n ...(options?.required && options?.defaultValue === undefined\n ? { defaultValue: 0 }\n : {}),\n ...options,\n };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { NumberFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a number field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: render the number directly\n */\nexport function numberColumnDef(props: {\n fieldKey: string;\n field: NumberFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"right\" },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { NumberFieldDef } from \"../../types\";\nimport { NUMBER_VALUETYPE } from \"../constants\";\n\n/**\n * Converts number field definition to a Convex value type string.\n *\n * @returns `\"v.number()\"` or `\"v.optional(v.number())\"`\n */\nexport function numberToValueTypeString(props: {\n field: NumberFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"number\",\n valueType: NUMBER_VALUETYPE,\n });\n}\n","import type { SelectFieldDef, SelectFieldSingle, SelectFieldMany } from \"../../types\";\n\nexport function select<T extends string = string>(\n options: Omit<SelectFieldMany<T>, \"type\">,\n): SelectFieldDef<T>;\nexport function select<T extends string = string>(\n options: Omit<SelectFieldSingle<T>, \"type\">,\n): SelectFieldDef<T>;\nexport function select<T extends string = string>(\n options: Omit<SelectFieldSingle<T>, \"type\"> | Omit<SelectFieldMany<T>, \"type\">,\n): SelectFieldDef<T> {\n return { type: \"select\", ...options } as SelectFieldDef<T>;\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { SelectFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Default hex colors rotated through when options don't specify a `badgeColor`.\n */\nconst DEFAULT_BADGE_COLORS = [\n \"#3b82f6\", // blue\n \"#22c55e\", // green\n \"#a855f7\", // purple\n \"#f59e0b\", // amber\n \"#f43f5e\", // rose\n \"#06b6d4\", // cyan\n \"#6366f1\", // indigo\n \"#14b8a6\", // teal\n \"#f97316\", // orange\n \"#d946ef\", // fuchsia\n] as const;\n\n/**\n * Builds a ColumnDef for a select field.\n *\n * @param props.fieldKey - The field name (used as accessorKey)\n * @param props.field - The select field definition (includes options for label lookup)\n * @returns A ColumnDef for the select field\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: renders option values as colored badges in a scrollable flex grid\n */\nexport function selectColumnDef(props: {\n fieldKey: string;\n field: SelectFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n const optionMap = new Map(\n props.field.options.map((opt, i) => [\n opt.value,\n {\n label: opt.label,\n color: opt.badgeColor ?? DEFAULT_BADGE_COLORS[i % DEFAULT_BADGE_COLORS.length],\n },\n ]),\n );\n\n return {\n accessorKey: props.fieldKey,\n header:\n (props.field.hasMany\n ? props.field.labels?.singular\n : props.field.label) ?? toTitleCase(props.fieldKey),\n meta: {\n align: props.field.admin?.cellAlignment ?? \"left\",\n noTruncate: true,\n },\n cell: (info) => {\n const raw = info.getValue();\n const values = Array.isArray(raw)\n ? (raw as string[])\n : raw != null\n ? [String(raw)]\n : [];\n\n if (values.length === 0) return null;\n\n return (\n <div className=\"flex flex-wrap gap-1 max-w-[240px] max-h-[60px] overflow-auto\">\n {values.map((v) => {\n const opt = optionMap.get(v);\n return (\n <span\n key={v}\n className=\"inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium text-white shrink-0\"\n style={{ backgroundColor: opt?.color }}\n >\n {opt?.label ?? v}\n </span>\n );\n })}\n </div>\n );\n },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { SelectFieldDef } from \"../../types\";\n\n/**\n * Converts select field definition to a Convex value type string.\n *\n * @returns One of (each may be wrapped in v.optional()):\n * - Single select: `'v.union(v.literal(\"draft\"),v.literal(\"published\"))'`\n * - Multi select (hasMany): `'v.array(v.union(v.literal(\"draft\"),v.literal(\"published\")))'`\n */\nexport function selectToValueTypeString(props: {\n field: SelectFieldDef<string>;\n collectionSlug: string;\n fieldName: string;\n}): string {\n const literals = props.field.options.map((o) => `v.literal(\"${o.value}\")`).join(\",\");\n\n if (props.field.hasMany) {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: props.field.options.length === 1\n ? `v.array(${literals})`\n : `v.array(v.union(${literals}))`,\n skipDefaultValidation: true,\n });\n }\n\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"string\",\n valueType: `v.union(${literals})`,\n });\n}\n","import type { TextFieldDef } from \"../../types\";\n\nexport function text(options?: Omit<TextFieldDef, \"type\">): TextFieldDef {\n return {\n type: \"text\",\n ...(options?.required && options?.defaultValue === undefined\n ? { defaultValue: \"\" }\n : {}),\n ...options,\n };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { TextFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a text field.\n *\n * @param props.fieldKey - The field name (used as accessorKey)\n * @param props.field - The text field definition\n * @returns A ColumnDef for the text field\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? props.fieldKey (capitalize first letter of fieldKey as fallback)\n * - cell: render the value as a string, truncated to 80 characters with ellipsis if longer\n */\nexport function textColumnDef(props: {\n fieldKey: string;\n field: TextFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { TextFieldDef } from \"../../types\";\nimport { TEXT_VALUETYPE } from \"../constants\";\n\n/**\n * Converts text field definition to a Convex value type string.\n *\n * @returns `\"v.string()\"` or `\"v.optional(v.string())\"`\n *\n * minLength/maxLength are runtime validation concerns, not schema constraints.\n * The index property has no effect on the value type (handled by collectIndexes).\n */\nexport function textToValueTypeString(props: {\n field: TextFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"string\",\n valueType: TEXT_VALUETYPE,\n });\n}\n","import type { DateFieldDef } from \"../../types\";\n\nexport function date(options?: Omit<DateFieldDef, \"type\">): DateFieldDef {\n return {\n type: \"date\",\n ...(options?.required && options?.defaultValue === undefined\n ? { defaultValue: 0 }\n : {}),\n ...options,\n };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { DateFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a date field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: formats epoch ms as a human-readable date string\n */\nexport function dateColumnDef(props: {\n fieldKey: string;\n field: DateFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: {\n align: props.field.admin?.cellAlignment ?? \"left\",\n },\n cell: (info) => {\n const value = info.getValue();\n if (value == null) return \"\";\n return new Date(value as number).toLocaleDateString();\n },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { DateFieldDef } from \"../../types\";\nimport { DATE_VALUETYPE } from \"../constants\";\n\n/**\n * Converts date field definition to a Convex value type string.\n *\n * @returns `\"v.number()\"` or `\"v.optional(v.number())\"`\n *\n * Dates are stored as epoch milliseconds (number).\n */\nexport function dateToValueTypeString(props: {\n field: DateFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"number\",\n valueType: DATE_VALUETYPE,\n });\n}\n","import type { ImageUrlFieldDef } from \"../../types\";\n\nexport function imageUrl(options?: Omit<ImageUrlFieldDef, \"type\">): ImageUrlFieldDef {\n return {\n type: \"imageUrl\",\n ...(options?.required && options?.defaultValue === undefined\n ? { defaultValue: \"\" }\n : {}),\n ...options,\n };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { ImageUrlFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for an imageUrl field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: renders an <img> thumbnail with fallback on error\n */\nexport function imageUrlColumnDef(props: {\n fieldKey: string;\n field: ImageUrlFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"center\" },\n cell: (info) => {\n const value = info.getValue();\n if (!value || typeof value !== \"string\") return \"\";\n const size = props.field.width ?? 28;\n const height = props.field.height ?? size;\n return (\n <img\n src={value}\n alt=\"\"\n width={size}\n height={height}\n className=\"rounded-full object-cover bg-muted\"\n style={{ width: size, height }}\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n onError={(e) => {\n (e.currentTarget as any).style.display = \"none\";\n }}\n />\n );\n },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { ImageUrlFieldDef } from \"../../types\";\nimport { IMAGEURL_VALUETYPE } from \"../constants\";\n\n/**\n * Converts imageUrl field definition to a Convex value type string.\n *\n * @returns `\"v.string()\"` or `\"v.optional(v.string())\"`\n *\n * Image URLs are stored as strings, same schema as text.\n */\nexport function imageUrlToValueTypeString(props: {\n field: ImageUrlFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"string\",\n valueType: IMAGEURL_VALUETYPE,\n });\n}\n","import type { RelationshipFieldDef, RelationshipFieldSingle, RelationshipFieldMany } from \"../../types\";\n\nexport function relationship(\n options: Omit<RelationshipFieldMany, \"type\">,\n): RelationshipFieldDef;\nexport function relationship(\n options: Omit<RelationshipFieldSingle, \"type\">,\n): RelationshipFieldDef;\nexport function relationship(\n options: Omit<RelationshipFieldSingle, \"type\"> | Omit<RelationshipFieldMany, \"type\">,\n): RelationshipFieldDef {\n return { type: \"relationship\", ...options } as RelationshipFieldDef;\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { RelationshipFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a relationship field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - meta: includes relationship info (type, to) for DataTable to fetch related docs\n * - cell: shows raw ID (DataTable component resolves to useAsTitle at render time)\n */\nexport function relationshipColumnDef(props: {\n fieldKey: string;\n field: RelationshipFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: (props.field.hasMany ? props.field.labels?.singular : props.field.label) ?? toTitleCase(props.fieldKey),\n meta: { type: \"relationship\", to: props.field.to, align: props.field.admin?.cellAlignment ?? \"left\" },\n cell: (info) => {\n const value = info.getValue();\n if (value == null) return \"\";\n if (Array.isArray(value)) return `${value.length} item${value.length === 1 ? \"\" : \"s\"}`;\n return String(value);\n },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { RelationshipFieldDef } from \"../../types\";\n\n/**\n * Converts relationship field definition to a Convex value type string.\n *\n * @returns\n * - hasMany + required: `v.array(v.id(\"tableName\"))`\n * - hasMany + !required: `v.optional(v.array(v.id(\"tableName\")))`\n * - !hasMany + required: `v.id(\"tableName\")`\n * - !hasMany + !required: `v.optional(v.id(\"tableName\"))`\n */\nexport function relationshipToValueTypeString(props: {\n field: RelationshipFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n const idType = `v.id(\"${props.field.to}\")`;\n const baseValueType = props.field.hasMany ? `v.array(${idType})` : idType;\n\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"string\",\n valueType: baseValueType,\n skipDefaultValidation: true,\n });\n}\n","import type { JsonFieldDef } from \"../../types\";\n\nexport function json(options?: Omit<JsonFieldDef, \"type\">): JsonFieldDef {\n return {\n type: \"json\",\n ...options,\n };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { JsonFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a json field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: shows truncated JSON preview\n */\nexport function jsonColumnDef(props: {\n fieldKey: string;\n field: JsonFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n cell: (info) => {\n const value = info.getValue();\n if (value == null) return \"\";\n const str = JSON.stringify(value);\n return str.length > 50 ? str.slice(0, 50) + \"...\" : str;\n },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { JsonFieldDef } from \"../../types\";\nimport { JSON_VALUETYPE } from \"../constants\";\n\n/**\n * Converts json field definition to a Convex value type string.\n *\n * @returns\n * - required: `\"v.any()\"`\n * - !required: `\"v.optional(v.any())\"`\n */\nexport function jsonToValueTypeString(props: {\n field: JsonFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: JSON_VALUETYPE,\n skipDefaultValidation: true,\n });\n}\n","import type { ObjectFieldDef } from \"../../types\";\n\nexport function object(options: Omit<ObjectFieldDef, \"type\">): ObjectFieldDef {\n return { type: \"object\", ...options };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { ObjectFieldDef, VexField } from \"../../types\";\n\n/**\n * Converts an object field definition to a Convex value type string.\n *\n * Generates multi-line `v.object({...})` by resolving each sub-field's value type.\n * Each field is placed on its own line to avoid prettier reformatting issues.\n */\nexport function objectToValueTypeString(props: {\n field: ObjectFieldDef;\n collectionSlug: string;\n fieldName: string;\n resolveInnerField: (props: {\n field: VexField;\n collectionSlug: string;\n fieldName: string;\n visitedBlockSlugs?: Set<string>;\n }) => string;\n}): string {\n const fieldEntries: string[] = [];\n\n for (const [subFieldName, subField] of Object.entries(props.field.fields)) {\n const valueType = props.resolveInnerField({\n field: subField as VexField,\n collectionSlug: props.collectionSlug,\n fieldName: `${props.fieldName}.${subFieldName}`,\n });\n fieldEntries.push(`${subFieldName}: ${valueType}`);\n }\n\n const objectType = fieldEntries.length <= 2\n ? `v.object({ ${fieldEntries.join(\", \")} })`\n : `v.object({\\n${fieldEntries.map((e) => ` ${e},`).join(\"\\n\")}\\n})`;\n\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: objectType,\n skipDefaultValidation: true,\n });\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { ObjectFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for an object field.\n * Shows a truncated JSON preview in the table cell.\n */\nexport function objectColumnDef(props: {\n fieldKey: string;\n field: ObjectFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n cell: (info) => {\n const value = info.getValue();\n if (value == null) return \"\";\n const str = JSON.stringify(value);\n return str.length > 50 ? str.slice(0, 50) + \"...\" : str;\n },\n };\n}\n","import type { RichTextFieldDef } from \"../../types\";\n\n/**\n * Creates a rich text field definition.\n * Stores Plate/Slate JSON document as `v.any()` in Convex.\n *\n * @param options.label - Display label in admin form\n * @param options.required - Whether this field is required\n * @param options.editor - Per-field editor adapter override\n * @returns A RichTextFieldDef\n *\n * @example\n * ```ts\n * content: richtext({ label: \"Content\", required: true })\n * ```\n */\nexport function richtext(options?: Omit<RichTextFieldDef, \"type\">): RichTextFieldDef {\n return {\n type: \"richtext\",\n ...options,\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { RichTextFieldDef } from \"../../types\";\nimport { RICHTEXT_VALUETYPE } from \"../constants\";\n\n/**\n * Converts richtext field definition to a Convex value type string.\n *\n * @param props.field - The richtext field definition\n * @param props.collectionSlug - The collection this field belongs to\n * @param props.fieldName - The field key name\n * @returns\n * - required: `\"v.any()\"`\n * - !required: `\"v.optional(v.any())\"`\n */\nexport function richtextToValueTypeString(props: {\n field: RichTextFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: RICHTEXT_VALUETYPE,\n skipDefaultValidation: true,\n });\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { RichTextFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a richtext field.\n *\n * @param props.fieldKey - The field key name\n * @param props.field - The richtext field definition\n * @returns ColumnDef that shows \"Rich text\" or empty string in the data table\n */\nexport function richtextColumnDef(props: {\n fieldKey: string;\n field: RichTextFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n cell: (info) => {\n const value = info.getValue();\n if (value == null) return \"\";\n if (Array.isArray(value) && value.length === 0) return \"\";\n return \"Rich text\";\n },\n };\n}\n","import type { UploadFieldDef, UploadFieldSingle, UploadFieldMany } from \"../../types\";\n\nexport function upload(\n options: Omit<UploadFieldMany, \"type\">,\n): UploadFieldDef;\nexport function upload(\n options: Omit<UploadFieldSingle, \"type\">,\n): UploadFieldDef;\nexport function upload(\n options: Omit<UploadFieldSingle, \"type\"> | Omit<UploadFieldMany, \"type\">,\n): UploadFieldDef {\n return { type: \"upload\", ...options } as UploadFieldDef;\n}\n","import type { UploadFieldDef } from \"../../types\";\nimport { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\n\n/**\n * Converts upload field definition to a Convex value type string.\n *\n * @returns\n * - hasMany + required: `v.array(v.id(\"mediaCollectionSlug\"))`\n * - hasMany + !required: `v.optional(v.array(v.id(\"mediaCollectionSlug\")))`\n * - !hasMany + required: `v.id(\"mediaCollectionSlug\")`\n * - !hasMany + !required: `v.optional(v.id(\"mediaCollectionSlug\"))`\n */\nexport function uploadToValueTypeString(props: {\n field: UploadFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n const idType = `v.id(\"${props.field.to}\")`;\n const baseValueType = props.field.hasMany ? `v.array(${idType})` : idType;\n\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"string\",\n valueType: baseValueType,\n skipDefaultValidation: true,\n });\n}\n","import type { ArrayFieldDef } from \"../../types\";\n\nexport function array(options: Omit<ArrayFieldDef, \"type\">): ArrayFieldDef {\n return { type: \"array\", ...options };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { ArrayFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for an array field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: shows item count — \"no items\", \"1 item\", \"3 items\"\n */\nexport function arrayColumnDef(props: {\n fieldKey: string;\n field: ArrayFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n cell: (info) => {\n const value = info.getValue();\n if (!Array.isArray(value) || value.length === 0) return \"no items\";\n if (value.length === 1) return \"1 item\";\n return `${value.length} items`;\n },\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { ArrayFieldDef, VexField } from \"../../types\";\n\n/**\n * Converts array field definition to a Convex value type string.\n *\n * Uses callback injection to resolve the inner field type,\n * avoiding circular imports with fieldToValueType.\n *\n * @returns e.g. `\"v.array(v.string())\"` or `\"v.optional(v.array(v.string()))\"`\n */\nexport function arrayToValueTypeString(props: {\n field: ArrayFieldDef;\n collectionSlug: string;\n fieldName: string;\n resolveInnerField: (props: {\n field: VexField;\n collectionSlug: string;\n fieldName: string;\n }) => string;\n}): string {\n const innerValueType = props.resolveInnerField({\n field: props.field.items,\n collectionSlug: props.collectionSlug,\n fieldName: `${props.fieldName}[]`,\n });\n // Strip v.optional() from inner — array wrapping handles optionality\n // Use a function to find the matching closing paren for v.optional(\n let unwrapped = innerValueType;\n if (unwrapped.startsWith(\"v.optional(\")) {\n // Remove \"v.optional(\" prefix and matching \")\" suffix\n const inner = unwrapped.slice(\"v.optional(\".length);\n // Find the matching closing paren (last char should be \")\")\n if (inner.endsWith(\")\")) {\n unwrapped = inner.slice(0, -1);\n }\n }\n const arrayType = `v.array(${unwrapped})`;\n\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: arrayType,\n skipDefaultValidation: true,\n });\n}\n","import type { BlocksFieldDef, BlockDef } from \"../../types\";\nimport { VexBlockValidationError } from \"../../errors\";\n\n/**\n * Create a blocks field that stores an ordered array of block instances.\n *\n * @param props.blocks - Array of BlockDef objects allowed in this field\n * @param props.labels - Optional singular/plural display labels\n * @param props.min - Minimum number of blocks\n * @param props.max - Maximum number of blocks\n * @returns A BlocksFieldDef\n *\n * @throws VexBlockValidationError if two blocks share the same slug\n *\n * @example\n * ```ts\n * content: blocks({\n * blocks: [heroBlock, ctaBlock, featureGridBlock],\n * })\n * ```\n */\nexport function blocks(props: {\n blocks: BlockDef[];\n labels?: BlocksFieldDef[\"labels\"];\n min?: number;\n max?: number;\n label?: string;\n description?: string;\n required?: boolean;\n admin?: BlocksFieldDef[\"admin\"];\n}): BlocksFieldDef {\n const seen = new Set<string>();\n for (const block of props.blocks) {\n if (seen.has(block.slug)) {\n throw new VexBlockValidationError(\n block.slug,\n `Duplicate block slug \"${block.slug}\" in blocks field. Each block in a blocks() field must have a unique slug.`,\n );\n }\n seen.add(block.slug);\n }\n\n return {\n type: \"blocks\",\n blocks: props.blocks,\n labels: props.labels,\n min: props.min,\n max: props.max,\n label: props.label,\n description: props.description,\n required: props.required,\n admin: props.admin,\n };\n}\n","import { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\nimport type { BlocksFieldDef, VexField } from \"../../types\";\nimport { VexBlockValidationError } from \"../../errors\";\n\n/**\n * Converts a blocks field definition to a Convex value type string.\n *\n * Generates `v.array(v.union(v.object({...}), v.object({...})))` where each\n * v.object corresponds to a block type with `blockType: v.literal(\"slug\")`\n * as the discriminant, `_key: v.string()`, and each block field converted\n * to its Convex value type.\n *\n * @param props.field - The BlocksFieldDef\n * @param props.collectionSlug - Parent collection slug (for error messages)\n * @param props.fieldName - Field name on the parent collection (for error messages)\n * @param props.resolveInnerField - Callback to resolve inner field value types (avoids circular imports)\n * @param props.visitedBlockSlugs - Set of block slugs already being processed (cycle detection)\n * @returns Convex value type string, e.g. `\"v.array(v.union(v.object({...}), ...))\"`\n *\n * @throws VexBlockValidationError if a cycle is detected in nested blocks\n */\nexport function blocksToValueTypeString(props: {\n field: BlocksFieldDef;\n collectionSlug: string;\n fieldName: string;\n resolveInnerField: (props: {\n field: VexField;\n collectionSlug: string;\n fieldName: string;\n visitedBlockSlugs?: Set<string>;\n }) => string;\n visitedBlockSlugs?: Set<string>;\n}): string {\n const visited = props.visitedBlockSlugs ?? new Set<string>();\n\n if (props.field.blocks.length === 0) {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: \"v.array(v.any())\",\n skipDefaultValidation: true,\n });\n }\n\n const objectTypes: string[] = [];\n\n for (const block of props.field.blocks) {\n if (visited.has(block.slug)) {\n throw new VexBlockValidationError(\n block.slug,\n `Circular block reference detected: block \"${block.slug}\" references itself (directly or through a cycle).`,\n );\n }\n\n const blockVisited = new Set(visited);\n blockVisited.add(block.slug);\n\n const fieldEntries: string[] = [\n `blockType: v.literal(\"${block.slug}\")`,\n `blockName: v.optional(v.string())`,\n `blockStyles: v.optional(v.string())`,\n `_key: v.string()`,\n ];\n\n for (const [fieldName, field] of Object.entries(block.fields)) {\n const valueType = props.resolveInnerField({\n field: field as VexField,\n collectionSlug: props.collectionSlug,\n fieldName: `${props.fieldName}.${block.slug}.${fieldName}`,\n visitedBlockSlugs: blockVisited,\n });\n fieldEntries.push(`${fieldName}: ${valueType}`);\n }\n\n objectTypes.push(\n `v.object({\\n${fieldEntries.map((e) => ` ${e},`).join(\"\\n\")}\\n})`,\n );\n }\n\n const innerType =\n objectTypes.length === 1\n ? objectTypes[0]\n : `v.union(\\n${objectTypes.map((o) => ` ${o},`).join(\"\\n\")}\\n)`;\n\n const arrayType = `v.array(\\n${innerType}\\n)`;\n\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"object\",\n valueType: arrayType,\n skipDefaultValidation: true,\n });\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { BlocksFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for a blocks field.\n *\n * Behavior:\n * - accessorKey: props.fieldKey\n * - header: props.field.label ?? toTitleCase(props.fieldKey)\n * - cell: shows block count — \"no blocks\", \"1 block\", \"3 blocks\"\n * Uses field.labels if provided (e.g., \"1 section\", \"3 sections\").\n */\nexport function blocksColumnDef(props: {\n fieldKey: string;\n field: BlocksFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n const singular = props.field.labels?.singular ?? \"block\";\n const plural = props.field.labels?.plural ?? \"blocks\";\n\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? toTitleCase(props.fieldKey),\n meta: { align: props.field.admin?.cellAlignment ?? \"left\" },\n cell: (info) => {\n const value = info.getValue();\n if (!Array.isArray(value) || value.length === 0) return `no ${plural}`;\n if (value.length === 1) return `1 ${singular}`;\n return `${value.length} ${plural}`;\n },\n };\n}\n","import type { ColorFieldDef } from \"../../types/fields\";\n\n/**\n * Creates a color field definition.\n *\n * @param props - Color field configuration\n * @param props.label - Display label in admin panel\n * @param props.format - Output format: \"hex\" (default), \"hsl\", or \"oklch\"\n * @param props.themeColors - When true, shows theme CSS variable picker tab\n * @returns ColorFieldDef\n */\nexport function color(props?: Omit<ColorFieldDef, \"type\">): ColorFieldDef {\n return {\n ...props,\n type: \"color\" as const,\n };\n}\n","import type { ColorFieldDef } from \"../../types/fields\";\nimport { TEXT_VALUETYPE } from \"../constants\";\nimport { processFieldValueTypeOptions } from \"../../valueTypes/processAdminOptions\";\n\n/**\n * Convert a color field to its Convex schema value type string.\n * Color fields store strings (hex, hsl, or oklch) so they use v.string().\n */\nexport function colorToValueTypeString(props: {\n field: ColorFieldDef;\n collectionSlug: string;\n fieldName: string;\n}): string {\n return processFieldValueTypeOptions({\n field: props.field,\n collectionSlug: props.collectionSlug,\n fieldName: props.fieldName,\n expectedType: \"string\",\n valueType: TEXT_VALUETYPE,\n });\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { ColorFieldDef } from \"../../types/fields\";\n\n/**\n * Generate a column definition for a color field.\n * Shows the color value as text with a color swatch indicator.\n */\nexport function colorColumnDef(props: {\n fieldKey: string;\n field: ColorFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: props.field.label ?? props.fieldKey,\n size: 120,\n cell: (info) => {\n const value = info.getValue() as string | undefined;\n if (!value) return \"\";\n return value;\n },\n meta: {\n type: \"color\" as const,\n },\n };\n}\n","import { VexFieldValidationError } from \"../errors\";\nimport { checkboxToValueTypeString } from \"../fields/checkbox\";\nimport { numberToValueTypeString } from \"../fields/number\";\nimport { selectToValueTypeString } from \"../fields/select\";\nimport { textToValueTypeString } from \"../fields/text\";\nimport { dateToValueTypeString } from \"../fields/date\";\nimport { imageUrlToValueTypeString } from \"../fields/imageUrl\";\nimport { relationshipToValueTypeString } from \"../fields/relationship\";\nimport { jsonToValueTypeString } from \"../fields/json\";\nimport { objectToValueTypeString } from \"../fields/object\";\nimport { richtextToValueTypeString } from \"../fields/richtext\";\nimport { uploadToValueTypeString } from \"../fields/media\";\nimport { arrayToValueTypeString } from \"../fields/array\";\nimport { blocksToValueTypeString } from \"../fields/blocks\";\nimport { colorToValueTypeString } from \"../fields/color\";\nimport type { VexField } from \"../types\";\n\n/**\n * Converts a VexField to its Convex value type string representation.\n * Dispatches to the appropriate per-field function based on `type`.\n *\n * Each per-field function handles its own validation (via processFieldValueTypeOptions())\n * and its own v.optional() wrapping. This dispatcher just routes by type.\n */\nexport function fieldToValueType(props: {\n field: VexField;\n collectionSlug: string;\n fieldName: string;\n visitedBlockSlugs?: Set<string>;\n}): string {\n const { field, collectionSlug, fieldName } = props;\n switch (field.type) {\n case \"text\":\n return textToValueTypeString({ field, collectionSlug, fieldName });\n case \"number\":\n return numberToValueTypeString({ field, collectionSlug, fieldName });\n case \"checkbox\":\n return checkboxToValueTypeString({ field, collectionSlug, fieldName });\n case \"select\":\n return selectToValueTypeString({ field, collectionSlug, fieldName });\n case \"date\":\n return dateToValueTypeString({ field, collectionSlug, fieldName });\n case \"imageUrl\":\n return imageUrlToValueTypeString({ field, collectionSlug, fieldName });\n case \"relationship\":\n return relationshipToValueTypeString({ field, collectionSlug, fieldName });\n case \"upload\":\n return uploadToValueTypeString({ field, collectionSlug, fieldName });\n case \"json\":\n return jsonToValueTypeString({ field, collectionSlug, fieldName });\n case \"object\":\n return objectToValueTypeString({\n field,\n collectionSlug,\n fieldName,\n resolveInnerField: fieldToValueType,\n });\n case \"richtext\":\n return richtextToValueTypeString({ field, collectionSlug, fieldName });\n case \"array\":\n return arrayToValueTypeString({\n field,\n collectionSlug,\n fieldName,\n resolveInnerField: fieldToValueType,\n });\n case \"blocks\":\n return blocksToValueTypeString({\n field,\n collectionSlug,\n fieldName,\n resolveInnerField: (innerProps) =>\n fieldToValueType({\n field: innerProps.field,\n collectionSlug: innerProps.collectionSlug,\n fieldName: innerProps.fieldName,\n visitedBlockSlugs: innerProps.visitedBlockSlugs,\n }),\n visitedBlockSlugs: props.visitedBlockSlugs,\n });\n case \"color\":\n return colorToValueTypeString({ field, collectionSlug, fieldName });\n case \"tabs\":\n // Tabs are expanded by generate.ts's expandFields(), not here\n return \"v.any()\";\n case \"ui\":\n throw new VexFieldValidationError(\n collectionSlug,\n fieldName,\n `UI field \"${fieldName}\" on collection \"${collectionSlug}\" has no database representation and should not be included in schema generation.`,\n );\n default:\n throw new VexFieldValidationError(\n collectionSlug,\n fieldName,\n `Unknown Field Type: ${(field as any).type}`,\n );\n }\n}\n","import { VexFieldValidationError } from \"../errors\";\nimport type {\n VexCollection,\n VexField,\n ResolvedIndex,\n} from \"../types\";\n\n/**\n * Collects all indexes for a collection from three sources:\n * 1. Per-field `index` property on individual fields\n * 2. Collection-level `indexes` array on the collection\n * 3. Auto-generated index for `admin.useAsTitle` field (for fast admin panel title queries)\n *\n * @param collection - The collection to extract indexes from\n * @returns Array of resolved indexes, deduplicated by name\n */\nexport function collectIndexes(props: { collection: VexCollection }): ResolvedIndex[] {\n const { collection } = props;\n const fieldIndexes = new Map<string, ResolvedIndex>();\n\n for (const [fieldKey, field] of Object.entries(collection.fields) as [string, VexField][]) {\n const indexName = field.index;\n if (indexName) {\n if (fieldIndexes.has(indexName)) {\n throw new VexFieldValidationError(\n collection.slug,\n fieldKey,\n `Duplicate Indexes detected: ${indexName}`,\n );\n }\n fieldIndexes.set(indexName, { name: indexName, fields: [fieldKey] });\n }\n }\n\n collection.indexes?.forEach((index) => {\n fieldIndexes.set(index.name, { name: index.name, fields: index.fields });\n });\n\n const useAsTitle = collection.admin?.useAsTitle as string;\n if (useAsTitle && useAsTitle !== \"_id\") {\n const autoName = `by_${useAsTitle}`;\n if (!fieldIndexes.has(autoName)) {\n fieldIndexes.set(autoName, { name: autoName, fields: [useAsTitle] });\n }\n }\n\n return Array.from(fieldIndexes.values());\n}\n","import { VexFieldValidationError } from \"../errors\";\nimport type {\n VexCollection,\n VexField,\n ResolvedSearchIndex,\n} from \"../types\";\n\n/**\n * Collects all search indexes for a collection from three sources:\n * 1. Per-field `searchIndex` property on individual fields\n * 2. Collection-level `searchIndexes` array on the collection\n * 3. Auto-generated search index for `admin.useAsTitle` field\n *\n * @param collection - The collection to extract search indexes from\n * @returns Array of resolved search indexes, deduplicated by name\n */\nexport function collectSearchIndexes(props: { collection: VexCollection }): ResolvedSearchIndex[] {\n const { collection } = props;\n const searchIndexes = new Map<string, ResolvedSearchIndex>();\n\n for (const [fieldKey, field] of Object.entries(collection.fields) as [string, VexField][]) {\n const searchIndex = field.searchIndex;\n if (searchIndex && searchIndex.name) {\n if (searchIndexes.has(searchIndex.name)) {\n throw new VexFieldValidationError(\n collection.slug,\n fieldKey,\n `Duplicate search index name: ${searchIndex.name}`,\n );\n }\n searchIndexes.set(searchIndex.name, {\n name: searchIndex.name,\n searchField: fieldKey,\n filterFields: searchIndex.filterFields,\n });\n }\n }\n\n collection.searchIndexes?.forEach((entry) => {\n searchIndexes.set(entry.name, {\n name: entry.name,\n searchField: entry.searchField,\n filterFields: entry.filterFields ?? [],\n });\n });\n\n const useAsTitle = collection.admin?.useAsTitle as string;\n if (useAsTitle && useAsTitle !== \"_id\") {\n const autoName = `search_${useAsTitle}`;\n const alreadyCovered = Array.from(searchIndexes.values()).some(\n (si) => si.searchField === useAsTitle,\n );\n if (!alreadyCovered && !searchIndexes.has(autoName)) {\n searchIndexes.set(autoName, {\n name: autoName,\n searchField: useAsTitle,\n filterFields: [],\n });\n }\n }\n\n return Array.from(searchIndexes.values());\n}\n","import type { VexField } from \"../types\";\nimport type { VexCollection } from \"../types\";\nimport type { ResolvedIndex, ResolvedSearchIndex } from \"../types\";\n\n/**\n * Result of merging an auth collection with a user collection.\n * Contains merged VexFields and metadata about field sources.\n */\nexport interface MergedCollectionResult {\n /**\n * The final merged field map.\n * Key is field name, value is the VexField object.\n * Auth fields win for schema generation; user admin config is preserved.\n */\n fields: Record<string, VexField>;\n\n /** Indexes from both auth and user collections (deduplicated by name). */\n indexes: ResolvedIndex[];\n\n /** Search indexes from the user collection. */\n searchIndexes: ResolvedSearchIndex[];\n\n /**\n * Fields that exist in both auth collection and user config.\n * The auth VexField wins for schema gen; user admin config wins for UI.\n */\n overlapping: string[];\n\n /** Fields that only exist in the auth collection (not in user's collection). */\n authOnly: string[];\n\n /** Fields that only exist in the user's collection (not from auth). */\n userOnly: string[];\n}\n\n/**\n * Merges an auth collection's fields with a user-defined collection's fields.\n *\n * Both sides are VexField records. For overlapping fields, the auth\n * VexField's schema properties are used (it controls the DB shape), but\n * the user's admin config (label, hidden, etc.) is preserved by copying\n * admin-related metadata from the user's field onto the auth field.\n *\n * @param authCollection - The auth collection with fully resolved fields\n * @param userCollection - The user's collection that matches this auth table by slug\n * @returns Merged collection result with combined fields and source tracking\n */\nexport function mergeAuthCollectionWithUserCollection(props: {\n authCollection: VexCollection;\n userCollection: VexCollection;\n}): MergedCollectionResult {\n const { authCollection, userCollection } = props;\n const fields: Record<string, VexField> = {};\n const overlapping: string[] = [];\n const authOnly: string[] = [];\n const userOnly: string[] = [];\n\n const authFields = authCollection.fields;\n const userFields = userCollection.fields;\n const authFieldKeys = Object.keys(authFields);\n const userFieldKeys = Object.keys(userFields);\n\n // Process auth fields\n for (const fieldKey of authFieldKeys) {\n if (userFieldKeys.includes(fieldKey)) {\n overlapping.push(fieldKey);\n // Auth field wins for schema, but user field wins for rendering.\n // Use user's field as base so type, label, admin, etc. are preserved,\n // then layer auth's schema-relevant props (required, defaultValue).\n const authField = authFields[fieldKey];\n const userField = userFields[fieldKey];\n fields[fieldKey] = {\n ...userField,\n required: authField.required,\n ...((authField as any).defaultValue !== undefined && { defaultValue: (authField as any).defaultValue }),\n } as VexField;\n } else {\n authOnly.push(fieldKey);\n fields[fieldKey] = authFields[fieldKey];\n }\n }\n\n // Process user-only fields\n for (const fieldKey of userFieldKeys) {\n if (authFieldKeys.includes(fieldKey)) continue;\n userOnly.push(fieldKey);\n fields[fieldKey] = userFields[fieldKey];\n }\n\n // Merge indexes (auth indexes first, user indexes added if name doesn't conflict)\n const indexes: ResolvedIndex[] = [];\n const indexNames = new Set<string>();\n\n // Auth collection indexes (from collection-level)\n for (const idx of authCollection.indexes ?? []) {\n indexes.push({ name: idx.name, fields: idx.fields as string[] });\n indexNames.add(idx.name);\n }\n\n // User collection indexes\n for (const idx of userCollection.indexes ?? []) {\n if (!indexNames.has(idx.name)) {\n indexes.push({ name: idx.name, fields: idx.fields as string[] });\n indexNames.add(idx.name);\n }\n }\n\n // Search indexes from user collection\n const searchIndexes: ResolvedSearchIndex[] = (\n userCollection.searchIndexes ?? []\n ).map((si) => ({\n name: si.name,\n searchField: si.searchField as string,\n filterFields: (si.filterFields ?? []) as string[],\n }));\n\n return { fields, indexes, searchIndexes, overlapping, authOnly, userOnly };\n}\n","import { VexSlugConflictError } from \"../errors\";\nimport type { VexConfig } from \"../types\";\n\n// =============================================================================\n// SLUG REGISTRY — tracks table slugs and validates uniqueness on register\n// =============================================================================\n\n/**\n * Where a slug was registered from.\n */\nexport const SLUG_SOURCES = {\n userCollection: \"user-collection\",\n userGlobal: \"user-global\",\n authTable: \"auth-table\",\n mediaCollection: \"media-collection\",\n system: \"system\",\n} as const;\nexport type SlugSource = (typeof SLUG_SOURCES)[keyof typeof SLUG_SOURCES];\n\n/**\n * A registered slug with its source information.\n */\nexport interface SlugRegistration {\n slug: string;\n source: SlugSource;\n /** Human-readable description of where this slug was defined */\n location: string;\n}\n\n/**\n * Registry that collects all table slugs and validates uniqueness.\n * Throws immediately on duplicate — fail fast during schema generation.\n */\nexport class SlugRegistry {\n private registrations = new Map<string, SlugRegistration>();\n\n /**\n * Register a slug with its source.\n * Throws VexSlugConflictError immediately if the slug is already registered,\n * UNLESS an auth table slug overlaps with a user collection slug — this is\n * expected behavior indicating the user wants to customize that auth table's\n * admin UI. In that case, the user collection's registration takes precedence\n * (it was registered first as \"user-collection\") and the auth table is\n * silently skipped in the registry. The merge happens during schema generation.\n *\n * @param props.slug - The table slug to register\n * @param props.source - Where this slug comes from (e.g., \"user-collection\", \"auth-table\")\n * @param props.location - Human-readable location for error messages (e.g., `collection \"posts\"`)\n *\n * Edge cases:\n * - Auth table slug matches user collection slug: NOT a conflict — skip\n * registration (user collection already registered, merge happens later)\n * - System table prefixed with \"vex_\" should not conflict with user tables\n * because defineCollection already warns about \"vex_\" prefix\n */\n register(props: {\n slug: string;\n source: SlugSource;\n location: string;\n }): void {\n const existing = this.registrations.get(props.slug);\n if (existing) {\n // Auth table overlapping with user collection is expected — it means\n // the user wants to customize that auth table. The user collection\n // registration takes precedence; merge happens during schema generation.\n if (\n (existing.source === \"user-collection\" &&\n props.source === \"auth-table\") ||\n (existing.source === \"auth-table\" && props.source === \"user-collection\")\n ) {\n // Keep the user-collection registration, skip the auth-table one\n if (props.source === \"user-collection\") {\n this.registrations.set(props.slug, {\n slug: props.slug,\n source: props.source,\n location: props.location,\n });\n }\n return;\n }\n throw new VexSlugConflictError(\n props.slug,\n existing.source,\n existing.location,\n props.source,\n props.location,\n );\n }\n this.registrations.set(props.slug, {\n slug: props.slug,\n source: props.source,\n location: props.location,\n });\n }\n\n /**\n * Get all registered slugs.\n */\n getAll(): SlugRegistration[] {\n return [...this.registrations.values()];\n }\n}\n\n/**\n * Populate a SlugRegistry from a VexConfig.\n *\n * Registers slugs from:\n * 1. User collections (source: \"user-collection\")\n * 2. User globals (source: \"user-global\")\n * 3. Auth tables (source: \"auth-table\") — including the user table\n * 4. System tables like vex_globals (source: \"system\")\n *\n * Each register() call throws immediately on duplicate slug, except\n * when an auth table slug matches a user collection slug — this is\n * expected behavior indicating the user wants to customize that auth\n * table's admin UI. The merge happens during schema generation.\n *\n * Edge cases:\n * - No globals: skip global registration\n * - Auth table slug matches user collection slug: NOT a conflict —\n * the user collection registration takes precedence, merge happens later\n */\nexport function buildSlugRegistry(props: { config: VexConfig }): SlugRegistry {\n const registry = new SlugRegistry();\n\n for (const collection of props.config.collections) {\n registry.register({\n slug: collection.slug,\n source: SLUG_SOURCES.userCollection,\n location: `Collection ${collection.slug}`,\n });\n }\n\n // Register media collection slugs\n if (props.config.media) {\n for (const collection of props.config.media.collections) {\n registry.register({\n slug: collection.slug,\n source: SLUG_SOURCES.mediaCollection,\n location: `Media Collection ${collection.slug}`,\n });\n }\n }\n\n for (const global of props.config.globals) {\n registry.register({\n slug: global.slug,\n source: SLUG_SOURCES.userGlobal,\n location: `Global ${global.slug}`,\n });\n }\n\n for (const collection of props.config.auth.collections) {\n registry.register({\n slug: collection.slug,\n source: SLUG_SOURCES.authTable,\n location: `Auth Table ${collection.slug}`,\n });\n }\n\n return registry;\n}\n","import type { ResolvedIndex, ResolvedSearchIndex, VexConfig, VexField } from \"../types\";\nimport type { TabsFieldDef } from \"../types/fields\";\nimport { fieldToValueType } from \"./extract\";\nimport { collectIndexes } from \"./indexes\";\nimport { collectSearchIndexes } from \"./searchIndexes\";\nimport { mergeAuthCollectionWithUserCollection } from \"./merge\";\nimport { buildSlugRegistry } from \"./slugs\";\n\n/**\n * Expand a record of fields into flat name/valueType pairs,\n * handling tabs fields by expanding their sub-fields.\n * Each tab produces a v.optional(v.object({ ... })) entry keyed by its slug.\n */\nfunction expandFields(props: {\n fields: Record<string, VexField>;\n collectionSlug: string;\n}): { name: string; valueType: string }[] {\n const result: { name: string; valueType: string }[] = [];\n\n for (const [fieldName, field] of Object.entries(props.fields) as [string, VexField][]) {\n if (field.type === \"ui\") continue;\n\n if (field.type === \"tabs\") {\n const tabsField = field as TabsFieldDef;\n for (const tab of tabsField.tabs) {\n const innerFields: string[] = [];\n for (const [innerName, innerField] of Object.entries(tab.fields) as [string, VexField][]) {\n if (innerField.type === \"ui\") continue;\n const innerValueType = fieldToValueType({\n field: innerField,\n collectionSlug: props.collectionSlug,\n fieldName: innerName,\n });\n innerFields.push(`${innerName}: ${innerValueType}`);\n }\n if (innerFields.length > 0) {\n result.push({\n name: tab.slug,\n valueType: `v.optional(v.object({ ${innerFields.join(\", \")} }))`,\n });\n }\n }\n } else {\n result.push({\n name: fieldName,\n valueType: fieldToValueType({\n fieldName,\n field,\n collectionSlug: props.collectionSlug,\n }),\n });\n }\n }\n\n return result;\n}\n\n/**\n * Generates the full TypeScript source content for `convex/vex.schema.ts`.\n *\n * This is the main entry point for schema generation. It:\n * 1. Validates all slugs are unique (via SlugRegistry)\n * 2. For each auth collection, checks if a matching user collection exists (by slug):\n * a. If yes: merges auth collection fields with user collection fields\n * b. If no matching collection: generates the auth collection as-is\n * 3. User collections that don't match any auth collection: generates from collection fields only\n * 4. Collects indexes from per-field `index` properties and collection-level `indexes`\n * 5. Generates defineTable() calls for each table with chained .index() calls\n * 6. Generates defineTable() calls for system tables (vex_globals if globals exist)\n *\n * All fields go through fieldToValueType() uniformly — no dual path for auth vs user.\n */\nexport function generateVexSchema(props: { config: VexConfig }): string {\n const config = props.config;\n buildSlugRegistry({ config });\n const authCollectionMap = new Map(\n config.auth.collections.map((c) => [c.slug, c]),\n );\n const mergedAuthSlugs = new Set<string>();\n\n const lines: string[] = [\n \"// ⚠️ AUTO-GENERATED BY VEX CMS — DO NOT EDIT ⚠️\",\n \"\",\n 'import { defineTable } from \"convex/server\";',\n 'import { v } from \"convex/values\";',\n ];\n\n if (config.collections.length > 0) {\n lines.push(\"\", \"/**\", \" * USER COLLECTIONS\", \" **/\");\n }\n\n for (const collection of config.collections) {\n const authCollection = authCollectionMap.get(collection.slug);\n const fields: { name: string; valueType: string }[] = [];\n const indexes: ResolvedIndex[] = collectIndexes({ collection });\n const searchIndexes: ResolvedSearchIndex[] = collectSearchIndexes({\n collection,\n });\n\n if (authCollection) {\n mergedAuthSlugs.add(authCollection.slug);\n const merged = mergeAuthCollectionWithUserCollection({\n authCollection,\n userCollection: collection,\n });\n\n // All merged fields go through fieldToValueType uniformly\n for (const [name, field] of Object.entries(merged.fields)) {\n if (field.type === \"ui\") continue; // UI fields have no database representation\n fields.push({\n name,\n valueType: fieldToValueType({\n field,\n collectionSlug: collection.slug,\n fieldName: name,\n }),\n });\n }\n\n // Add merged indexes (deduplicated)\n for (const index of merged.indexes) {\n if (indexes.find((ui) => ui.name === index.name)) continue;\n indexes.push(index);\n }\n\n // Add merged search indexes\n for (const si of merged.searchIndexes) {\n if (searchIndexes.find((existing) => existing.name === si.name))\n continue;\n searchIndexes.push(si);\n }\n } else {\n fields.push(...expandFields({\n fields: collection.fields as Record<string, VexField>,\n collectionSlug: collection.slug,\n }));\n }\n\n lines.push(\n \"\",\n `export const ${collection.tableName ?? collection.slug} = defineTable({`,\n );\n for (const f of fields) {\n lines.push(` ${f.name}: ${f.valueType},`);\n }\n // vex_status on all user collections — defaults to \"published\"\n lines.push(` vex_status: v.optional(v.union(v.literal(\"draft\"), v.literal(\"published\"))),`);\n if (collection.versions?.drafts) {\n lines.push(` vex_version: v.optional(v.number()),`);\n lines.push(` vex_publishedAt: v.optional(v.number()),`);\n }\n lines.push(\"})\");\n for (const i of indexes) {\n const fieldList = i.fields.map((f) => `\"${f}\"`).join(\", \");\n lines.push(` .index(\"${i.name}\", [${fieldList}])`);\n }\n for (const si of searchIndexes) {\n const filterList =\n si.filterFields.length > 0\n ? `, filterFields: [${si.filterFields.map((f) => `\"${f}\"`).join(\", \")}]`\n : \"\";\n lines.push(\n ` .searchIndex(\"${si.name}\", { searchField: \"${si.searchField}\"${filterList} })`,\n );\n }\n }\n\n // --- MEDIA COLLECTIONS ---\n if (config.media && config.media.collections.length > 0) {\n lines.push(\"\", \"/**\", \" * MEDIA COLLECTIONS\", \" **/\");\n\n for (const mediaCollection of config.media.collections) {\n const fields: { name: string; valueType: string }[] = [];\n const indexes: ResolvedIndex[] = collectIndexes({ collection: mediaCollection });\n const searchIndexes: ResolvedSearchIndex[] = collectSearchIndexes({\n collection: mediaCollection,\n });\n\n for (const [fieldName, field] of Object.entries(\n mediaCollection.fields,\n ) as [string, VexField][]) {\n if (field.type === \"ui\") continue;\n if (fieldName === \"storageId\") {\n // Use adapter's storageIdValueType instead of fieldToValueType\n fields.push({\n name: fieldName,\n valueType: config.media.storageAdapter.storageIdValueType,\n });\n } else {\n fields.push({\n name: fieldName,\n valueType: fieldToValueType({\n fieldName,\n field,\n collectionSlug: mediaCollection.slug,\n }),\n });\n }\n }\n\n lines.push(\n \"\",\n `export const ${mediaCollection.tableName ?? mediaCollection.slug} = defineTable({`,\n );\n for (const f of fields) {\n lines.push(` ${f.name}: ${f.valueType},`);\n }\n lines.push(\"})\");\n for (const i of indexes) {\n const fieldList = i.fields.map((f) => `\"${f}\"`).join(\", \");\n lines.push(` .index(\"${i.name}\", [${fieldList}])`);\n }\n for (const si of searchIndexes) {\n const filterList =\n si.filterFields.length > 0\n ? `, filterFields: [${si.filterFields.map((f) => `\"${f}\"`).join(\", \")}]`\n : \"\";\n lines.push(\n ` .searchIndex(\"${si.name}\", { searchField: \"${si.searchField}\"${filterList} })`,\n );\n }\n }\n }\n\n const unmergedAuthCollections = config.auth.collections.filter(\n (c) => !mergedAuthSlugs.has(c.slug),\n );\n\n if (unmergedAuthCollections.length > 0) {\n lines.push(\"\", \"/**\", \" * AUTH TABLES\", \" **/\");\n }\n\n for (const authCollection of unmergedAuthCollections) {\n const indexes: ResolvedIndex[] = collectIndexes({\n collection: authCollection,\n });\n lines.push(\n \"\",\n `export const ${authCollection.tableName ?? authCollection.slug} = defineTable({`,\n );\n for (const [name, field] of Object.entries(authCollection.fields) as [string, VexField][]) {\n lines.push(\n ` ${name}: ${fieldToValueType({\n field,\n collectionSlug: authCollection.slug,\n fieldName: name,\n })},`,\n );\n }\n lines.push(\"})\");\n for (const i of indexes) {\n const fieldList = i.fields.map((f) => `\"${f}\"`).join(\", \");\n lines.push(` .index(\"${i.name}\", [${fieldList}])`);\n }\n }\n\n for (const global of config.globals) {\n const fields: { name: string; valueType: string }[] = [];\n const indexes: ResolvedIndex[] = collectIndexes({ collection: global });\n for (const [fieldName, field] of Object.entries(global.fields)) {\n fields.push({\n name: fieldName,\n valueType: fieldToValueType({\n fieldName,\n field,\n collectionSlug: global.slug,\n }),\n });\n }\n\n lines.push(\n \"\",\n `export const ${global.tableName ?? global.slug} = defineTable({`,\n );\n for (const f of fields) {\n lines.push(` ${f.name}: ${f.valueType},`);\n }\n // vex_status on all globals — defaults to \"published\"\n lines.push(` vex_status: v.optional(v.union(v.literal(\"draft\"), v.literal(\"published\"))),`);\n if ((global as any).versions?.drafts) {\n lines.push(` vex_version: v.optional(v.number()),`);\n lines.push(` vex_publishedAt: v.optional(v.number()),`);\n }\n lines.push(\"})\");\n for (const i of indexes) {\n const fieldList = i.fields.map((f) => `\"${f}\"`).join(\", \");\n lines.push(` .index(\"${i.name}\", [${fieldList}])`);\n }\n }\n\n // Always generate vex_versions so removing versioning from a collection\n // doesn't break schema.ts imports that reference vex_versions.\n {\n lines.push(\"\", \"/**\", \" * VEX SYSTEM TABLES\", \" **/\");\n lines.push(\"\");\n lines.push(\"export const vex_versions = defineTable({\");\n lines.push(\" collection: v.string(),\");\n lines.push(\" documentId: v.string(),\");\n lines.push(\" version: v.number(),\");\n lines.push(\" status: v.union(\");\n lines.push(` v.literal(\"draft\"),`);\n lines.push(` v.literal(\"published\"),`);\n lines.push(` v.literal(\"autosave\"),`);\n lines.push(` v.literal(\"previewSnapshot\"),`);\n lines.push(\" ),\");\n lines.push(\" snapshot: v.any(),\");\n lines.push(\" createdAt: v.number(),\");\n lines.push(\" createdBy: v.optional(v.string()),\");\n lines.push(\" isAutosave: v.boolean(),\");\n lines.push(\" restoredFrom: v.optional(v.number()),\");\n lines.push(\"})\");\n lines.push(` .index(\"by_document\", [\"collection\", \"documentId\"])`);\n lines.push(` .index(\"by_document_version\", [\"collection\", \"documentId\", \"version\"])`);\n lines.push(` .index(\"by_document_latest\", [\"collection\", \"documentId\", \"createdAt\"])`);\n lines.push(` .index(\"by_document_status\", [\"collection\", \"documentId\", \"status\"])`);\n lines.push(` .index(\"by_autosave\", [\"collection\", \"documentId\", \"isAutosave\"])`);\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n","import { defineTable, type TableDefinition } from \"convex/server\";\nimport type { GenericValidator, ObjectType, VObject } from \"convex/values\";\n\ntype ExtractFields<T> =\n T extends TableDefinition<VObject<any, infer F>> ? F : never;\n\ntype ForbidExistingKeys<Existing, New> = {\n [K in keyof New]: K extends keyof Existing ? never : New[K];\n};\n\n/**\n * Compute the TableDefinition type that preserves field types.\n * Matches the second overload of defineTable:\n * defineTable(fields) → TableDefinition<VObject<ObjectType<Fields>, Fields>>\n */\ntype ExtendedTableDef<Fields extends Record<string, GenericValidator>> =\n TableDefinition<VObject<ObjectType<Fields>, Fields>>;\n\n/**\n * Extends a vex-generated table definition with additional fields,\n * preserving all indexes from the original table.\n *\n * Use this in your `convex/schema.ts` when you need to add custom\n * fields to a vex-managed table (e.g., adding a `body` field to posts).\n *\n * @param props.table - The table definition from vex.schema.ts\n * @param props.additionalFields - Additional Convex validator fields to add.\n * Keys that already exist on the table will cause a type error.\n * @returns A new TableDefinition with merged fields and original indexes.\n * You can chain additional `.index()` calls on the result.\n *\n * @example\n * ```ts\n * import { posts } from \"./vex.schema\";\n * import { extendTable } from \"@vexcms/core\";\n * import { v } from \"convex/values\";\n *\n * export default defineSchema({\n * posts: extendTable({\n * table: posts,\n * additionalFields: { body: v.optional(v.string()) },\n * }).index(\"by_status\", [\"status\"]),\n * });\n * ```\n */\nexport function extendTable<\n T extends TableDefinition<VObject<any, any>>,\n A extends Record<string, GenericValidator> = {},\n>(props: {\n table: T;\n additionalFields?: A & ForbidExistingKeys<ExtractFields<T>, A>;\n}): ExtendedTableDef<ExtractFields<T> & A> {\n const { validator } = props.table;\n\n let extended = defineTable({\n ...validator.fields,\n ...props.additionalFields,\n });\n\n // Use the public \" indexes\"() method (note: the method name has a leading space)\n for (const idx of props.table[\" indexes\"]()) {\n extended = extended.index(\n idx.indexDescriptor,\n idx.fields as [string, ...string[]],\n );\n }\n\n // searchIndexes and vectorIndexes are private — access via any cast\n const source = props.table as any;\n\n for (const idx of source.searchIndexes ?? []) {\n extended = extended.searchIndex(idx.indexDescriptor, {\n searchField: idx.searchField,\n filterFields: idx.filterFields,\n } as any);\n }\n\n for (const idx of source.vectorIndexes ?? []) {\n extended = extended.vectorIndex(idx.indexDescriptor, {\n vectorField: idx.vectorField,\n dimensions: idx.dimensions,\n filterFields: idx.filterFields,\n } as any);\n }\n\n return extended as ExtendedTableDef<ExtractFields<T> & A>;\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { UploadFieldDef } from \"../../types\";\nimport { toTitleCase } from \"../../utils\";\n\n/**\n * Builds a ColumnDef for an upload field.\n *\n * The cell renders the raw document ID by default. Consumers (e.g., admin-next)\n * can replace the cell renderer using the column meta to show a file preview.\n *\n * Meta includes `type: \"upload\"` and `to` (target collection slug) so that\n * the rendering layer can detect upload columns and provide custom rendering.\n */\nexport function uploadColumnDef(props: {\n fieldKey: string;\n field: UploadFieldDef;\n}): ColumnDef<Record<string, unknown>> {\n return {\n accessorKey: props.fieldKey,\n header: (props.field.hasMany ? props.field.labels?.singular : props.field.label) ?? toTitleCase(props.fieldKey),\n meta: {\n type: \"upload\",\n to: props.field.to,\n noTruncate: true,\n },\n cell: (info) => {\n const value = info.getValue();\n if (!value || typeof value !== \"string\") return \"\";\n return value;\n },\n };\n}\n","import type { ColumnDef } from \"@tanstack/react-table\";\nimport type { VexAuthAdapter, VexCollection, VexField } from \"../types\";\nimport { textColumnDef } from \"../fields/text/columnDef\";\nimport { numberColumnDef } from \"../fields/number/columnDef\";\nimport { checkboxColumnDef } from \"../fields/checkbox/columnDef\";\nimport { selectColumnDef } from \"../fields/select/columnDef\";\nimport { dateColumnDef } from \"../fields/date/columnDef\";\nimport { imageUrlColumnDef } from \"../fields/imageUrl/columnDef\";\nimport { relationshipColumnDef } from \"../fields/relationship/columnDef\";\nimport { jsonColumnDef } from \"../fields/json/columnDef\";\nimport { objectColumnDef } from \"../fields/object/columnDef\";\nimport { richtextColumnDef } from \"../fields/richtext/columnDef\";\nimport { arrayColumnDef } from \"../fields/array/columnDef\";\nimport { uploadColumnDef } from \"../fields/media/columnDef\";\nimport { blocksColumnDef } from \"../fields/blocks/columnDef\";\nimport { colorColumnDef } from \"../fields/color/columnDef\";\nimport { toTitleCase } from \"../utils\";\n\n/**\n * Generates an array of ColumnDef objects from a VexCollection's field configs.\n *\n * @param props.collection - The collection to generate columns for\n * @param props.auth - Optional auth adapter. When provided, auth fields (e.g. createdAt)\n * get proper columnDef dispatch instead of falling back to plain text columns.\n * @returns Array of ColumnDef objects for use with @tanstack/react-table\n */\nexport function generateColumns(props: {\n collection: VexCollection;\n auth?: VexAuthAdapter;\n}): ColumnDef<Record<string, unknown>>[] {\n const { collection, auth } = props;\n const columns: ColumnDef<Record<string, unknown>>[] = [];\n const useAsTitle = collection.admin?.useAsTitle as string | undefined;\n const defaultColumns = collection.admin?.defaultColumns as\n | string[]\n | undefined;\n const fields = collection.fields;\n\n // Build a lookup of auth fields for this collection's slug\n const authFields: Record<string, VexField> = {};\n if (auth) {\n const authCollection = auth.collections.find(\n (c: VexCollection) => c.slug === collection.slug,\n );\n if (authCollection) {\n for (const [k, v] of Object.entries(authCollection.fields) as [\n string,\n VexField,\n ][]) {\n authFields[k] = v;\n }\n }\n }\n\n if (defaultColumns) {\n for (const fieldKey of defaultColumns) {\n if (fieldKey === \"_id\") {\n columns.push({ accessorKey: \"_id\", header: \"ID\" });\n continue;\n }\n\n const field = (fields[fieldKey] ?? authFields[fieldKey]) as\n | VexField\n | undefined;\n\n if (!field) {\n columns.push({ accessorKey: fieldKey, header: toTitleCase(fieldKey) });\n continue;\n }\n\n if (field.admin?.hidden) continue;\n if (field.type === \"ui\" || field.type === \"tabs\") continue;\n\n const col = buildColumnDef(fieldKey, field);\n\n if (useAsTitle && fieldKey === useAsTitle) {\n col.meta = { ...col.meta, isTitle: true };\n }\n\n // Attach custom Cell component to meta if present\n if (field.admin?.components?.Cell) {\n col.meta = {\n ...col.meta,\n customCell: field.admin.components.Cell,\n fieldDef: field,\n };\n }\n\n columns.push(col);\n }\n } else {\n columns.push({ accessorKey: \"_id\", header: \"ID\" });\n\n // Collect all field keys: user fields first, then auth-only fields\n const allFieldKeys = new Set(Object.keys(fields));\n for (const k of Object.keys(authFields)) {\n allFieldKeys.add(k);\n }\n\n for (const fieldKey of allFieldKeys) {\n const field = (fields[fieldKey] ?? authFields[fieldKey]) as VexField;\n if (field.admin?.hidden) continue;\n if (field.type === \"ui\" || field.type === \"tabs\") continue;\n\n const col = buildColumnDef(fieldKey, field);\n\n if (useAsTitle && fieldKey === useAsTitle) {\n col.meta = { ...col.meta, isTitle: true };\n }\n\n // Attach custom Cell component to meta if present\n if (field.admin?.components?.Cell) {\n col.meta = {\n ...col.meta,\n customCell: field.admin.components.Cell,\n fieldDef: field,\n };\n }\n\n columns.push(col);\n }\n }\n\n return columns;\n}\n\nfunction buildColumnDef(\n fieldKey: string,\n field: VexField,\n): ColumnDef<Record<string, unknown>> {\n switch (field.type) {\n case \"text\":\n return textColumnDef({ fieldKey, field });\n case \"number\":\n return numberColumnDef({ fieldKey, field });\n case \"checkbox\":\n return checkboxColumnDef({ fieldKey, field });\n case \"select\":\n return selectColumnDef({ fieldKey, field });\n case \"date\":\n return dateColumnDef({ fieldKey, field });\n case \"imageUrl\":\n return imageUrlColumnDef({ fieldKey, field });\n case \"relationship\":\n return relationshipColumnDef({ fieldKey, field });\n case \"json\":\n return jsonColumnDef({ fieldKey, field });\n case \"object\":\n return objectColumnDef({ fieldKey, field });\n case \"richtext\":\n return richtextColumnDef({ fieldKey, field });\n case \"array\":\n return arrayColumnDef({ fieldKey, field });\n case \"upload\":\n return uploadColumnDef({ fieldKey, field });\n case \"blocks\":\n return blocksColumnDef({ fieldKey, field });\n case \"color\":\n return colorColumnDef({ fieldKey, field });\n default:\n return {\n accessorKey: fieldKey,\n header: toTitleCase(fieldKey),\n };\n }\n}\n","import { z, type ZodTypeAny } from \"zod\";\nimport type { VexField } from \"../types\";\n\n/**\n * Generate a Zod schema from a collection's field definitions.\n * Used by both the client-side form (for validation on submit)\n * and the server-side mutation (for payload validation).\n *\n * @param props.fields - Record of field name → VexField from the collection\n * @returns A z.object() schema matching the collection's editable fields\n */\nexport function generateFormSchema(props: {\n fields: Record<string, VexField>;\n}): z.ZodObject<Record<string, ZodTypeAny>> {\n const shape: Record<string, ZodTypeAny> = {};\n\n for (const [fieldName, field] of Object.entries(props.fields)) {\n if (field.admin?.hidden) continue;\n if (field.type === \"ui\") continue;\n\n // Tabs expand into slug-keyed z.object() entries\n if (field.type === \"tabs\") {\n for (const tab of field.tabs) {\n const tabFields: Record<string, ZodTypeAny> = {};\n for (const [subName, subField] of Object.entries(tab.fields)) {\n if (subField.type === \"ui\") continue;\n let subValidator = fieldMetaToZod({ field: subField });\n if (!subField.required) subValidator = subValidator.optional();\n tabFields[subName] = subValidator;\n }\n shape[tab.slug] = z.object(tabFields).optional();\n }\n continue;\n }\n\n let validator = fieldMetaToZod({ field });\n\n if (!field.required) {\n validator = validator.optional();\n }\n\n shape[fieldName] = validator;\n }\n\n return z.object(shape);\n}\n\n/**\n * Convert a single field to its Zod validator.\n * Does NOT handle optional wrapping — that's done by the caller.\n *\n * @param props.field - The field definition (discriminated on `type`)\n * @returns The base Zod type for this field (always required)\n */\nexport function fieldMetaToZod(props: { field: VexField }): ZodTypeAny {\n switch (props.field.type) {\n case \"text\": {\n let schema = z.string();\n if (props.field.minLength != null) schema = schema.min(props.field.minLength);\n if (props.field.maxLength != null) schema = schema.max(props.field.maxLength);\n return schema;\n }\n\n case \"number\": {\n let schema = z.number();\n if (props.field.min != null) schema = schema.min(props.field.min);\n if (props.field.max != null) schema = schema.max(props.field.max);\n return schema;\n }\n\n case \"checkbox\":\n return z.boolean();\n\n case \"select\": {\n const values = props.field.options.map((o) => o.value);\n if (values.length === 0) return z.string();\n const enumSchema = z.enum(values as [string, ...string[]]);\n if (props.field.hasMany) {\n return z.array(enumSchema);\n }\n return enumSchema;\n }\n\n case \"date\":\n return z.number();\n\n case \"imageUrl\":\n return z.string().url().or(z.literal(\"\"));\n\n case \"relationship\": {\n if (props.field.hasMany) {\n return z.array(z.string());\n }\n return z.string();\n }\n\n case \"upload\": {\n if (props.field.hasMany) {\n return z.array(z.string());\n }\n return z.string();\n }\n\n case \"json\":\n return z.any();\n\n case \"object\": {\n const shape: Record<string, ZodTypeAny> = {};\n for (const [subName, subField] of Object.entries(props.field.fields)) {\n let subValidator = fieldMetaToZod({ field: subField as VexField });\n if (!(subField as VexField).required) subValidator = subValidator.optional();\n shape[subName] = subValidator;\n }\n return z.object(shape);\n }\n\n case \"richtext\":\n return z.any();\n\n case \"color\":\n return z.string();\n\n case \"tabs\":\n // Tabs are expanded in generateFormSchema's loop, not here\n return z.any();\n\n case \"array\": {\n let schema = z.array(fieldMetaToZod({ field: props.field.items }));\n if (props.field.min != null) schema = schema.min(props.field.min);\n if (props.field.max != null) schema = schema.max(props.field.max);\n return schema;\n }\n\n case \"blocks\": {\n const blockSchemas = props.field.blocks.map((blockDef) => {\n const shape: Record<string, ZodTypeAny> = {\n blockType: z.literal(blockDef.slug),\n blockName: z.string().optional(),\n _key: z.string(),\n };\n for (const [fieldName, field] of Object.entries(blockDef.fields)) {\n let validator = fieldMetaToZod({ field: field as VexField });\n if (!(field as VexField).required) {\n validator = validator.optional();\n }\n shape[fieldName] = validator;\n }\n return z.object(shape);\n });\n\n if (blockSchemas.length === 0) {\n let schema = z.array(z.any());\n if (props.field.min != null) schema = schema.min(props.field.min);\n if (props.field.max != null) schema = schema.max(props.field.max);\n return schema;\n }\n\n const union =\n blockSchemas.length === 1\n ? blockSchemas[0]\n : z.discriminatedUnion(\n \"blockType\",\n blockSchemas as [z.ZodObject<any>, z.ZodObject<any>, ...z.ZodObject<any>[]],\n );\n\n let schema = z.array(union);\n if (props.field.min != null) schema = schema.min(props.field.min);\n if (props.field.max != null) schema = schema.max(props.field.max);\n return schema;\n }\n\n default:\n return z.any();\n }\n}\n","import type { VexField } from \"../types\";\n\n/**\n * Compute the zero-value for a field type (used as initial form value).\n */\nfunction getFormDefaultValue(props: { field: VexField }): unknown {\n switch (props.field.type) {\n case \"text\":\n return props.field.defaultValue ?? \"\";\n case \"number\":\n return props.field.defaultValue ?? 0;\n case \"checkbox\":\n return props.field.defaultValue ?? false;\n case \"select\":\n if (props.field.hasMany) {\n return props.field.defaultValue ? [props.field.defaultValue] : [];\n }\n return props.field.defaultValue ?? \"\";\n case \"date\":\n return props.field.defaultValue ?? 0;\n case \"imageUrl\":\n return props.field.defaultValue ?? \"\";\n case \"relationship\":\n return props.field.hasMany ? [] : undefined;\n case \"upload\":\n return props.field.hasMany ? [] : undefined;\n case \"json\":\n return {};\n case \"object\": {\n const defaults: Record<string, unknown> = {};\n for (const [subName, subField] of Object.entries(props.field.fields)) {\n defaults[subName] = getFormDefaultValue({ field: subField });\n }\n return defaults;\n }\n case \"richtext\":\n return [];\n case \"color\":\n return props.field.defaultValue ?? \"\";\n case \"tabs\":\n return {};\n case \"array\":\n return props.field.defaultValue ?? [];\n case \"blocks\":\n return [];\n case \"ui\":\n return undefined;\n default:\n return undefined;\n }\n}\n\n/**\n * Generate default values for a create form from a collection's field definitions.\n * Skips hidden fields.\n *\n * @param props.fields - Record of field name -> VexField from the collection\n * @returns Record of field name -> default value for the create form\n */\nexport function generateFormDefaultValues(props: {\n fields: Record<string, VexField>;\n}): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [fieldName, field] of Object.entries(props.fields)) {\n if (field.admin?.hidden) continue;\n if (field.type === \"ui\") continue;\n\n // Tabs expand into slug-keyed objects with sub-field defaults\n if (field.type === \"tabs\") {\n for (const tab of field.tabs) {\n const tabDefaults: Record<string, unknown> = {};\n for (const [subName, subField] of Object.entries(tab.fields)) {\n if (subField.type === \"ui\") continue;\n tabDefaults[subName] = getFormDefaultValue({ field: subField });\n }\n result[tab.slug] = tabDefaults;\n }\n continue;\n }\n\n result[fieldName] = getFormDefaultValue({ field });\n }\n\n return result;\n}\n","import type { UIFieldDef, FieldAdminConfig, FieldComponentProps } from \"../../types\";\nimport type { ComponentType } from \"react\";\n\n/**\n * Creates a UI field — a non-persisted field that renders a custom component.\n * UI fields are skipped during schema generation, form validation, and column generation.\n * They are useful for computed displays, action buttons, and embedded widgets.\n *\n * @param props.label - Display label for the field\n * @param props.admin - Admin config. components.Field is required.\n * @param props.description - Helper text displayed below the field\n * @returns A UIFieldDef\n *\n * @example\n * ```ts\n * import { ui } from \"@vexcms/core\";\n * import WordCount from \"~/components/admin/WordCount\";\n *\n * const collection = defineCollection({\n * slug: \"posts\",\n * fields: {\n * wordCount: ui({\n * label: \"Word Count\",\n * admin: {\n * components: { Field: WordCount },\n * position: \"sidebar\",\n * },\n * }),\n * },\n * });\n * ```\n */\nexport function ui(props: {\n label?: string;\n admin: FieldAdminConfig & {\n components: {\n Field: ComponentType<FieldComponentProps>;\n };\n };\n description?: string;\n}): UIFieldDef {\n return {\n type: \"ui\" as const,\n label: props.label,\n description: props.description,\n admin: props.admin,\n };\n}\n","import type { TabDef, TabsFieldDef } from \"../../types/fields\";\n\n/**\n * Creates a tabs field definition.\n * Groups fields into tabbed UI sections in the admin panel.\n *\n * Tabs with `slug` create nested objects in the document.\n * Tabs without `slug` flatten their fields onto the parent.\n *\n * @param props - Tabs field configuration\n * @param props.tabs - Array of tab definitions with label, optional slug, and fields\n * @returns TabsFieldDef with preserved tab slug and field type information\n */\nexport function tabs<const TTabs extends TabDef[]>(\n props: Omit<TabsFieldDef<TTabs>, \"type\">,\n): TabsFieldDef<TTabs> {\n return {\n ...props,\n type: \"tabs\" as const,\n };\n}\n","// =============================================================================\n// FIELD TYPES — Object-based configuration\n// =============================================================================\n\nimport type { ComponentType } from \"react\";\nimport type { StyleTier } from \"../styles/types\";\n\n/** Content alignment for data table cells. */\nexport type Alignment = \"left\" | \"right\" | \"center\";\nexport type Labels = {\n singular: string;\n plural: string;\n};\n\n/**\n * Props passed to custom field components.\n * Custom components receive these props and use useVexField() for state.\n *\n * Use the generic parameter to narrow the field type for type-safe access\n * to field-specific properties like `options` on select fields.\n *\n * @example\n * ```tsx\n * // Generic — fieldDef has label, admin, description, required\n * function MyField({ name, fieldDef, readOnly }: FieldComponentProps) { ... }\n *\n * // Narrowed — fieldDef is TextFieldDef with maxLength, minLength, etc.\n * function MyTextField({ name, fieldDef }: FieldComponentProps<TextFieldDef>) { ... }\n * ```\n */\nexport interface FieldComponentProps<TField extends VexField = VexField> {\n /** The field key name (e.g., \"primaryColor\") */\n name: string;\n /** The VexField definition for this field */\n fieldDef: TField;\n /** Whether the field is read-only (from permissions or config) */\n readOnly: boolean;\n}\n\n/**\n * Props passed to custom cell components in the data table.\n */\nexport interface CellComponentProps<TField extends VexField = VexField> {\n /** The raw cell value from the document */\n value: unknown;\n /** The full row data (document) */\n row: Record<string, unknown>;\n /** The VexField definition for this column's field */\n fieldDef: TField;\n}\n\n/**\n * Admin panel configuration for individual fields.\n * Controls visibility, layout, and input behavior in the admin UI.\n */\nexport interface FieldAdminConfig {\n /**\n * Hide this field from the admin form.\n * Hidden fields are still stored in the database.\n *\n * Default: `false`\n */\n hidden?: boolean;\n /**\n * Make this field read-only in the admin form.\n * The value is displayed but cannot be edited.\n *\n * Default: `false`\n */\n readOnly?: boolean;\n /**\n * Position of the field in the form layout.\n *\n * - `\"main\"` — placed in the main content area\n * - `\"sidebar\"` — placed in the sidebar panel\n *\n * Default: `\"main\"`\n */\n position?: \"main\" | \"sidebar\";\n /**\n * Width of the field within its row.\n *\n * - `\"full\"` — spans the full width\n * - `\"half\"` — spans half the width (two fields per row)\n *\n * Default: `\"full\"`\n */\n width?: \"full\" | \"half\";\n /**\n * Placeholder text shown in the input when empty.\n */\n placeholder?: string;\n /**\n * Helper text displayed below the field input.\n * Use for additional context or formatting hints.\n */\n description?: string;\n /**\n * Content alignment in data table cells. 'left' | 'right' | 'center'\n */\n cellAlignment?: Alignment;\n /**\n * Custom components for this field.\n *\n * - `Field` replaces the entire field input in the edit form.\n * Only allowed on text, number, checkbox, and select fields.\n * The component receives FieldComponentProps and uses useVexField() for state.\n *\n * - `Cell` replaces the cell renderer in the data table list view.\n * Allowed on any field type.\n */\n components?: {\n Field?: ComponentType<FieldComponentProps>;\n Cell?: ComponentType<CellComponentProps>;\n };\n}\n\n// =============================================================================\n// BASE FIELD PROPERTIES (shared by all field types)\n// =============================================================================\n\n/**\n * Properties shared by all field types.\n * Each concrete field type extends this with its `type` discriminant\n * and type-specific options.\n */\ninterface BaseField {\n /** Display label for the field in the admin form. */\n label?: string;\n /** Description text shown below the field. */\n description?: string;\n /**\n * Whether this field is required.\n *\n * Default: `false`\n */\n required?: boolean;\n /** Admin UI configuration for this field. */\n admin?: FieldAdminConfig;\n /**\n * Create a database index on this field.\n * The string value becomes the index name in Convex.\n *\n * @example\n * ```ts\n * slug: { type: \"text\", index: \"by_slug\", required: true }\n * // Generates: .index(\"by_slug\", [\"slug\"])\n * ```\n */\n index?: string;\n /**\n * Create a full-text search index on this field.\n * The field this is defined on becomes the `searchField`.\n *\n * @example\n * ```ts\n * title: {\n * type: \"text\",\n * searchIndex: { name: \"search_title\", filterFields: [\"status\", \"author\"] },\n * }\n * // Generates: .searchIndex(\"search_title\", { searchField: \"title\", filterFields: [\"status\", \"author\"] })\n * ```\n */\n searchIndex?: {\n /** Search index name (must be unique within the collection). */\n name: string;\n /**\n * Fields to filter search results by.\n * String array — validated at runtime against collection field names.\n */\n filterFields: string[];\n };\n}\n\n// =============================================================================\n// CONCRETE FIELD TYPES\n// =============================================================================\n\n/** Text field definition. */\nexport interface TextFieldDef extends BaseField {\n readonly type: \"text\";\n /** Default value for new documents. */\n defaultValue?: string;\n /** Minimum character length. */\n minLength?: number;\n /** Maximum character length. */\n maxLength?: number;\n}\n\n/** Number field definition. */\nexport interface NumberFieldDef extends BaseField {\n readonly type: \"number\";\n /** Default value for new documents. */\n defaultValue?: number;\n /** Minimum allowed value. */\n min?: number;\n /** Maximum allowed value. */\n max?: number;\n /** Step increment for the input. */\n step?: number;\n}\n\n/** Checkbox field definition. */\nexport interface CheckboxFieldDef extends BaseField {\n readonly type: \"checkbox\";\n /** Default value for new documents. */\n defaultValue?: boolean;\n}\n\n/**\n * A single option in a select field.\n */\nexport interface SelectOption<T extends string = string> {\n /** The stored value. */\n readonly value: T;\n /** The display label shown in the dropdown. */\n readonly label: string;\n /** Optional badge color for the data table. Accepts a hex string (e.g. \"#3b82f6\"). */\n readonly badgeColor?: string;\n}\n\n/** Select field — single value variant. */\nexport interface SelectFieldSingle<T extends string = string> extends BaseField {\n readonly type: \"select\";\n /** The available options for this select field. */\n options: readonly SelectOption<T>[];\n /** Default value for new documents. */\n defaultValue?: T;\n hasMany?: false;\n}\n\n/** Select field — multi-value variant. */\nexport interface SelectFieldMany<T extends string = string> extends BaseField {\n readonly type: \"select\";\n /** The available options for this select field. */\n options: readonly SelectOption<T>[];\n /** Default value for new documents. */\n defaultValue?: T;\n /** Display labels for the field (singular/plural). */\n labels?: Labels;\n hasMany: true;\n}\n\n/** Select field definition with typed options. Discriminated on `hasMany`. */\nexport type SelectFieldDef<T extends string = string> =\n | SelectFieldSingle<T>\n | SelectFieldMany<T>;\n\n/** Date field definition. Stores epoch milliseconds. */\nexport interface DateFieldDef extends BaseField {\n readonly type: \"date\";\n /** Default value for new documents (epoch ms). */\n defaultValue?: number;\n}\n\n/** Image URL field definition. Stores a URL string, renders as thumbnail. */\nexport interface ImageUrlFieldDef extends BaseField {\n readonly type: \"imageUrl\";\n /** Default value for new documents. */\n defaultValue?: string;\n /** Width (px) of the image */\n width?: number;\n /** Height (px) of the image */\n height?: number;\n}\n\n/** Relationship field — single reference variant. */\nexport interface RelationshipFieldSingle extends BaseField {\n readonly type: \"relationship\";\n /** Target table name. */\n to: string;\n hasMany?: false;\n}\n\n/** Relationship field — multi-reference variant. */\nexport interface RelationshipFieldMany extends BaseField {\n readonly type: \"relationship\";\n /** Target table name. */\n to: string;\n /** Display labels for the field (singular/plural). */\n labels?: Labels;\n hasMany: true;\n}\n\n/** Relationship field definition. Discriminated on `hasMany`. */\nexport type RelationshipFieldDef = RelationshipFieldSingle | RelationshipFieldMany;\n\n/** Shared upload field properties. */\ninterface UploadFieldBase extends BaseField {\n readonly type: \"upload\";\n /** Target media collection slug. */\n to: string;\n /**\n * Accepted MIME types for file uploads.\n * Supports exact types (\"image/png\") and wildcards (\"image/*\").\n * When not set, all file types are accepted.\n */\n accept?: string[];\n /**\n * Maximum file size in bytes for uploads.\n * When not set, no size limit is enforced (beyond storage provider limits).\n */\n maxSize?: number;\n}\n\n/** Upload field — single reference variant. */\nexport interface UploadFieldSingle extends UploadFieldBase {\n hasMany?: false;\n}\n\n/** Upload field — multi-reference variant. */\nexport interface UploadFieldMany extends UploadFieldBase {\n /** Display labels for the field (singular/plural). */\n labels?: Labels;\n hasMany: true;\n}\n\n/**\n * Upload field definition. References a media collection document via `v.id()`.\n * Discriminated on `hasMany`.\n */\nexport type UploadFieldDef = UploadFieldSingle | UploadFieldMany;\n\n/** JSON field definition. Stores arbitrary data via `v.any()`. */\nexport interface JsonFieldDef extends BaseField {\n readonly type: \"json\";\n}\n\n/** Object field definition. Stores a named group of sub-fields as `v.object()`. */\nexport interface ObjectFieldDef extends BaseField {\n readonly type: \"object\";\n /** Named sub-fields that make up this object. */\n fields: Record<string, VexField>;\n}\n\n/** Array field definition. Wraps an inner field in `v.array()`. */\nexport interface ArrayFieldDef extends BaseField {\n readonly type: \"array\";\n /** Display labels for the field (singular/plural). */\n labels?: Labels;\n /** The field type for each item in the array. */\n items: VexField;\n /** Default value for the array (used when creating new documents/blocks). */\n defaultValue?: unknown[];\n /** Minimum number of items. */\n min?: number;\n /** Maximum number of items. */\n max?: number;\n}\n\nimport type { VexEditorAdapter, RichTextDocument } from \"./editor\";\n\n/** Rich text field definition. Stores Plate/Slate JSON via `v.any()`. */\nexport interface RichTextFieldDef extends BaseField {\n readonly type: \"richtext\";\n /**\n * Editor adapter override for this specific field.\n * If not set, uses the global editor from `VexConfig.editor`.\n */\n editor?: VexEditorAdapter;\n /**\n * Media collection slug for image uploads.\n * When set, the editor can pick images from the specified media collection,\n * and paste/drop image uploads are auto-saved to this collection.\n * When not set, images can only be inserted by URL.\n */\n mediaCollection?: string;\n}\n\n/**\n * Color picker field. Stores a color string in the configured format.\n *\n * @example\n * ```ts\n * accentColor: color({ label: \"Accent Color\", format: \"hex\" })\n * primaryColor: color({ label: \"Primary\", format: \"oklch\", themeColors: true })\n * ```\n */\nexport interface ColorFieldDef extends BaseField {\n readonly type: \"color\";\n /**\n * Default color value.\n * Should be in the configured format (hex, hsl, or oklch).\n */\n defaultValue?: string;\n /**\n * Output format for the color value.\n * - \"hex\" — e.g., \"#3b82f6\" (default)\n * - \"hsl\" — e.g., \"hsl(217, 91%, 60%)\"\n * - \"oklch\" — e.g., \"oklch(0.623 0.214 259.1)\"\n */\n format?: \"hex\" | \"hsl\" | \"oklch\";\n /**\n * When true, shows a \"Theme Colors\" tab in the color picker\n * that displays CSS variables from the current page's computed styles.\n * Users can select a theme color variable instead of picking a custom color.\n *\n * Default: false\n */\n themeColors?: boolean;\n}\n\n/**\n * A single tab definition within a tabs field.\n */\nexport interface TabDef<\n TSlug extends string = string,\n TFields extends Record<string, VexField> = Record<string, VexField>,\n> {\n /** Display label for the tab in the admin panel. */\n label: string;\n /**\n * All fields in this tab are nested under this key as an object.\n * e.g., `slug: \"light\"` → `{ light: { background: \"#fff\", ... } }`\n */\n slug: TSlug;\n /** Fields within this tab. */\n fields: TFields;\n}\n\n/**\n * Tabs field definition. Groups fields into tabbed UI sections in the admin panel.\n *\n * - Tabs with `slug` create nested objects in the document\n * - Tabs without `slug` flatten their fields onto the parent\n *\n * @example\n * ```ts\n * themeColors: tabs({\n * label: \"Theme Colors\",\n * tabs: [\n * {\n * label: \"Light\",\n * slug: \"light\",\n * fields: {\n * background: color({ label: \"Background\" }),\n * foreground: color({ label: \"Foreground\" }),\n * },\n * },\n * {\n * label: \"Dark\",\n * slug: \"dark\",\n * fields: {\n * background: color({ label: \"Background\" }),\n * foreground: color({ label: \"Foreground\" }),\n * },\n * },\n * ],\n * })\n * ```\n */\nexport interface TabsFieldDef<TTabs extends TabDef[] = TabDef[]> extends BaseField {\n readonly type: \"tabs\";\n /** The tab definitions. */\n tabs: TTabs;\n}\n\n/**\n * UI field definition. Non-persisted — renders a custom component only.\n * Skipped during schema generation, form validation, and column generation.\n * Requires admin.components.Field to be set.\n */\nexport interface UIFieldDef extends BaseField {\n readonly type: \"ui\";\n /**\n * Admin config — components.Field is required for ui fields.\n */\n admin: FieldAdminConfig & {\n components: {\n Field: ComponentType<FieldComponentProps>;\n };\n };\n}\n\n// =============================================================================\n// BLOCK TYPES\n// =============================================================================\n\n/**\n * Admin configuration specific to block definitions.\n */\nexport interface BlockAdminConfig {\n /** Icon identifier for the block picker UI (e.g., \"layout-template\"). */\n icon?: string;\n /** Custom admin components for this block (future — Spec 09b). */\n components?: {\n Editor?: ComponentType<any>;\n };\n /**\n * Enable block style controls in the admin panel.\n *\n * - `true` — enables container styles only (equivalent to `[\"container\"]`)\n * - `StyleTier[]` — enables specific style tiers (e.g., `[\"container\", \"text\", \"media\"]`)\n * - `undefined` / omitted — no style controls shown\n *\n * Available tiers: \"container\", \"text\", \"layout\", \"media\"\n */\n blockStyles?: true | StyleTier[];\n}\n\n/**\n * A block definition created by `defineBlock()`.\n * Blocks are reusable field groups composed into ordered lists via the `blocks()` field type.\n *\n * @example\n * ```ts\n * const heroBlock = defineBlock({\n * slug: \"hero\",\n * label: \"Hero Section\",\n * fields: { heading: text({ required: true }), subheading: text() },\n * })\n * ```\n */\nexport interface BlockDef<TFields extends Record<string, VexField> = Record<string, VexField>> {\n /** Unique identifier for this block type. Used as the `blockType` discriminant in stored data. */\n readonly slug: string;\n /** Display label for the block in the admin picker. */\n label: string;\n /** Field definitions for this block's data shape. */\n fields: TFields;\n /** Admin UI configuration. */\n admin?: BlockAdminConfig;\n /**\n * TypeScript interface name used in generated `vex.types.ts`.\n * If not set, auto-generated from slug via PascalCase conversion.\n * @example \"HeroBlock\"\n */\n interfaceName?: string;\n}\n\n/** Reserved field names that cannot be used in block field definitions. */\nexport const RESERVED_BLOCK_FIELD_NAMES = [\"blockType\", \"blockName\", \"_key\", \"blockStyles\"] as const;\n\n/** Blocks field definition. Stores an ordered array of block instances. */\nexport interface BlocksFieldDef extends BaseField {\n readonly type: \"blocks\";\n /** The block definitions allowed in this field. */\n blocks: BlockDef[];\n /** Display labels for the field (singular/plural). */\n labels?: Labels;\n /** Minimum number of blocks. */\n min?: number;\n /** Maximum number of blocks. */\n max?: number;\n}\n\n// =============================================================================\n// UTILITY TYPES\n// =============================================================================\n\n/**\n * Distributive version of `Omit` that preserves union branches.\n * Standard `Omit` collapses unions; this applies `Omit` to each branch individually.\n */\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown\n ? Omit<T, K>\n : never;\n\n// =============================================================================\n// DISCRIMINATED UNION\n// =============================================================================\n\n/**\n * Discriminated union of all field types. Switch on `field.type` to narrow.\n *\n * @example\n * ```ts\n * function handle(field: VexField) {\n * switch (field.type) {\n * case \"text\":\n * field.maxLength; // TextFieldDef ✓\n * break;\n * case \"select\":\n * field.options; // SelectFieldDef ✓\n * break;\n * }\n * }\n * ```\n */\nexport type VexField =\n | TextFieldDef\n | NumberFieldDef\n | CheckboxFieldDef\n | SelectFieldDef<string>\n | DateFieldDef\n | ImageUrlFieldDef\n | RelationshipFieldDef\n | UploadFieldDef\n | JsonFieldDef\n | ObjectFieldDef\n | ArrayFieldDef\n | RichTextFieldDef\n | UIFieldDef\n | BlocksFieldDef\n | ColorFieldDef\n | TabsFieldDef;\n\n// =============================================================================\n// TYPE INFERENCE\n// =============================================================================\n\n/**\n * Infer the TypeScript value type from a VexField.\n * Uses the `type` discriminant and field options to determine the type.\n */\nexport type InferFieldType<F extends VexField> = F extends { type: \"text\" }\n ? string\n : F extends { type: \"number\" }\n ? number\n : F extends { type: \"checkbox\" }\n ? boolean\n : F extends { type: \"select\"; hasMany: true }\n ? string[]\n : F extends { type: \"select\" }\n ? string\n : F extends { type: \"date\" }\n ? number\n : F extends { type: \"imageUrl\" }\n ? string\n : F extends { type: \"relationship\"; hasMany: true }\n ? string[]\n : F extends { type: \"relationship\" }\n ? string\n : F extends { type: \"upload\"; hasMany: true }\n ? string[]\n : F extends { type: \"upload\" }\n ? string\n : F extends { type: \"json\" }\n ? unknown\n : F extends { type: \"object\" }\n ? Record<string, unknown>\n : F extends { type: \"richtext\" }\n ? RichTextDocument\n : F extends { type: \"blocks\" }\n ? Array<InferBlockUnion<F>>\n : F extends { type: \"array\" }\n ? unknown[]\n : F extends { type: \"ui\" }\n ? never\n : F extends { type: \"color\" }\n ? string\n : F extends { type: \"tabs\" }\n ? Record<string, unknown>\n : never;\n\n/**\n * Infer the discriminated union type for a blocks field.\n * Each block becomes an object type with `blockType` literal + `_key` + its field types.\n */\nexport type InferBlockUnion<F extends VexField> = F extends BlocksFieldDef\n ? F[\"blocks\"][number] extends infer B\n ? B extends BlockDef<infer TFields>\n ? { blockType: B[\"slug\"]; blockName?: string; _key: string } & {\n [K in keyof TFields]: InferFieldType<TFields[K] & VexField>;\n }\n : never\n : never\n : never;\n\n/**\n * Infer the expanded tab fields from a tabs field definition.\n * Each tab becomes a property keyed by its slug with an object of its inferred fields.\n */\ntype InferTabsExpansion<F extends TabsFieldDef> =\n F[\"tabs\"][number] extends infer T\n ? T extends TabDef<infer TSlug, infer TFields>\n ? { [K in TSlug]?: { [FK in keyof TFields]: InferFieldType<TFields[FK] & VexField> } }\n : {}\n : {};\n\n/**\n * Extract keys of fields that are tabs fields.\n */\ntype TabsFieldKeys<F extends Record<string, any>> = {\n [K in keyof F]: (F[K] & VexField) extends { type: \"tabs\" } ? K : never;\n}[keyof F];\n\n/**\n * Extract keys of fields that are NOT tabs fields.\n */\ntype NonTabsFieldKeys<F extends Record<string, any>> = {\n [K in keyof F]: (F[K] & VexField) extends { type: \"tabs\" } ? never : K;\n}[keyof F];\n\n/**\n * Expand all tabs fields in a record into their tab slug entries.\n * Produces a union of objects (one per tabs field) which gets intersected.\n */\ntype ExpandTabsFields<F extends Record<string, any>> =\n TabsFieldKeys<F> extends infer TK\n ? TK extends keyof F\n ? InferTabsExpansion<F[TK] & TabsFieldDef>\n : {}\n : {};\n\n/**\n * Infer the document type from a record of fields.\n * Tabs fields are expanded: instead of `colors: Record<string, unknown>`,\n * produces `light?: { ... }; dark?: { ... }` based on the tab definitions.\n *\n * @example\n * ```ts\n * type Doc = InferFieldsType<{\n * title: { type: \"text\"; required: true };\n * count: { type: \"number\" };\n * }>;\n * // { title: string; count: number }\n * ```\n */\nexport type InferFieldsType<F extends Record<string, VexField>> =\n // When F is `any`, fall back to a simple index signature to avoid conditional type issues\n 0 extends (1 & F)\n ? { [x: string]: unknown }\n : {\n [K in NonTabsFieldKeys<F> & keyof F]: InferFieldType<F[K] & VexField>;\n } & UnionToIntersection<ExpandTabsFields<F>>;\n\n/**\n * Convert a union to an intersection.\n * Used to merge expanded tab objects into a single type.\n */\ntype UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;\n","import type { BlockDef, VexField } from \"../types\";\nimport { RESERVED_BLOCK_FIELD_NAMES } from \"../types/fields\";\nimport { VexBlockValidationError } from \"../errors\";\n\n/**\n * Define a block type for use with the `blocks()` field.\n *\n * @param props.slug - Unique identifier for this block type\n * @param props.label - Display label for the admin picker\n * @param props.fields - Field definitions for this block's data shape\n * @param props.admin - Optional admin UI configuration (icon, custom components)\n * @returns A BlockDef object\n *\n * @throws VexBlockValidationError if slug is empty or contains invalid characters\n * @throws VexBlockValidationError if any field name is reserved (blockType, _key)\n *\n * @example\n * ```ts\n * const heroBlock = defineBlock({\n * slug: \"hero\",\n * label: \"Hero Section\",\n * fields: {\n * heading: text({ required: true }),\n * subheading: text(),\n * },\n * })\n * ```\n */\nexport function defineBlock<TFields extends Record<string, VexField>>(props: {\n slug: string;\n label: string;\n fields: TFields;\n admin?: BlockDef[\"admin\"];\n interfaceName?: string;\n}): BlockDef<TFields> {\n if (!props.slug || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(props.slug)) {\n throw new VexBlockValidationError(\n props.slug || \"(empty)\",\n `Invalid block slug \"${props.slug}\". Slugs must start with a letter and contain only letters, numbers, hyphens, and underscores.`,\n );\n }\n\n for (const fieldName of Object.keys(props.fields)) {\n if ((RESERVED_BLOCK_FIELD_NAMES as readonly string[]).includes(fieldName)) {\n throw new VexBlockValidationError(\n props.slug,\n `Field name \"${fieldName}\" is reserved in block definitions. Reserved names: ${RESERVED_BLOCK_FIELD_NAMES.join(\", \")}`,\n );\n }\n }\n\n // Validate admin.blockStyles\n const VALID_STYLE_TIERS = [\"container\", \"text\", \"layout\", \"media\"];\n\n if (props.admin?.blockStyles && props.admin.blockStyles !== true) {\n if (!Array.isArray(props.admin.blockStyles)) {\n throw new VexBlockValidationError(\n props.slug,\n `admin.blockStyles must be true or an array of style tier names. Got: ${typeof props.admin.blockStyles}`,\n );\n }\n for (const tier of props.admin.blockStyles) {\n if (!VALID_STYLE_TIERS.includes(tier)) {\n throw new VexBlockValidationError(\n props.slug,\n `Invalid style tier \"${tier}\" in admin.blockStyles. Valid tiers: ${VALID_STYLE_TIERS.join(\", \")}`,\n );\n }\n }\n }\n\n return {\n slug: props.slug,\n label: props.label,\n fields: props.fields,\n admin: props.admin,\n interfaceName: props.interfaceName,\n };\n}\n","export interface StylePreset {\n /** Tailwind scale value (stored in blockStyles JSON). */\n value: string;\n /** Display label in the popover. */\n label: string;\n /** Size hint shown next to the label (e.g., \"16px / 1rem\"). */\n hint: string;\n}\n\n// ---------------------------------------------------------------------------\n// Spacing presets (margin, padding, gap)\n// ---------------------------------------------------------------------------\n\nexport const SPACING_PRESETS: StylePreset[] = [\n { value: \"0\", label: \"0\", hint: \"0px\" },\n { value: \"0.5\", label: \"0.5\", hint: \"2px / 0.125rem\" },\n { value: \"1\", label: \"1\", hint: \"4px / 0.25rem\" },\n { value: \"1.5\", label: \"1.5\", hint: \"6px / 0.375rem\" },\n { value: \"2\", label: \"2\", hint: \"8px / 0.5rem\" },\n { value: \"3\", label: \"3\", hint: \"12px / 0.75rem\" },\n { value: \"4\", label: \"4\", hint: \"16px / 1rem\" },\n { value: \"5\", label: \"5\", hint: \"20px / 1.25rem\" },\n { value: \"6\", label: \"6\", hint: \"24px / 1.5rem\" },\n { value: \"8\", label: \"8\", hint: \"32px / 2rem\" },\n { value: \"10\", label: \"10\", hint: \"40px / 2.5rem\" },\n { value: \"12\", label: \"12\", hint: \"48px / 3rem\" },\n { value: \"16\", label: \"16\", hint: \"64px / 4rem\" },\n { value: \"20\", label: \"20\", hint: \"80px / 5rem\" },\n { value: \"24\", label: \"24\", hint: \"96px / 6rem\" },\n];\n\n// ---------------------------------------------------------------------------\n// Font size presets\n// ---------------------------------------------------------------------------\n\nexport const FONT_SIZE_PRESETS: StylePreset[] = [\n { value: \"xs\", label: \"XS\", hint: \"12px / 0.75rem\" },\n { value: \"sm\", label: \"SM\", hint: \"14px / 0.875rem\" },\n { value: \"base\", label: \"Base\", hint: \"16px / 1rem\" },\n { value: \"lg\", label: \"LG\", hint: \"18px / 1.125rem\" },\n { value: \"xl\", label: \"XL\", hint: \"20px / 1.25rem\" },\n { value: \"2xl\", label: \"2XL\", hint: \"24px / 1.5rem\" },\n { value: \"3xl\", label: \"3XL\", hint: \"30px / 1.875rem\" },\n { value: \"4xl\", label: \"4XL\", hint: \"36px / 2.25rem\" },\n { value: \"5xl\", label: \"5XL\", hint: \"48px / 3rem\" },\n];\n\n// ---------------------------------------------------------------------------\n// Font weight presets\n// ---------------------------------------------------------------------------\n\nexport const FONT_WEIGHT_PRESETS: StylePreset[] = [\n { value: \"thin\", label: \"Thin\", hint: \"100\" },\n { value: \"light\", label: \"Light\", hint: \"300\" },\n { value: \"normal\", label: \"Normal\", hint: \"400\" },\n { value: \"medium\", label: \"Medium\", hint: \"500\" },\n { value: \"semibold\", label: \"Semibold\", hint: \"600\" },\n { value: \"bold\", label: \"Bold\", hint: \"700\" },\n { value: \"extrabold\", label: \"Extra Bold\", hint: \"800\" },\n];\n\n// ---------------------------------------------------------------------------\n// Border radius presets\n// ---------------------------------------------------------------------------\n\nexport const BORDER_RADIUS_PRESETS: StylePreset[] = [\n { value: \"none\", label: \"None\", hint: \"0px\" },\n { value: \"sm\", label: \"SM\", hint: \"2px / 0.125rem\" },\n { value: \"DEFAULT\", label: \"Default\", hint: \"4px / 0.25rem\" },\n { value: \"md\", label: \"MD\", hint: \"6px / 0.375rem\" },\n { value: \"lg\", label: \"LG\", hint: \"8px / 0.5rem\" },\n { value: \"xl\", label: \"XL\", hint: \"12px / 0.75rem\" },\n { value: \"2xl\", label: \"2XL\", hint: \"16px / 1rem\" },\n { value: \"3xl\", label: \"3XL\", hint: \"24px / 1.5rem\" },\n { value: \"full\", label: \"Full\", hint: \"9999px\" },\n];\n\n// ---------------------------------------------------------------------------\n// Box shadow presets\n// ---------------------------------------------------------------------------\n\nexport const BOX_SHADOW_PRESETS: StylePreset[] = [\n { value: \"none\", label: \"None\", hint: \"no shadow\" },\n { value: \"sm\", label: \"SM\", hint: \"small\" },\n { value: \"DEFAULT\", label: \"Default\", hint: \"medium\" },\n { value: \"md\", label: \"MD\", hint: \"medium\" },\n { value: \"lg\", label: \"LG\", hint: \"large\" },\n { value: \"xl\", label: \"XL\", hint: \"extra large\" },\n { value: \"2xl\", label: \"2XL\", hint: \"xx-large\" },\n];\n\n// ---------------------------------------------------------------------------\n// Opacity presets\n// ---------------------------------------------------------------------------\n\nexport const OPACITY_PRESETS: StylePreset[] = [\n { value: \"0\", label: \"0%\", hint: \"invisible\" },\n { value: \"5\", label: \"5%\", hint: \"\" },\n { value: \"10\", label: \"10%\", hint: \"\" },\n { value: \"25\", label: \"25%\", hint: \"\" },\n { value: \"50\", label: \"50%\", hint: \"\" },\n { value: \"75\", label: \"75%\", hint: \"\" },\n { value: \"100\", label: \"100%\", hint: \"fully visible\" },\n];\n\n// ---------------------------------------------------------------------------\n// Width presets\n// ---------------------------------------------------------------------------\n\nexport const WIDTH_PRESETS: StylePreset[] = [\n { value: \"auto\", label: \"Auto\", hint: \"auto\" },\n { value: \"full\", label: \"Full\", hint: \"100%\" },\n { value: \"screen\", label: \"Screen\", hint: \"100vw\" },\n { value: \"1/2\", label: \"1/2\", hint: \"50%\" },\n { value: \"1/3\", label: \"1/3\", hint: \"33.33%\" },\n { value: \"2/3\", label: \"2/3\", hint: \"66.67%\" },\n { value: \"1/4\", label: \"1/4\", hint: \"25%\" },\n { value: \"3/4\", label: \"3/4\", hint: \"75%\" },\n { value: \"max\", label: \"Max Content\", hint: \"max-content\" },\n { value: \"fit\", label: \"Fit Content\", hint: \"fit-content\" },\n];\n\n// ---------------------------------------------------------------------------\n// Max-width presets\n// ---------------------------------------------------------------------------\n\nexport const MAX_WIDTH_PRESETS: StylePreset[] = [\n { value: \"none\", label: \"None\", hint: \"no limit\" },\n { value: \"xs\", label: \"XS\", hint: \"320px / 20rem\" },\n { value: \"sm\", label: \"SM\", hint: \"384px / 24rem\" },\n { value: \"md\", label: \"MD\", hint: \"448px / 28rem\" },\n { value: \"lg\", label: \"LG\", hint: \"512px / 32rem\" },\n { value: \"xl\", label: \"XL\", hint: \"576px / 36rem\" },\n { value: \"2xl\", label: \"2XL\", hint: \"672px / 42rem\" },\n { value: \"3xl\", label: \"3XL\", hint: \"768px / 48rem\" },\n { value: \"4xl\", label: \"4XL\", hint: \"896px / 56rem\" },\n { value: \"5xl\", label: \"5XL\", hint: \"1024px / 64rem\" },\n { value: \"6xl\", label: \"6XL\", hint: \"1152px / 72rem\" },\n { value: \"7xl\", label: \"7XL\", hint: \"1280px / 80rem\" },\n { value: \"full\", label: \"Full\", hint: \"100%\" },\n { value: \"screen\", label: \"Screen\", hint: \"100vw\" },\n];\n\n// ---------------------------------------------------------------------------\n// Line height presets\n// ---------------------------------------------------------------------------\n\nexport const LINE_HEIGHT_PRESETS: StylePreset[] = [\n { value: \"none\", label: \"None\", hint: \"1\" },\n { value: \"tight\", label: \"Tight\", hint: \"1.25\" },\n { value: \"snug\", label: \"Snug\", hint: \"1.375\" },\n { value: \"normal\", label: \"Normal\", hint: \"1.5\" },\n { value: \"relaxed\", label: \"Relaxed\", hint: \"1.625\" },\n { value: \"loose\", label: \"Loose\", hint: \"2\" },\n];\n\n// ---------------------------------------------------------------------------\n// Letter spacing presets\n// ---------------------------------------------------------------------------\n\nexport const LETTER_SPACING_PRESETS: StylePreset[] = [\n { value: \"tighter\", label: \"Tighter\", hint: \"-0.05em\" },\n { value: \"tight\", label: \"Tight\", hint: \"-0.025em\" },\n { value: \"normal\", label: \"Normal\", hint: \"0em\" },\n { value: \"wide\", label: \"Wide\", hint: \"0.025em\" },\n { value: \"wider\", label: \"Wider\", hint: \"0.05em\" },\n { value: \"widest\", label: \"Widest\", hint: \"0.1em\" },\n];\n\n// ---------------------------------------------------------------------------\n// Border width presets\n// ---------------------------------------------------------------------------\n\nexport const BORDER_WIDTH_PRESETS: StylePreset[] = [\n { value: \"0\", label: \"None\", hint: \"0px\" },\n { value: \"DEFAULT\", label: \"Default\", hint: \"1px\" },\n { value: \"2\", label: \"2\", hint: \"2px\" },\n { value: \"4\", label: \"4\", hint: \"4px\" },\n { value: \"8\", label: \"8\", hint: \"8px\" },\n];\n\n// ---------------------------------------------------------------------------\n// Aspect ratio presets\n// ---------------------------------------------------------------------------\n\nexport const ASPECT_RATIO_PRESETS: StylePreset[] = [\n { value: \"auto\", label: \"Auto\", hint: \"auto\" },\n { value: \"square\", label: \"Square\", hint: \"1 / 1\" },\n { value: \"video\", label: \"Video\", hint: \"16 / 9\" },\n { value: \"4/3\", label: \"4:3\", hint: \"4 / 3\" },\n { value: \"3/2\", label: \"3:2\", hint: \"3 / 2\" },\n];\n","import type { BlockStylesData, BlockStyleValues } from \"./types\";\n\n/**\n * Property-to-Tailwind class mapping.\n * Each function takes a style value and returns the corresponding Tailwind class.\n */\nconst PROPERTY_CLASS_MAP: Record<\n keyof BlockStyleValues,\n (v: string) => string\n> = {\n // Container — spacing\n margin: (v) => `m-${v}`,\n marginTop: (v) => `mt-${v}`,\n marginRight: (v) => `mr-${v}`,\n marginBottom: (v) => `mb-${v}`,\n marginLeft: (v) => `ml-${v}`,\n padding: (v) => `p-${v}`,\n paddingTop: (v) => `pt-${v}`,\n paddingRight: (v) => `pr-${v}`,\n paddingBottom: (v) => `pb-${v}`,\n paddingLeft: (v) => `pl-${v}`,\n\n // Container — sizing\n width: (v) => `w-${v}`,\n maxWidth: (v) => `max-w-${v}`,\n\n // Container — background\n backgroundColor: (v) => {\n if (\n v.startsWith(\"var(\") ||\n v.startsWith(\"#\") ||\n v.startsWith(\"rgb\") ||\n v.startsWith(\"hsl\") ||\n v.startsWith(\"oklch\")\n ) {\n return `bg-[${v}]`;\n }\n return `bg-${v}`;\n },\n\n // Container — border\n borderWidth: (v) => (v === \"DEFAULT\" ? \"border\" : `border-${v}`),\n borderColor: (v) => {\n if (\n v.startsWith(\"var(\") ||\n v.startsWith(\"#\") ||\n v.startsWith(\"rgb\") ||\n v.startsWith(\"hsl\") ||\n v.startsWith(\"oklch\")\n ) {\n return `border-[${v}]`;\n }\n return `border-${v}`;\n },\n borderStyle: (v) => `border-${v}`,\n borderRadius: (v) => (v === \"DEFAULT\" ? \"rounded\" : `rounded-${v}`),\n\n // Container — effects\n boxShadow: (v) => (v === \"DEFAULT\" ? \"shadow\" : `shadow-${v}`),\n opacity: (v) => `opacity-${v}`,\n\n // Container — display\n display: (v) => {\n if (v === \"inline-flex\") return \"inline-flex\";\n return v;\n },\n overflow: (v) => `overflow-${v}`,\n\n // Text\n textAlign: (v) => `text-${v}`,\n fontSize: (v) => `text-${v}`,\n fontWeight: (v) => `font-${v}`,\n color: (v) => {\n if (\n v.startsWith(\"var(\") ||\n v.startsWith(\"#\") ||\n v.startsWith(\"rgb\") ||\n v.startsWith(\"hsl\") ||\n v.startsWith(\"oklch\")\n ) {\n return `text-[${v}]`;\n }\n return `text-${v}`;\n },\n lineHeight: (v) => `leading-${v}`,\n letterSpacing: (v) => `tracking-${v}`,\n\n // Layout\n gap: (v) => `gap-${v}`,\n flexDirection: (v) => {\n const map: Record<string, string> = {\n row: \"flex-row\",\n column: \"flex-col\",\n \"row-reverse\": \"flex-row-reverse\",\n \"column-reverse\": \"flex-col-reverse\",\n };\n return map[v] ?? `flex-${v}`;\n },\n alignItems: (v) => `items-${v}`,\n justifyContent: (v) => `justify-${v}`,\n flexWrap: (v) => `flex-${v}`,\n\n // Media\n objectFit: (v) => `object-${v}`,\n aspectRatio: (v) => `aspect-${v}`,\n objectPosition: (v) => `object-${v}`,\n};\n\n/**\n * Convert a single breakpoint's style values into an array of Tailwind classes.\n */\nfunction stylesToClasses(props: { styles: BlockStyleValues }): string[] {\n const classes: string[] = [];\n\n for (const [key, value] of Object.entries(props.styles)) {\n if (value === undefined || value === null || value === \"\") continue;\n\n const mapper = PROPERTY_CLASS_MAP[key as keyof BlockStyleValues];\n if (!mapper) continue;\n\n classes.push(mapper(String(value)));\n }\n\n return classes;\n}\n\n/**\n * Convert a blockStyles JSON string into a Tailwind class string.\n *\n * Handles responsive breakpoint prefixes. The \"base\" breakpoint has no prefix,\n * all other breakpoints use their key as prefix (e.g., \"sm:\", \"md:\", \"lg:\").\n *\n * @param props.blockStylesJson - The raw JSON string from the block instance's blockStyles field\n * @returns Tailwind class string ready to use in className, or empty string if input is empty/invalid\n *\n * @example\n * ```ts\n * blockStylesToTailwind({\n * blockStylesJson: '{\"base\":{\"margin\":\"4\",\"padding\":\"2\"},\"sm\":{\"margin\":\"6\"}}'\n * })\n * // → \"m-4 p-2 sm:m-6\"\n * ```\n */\nexport function blockStylesToTailwind(props: {\n blockStylesJson: string | undefined;\n}): string {\n if (!props.blockStylesJson) return \"\";\n\n let data: BlockStylesData;\n try {\n data = JSON.parse(props.blockStylesJson);\n } catch {\n return \"\";\n }\n\n const result: string[] = [];\n\n // Process \"base\" first (no breakpoint prefix)\n if (data.base) {\n result.push(...stylesToClasses({ styles: data.base }));\n }\n\n // Process remaining breakpoints sorted alphabetically for deterministic output\n const breakpointKeys = Object.keys(data)\n .filter((k) => k !== \"base\")\n .sort();\n\n for (const bp of breakpointKeys) {\n const classes = stylesToClasses({ styles: data[bp] });\n for (const cls of classes) {\n result.push(`${bp}:${cls}`);\n }\n }\n\n return result.join(\" \");\n}\n","/**\n * Convert a slug string to a PascalCase interface name.\n *\n * @param props.slug - The slug to convert (e.g., \"blog-posts\", \"new_block\", \"media\")\n * @returns PascalCase string (e.g., \"BlogPosts\", \"NewBlock\", \"Media\")\n */\nexport function slugToInterfaceName(props: { slug: string }): string {\n return props.slug\n .replace(/[-_]+/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .split(/\\s+/)\n .filter(Boolean)\n .map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1).toLowerCase())\n .join(\"\");\n}\n","import type { VexField } from \"../types\";\nimport { slugToInterfaceName } from \"./slugToInterfaceName\";\n\n/**\n * Convert a VexField to its TypeScript type string for generated interfaces.\n *\n * @param props.field - The field definition\n * @param props.blockInterfaceNames - Map of block slug → interface name (for blocks fields)\n * @returns TypeScript type string (e.g., \"string\", \"number\", \"'draft' | 'published'\", \"HeroBlock[]\")\n */\nexport function fieldToTypeString(props: {\n field: VexField;\n blockInterfaceNames?: Map<string, string>;\n}): string {\n switch (props.field.type) {\n case \"text\":\n return \"string\";\n case \"number\":\n return \"number\";\n case \"checkbox\":\n return \"boolean\";\n case \"date\":\n return \"number\";\n case \"imageUrl\":\n return \"string\";\n case \"json\":\n return \"Record<string, unknown>\";\n case \"object\":\n return \"Record<string, unknown>\";\n case \"richtext\":\n return \"RichTextDocument\";\n case \"color\":\n return \"string\";\n case \"tabs\":\n return \"Record<string, unknown>\";\n case \"ui\":\n return \"never\";\n\n case \"select\": {\n const values = props.field.options.map((o) => o.value);\n if (values.length === 0) return \"string\";\n const union = values.map((v) => `'${v}'`).join(\" | \");\n if (props.field.hasMany) {\n return `(${union})[]`;\n }\n return union;\n }\n\n case \"relationship\": {\n const idType = `Id<'${props.field.to}'>`;\n return props.field.hasMany ? `${idType}[]` : idType;\n }\n\n case \"upload\": {\n const idType = `Id<'${props.field.to}'>`;\n return props.field.hasMany ? `${idType}[]` : idType;\n }\n\n case \"array\": {\n const inner = fieldToTypeString({\n field: props.field.items,\n blockInterfaceNames: props.blockInterfaceNames,\n });\n const needsParens = inner.includes(\"|\");\n return needsParens ? `(${inner})[]` : `${inner}[]`;\n }\n\n case \"blocks\": {\n const names = props.field.blocks.map((b) => {\n if (props.blockInterfaceNames?.has(b.slug)) {\n return props.blockInterfaceNames.get(b.slug)!;\n }\n return b.interfaceName ?? slugToInterfaceName({ slug: b.slug });\n });\n if (names.length === 0) return \"unknown[]\";\n if (names.length === 1) return `${names[0]}[]`;\n return `(${names.join(\" | \")})[]`;\n }\n\n default:\n return \"unknown\";\n }\n}\n","import type { VexConfig, VexField, BlockDef } from \"../types\";\nimport type { TabsFieldDef } from \"../types/fields\";\nimport { mergeAuthCollectionWithUserCollection } from \"../valueTypes/merge\";\nimport { LOCKED_MEDIA_FIELDS, OVERRIDABLE_MEDIA_FIELDS } from \"../types/media\";\nimport { fieldToTypeString } from \"./fieldToTypeString\";\nimport { slugToInterfaceName } from \"./slugToInterfaceName\";\nimport { VexError } from \"../errors\";\n\n/**\n * Generate the complete TypeScript source for `vex.types.ts`.\n *\n * @param props.config - The resolved VexConfig\n * @returns TypeScript source code string\n */\nexport function generateVexTypes(props: { config: VexConfig }): string {\n const config = props.config;\n const parts: string[] = [];\n\n // ── 1. Collect all blocks and build name maps ──\n\n const blocksBySlug = new Map<string, BlockDef>();\n const blockInterfaceNames = new Map<string, string>();\n\n function collectBlocks(fields: Record<string, VexField>) {\n for (const field of Object.values(fields)) {\n if (field.type === \"blocks\") {\n for (const block of field.blocks) {\n if (!blocksBySlug.has(block.slug)) {\n blocksBySlug.set(block.slug, block);\n collectBlocks(block.fields as Record<string, VexField>);\n }\n }\n } else if (field.type === \"tabs\") {\n for (const tab of (field as TabsFieldDef).tabs) {\n collectBlocks(tab.fields as Record<string, VexField>);\n }\n }\n }\n }\n\n for (const col of config.collections) {\n collectBlocks(col.fields as Record<string, VexField>);\n }\n if (config.media?.collections) {\n for (const col of config.media.collections) {\n collectBlocks(col.fields as Record<string, VexField>);\n }\n }\n for (const g of config.globals) {\n collectBlocks(g.fields as Record<string, VexField>);\n }\n\n for (const [slug, block] of blocksBySlug) {\n blockInterfaceNames.set(\n slug,\n block.interfaceName ?? slugToInterfaceName({ slug }),\n );\n }\n\n // ── 2. Build collection & global name maps, check for duplicates ──\n\n const allNames = new Map<string, string>(); // name → source description\n\n function registerName(name: string, source: string) {\n if (allNames.has(name)) {\n throw new VexError(\n `Duplicate interface name \"${name}\" — used by ${allNames.get(name)} and ${source}. ` +\n `Set a unique \\`interfaceName\\` on one of them.`,\n );\n }\n allNames.set(name, source);\n }\n\n const collectionNames = new Map<string, string>(); // slug → interfaceName\n for (const col of config.collections) {\n const name = col.interfaceName ?? slugToInterfaceName({ slug: col.slug });\n registerName(name, `collection \"${col.slug}\"`);\n collectionNames.set(col.slug, name);\n }\n\n if (config.media?.collections) {\n for (const col of config.media.collections) {\n const name = col.interfaceName ?? slugToInterfaceName({ slug: col.slug });\n registerName(name, `media collection \"${col.slug}\"`);\n collectionNames.set(col.slug, name);\n }\n }\n\n // Auth-only collections (not matched to user collections)\n const authCollectionMap = new Map(\n config.auth.collections.map((c) => [c.slug, c]),\n );\n const userCollectionSlugs = new Set(config.collections.map((c) => c.slug));\n const mediaSlugs = new Set(\n (config.media?.collections ?? []).map((c) => c.slug),\n );\n for (const authCol of config.auth.collections) {\n if (!userCollectionSlugs.has(authCol.slug) && !mediaSlugs.has(authCol.slug)) {\n const name = authCol.interfaceName ?? slugToInterfaceName({ slug: authCol.slug });\n registerName(name, `auth collection \"${authCol.slug}\"`);\n collectionNames.set(authCol.slug, name);\n }\n }\n\n const globalNames = new Map<string, string>();\n for (const g of config.globals) {\n const name = g.interfaceName ?? slugToInterfaceName({ slug: g.slug });\n registerName(name, `global \"${g.slug}\"`);\n globalNames.set(g.slug, name);\n }\n\n for (const [slug, name] of blockInterfaceNames) {\n registerName(name, `block \"${slug}\"`);\n }\n\n // ── 3. Check if Id import is needed ──\n\n let needsIdImport = false;\n function checkForIdFields(fields: Record<string, VexField>) {\n for (const field of Object.values(fields)) {\n if (field.type === \"relationship\" || field.type === \"upload\") {\n needsIdImport = true;\n } else if (field.type === \"tabs\") {\n for (const tab of (field as TabsFieldDef).tabs) {\n checkForIdFields(tab.fields as Record<string, VexField>);\n }\n }\n }\n }\n for (const col of config.collections) {\n checkForIdFields(col.fields as Record<string, VexField>);\n }\n if (config.media?.collections) {\n for (const col of config.media.collections) {\n checkForIdFields(col.fields as Record<string, VexField>);\n }\n }\n for (const g of config.globals) {\n checkForIdFields(g.fields as Record<string, VexField>);\n }\n for (const block of blocksBySlug.values()) {\n checkForIdFields(block.fields as Record<string, VexField>);\n }\n // Collections always have _id which is Id<slug>, so always need it\n if (config.collections.length > 0 || (config.media?.collections?.length ?? 0) > 0 || config.globals.length > 0) {\n needsIdImport = true;\n }\n\n // Check if RichTextDocument import is needed\n let needsRichTextImport = false;\n function checkForRichTextFields(fields: Record<string, VexField>) {\n for (const field of Object.values(fields)) {\n if (field.type === \"richtext\") {\n needsRichTextImport = true;\n } else if (field.type === \"tabs\") {\n for (const tab of (field as TabsFieldDef).tabs) {\n checkForRichTextFields(tab.fields as Record<string, VexField>);\n }\n }\n }\n }\n for (const col of config.collections) {\n checkForRichTextFields(col.fields as Record<string, VexField>);\n }\n if (config.media?.collections) {\n for (const col of config.media.collections) {\n checkForRichTextFields(col.fields as Record<string, VexField>);\n }\n }\n for (const g of config.globals) {\n checkForRichTextFields(g.fields as Record<string, VexField>);\n }\n for (const block of blocksBySlug.values()) {\n checkForRichTextFields(block.fields as Record<string, VexField>);\n }\n\n // ── 4. File header ──\n\n parts.push(\"// ⚠️ AUTO-GENERATED BY VEX CMS — DO NOT EDIT ⚠️\");\n parts.push(\"\");\n if (needsIdImport) {\n parts.push(\"import type { Id } from './_generated/dataModel';\");\n }\n if (needsRichTextImport) {\n parts.push(\"import type { RichTextDocument } from '@vexcms/core';\");\n }\n if (needsIdImport || needsRichTextImport) {\n parts.push(\"\");\n }\n\n // ── 5. Block interfaces ──\n\n const sortedBlockSlugs = [...blocksBySlug.keys()].sort();\n for (const slug of sortedBlockSlugs) {\n const block = blocksBySlug.get(slug)!;\n const name = blockInterfaceNames.get(slug)!;\n parts.push(generateBlockInterface({ block, name, blockInterfaceNames }));\n parts.push(\"\");\n }\n\n // ── 6. Collection interfaces ──\n\n for (const col of config.collections) {\n const name = collectionNames.get(col.slug)!;\n const authCol = authCollectionMap.get(col.slug);\n let fields: Record<string, VexField>;\n\n if (authCol) {\n const merged = mergeAuthCollectionWithUserCollection({\n authCollection: authCol,\n userCollection: col,\n });\n fields = merged.fields;\n } else {\n fields = col.fields as Record<string, VexField>;\n }\n\n const isVersioned = !!(col as any).versions?.drafts;\n parts.push(\n generateCollectionInterface({\n name,\n slug: col.slug,\n fields,\n isVersioned,\n blockInterfaceNames,\n }),\n );\n parts.push(\"\");\n }\n\n // Auth-only collections\n for (const authCol of config.auth.collections) {\n if (userCollectionSlugs.has(authCol.slug) || mediaSlugs.has(authCol.slug)) continue;\n const name = collectionNames.get(authCol.slug)!;\n parts.push(\n generateCollectionInterface({\n name,\n slug: authCol.slug,\n fields: authCol.fields as Record<string, VexField>,\n isVersioned: false,\n blockInterfaceNames,\n }),\n );\n parts.push(\"\");\n }\n\n // Media collections\n if (config.media?.collections) {\n for (const col of config.media.collections) {\n const name = collectionNames.get(col.slug)!;\n parts.push(\n generateMediaCollectionInterface({\n name,\n slug: col.slug,\n userFields: col.fields as Record<string, VexField>,\n blockInterfaceNames,\n }),\n );\n parts.push(\"\");\n }\n }\n\n // ── 7. Global interfaces ──\n\n for (const g of config.globals) {\n const name = globalNames.get(g.slug)!;\n parts.push(\n generateGlobalInterface({\n name,\n slug: g.slug,\n tableName: g.tableName ?? g.slug,\n fields: g.fields as Record<string, VexField>,\n blockInterfaceNames,\n }),\n );\n parts.push(\"\");\n }\n\n // ── 8. Barrel types ──\n\n if (collectionNames.size > 0) {\n const entries = [...collectionNames.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([slug, name]) => ` ${slug}: ${name};`)\n .join(\"\\n\");\n parts.push(`export interface VexCollectionTypes {\\n${entries}\\n}`);\n parts.push(\"\");\n }\n\n if (globalNames.size > 0) {\n const entries = [...globalNames.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([slug, name]) => ` ${slug}: ${name};`)\n .join(\"\\n\");\n parts.push(`export interface VexGlobalTypes {\\n${entries}\\n}`);\n parts.push(\"\");\n }\n\n return parts.join(\"\\n\");\n}\n\n// ── Helpers ──\n\nfunction generateBlockInterface(props: {\n block: BlockDef;\n name: string;\n blockInterfaceNames: Map<string, string>;\n}): string {\n const lines: string[] = [];\n lines.push(`export interface ${props.name} {`);\n lines.push(` blockType: '${props.block.slug}';`);\n lines.push(` blockName?: string;`);\n lines.push(` _key: string;`);\n\n lines.push(...generateFieldLines({ fields: props.block.fields as Record<string, VexField>, blockInterfaceNames: props.blockInterfaceNames }));\n\n lines.push(\"}\");\n return lines.join(\"\\n\");\n}\n\nfunction generateCollectionInterface(props: {\n name: string;\n slug: string;\n fields: Record<string, VexField>;\n isVersioned: boolean;\n blockInterfaceNames: Map<string, string>;\n}): string {\n const lines: string[] = [];\n lines.push(`export interface ${props.name} {`);\n lines.push(` _id: Id<'${props.slug}'>;`);\n lines.push(` _creationTime: number;`);\n\n if (props.isVersioned) {\n lines.push(` vex_status?: 'draft' | 'published';`);\n lines.push(` vex_version?: number;`);\n lines.push(` vex_publishedAt?: number;`);\n }\n\n lines.push(...generateFieldLines({ fields: props.fields, blockInterfaceNames: props.blockInterfaceNames }));\n\n lines.push(\"}\");\n return lines.join(\"\\n\");\n}\n\nfunction generateMediaCollectionInterface(props: {\n name: string;\n slug: string;\n userFields: Record<string, VexField>;\n blockInterfaceNames: Map<string, string>;\n}): string {\n const lines: string[] = [];\n lines.push(`export interface ${props.name} {`);\n lines.push(` _id: Id<'${props.slug}'>;`);\n lines.push(` _creationTime: number;`);\n\n // Locked fields\n lines.push(` storageId: string;`);\n lines.push(` filename: string;`);\n lines.push(` mimeType: string;`);\n lines.push(` size: number;`);\n\n // Overridable fields (optional unless user defines them)\n lines.push(` url?: string;`);\n lines.push(` width?: number;`);\n lines.push(` height?: number;`);\n\n // User-defined fields\n const lockedSet = new Set([...LOCKED_MEDIA_FIELDS, ...OVERRIDABLE_MEDIA_FIELDS]);\n const filteredFields: Record<string, VexField> = {};\n for (const [fieldName, field] of Object.entries(props.userFields)) {\n if (lockedSet.has(fieldName as any)) continue;\n filteredFields[fieldName] = field as VexField;\n }\n lines.push(...generateFieldLines({ fields: filteredFields, blockInterfaceNames: props.blockInterfaceNames }));\n\n lines.push(\"}\");\n return lines.join(\"\\n\");\n}\n\nfunction generateGlobalInterface(props: {\n name: string;\n slug: string;\n tableName: string;\n fields: Record<string, VexField>;\n blockInterfaceNames: Map<string, string>;\n}): string {\n const lines: string[] = [];\n lines.push(`export interface ${props.name} {`);\n lines.push(` _id: Id<'${props.tableName}'>;`);\n lines.push(` _creationTime: number;`);\n\n lines.push(...generateFieldLines({ fields: props.fields, blockInterfaceNames: props.blockInterfaceNames }));\n\n lines.push(\"}\");\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate interface field lines from a record of fields, expanding tabs fields\n * into their individual tab slugs with proper nested object types.\n * This mirrors the expandFields() logic in schema generation.\n */\nfunction generateFieldLines(props: {\n fields: Record<string, VexField>;\n blockInterfaceNames: Map<string, string>;\n}): string[] {\n const lines: string[] = [];\n\n for (const [fieldName, field] of Object.entries(props.fields)) {\n const f = field as VexField;\n if (f.type === \"ui\") continue;\n\n if (f.type === \"tabs\") {\n const tabsField = f as TabsFieldDef;\n for (const tab of tabsField.tabs) {\n const innerProps: string[] = [];\n for (const [innerName, innerField] of Object.entries(tab.fields) as [string, VexField][]) {\n if (innerField.type === \"ui\") continue;\n const innerOptional = innerField.required ? \"\" : \"?\";\n const innerTypeStr = fieldToTypeString({\n field: innerField,\n blockInterfaceNames: props.blockInterfaceNames,\n });\n innerProps.push(`${innerName}${innerOptional}: ${innerTypeStr}`);\n }\n if (innerProps.length > 0) {\n lines.push(` ${tab.slug}?: { ${innerProps.join(\"; \")} };`);\n }\n }\n } else {\n const label = f.label;\n if (label) lines.push(` /** ${label} */`);\n const optional = f.required ? \"\" : \"?\";\n const typeStr = fieldToTypeString({\n field: f,\n blockInterfaceNames: props.blockInterfaceNames,\n });\n lines.push(` ${fieldName}${optional}: ${typeStr};`);\n }\n }\n\n return lines;\n}\n","/**\n * System field names injected into versioned collection schemas.\n * These are excluded from user-editable fields and version snapshots.\n */\nexport const VERSION_SYSTEM_FIELDS = [\n \"vex_status\",\n \"vex_version\",\n \"vex_publishedAt\",\n] as const;\n\n/**\n * All system fields (Convex built-in + versioning) to strip when\n * extracting user content from a document.\n */\nexport const ALL_SYSTEM_FIELDS = new Set([\n \"_id\",\n \"_creationTime\",\n ...VERSION_SYSTEM_FIELDS,\n]);\n\n/**\n * Default max versions to keep per document.\n */\nexport const DEFAULT_MAX_VERSIONS_PER_DOC = 100;\n\n/**\n * Default autosave interval in milliseconds.\n */\nexport const DEFAULT_AUTOSAVE_INTERVAL = 2000;\n","import { ALL_SYSTEM_FIELDS } from \"./constants\";\n\n/**\n * Extracts user-defined fields from a document, stripping all\n * system fields (_id, _creationTime, _status, _version, _publishedAt).\n *\n * Used to create version snapshots that contain only content fields.\n *\n * @param props.document - The full document including system fields\n * @returns A new object with only user-defined fields\n */\nexport function extractUserFields(props: {\n document: Record<string, unknown>;\n}): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props.document)) {\n if (!ALL_SYSTEM_FIELDS.has(key)) {\n result[key] = value;\n }\n }\n return result;\n}\n","import type { LivePreviewConfig } from \"../types/livePreview\";\n\n/**\n * Resolves the preview URL from a collection's live preview config.\n *\n * @param props.config - The collection's livePreview config\n * @param props.doc - The current document data (must include `_id`)\n * @param props.fallbackURL - URL to return if the function throws\n * @returns The resolved preview URL\n * @throws If the resolved URL is empty and no fallbackURL is provided\n */\nexport function resolvePreviewURL(props: {\n config: LivePreviewConfig;\n doc: { _id: string; [key: string]: any };\n fallbackURL?: string;\n}): string {\n if (typeof props.config.url === \"string\") {\n return props.config.url;\n }\n\n try {\n const result = props.config.url(props.doc);\n if (!result) {\n throw new Error(\n `Live preview URL resolved to empty string for document ${props.doc._id}`,\n );\n }\n return result;\n } catch (error) {\n if (props.fallbackURL !== undefined) {\n return props.fallbackURL;\n }\n throw error;\n }\n}\n","import type { LivePreviewConfig } from \"../types/livePreview\";\n\n/**\n * Determines if the preview iframe URL should be recomputed.\n *\n * @param props.config - The collection's livePreview config\n * @param props.changedFields - Set of field names that changed in the save\n * @returns true if the URL should be recomputed\n */\nexport function shouldReloadURL(props: {\n config: LivePreviewConfig;\n changedFields: string[];\n}): boolean {\n if (props.config.reloadOnFields === undefined) {\n return true;\n }\n\n if (props.config.reloadOnFields.length === 0) {\n return false;\n }\n\n return props.changedFields.some((field) =>\n props.config.reloadOnFields!.includes(field),\n );\n}\n","import type { LivePreviewBreakpoint } from \"../types/livePreview\";\n\nexport const DEFAULT_BREAKPOINTS: LivePreviewBreakpoint[] = [\n { label: \"Mobile\", width: 375, height: 667, icon: \"smartphone\" },\n { label: \"Tablet\", width: 768, height: 1024, icon: \"tablet\" },\n { label: \"Laptop\", width: 1280, height: 800, icon: \"laptop\" },\n { label: \"Desktop\", width: 1920, height: 1080, icon: \"monitor\" },\n];\n\n/**\n * Debounce interval for writing preview snapshots on form changes.\n */\nexport const PREVIEW_SNAPSHOT_DEBOUNCE_MS = 500;\n","import type { GenericMutationCtx, GenericQueryCtx, GenericDataModel } from \"convex/server\";\n\n/**\n * Upserts a preview snapshot for a document.\n * If a snapshot already exists for this collection+document, it is updated in place.\n * If not, a new entry is created.\n *\n * @param props.ctx - Convex mutation context\n * @param props.collection - Collection slug\n * @param props.documentId - Document ID\n * @param props.snapshot - Complete field snapshot from the form\n */\nexport async function upsertPreviewSnapshot<DataModel extends GenericDataModel>(props: {\n ctx: GenericMutationCtx<DataModel>;\n collection: string;\n documentId: string;\n snapshot: Record<string, unknown>;\n}): Promise<void> {\n const existing = await (props.ctx.db as any)\n .query(\"vex_versions\")\n .withIndex(\"by_document_status\", (q: any) =>\n q\n .eq(\"collection\", props.collection)\n .eq(\"documentId\", props.documentId)\n .eq(\"status\", \"previewSnapshot\"),\n )\n .first();\n\n if (existing) {\n await (props.ctx.db as any).patch(existing._id, {\n snapshot: props.snapshot,\n createdAt: Date.now(),\n });\n } else {\n await (props.ctx.db as any).insert(\"vex_versions\", {\n collection: props.collection,\n documentId: props.documentId,\n version: 0,\n status: \"previewSnapshot\",\n snapshot: props.snapshot,\n createdAt: Date.now(),\n createdBy: undefined,\n isAutosave: false,\n restoredFrom: undefined,\n });\n }\n}\n\n/**\n * Deletes the preview snapshot for a document.\n * Called after a successful save to clean up transient state.\n *\n * @param props.ctx - Convex mutation context\n * @param props.collection - Collection slug\n * @param props.documentId - Document ID\n */\nexport async function deletePreviewSnapshot<DataModel extends GenericDataModel>(props: {\n ctx: GenericMutationCtx<DataModel>;\n collection: string;\n documentId: string;\n}): Promise<void> {\n const entries = await (props.ctx.db as any)\n .query(\"vex_versions\")\n .withIndex(\"by_document_status\", (q: any) =>\n q\n .eq(\"collection\", props.collection)\n .eq(\"documentId\", props.documentId)\n .eq(\"status\", \"previewSnapshot\"),\n )\n .collect();\n\n for (const entry of entries) {\n await (props.ctx.db as any).delete(entry._id);\n }\n}\n\n/**\n * Gets the preview data for a document.\n *\n * Lookup order:\n * 1. Preview snapshot (transient, written by admin form on each change)\n * 2. Latest version from vex_versions (draft or published, excluding autosave/previewSnapshot)\n * 3. null (fall back to main document)\n *\n * @param props.ctx - Convex query context\n * @param props.collection - Collection slug\n * @param props.documentId - Document ID\n * @returns The snapshot data, or null if no preview/version exists\n */\nexport async function getPreviewSnapshot<DataModel extends GenericDataModel>(props: {\n ctx: GenericQueryCtx<DataModel>;\n collection: string;\n documentId: string;\n}): Promise<Record<string, unknown> | null> {\n // 1. Check for a transient preview snapshot (written by admin form edits)\n const previewEntry = await (props.ctx.db as any)\n .query(\"vex_versions\")\n .withIndex(\"by_document_status\", (q: any) =>\n q\n .eq(\"collection\", props.collection)\n .eq(\"documentId\", props.documentId)\n .eq(\"status\", \"previewSnapshot\"),\n )\n .first();\n\n if (previewEntry) {\n return previewEntry.snapshot as Record<string, unknown>;\n }\n\n // 2. Fall back to the latest version (draft or published)\n const allVersions = await (props.ctx.db as any)\n .query(\"vex_versions\")\n .withIndex(\"by_document\", (q: any) =>\n q.eq(\"collection\", props.collection).eq(\"documentId\", props.documentId),\n )\n .collect();\n\n let latestVersion: Record<string, unknown> | null = null;\n let maxVersion = -1;\n for (const v of allVersions) {\n if (v.status === \"previewSnapshot\" || v.status === \"autosave\") continue;\n const ver = v.version as number;\n if (ver > maxVersion) {\n maxVersion = ver;\n latestVersion = v;\n }\n }\n\n if (latestVersion) {\n return (latestVersion as any).snapshot as Record<string, unknown>;\n }\n\n // 3. No versions at all — caller will use the main document\n return null;\n}\n","import {\n queryGeneric,\n type QueryBuilder,\n type GenericQueryCtx,\n type GenericDataModel,\n type RegisteredQuery,\n} from \"convex/server\";\nimport { v, type ObjectType, type PropertyValidators } from \"convex/values\";\n\n/**\n * Drafts mode for vexQuery.\n * - \"snapshot\": Fetch the transient preview snapshot (written by admin on form changes)\n * - true: Fetch the latest draft version (from versioning system)\n * - false: Fetch published content only\n */\nexport type VexDraftsMode = \"snapshot\" | boolean;\n\n/**\n * Context passed to vexQuery handlers.\n * Extends the standard Convex QueryCtx with draft-awareness.\n */\nexport interface VexQueryCtx<DataModel extends GenericDataModel = GenericDataModel>\n extends GenericQueryCtx<DataModel> {\n /**\n * The resolved drafts mode.\n * - \"snapshot\": caller wants preview snapshot data\n * - true: caller wants latest draft version\n * - false: caller wants published content only\n *\n * Defaults to \"snapshot\" when not explicitly passed by the caller.\n */\n drafts: VexDraftsMode;\n}\n\nfunction wrapHandler<DataModel extends GenericDataModel, Args extends PropertyValidators, Output>(\n handler: (ctx: VexQueryCtx<DataModel>, args: ObjectType<Args>) => Output | Promise<Output>,\n) {\n return async (ctx: GenericQueryCtx<any>, args: any): Promise<Awaited<Output>> => {\n const { _vexDrafts, ...userArgs } = args;\n\n const drafts: VexDraftsMode = _vexDrafts !== undefined\n ? (_vexDrafts as VexDraftsMode)\n : \"snapshot\";\n\n const vexCtx = Object.assign(\n Object.create(Object.getPrototypeOf(ctx)),\n ctx,\n { drafts },\n ) as VexQueryCtx<DataModel>;\n\n return handler(vexCtx, userArgs as ObjectType<Args>) as Promise<Awaited<Output>>;\n };\n}\n\n/**\n * Create a typed vexQuery builder from your project's query builder.\n *\n * Call this once in your project to get a `vexQuery` function that\n * preserves full return type inference from your DataModel.\n *\n * @example\n * ```ts\n * // convex/vex/helpers.ts\n * import { createVexQuery } from \"@vexcms/core\";\n * import { query } from \"../_generated/server\";\n *\n * export const vexQuery = createVexQuery(query);\n * ```\n *\n * Then use it in your query files:\n * ```ts\n * // convex/pages.ts\n * import { vexQuery } from \"./vex/helpers\";\n * import { getPreviewSnapshot } from \"@vexcms/core\";\n *\n * export const getBySlug = vexQuery({\n * args: { slug: v.string() },\n * handler: async (ctx, args) => {\n * const page = await ctx.db\n * .query(\"pages\")\n * .withIndex(\"by_slug\", (q) => q.eq(\"slug\", args.slug))\n * .first();\n * if (!page) return null;\n * if (ctx.drafts === \"snapshot\") {\n * const snapshot = await getPreviewSnapshot({ ctx, collection: \"pages\", documentId: page._id });\n * if (snapshot) return { ...page, ...snapshot };\n * }\n * return page;\n * },\n * });\n * ```\n */\nexport function createVexQuery<DataModel extends GenericDataModel>(\n _queryBuilder: QueryBuilder<DataModel, \"public\">,\n) {\n return <Args extends PropertyValidators, Output>(props: {\n args: Args;\n handler: (\n ctx: VexQueryCtx<DataModel>,\n args: ObjectType<Args>,\n ) => Output | Promise<Output>;\n }): RegisteredQuery<\"public\", ObjectType<Args & { _vexDrafts: typeof v.optional<any> }>, Awaited<Output>> => {\n const mergedArgs = {\n ...props.args,\n _vexDrafts: v.optional(v.union(v.literal(\"snapshot\"), v.boolean())),\n };\n\n return queryGeneric({\n args: mergedArgs,\n handler: wrapHandler<DataModel, Args, Output>(props.handler),\n }) as RegisteredQuery<\"public\", ObjectType<Args & { _vexDrafts: typeof v.optional<any> }>, Awaited<Output>>;\n };\n}\n\n/**\n * Generic vexQuery for use without project-specific types.\n * Prefer `createVexQuery(query)` for full type inference.\n *\n * @deprecated Use `createVexQuery(query)` instead for proper return type inference.\n */\nexport function vexQuery<Args extends PropertyValidators, Output>(props: {\n args: Args;\n handler: (\n ctx: VexQueryCtx,\n args: ObjectType<Args>,\n ) => Output | Promise<Output>;\n}): RegisteredQuery<\"public\", ObjectType<Args & { _vexDrafts: typeof v.optional<any> }>, Awaited<Output>> {\n const mergedArgs = {\n ...props.args,\n _vexDrafts: v.optional(v.union(v.literal(\"snapshot\"), v.boolean())),\n };\n\n return queryGeneric({\n args: mergedArgs,\n handler: wrapHandler(props.handler),\n }) as RegisteredQuery<\"public\", ObjectType<Args & { _vexDrafts: typeof v.optional<any> }>, Awaited<Output>>;\n}\n","import type {\n GenericDataModel,\n GenericMutationCtx,\n GenericQueryCtx,\n PaginationOptions,\n TableNamesInDataModel,\n} from \"convex/server\"\n\nimport { ConvexError } from \"convex/values\"\nimport { generateFormSchema } from \"../../formSchema/generateFormSchema\"\nimport { getPreviewSnapshot } from \"../previewSnapshot\"\nimport type { VexField } from \"../../types\"\nimport type { CollectionKind } from \"../../config/findCollectionBySlug\"\n\nasync function resolveStorageUrl(\n ctx: { storage: { getUrl: (id: any) => Promise<string | null> } },\n doc: any,\n) {\n if (doc?.storageId && (!doc.url || doc.url === \"\")) {\n const url = await ctx.storage.getUrl(doc.storageId)\n if (url) return { ...doc, url }\n }\n return doc\n}\n\nexport async function listDocuments<DataModel extends GenericDataModel>(props: {\n args: {\n collectionSlug: TableNamesInDataModel<DataModel>\n paginationOpts: PaginationOptions\n order?: \"asc\" | \"desc\"\n }\n ctx: GenericQueryCtx<DataModel>\n}) {\n const { args, ctx } = props\n const q = args.order === \"desc\"\n ? ctx.db.query(args.collectionSlug).order(\"desc\")\n : ctx.db.query(args.collectionSlug)\n const result = await q.paginate(args.paginationOpts)\n const resolvedPage = await Promise.all(\n result.page.map((doc: any) => resolveStorageUrl(ctx, doc)),\n )\n return { ...result, page: resolvedPage }\n}\n\nexport async function countDocuments<DataModel extends GenericDataModel>(props: {\n ctx: GenericQueryCtx<DataModel>\n args: { collectionSlug: TableNamesInDataModel<DataModel> }\n}): Promise<number> {\n return await (props.ctx.db.query(props.args.collectionSlug) as any).count()\n}\n\nexport async function getDocument<DataModel extends GenericDataModel>(props: {\n ctx: GenericQueryCtx<DataModel>\n args: {\n collectionSlug: TableNamesInDataModel<DataModel>\n documentId: string\n /** When true, merges the transient preview snapshot (from admin live preview) */\n preview?: boolean\n }\n}) {\n const doc = await props.ctx.db.get(props.args.documentId as any)\n if (!doc) return null\n const resolved = await resolveStorageUrl(props.ctx, doc)\n\n // Merge preview snapshot when explicitly requested (live preview iframe).\n if (props.args.preview) {\n const snapshot = await getPreviewSnapshot<DataModel>({\n ctx: props.ctx,\n collection: props.args.collectionSlug as string,\n documentId: props.args.documentId,\n })\n if (snapshot) {\n return { ...resolved, ...snapshot }\n }\n }\n\n return resolved\n}\n\nexport async function updateDocument<DataModel extends GenericDataModel>(props: {\n ctx: GenericMutationCtx<DataModel>\n args: {\n collectionSlug: TableNamesInDataModel<DataModel>\n documentId: string\n fields: Record<string, unknown>\n collectionFields: Record<string, VexField>\n }\n}) {\n const f = { ...props.args.fields }\n\n // Resolve the file URL from storageId when replacing a media file\n if (f.storageId && f.url === \"\") {\n const url = await props.ctx.storage.getUrl(f.storageId as any)\n if (url) f.url = url\n }\n\n const schema = generateFormSchema({\n fields: props.args.collectionFields,\n }).partial()\n\n const result = schema.safeParse(f)\n if (!result.success) {\n throw new ConvexError({\n message: \"Validation failed\",\n errors: result.error.flatten(),\n })\n }\n\n await props.ctx.db.patch(props.args.documentId as any, result.data as any)\n return props.args.documentId\n}\n\nexport async function createDocument<DataModel extends GenericDataModel>(props: {\n ctx: GenericMutationCtx<DataModel>\n args: {\n collectionSlug: TableNamesInDataModel<DataModel>\n fields: Record<string, unknown>\n collectionFields: Record<string, VexField>\n kind: CollectionKind\n }\n}): Promise<string> {\n if (props.args.kind === \"global\") {\n const existing = await props.ctx.db.query(props.args.collectionSlug).first()\n if (existing) {\n throw new ConvexError(\n `Global \"${props.args.collectionSlug}\" already exists. Globals can only have one document.`,\n )\n }\n }\n\n const schema = generateFormSchema({\n fields: props.args.collectionFields,\n })\n\n const result = schema.safeParse(props.args.fields)\n if (!result.success) {\n throw new ConvexError({\n message: \"Validation failed\",\n errors: result.error.flatten(),\n })\n }\n\n const id = await props.ctx.db.insert(props.args.collectionSlug as any, result.data as any)\n return id as string\n}\n\nexport async function deleteDocument<DataModel extends GenericDataModel>(props: {\n ctx: GenericMutationCtx<DataModel>\n args: {\n collectionSlug: TableNamesInDataModel<DataModel>\n documentId: string\n kind: CollectionKind\n }\n}): Promise<void> {\n if (props.args.kind === \"global\") {\n const existing = await props.ctx.db.get(props.args.documentId as any)\n if (!existing) {\n throw new ConvexError(\n `Global \"${props.args.collectionSlug}\" document not found. Cannot delete a non-existent global.`,\n )\n }\n }\n\n await props.ctx.db.delete(props.args.documentId as any)\n}\n\nexport async function bulkDeleteDocuments<DataModel extends GenericDataModel>(props: {\n ctx: GenericMutationCtx<DataModel>\n args: {\n documentIds: string[]\n }\n}): Promise<{ deleted: number }> {\n for (const id of props.args.documentIds) {\n await props.ctx.db.delete(id as any)\n }\n return { deleted: props.args.documentIds.length }\n}\n\nexport async function searchDocuments<DataModel extends GenericDataModel>(props: {\n args: {\n collectionSlug: TableNamesInDataModel<DataModel>\n searchIndexName: string\n searchField: string\n query: string\n }\n ctx: GenericQueryCtx<DataModel>\n}) {\n const { args, ctx } = props\n const docs = await (ctx.db.query(args.collectionSlug) as any)\n .withSearchIndex(args.searchIndexName, (q: any) => q.search(args.searchField, args.query))\n .take(50)\n return Promise.all(docs.map((doc: any) => resolveStorageUrl(ctx, doc)))\n}\n","import type { VexConfig, VexCollection } from \"../types\";\n\n/** Sentinel string placed at the top of every generated file. */\nexport const GENERATED_HEADER =\n \"// ⚠️ AUTO-GENERATED BY VEX CMS — DO NOT EDIT ⚠️\";\n\n/**\n * Relative import paths used inside generated files.\n * Computed by the CLI from cwd + convexDir; passed in so this function\n * stays pure and testable.\n */\nexport interface CollectionQueryImports {\n /** Import path for vex.config.ts from api/ dir. e.g. `\"../../../vex.config\"` */\n vexConfigFromApi: string;\n /** Import path for _generated/ from api/ dir. e.g. `\"../../_generated\"` */\n generatedDirFromApi: string;\n /** Import path for the user's auth helper from api/ dir. e.g. `\"../auth\"` */\n authFromApi: string;\n /** Import path for _generated/ from model/api/ dir. e.g. `\"../../../_generated\"` */\n generatedDirFromModel: string;\n}\n\n/**\n * Result of generating all collection files.\n * Keys are relative paths from the vex/ directory.\n * e.g. `\"api/articles.ts\"`, `\"model/api/articles.ts\"`, `\"api/index.ts\"`\n */\nexport type GeneratedFiles = Record<string, string>;\n\n/**\n * Generate typed Convex query/mutation files for all collections in `config`.\n *\n * Produces two files per collection:\n * - `model/api/{slug}.ts` — typed model functions (DB logic)\n * - `api/{slug}.ts` — Convex query/mutation exports (auth + RBAC + calls model)\n * Plus a barrel `api/index.ts`.\n */\nexport function generateCollectionQueries(props: {\n config: VexConfig;\n imports: CollectionQueryImports;\n}): GeneratedFiles {\n const { config, imports } = props;\n const result: GeneratedFiles = {};\n const slugs: string[] = [];\n\n // Regular collections\n for (const collection of config.collections) {\n const { apiFile, modelFile } = generateCollectionPair({\n collection,\n isMedia: false,\n imports,\n });\n result[`api/${collection.slug}.ts`] = apiFile;\n result[`model/api/${collection.slug}.ts`] = modelFile;\n slugs.push(collection.slug);\n }\n\n // Media collections\n if (config.media?.collections) {\n for (const collection of config.media.collections) {\n const { apiFile, modelFile } = generateCollectionPair({\n collection,\n isMedia: true,\n imports,\n });\n result[`api/${collection.slug}.ts`] = apiFile;\n result[`model/api/${collection.slug}.ts`] = modelFile;\n slugs.push(collection.slug);\n }\n }\n\n // Globals (treated like collections for API generation)\n if (config.globals) {\n for (const global of config.globals) {\n if (slugs.includes(global.slug)) continue;\n const collection = {\n slug: global.slug,\n tableName: global.tableName ?? global.slug,\n fields: global.fields,\n searchIndexes: undefined,\n } as unknown as VexCollection;\n const { apiFile, modelFile } = generateCollectionPair({\n collection,\n isMedia: false,\n imports,\n });\n result[`api/${global.slug}.ts`] = apiFile;\n result[`model/api/${global.slug}.ts`] = modelFile;\n slugs.push(global.slug);\n }\n }\n\n // Auth collections that opt in with generateApi: true\n if (config.auth?.collections) {\n for (const collection of config.auth.collections) {\n if (!collection.generateApi) continue;\n // Skip if already generated (user may have the same collection in config.collections)\n if (slugs.includes(collection.slug)) continue;\n const { apiFile, modelFile } = generateCollectionPair({\n collection,\n isMedia: false,\n imports,\n });\n result[`api/${collection.slug}.ts`] = apiFile;\n result[`model/api/${collection.slug}.ts`] = modelFile;\n slugs.push(collection.slug);\n }\n }\n\n // Barrel index\n result[\"api/index.ts\"] = generateIndexFile({ slugs });\n\n return result;\n}\n\n// ─── Per-collection pair generation ──────────────────────────────────────────\n\n/**\n * Generate both the model file and the API file for a single collection.\n */\nexport function generateCollectionPair(props: {\n collection: VexCollection;\n isMedia: boolean;\n imports: CollectionQueryImports;\n}): { apiFile: string; modelFile: string } {\n const { collection, isMedia, imports } = props;\n const slug = collection.slug;\n const tableName = collection.tableName ?? collection.slug;\n const firstSearchIndex = collection.searchIndexes?.[0] ?? null;\n\n const modelFile = generateModelFile({ slug, tableName, isMedia, firstSearchIndex, imports });\n const apiFile = generateApiFile({ slug, tableName, isMedia, firstSearchIndex, imports });\n\n return { apiFile, modelFile };\n}\n\n// ─── Model file generation ──────────────────────────────────────────────────\n\nexport function generateModelFile(props: {\n slug: string;\n tableName: string;\n isMedia: boolean;\n firstSearchIndex: { name: string; searchField: string } | null;\n imports: CollectionQueryImports;\n}): string {\n const { tableName, isMedia, firstSearchIndex, imports } = props;\n const parts: string[] = [];\n\n // Header + imports\n const coreImports = [\"getPreviewSnapshot\"];\n if (!isMedia) {\n coreImports.push(\"generateFormSchema\");\n }\n\n const coreTypeImports: string[] = [\"CollectionKind\"];\n if (!isMedia) {\n coreTypeImports.push(\"VexField\");\n }\n\n const coreTypeImportLine = coreTypeImports.length > 0\n ? `\\nimport type { ${coreTypeImports.join(\", \")} } from \"@vexcms/core\"`\n : \"\";\n\n const convexTypeImports = isMedia ? \"\" : `\\nimport type { WithoutSystemFields } from \"convex/server\"`;\n\n parts.push(`${GENERATED_HEADER}\nimport type { Doc, Id } from \"${imports.generatedDirFromModel}/dataModel\"\nimport type { QueryCtx, MutationCtx } from \"${imports.generatedDirFromModel}/server\"${convexTypeImports}\nimport { ConvexError } from \"convex/values\"\nimport { ${coreImports.join(\", \")} } from \"@vexcms/core\"${coreTypeImportLine}`);\n\n // getDocument\n parts.push(buildModelGetDocument({ tableName }));\n\n // listDocuments\n parts.push(buildModelListDocuments({ tableName }));\n\n // createDocument (not for media)\n if (!isMedia) {\n parts.push(buildModelCreateDocument({ tableName }));\n }\n\n // updateDocument (not for media)\n if (!isMedia) {\n parts.push(buildModelUpdateDocument({ tableName }));\n }\n\n // deleteDocument\n parts.push(buildModelDeleteDocument({ tableName }));\n\n // searchDocuments (only if search index)\n if (firstSearchIndex) {\n parts.push(buildModelSearchDocuments({\n tableName,\n searchIndexName: firstSearchIndex.name,\n searchField: firstSearchIndex.searchField as string,\n }));\n }\n\n return parts.join(\"\\n\\n\") + \"\\n\";\n}\n\nexport function buildModelGetDocument(props: { tableName: string }): string {\n const { tableName } = props;\n return `export async function getDocument(props: {\n ctx: QueryCtx\n documentId: Id<\"${tableName}\">\n preview?: boolean\n}): Promise<Doc<\"${tableName}\"> | null> {\n const doc = await props.ctx.db.get(props.documentId)\n if (!doc) return null\n\n if (props.preview) {\n const snapshot = await getPreviewSnapshot({\n ctx: props.ctx,\n collection: \"${tableName}\",\n documentId: props.documentId,\n })\n if (snapshot) {\n return { ...doc, ...snapshot } as Doc<\"${tableName}\">\n }\n }\n\n return doc\n}`;\n}\n\nexport function buildModelListDocuments(props: { tableName: string }): string {\n const { tableName } = props;\n return `export async function listDocuments(props: {\n ctx: QueryCtx\n paginationOpts: { numItems: number; cursor: string | null }\n order?: \"asc\" | \"desc\"\n}) {\n const q = props.order === \"desc\"\n ? props.ctx.db.query(\"${tableName}\").order(\"desc\")\n : props.ctx.db.query(\"${tableName}\")\n return await q.paginate(props.paginationOpts)\n}`;\n}\n\nexport function buildModelCreateDocument(props: { tableName: string }): string {\n const { tableName } = props;\n return `export async function createDocument(props: {\n collectionFields: Record<string, VexField>\n ctx: MutationCtx\n fields: unknown\n kind: CollectionKind\n}): Promise<Id<\"${tableName}\">> {\n if (props.kind === \"global\") {\n const existing = await props.ctx.db.query(\"${tableName}\").first()\n if (existing) {\n throw new ConvexError(\\`Global \"${tableName}\" already exists. Globals can only have one document.\\`)\n }\n }\n\n const schema = generateFormSchema({ fields: props.collectionFields })\n const parsed = schema.safeParse(props.fields)\n if (!parsed.success) {\n throw new ConvexError({ message: \"Validation failed\", errors: parsed.error.flatten() })\n }\n\n const data = { ...parsed.data }\n data.vex_status ??= \"published\"\n return await props.ctx.db.insert(\"${tableName}\", data as WithoutSystemFields<Doc<\"${tableName}\">>)\n}`;\n}\n\nexport function buildModelUpdateDocument(props: { tableName: string }): string {\n const { tableName } = props;\n return `export async function updateDocument(props: {\n collectionFields: Record<string, VexField>\n ctx: MutationCtx\n documentId: Id<\"${tableName}\">\n fields: unknown\n}): Promise<Id<\"${tableName}\">> {\n const schema = generateFormSchema({ fields: props.collectionFields }).partial()\n const parsed = schema.safeParse(props.fields)\n if (!parsed.success) {\n throw new ConvexError({ message: \"Validation failed\", errors: parsed.error.flatten() })\n }\n\n await props.ctx.db.patch(props.documentId, parsed.data as Partial<Doc<\"${tableName}\">>)\n return props.documentId\n}`;\n}\n\nexport function buildModelDeleteDocument(props: { tableName: string }): string {\n const { tableName } = props;\n return `export async function deleteDocument(props: {\n ctx: MutationCtx\n documentId: Id<\"${tableName}\">\n kind: CollectionKind\n}): Promise<void> {\n if (props.kind === \"global\") {\n const existing = await props.ctx.db.get(props.documentId)\n if (!existing) {\n throw new ConvexError(\\`Global \"${tableName}\" document not found. Cannot delete a non-existent global.\\`)\n }\n }\n\n await props.ctx.db.delete(props.documentId)\n}`;\n}\n\nexport function buildModelSearchDocuments(props: {\n tableName: string;\n searchIndexName: string;\n searchField: string;\n}): string {\n const { tableName, searchIndexName, searchField } = props;\n return `export async function searchDocuments(props: {\n ctx: QueryCtx\n query: string\n}): Promise<Doc<\"${tableName}\">[]> {\n return await props.ctx.db.query(\"${tableName}\")\n .withSearchIndex(\"${searchIndexName}\", (q) => q.search(\"${searchField}\", props.query))\n .take(50)\n}`;\n}\n\n// ─── API file generation ─────────────────────────────────────────────────────\n\nexport function generateApiFile(props: {\n slug: string;\n tableName: string;\n isMedia: boolean;\n firstSearchIndex: { name: string; searchField: string } | null;\n imports: CollectionQueryImports;\n}): string {\n const { slug, tableName, isMedia, firstSearchIndex, imports } = props;\n const parts: string[] = [];\n\n // Model imports\n const modelFns = [\n \"getDocument\",\n \"listDocuments\",\n ...(isMedia ? [] : [\"createDocument\", \"updateDocument\"]),\n \"deleteDocument\",\n ...(firstSearchIndex ? [\"searchDocuments\"] : []),\n ];\n\n parts.push(`${GENERATED_HEADER}\nimport { v } from \"convex/values\"\nimport { paginationOptsValidator } from \"convex/server\"\nimport { ConvexError } from \"convex/values\"\nimport { query, mutation } from \"${imports.generatedDirFromApi}/server\"\nimport type { QueryCtx, MutationCtx } from \"${imports.generatedDirFromApi}/server\"\nimport { hasPermission, findCollectionBySlug } from \"@vexcms/core\"\nimport { getUser } from \"${imports.authFromApi}\"\nimport vexConfig from \"${imports.vexConfigFromApi}\"\nimport { ${modelFns.join(\", \")} } from \"../model/api/${slug}\"`);\n\n // SLUG constant + requireAuth helper\n parts.push(`const SLUG = \"${slug}\" as const\n\nasync function requireAuth(ctx: QueryCtx | MutationCtx) {\n const auth = await getUser(ctx)\n if (!auth) throw new ConvexError(\"Not authenticated\")\n return auth\n}`);\n\n // getDocument\n parts.push(buildApiGetDocument({ tableName }));\n\n // listDocuments\n parts.push(buildApiListDocuments({ tableName }));\n\n // createDocument (not for media)\n if (!isMedia) {\n parts.push(buildApiCreateDocument({ slug, tableName }));\n }\n\n // updateDocument (not for media)\n if (!isMedia) {\n parts.push(buildApiUpdateDocument({ slug, tableName }));\n }\n\n // deleteDocument\n parts.push(buildApiDeleteDocument({ tableName }));\n\n // searchDocuments (only if search index)\n if (firstSearchIndex) {\n parts.push(buildApiSearchDocuments());\n }\n\n return parts.join(\"\\n\\n\") + \"\\n\";\n}\n\nexport function buildApiGetDocument(props: { tableName: string }): string {\n const { tableName } = props;\n return `export const get = query({\n args: {\n id: v.id(\"${tableName}\"),\n _vexDrafts: v.optional(v.union(v.literal(\"snapshot\"), v.boolean())),\n },\n handler: async (ctx, args) => {\n const preview = (args._vexDrafts ?? \"snapshot\") === \"snapshot\"\n const doc = await getDocument({\n ctx,\n documentId: args.id,\n preview,\n })\n if (!doc) return null\n const auth = await getUser(ctx)\n if (auth) {\n const allowed = hasPermission({\n access: vexConfig.access,\n user: auth.user,\n userRoles: auth.roles,\n resource: SLUG,\n action: \"read\",\n data: doc,\n })\n if (!allowed) return null\n }\n return doc\n },\n})`;\n}\n\nexport function buildApiListDocuments(_props: { tableName: string }): string {\n return `export const list = query({\n args: {\n paginationOpts: paginationOptsValidator,\n order: v.optional(v.union(v.literal(\"asc\"), v.literal(\"desc\"))),\n },\n handler: async (ctx, args) => {\n const result = await listDocuments({\n ctx,\n paginationOpts: args.paginationOpts,\n order: args.order,\n })\n const auth = await getUser(ctx)\n if (!auth) return result\n const filteredPage = result.page.filter((doc) =>\n hasPermission({\n access: vexConfig.access,\n user: auth.user,\n userRoles: auth.roles,\n resource: SLUG,\n action: \"read\",\n data: doc,\n }) === true,\n )\n return { ...result, page: filteredPage }\n },\n})`;\n}\n\nexport function buildApiCreateDocument(_props: {\n slug: string;\n tableName: string;\n}): string {\n return `export const create = mutation({\n args: { fields: v.any() },\n handler: async (ctx, args) => {\n const { user, roles } = await requireAuth(ctx)\n hasPermission({\n access: vexConfig.access,\n user,\n userRoles: roles,\n resource: SLUG,\n action: \"create\",\n throwOnDenied: true,\n })\n const collection = findCollectionBySlug({ slug: SLUG, config: vexConfig })\n if (!collection) throw new ConvexError(\\`Collection \"\\${SLUG}\" not found in vex config\\`)\n return createDocument({\n collectionFields: collection.fields,\n ctx,\n fields: args.fields as unknown,\n kind: \"collection\",\n })\n },\n})`;\n}\n\nexport function buildApiUpdateDocument(props: {\n slug: string;\n tableName: string;\n}): string {\n const { tableName } = props;\n return `export const update = mutation({\n args: { id: v.id(\"${tableName}\"), fields: v.any() },\n handler: async (ctx, args) => {\n const { user, roles } = await requireAuth(ctx)\n hasPermission({\n access: vexConfig.access,\n user,\n userRoles: roles,\n resource: SLUG,\n action: \"update\",\n throwOnDenied: true,\n })\n const collection = findCollectionBySlug({ slug: SLUG, config: vexConfig })\n if (!collection) throw new ConvexError(\\`Collection \"\\${SLUG}\" not found in vex config\\`)\n return updateDocument({\n collectionFields: collection.fields,\n ctx,\n documentId: args.id,\n fields: args.fields,\n })\n },\n})`;\n}\n\nexport function buildApiDeleteDocument(props: { tableName: string }): string {\n const { tableName } = props;\n return `export const remove = mutation({\n args: { id: v.id(\"${tableName}\") },\n handler: async (ctx, args) => {\n const { user, roles } = await requireAuth(ctx)\n hasPermission({\n access: vexConfig.access,\n user,\n userRoles: roles,\n resource: SLUG,\n action: \"delete\",\n throwOnDenied: true,\n })\n await deleteDocument({\n ctx,\n documentId: args.id,\n kind: \"collection\",\n })\n },\n})`;\n}\n\nexport function buildApiSearchDocuments(): string {\n return `export const search = query({\n args: { query: v.string() },\n handler: async (ctx, args) => {\n const results = await searchDocuments({\n ctx,\n query: args.query,\n })\n const auth = await getUser(ctx)\n if (!auth) return results\n return results.filter((doc) =>\n hasPermission({\n access: vexConfig.access,\n user: auth.user,\n userRoles: auth.roles,\n resource: SLUG,\n action: \"read\",\n data: doc,\n }) === true,\n )\n },\n})`;\n}\n\n// ─── Barrel index ────────────────────────────────────────────────────────────\n\n/**\n * Generate the barrel `index.ts` that namespace-re-exports all collection files.\n */\nexport function generateIndexFile(props: { slugs: string[] }): string {\n const sorted = [...props.slugs].sort();\n if (sorted.length === 0) {\n return GENERATED_HEADER + \"\\n\";\n }\n const exports = sorted\n .map((slug) => `export * as ${slug} from \"./${slug}\"`)\n .join(\"\\n\");\n return `${GENERATED_HEADER}\\n${exports}\\n`;\n}\n","// =============================================================================\n// SCHEMA DIFF — compares old vs new generated schema to detect migration needs\n// =============================================================================\n\nexport interface SchemaFieldInfo {\n /** Table name (export const name). */\n table: string;\n /** Field name within the table. */\n field: string;\n /** Full value type string, e.g. \"v.string()\" or \"v.optional(v.string())\". */\n valueType: string;\n /** Whether the field is wrapped in v.optional(...). */\n isOptional: boolean;\n}\n\nexport interface RemovedFieldInfo {\n /** Table name (export const name). */\n table: string;\n /** Field name that was removed. */\n field: string;\n /** The old value type string, e.g. \"v.string()\". */\n valueType: string;\n /** Whether the field was optional in the old schema. */\n wasOptional: boolean;\n}\n\nexport interface SchemaDiff {\n /** Fields that changed from optional → required (need backfill). */\n newRequired: SchemaFieldInfo[];\n /** Fields that are entirely new and required (need backfill). */\n addedRequired: SchemaFieldInfo[];\n /** Fields that are entirely new and optional (may need backfill if they have a defaultValue). */\n addedOptional: SchemaFieldInfo[];\n /** Fields that existed in old schema but are absent in new schema. */\n removedFields: RemovedFieldInfo[];\n /** All fields that need migration. */\n needsMigration: SchemaFieldInfo[];\n}\n\ninterface ParsedTable {\n name: string;\n fields: Map<string, { valueType: string; isOptional: boolean }>;\n}\n\n/**\n * Parse a generated vex schema string into a map of table → fields.\n *\n * Relies on the known output format of `generateVexSchema()`:\n * ```\n * export const <name> = defineTable({\n * field1: v.string(),\n * field2: v.optional(v.string()),\n * })\n * ```\n */\nfunction parseTables(schema: string): Map<string, ParsedTable> {\n const tables = new Map<string, ParsedTable>();\n if (!schema.trim()) return tables;\n\n // Match each `export const <name> = defineTable({ ... })`\n const tableRegex =\n /export\\s+const\\s+(\\w+)\\s*=\\s*defineTable\\(\\{([\\s\\S]*?)\\}\\)/g;\n\n let match: RegExpExecArray | null;\n while ((match = tableRegex.exec(schema)) !== null) {\n const name = match[1]!;\n const body = match[2]!;\n const fields = new Map<string, { valueType: string; isOptional: boolean }>();\n\n // Match field entries like ` fieldName: v.string(),` or ` fieldName: v.optional(v.string()),`\n // The value type can contain nested parens, so we use a greedy match up to the trailing comma\n const fieldRegex = /^\\s+(\\w+):\\s+(v\\..+?),?\\s*$/gm;\n let fieldMatch: RegExpExecArray | null;\n while ((fieldMatch = fieldRegex.exec(body)) !== null) {\n const fieldName = fieldMatch[1]!;\n const valueType = fieldMatch[2]!.replace(/,\\s*$/, \"\");\n const isOptional = valueType.startsWith(\"v.optional(\");\n fields.set(fieldName, { valueType, isOptional });\n }\n\n tables.set(name, { name, fields });\n }\n\n return tables;\n}\n\n/**\n * Compare two generated schema strings and return fields that need migration.\n *\n * A field needs migration when:\n * 1. It exists in the new schema but not the old, and is NOT optional → `addedRequired`\n * 2. It exists in the new schema but not the old, and IS optional → `addedOptional`\n * (planMigration decides whether to backfill based on defaultValue)\n * 3. It exists in both, was optional in old but is NOT optional in new → `newRequired`\n */\nexport function diffSchema(oldSchema: string, newSchema: string): SchemaDiff {\n const oldTables = parseTables(oldSchema);\n const newTables = parseTables(newSchema);\n\n const addedRequired: SchemaFieldInfo[] = [];\n const addedOptional: SchemaFieldInfo[] = [];\n const newRequired: SchemaFieldInfo[] = [];\n const removedFields: RemovedFieldInfo[] = [];\n\n for (const [tableName, newTable] of newTables) {\n const oldTable = oldTables.get(tableName);\n\n for (const [fieldName, newField] of newTable.fields) {\n const info: SchemaFieldInfo = {\n table: tableName,\n field: fieldName,\n valueType: newField.valueType,\n isOptional: newField.isOptional,\n };\n\n if (!oldTable) {\n // Entire table is new\n if (newField.isOptional) {\n addedOptional.push(info);\n } else {\n addedRequired.push(info);\n }\n } else {\n const oldField = oldTable.fields.get(fieldName);\n if (!oldField) {\n // Field is new\n if (newField.isOptional) {\n addedOptional.push(info);\n } else {\n addedRequired.push(info);\n }\n } else if (oldField.isOptional && !newField.isOptional) {\n // Field changed from optional → required\n newRequired.push(info);\n }\n }\n }\n }\n\n // Detect removed fields: fields that exist in old but not in new\n for (const [tableName, oldTable] of oldTables) {\n const newTable = newTables.get(tableName);\n if (!newTable) continue; // Entire table removed — not our concern here\n\n for (const [fieldName, oldField] of oldTable.fields) {\n if (!newTable.fields.has(fieldName)) {\n removedFields.push({\n table: tableName,\n field: fieldName,\n valueType: oldField.valueType,\n wasOptional: oldField.isOptional,\n });\n }\n }\n }\n\n return {\n addedRequired,\n addedOptional,\n newRequired,\n removedFields,\n needsMigration: [...addedRequired, ...addedOptional, ...newRequired],\n };\n}\n\n/**\n * Rewrite specific fields in a schema string to be `v.optional(...)`.\n *\n * Used to produce an interim schema where new required fields are temporarily\n * optional, allowing Convex to accept the schema before documents are backfilled.\n */\nexport function makeFieldsOptional(\n schema: string,\n fields: SchemaFieldInfo[],\n): string {\n let result = schema;\n\n for (const field of fields) {\n if (field.isOptional) continue; // Already optional\n\n // Match ` <fieldName>: <valueType>,` within the schema and wrap in v.optional(...)\n // The field line looks like: ` fieldName: v.string(),`\n const escaped = field.field.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = new RegExp(\n `(\\\\s+${escaped}:\\\\s+)(${field.valueType.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")})(,?)`,\n );\n result = result.replace(pattern, `$1v.optional($2)$3`);\n }\n\n return result;\n}\n\n/**\n * Re-insert removed fields into a schema string as `v.optional(...)`.\n *\n * Used to produce an interim schema that still accepts documents with the\n * removed field, so we can strip the field from documents before deploying\n * the final schema without the field.\n */\nexport function addRemovedFieldsAsOptional(\n schema: string,\n fields: RemovedFieldInfo[],\n): string {\n let result = schema;\n\n // Group removed fields by table for efficient insertion\n const byTable = new Map<string, RemovedFieldInfo[]>();\n for (const f of fields) {\n const list = byTable.get(f.table) ?? [];\n list.push(f);\n byTable.set(f.table, list);\n }\n\n for (const [tableName, tableFields] of byTable) {\n // Find the closing `})` of the defineTable for this table\n const tablePattern = new RegExp(\n `(export\\\\s+const\\\\s+${tableName}\\\\s*=\\\\s*defineTable\\\\(\\\\{[\\\\s\\\\S]*?)(\\\\}\\\\))`,\n );\n const tableMatch = result.match(tablePattern);\n if (!tableMatch) continue;\n\n // Build the extra field lines\n const extraLines = tableFields.map((f) => {\n const optionalType = f.wasOptional\n ? f.valueType\n : `v.optional(${f.valueType})`;\n return ` ${f.field}: ${optionalType},`;\n });\n\n // Insert the extra fields before the closing `})`\n result = result.replace(\n tablePattern,\n `$1${extraLines.join(\"\\n\")}\\n$2`,\n );\n }\n\n return result;\n}\n","// =============================================================================\n// MIGRATION PLAN — maps schema diff to concrete backfill operations\n// =============================================================================\n\nimport type { SchemaDiff } from \"./diffSchema\";\nimport type { VexConfig } from \"../types\";\nimport type { VexField } from \"../types/fields\";\n\nexport interface MigrationOp {\n /** The table name (as exported in the schema). */\n table: string;\n /** The field name to backfill. */\n field: string;\n /** The default value to set on existing documents. */\n defaultValue: unknown;\n}\n\n/**\n * Given a schema diff and the full Vex config, produce a list of\n * migration operations — one per field that needs backfilling.\n *\n * Fields are matched by looking up the collection whose table name\n * (or slug) matches the diff's table, then finding the field's\n * `defaultValue`.\n *\n * Auth-only fields (fields that come from the auth adapter, not from\n * user-defined collections) are skipped — auth manages its own data.\n */\nexport function planMigration(props: {\n diff: SchemaDiff;\n config: VexConfig;\n}): MigrationOp[] {\n const { diff, config } = props;\n\n if (diff.needsMigration.length === 0) return [];\n\n // Build a lookup: table export name → collection fields\n const tableFieldsMap = new Map<\n string,\n Record<string, VexField>\n >();\n\n for (const collection of config.collections) {\n tableFieldsMap.set(collection.slug, collection.fields);\n }\n\n for (const global of config.globals) {\n tableFieldsMap.set(global.slug, global.fields);\n }\n\n const ops: MigrationOp[] = [];\n\n for (const fieldInfo of diff.needsMigration) {\n const collectionFields = tableFieldsMap.get(fieldInfo.table);\n\n if (!collectionFields) {\n // Table not found in user collections — likely an auth-only table\n continue;\n }\n\n const field = collectionFields[fieldInfo.field] as VexField | undefined;\n if (!field) {\n // Field not found in collection config — likely an auth-managed field\n continue;\n }\n\n if (!field.required) {\n // Only migrate required fields — optional fields don't need backfill\n continue;\n }\n const defaultValue = (field as any).defaultValue;\n if (defaultValue === undefined) {\n // No defaultValue — skip (required fields enforce defaultValue at config time)\n continue;\n }\n\n ops.push({\n table: fieldInfo.table,\n field: fieldInfo.field,\n defaultValue,\n });\n }\n\n return ops;\n}\n"],"mappings":";AA+CO,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAmCO,SAAS,wBAAkD;AAChE,SAAO;AAAA,IACL,WAAW;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO;AAAA,MACP,OAAO,EAAE,QAAQ,KAAK;AAAA,IACxB;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO;AAAA,MACP,OAAO,EAAE,UAAU,KAAK;AAAA,IAC1B;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO,EAAE,UAAU,KAAK;AAAA,IAC1B;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO;AAAA,MACP,OAAO,EAAE,UAAU,KAAK;AAAA,IAC1B;AAAA,IACA,KAAK;AAAA,MACH,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO;AAAA,MACP,OAAO,EAAE,UAAU,KAAK;AAAA,IAC1B;AAAA,IACA,KAAK,EAAE,MAAM,QAAQ,OAAO,WAAW;AAAA,IACvC,OAAO,EAAE,MAAM,UAAU,OAAO,aAAa;AAAA,IAC7C,QAAQ,EAAE,MAAM,UAAU,OAAO,cAAc;AAAA,EACjD;AACF;;;ACxIO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YAAY,SAAiB;AAC3B,UAAM,SAAS,OAAO,EAAE;AACxB,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,uBAAN,cAAmC,SAAS;AAAA,EACjD,YACkB,MACA,gBACA,kBACA,WACA,aAChB;AACA;AAAA,MACE,yBAAyB,IAAI;AAAA,MACtB,cAAc,KAAK,gBAAgB;AAAA,MACnC,SAAS,KAAK,WAAW;AAAA;AAAA,IAElC;AAXgB;AACA;AACA;AACA;AACA;AAQhB,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,0BAAN,cAAsC,SAAS;AAAA,EACpD,YACkB,gBACA,WACA,QAChB;AACA,UAAM,UAAU,SAAS,oBAAoB,cAAc,MAAM,MAAM,EAAE;AAJzD;AACA;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,qBAAN,cAAiC,SAAS;AAAA,EAC/C,YAAY,QAAgB;AAC1B,UAAM,6BAA6B,MAAM,EAAE;AAC3C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,sBAAN,cAAkC,SAAS;AAAA,EAChD,YAAY,QAAgB;AAC1B,UAAM,8BAA8B,MAAM,EAAE;AAC5C,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,uBAAN,cAAmC,SAAS;AAAA,EACjD,YAAY,QAAgB;AAC1B,UAAM,+BAA+B,MAAM,EAAE;AAC7C,SAAK,OAAO;AAAA,EACd;AACF;AASO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAC3C,YACkB,UACA,QACA,OAChB;AACA,UAAM,SAAS,QACX,UAAU,KAAK,kBAAkB,QAAQ,MACzC,aAAa,QAAQ;AACzB,UAAM,kBAAkB,MAAM,OAAO,MAAM,EAAE;AAP7B;AACA;AACA;AAMhB,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,0BAAN,cAAsC,SAAS;AAAA,EACpD,YACkB,WACA,QAChB;AACA,UAAM,UAAU,SAAS,MAAM,MAAM,EAAE;AAHvB;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;AC5GO,IAAM,kBAA2C;AAAA,EACtD,UAAU;AAAA,EACV,SAAS,CAAC;AAAA,EACV,aAAa,CAAC;AAAA,EACd,OAAO;AAAA,IACL,MAAM;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,MAAM;AAAA,IACN,SAAS;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA,YAAY;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,YAAY;AAAA,EACd;AACF;AAOA,SAAS,uBAAuB,OAEd;AAChB,QAAM,WAAW,sBAAsB;AAGvC,MAAI,MAAM,gBAAgB,QAAQ;AAChC,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,gBAAgB,MAAM,GAAsB;AAChG,UAAK,oBAA0C,SAAS,SAAS,GAAG;AAClE,YAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,kBAAQ;AAAA,YACN,2BAA2B,MAAM,gBAAgB,IAAI,aAAa,SAAS;AAAA,UAC7E;AAAA,QACF;AACA;AAAA,MACF;AACA,eAAS,SAAS,IAAI;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,cAAuC;AAAA,IAC3C,GAAG,MAAM,gBAAgB;AAAA,IACzB,YAAY,MAAM,gBAAgB,OAAO,cAAc;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,MAAM,MAAM,gBAAgB;AAAA,IAC5B,QAAQ;AAAA,IACR,WAAW,MAAM,gBAAgB;AAAA,IACjC,QAAQ,MAAM,gBAAgB;AAAA,IAC9B,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEO,SAAS,aAAa,WAAsC;AAEjE,MAAI,gBAAgB;AACpB,MAAI,UAAU,WAAW,UAAU,QAAQ,SAAS,GAAG;AACrD,eAAW,UAAU,UAAU,SAAS;AACtC,sBAAgB,OAAO,aAAa;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,UAAU,GAAG,oBAAoB,IAAI;AAEtD,QAAM,EAAE,OAAO,YAAY,GAAG,UAAU,IAAI;AAC5C,QAAM,WAAW;AACjB,QAAM,SAAoB;AAAA,IACxB,GAAG;AAAA,IACH,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG,gBAAgB;AAAA,MACnB,GAAG,SAAS;AAAA,MACZ,MAAM;AAAA,QACJ,GAAG,gBAAgB,MAAM;AAAA,QACzB,GAAG,SAAS,OAAO;AAAA,MACrB;AAAA,MACA,SAAS;AAAA,QACP,GAAG,gBAAgB,MAAM;AAAA,QACzB,GAAG,SAAS,OAAO;AAAA,MACrB;AAAA,MACA,YAAY;AAAA,QACV,GAAG,gBAAgB,MAAM;AAAA,QACzB,GAAG,SAAS,OAAO;AAAA,MACrB;AAAA,MACA,aAAa,SAAS,OAAO;AAAA,IAC/B;AAAA,IACA,QAAQ;AAAA,MACN,GAAG,gBAAgB;AAAA,MACnB,GAAG,SAAS;AAAA,IACd;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,aAAa,SAAS;AAAA,EACxB;AAGA,MAAI,YAAY;AACd,QAAI,WAAW,YAAY,WAAW,GAAG;AACvC,aAAO,QAAQ;AAAA,IACjB,WAAW,CAAC,WAAW,gBAAgB;AACrC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,QAAQ;AAAA,QACb,aAAa,WAAW,YAAY;AAAA,UAAI,CAAC,OACvC,uBAAuB,EAAE,iBAAiB,GAAG,CAAC;AAAA,QAChD;AAAA,QACA,gBAAgB,WAAW;AAAA,MAC7B;AAAA,IACF;AAAA,EACF,OAAO;AACL,WAAO,QAAQ;AAAA,EACjB;AAEA,MAAI,QAAQ,IAAI,aAAa,cAAc;AAEzC,eAAW,cAAc,OAAO,aAAa;AAC3C,UAAI,CAAC,oBAAoB,KAAK,WAAW,IAAI,GAAG;AAC9C,gBAAQ;AAAA,UACN,0BAA0B,WAAW,IAAI;AAAA,QAC3C;AAAA,MACF;AACA,UAAI,WAAW,KAAK,WAAW,MAAM,GAAG;AACtC,gBAAQ;AAAA,UACN,0BAA0B,WAAW,IAAI;AAAA,QAC3C;AAAA,MACF;AACA,UAAI,OAAO,KAAK,WAAW,MAAM,EAAE,WAAW,GAAG;AAC/C,gBAAQ,KAAK,qBAAqB,WAAW,IAAI,yBAAyB;AAAA,MAC5E;AAAA,IACF;AAGA,eAAW,UAAU,OAAO,SAAS;AACnC,UAAI,CAAC,oBAAoB,KAAK,OAAO,IAAI,GAAG;AAC1C,gBAAQ;AAAA,UACN,sBAAsB,OAAO,IAAI;AAAA,QACnC;AAAA,MACF;AACA,UAAI,OAAO,KAAK,WAAW,MAAM,GAAG;AAClC,gBAAQ,KAAK,sBAAsB,OAAO,IAAI,+BAA+B;AAAA,MAC/E;AACA,UAAI,OAAO,KAAK,OAAO,MAAM,EAAE,WAAW,GAAG;AAC3C,gBAAQ,KAAK,iBAAiB,OAAO,IAAI,yBAAyB;AAAA,MACpE;AAAA,IACF;AAGA,UAAM,QAAQ,OAAO,YAAY,OAAO,OAAO,OAAgB,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAClF,UAAM,aAAa,MAAM,OAAO,CAAC,MAAM,MAAM,MAAM,QAAQ,IAAI,MAAM,CAAC;AACtE,QAAI,WAAW,SAAS,GAAG;AACzB,cAAQ;AAAA,QACN,8CAA8C,WAAW,KAAK,IAAI,CAAC;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACzIO,SAAS,iBAId,OAwBA;AACA,QAAM,EAAE,MAAM,OAAO,GAAG,KAAK,IAAI;AACjC,SAAO;AAKT;AAqBO,SAAS,sBAGd,OAMqC;AACrC,SAAO;AACT;;;AClFO,SAAS,aAGd,OAQ4B;AAC5B,SAAO;AACT;;;ACWO,SAAS,aAAa,OAUT;AAElB,MAAI,MAAM,iBAAiB,CAAC,MAAM,cAAc;AAC9C,UAAM,IAAI,qBAAqB,qCAAqC;AAAA,EACtE;AACA,MAAI,MAAM,gBAAgB,CAAC,MAAM,eAAe;AAC9C,UAAM,IAAI,qBAAqB,qCAAqC;AAAA,EACtE;AAGA,QAAM,aAAa,MAAM,cAAc,MAAM;AAE7C,MAAI,QAAQ,IAAI,aAAa,cAAc;AAEzC,QAAI,CAAC,MAAM,gBAAgB,MAAM;AAC/B,cAAQ,KAAK,qDAAqD;AAAA,IACpE;AAGA,QAAI,MAAM,iBAAiB,CAAC,MAAM,cAAc,MAAM;AACpD,cAAQ,KAAK,oDAAoD;AAAA,IACnE;AAGA,QAAI,MAAM,WAAW;AACnB,YAAM,gBAAgB,IAAI;AAAA,QACxB,MAAM,UAAU,IAAI,CAAC,MAAW,EAAE,IAAI;AAAA,MACxC;AACA,iBAAW,QAAQ,OAAO,KAAK,MAAM,WAAW,GAAG;AACjD,cAAM,YAAY,MAAM,YAAY,IAAI;AACxC,YAAI,CAAC,UAAW;AAChB,mBAAW,QAAQ,OAAO,KAAK,SAAS,GAAG;AAEzC,cAAI,SAAS,QAAS;AACtB,cAAI,CAAC,cAAc,IAAI,IAAI,GAAG;AAC5B,oBAAQ;AAAA,cACN,4CAA4C,IAAI;AAAA,YAClD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,UAAM,WAAW,IAAI,IAAI,MAAM,KAAK;AACpC,eAAW,QAAQ,OAAO,KAAK,MAAM,WAAW,GAAG;AACjD,UAAI,CAAC,SAAS,IAAI,IAAI,GAAG;AACvB,gBAAQ;AAAA,UACN,wCAAwC,IAAI;AAAA,QAC9C;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM,YAAY;AACpB,YAAM,mBAAmB,IAAI,IAAI,MAAM,KAAK;AAC5C,iBAAW,aAAa,MAAM,YAAY;AACxC,YAAI,CAAC,iBAAiB,IAAI,SAAS,GAAG;AACpC,kBAAQ;AAAA,YACN,kCAAkC,SAAS;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM,gBAAgB,MAAM,gBAAgB,QAAQ;AACtD,UAAI,EAAE,MAAM,gBAAgB,MAAM,eAAe,SAAS;AACxD,gBAAQ;AAAA,UACN,qCAAqC,MAAM,YAAY;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,MAAM;AAAA,IACb;AAAA,IACA,gBAAgB,MAAM,eAAe;AAAA,IACrC,eAAe,MAAM,eAAe;AAAA,IACpC,cAAc,MAAM;AAAA,IACpB,aAAa,MAAM;AAAA,EACrB;AACF;;;ACtHO,SAAS,uBAAuB,OAMA;AAErC,MAAI,MAAM,UAAU,QAAW;AAC7B,QAAI,MAAM,WAAW,UAAa,MAAM,OAAO,WAAW,EAAG,QAAO;AACpE,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EAC9D;AAGA,MAAI;AACJ,MAAI,OAAO,MAAM,UAAU,YAAY;AACrC,UAAM,gBAAqB,MAAM,iBAAiB,SAC9C,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,cAAc,MAAM,aAAa,IACvE,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,KAAK;AACzC,eAAW,MAAM,MAAM,aAAa;AAAA,EACtC,OAAO;AACL,eAAW,MAAM;AAAA,EACnB;AAGA,MAAI,aAAa,QAAW;AAC1B,QAAI,MAAM,WAAW,OAAW,QAAO;AACvC,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,EAC/D;AAGA,MAAI,OAAO,aAAa,WAAW;AACjC,QAAI,MAAM,WAAW,OAAW,QAAO;AACvC,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,QAAmB,CAAC,CAAC;AAAA,EAC7E;AAGA,MAAI,MAAM,WAAW,QAAW;AAK9B,QAAI,SAAS,SAAS,QAAS,QAAO,SAAS,OAAO,SAAS;AAC/D,QAAI,SAAS,SAAS,OAAQ,QAAO,SAAS,OAAO,WAAW;AAChE,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,SAAS,SAAS;AAC7B,UAAM,WAAW,IAAI,IAAI,SAAS,MAAM;AACxC,WAAO,OAAO;AAAA,MACZ,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC;AAAA,IAC9C;AAAA,EACF;AAGA,QAAM,UAAU,IAAI,IAAI,SAAS,MAAM;AACvC,SAAO,OAAO;AAAA,IACZ,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;AAAA,EAC9C;AACF;AAaO,SAAS,qBAAqB,OAGE;AACrC,MAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,QAAI,MAAM,WAAW,OAAW,QAAO;AACvC,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EAC9D;AAGA,MAAI,MAAM,WAAW,UAAa,MAAM,OAAO,WAAW,GAAG;AAC3D,WAAO,MAAM,QAAQ;AAAA,MAAK,CAAC,MACzB,OAAO,MAAM,YAAY,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,OAAO;AAAA,IAC5D;AAAA,EACF;AAGA,SAAO,OAAO;AAAA,IACZ,MAAM,OAAO,IAAI,CAAC,MAAM;AAAA,MACtB;AAAA,MACA,MAAM,QAAQ;AAAA,QAAK,CAAC,MAClB,OAAO,MAAM,YAAY,IAAK,EAAE,CAAC,MAAM;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAoBO,SAAS,cAAc,OAUS;AAErC,MAAI,MAAM,WAAW,QAAW;AAC9B,QAAI,MAAM,WAAW,OAAW,QAAO;AACvC,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EAC9D;AAGA,MAAI,MAAM,UAAU,WAAW,GAAG;AAChC,QAAI,MAAM,eAAe;AACvB,YAAM,IAAI,eAAe,MAAM,UAAU,MAAM,MAAM;AAAA,IACvD;AACA,QAAI,MAAM,WAAW,OAAW,QAAO;AACvC,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,EAC/D;AAGA,QAAM,gBAAgB,IAAI,IAAI,MAAM,OAAO,KAAK;AAChD,QAAM,aAAa,MAAM,UAAU,OAAO,CAAC,MAAM,cAAc,IAAI,CAAC,CAAC;AAGrE,MAAI,WAAW,WAAW,GAAG;AAC3B,QAAI,MAAM,eAAe;AACvB,YAAM,IAAI,eAAe,MAAM,UAAU,MAAM,MAAM;AAAA,IACvD;AACA,QAAI,MAAM,WAAW,OAAW,QAAO;AACvC,WAAO,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,EAC/D;AAGA,QAAM,UAAkD,CAAC;AACzD,QAAM,OAAO,MAAM,QAAQ,CAAC;AAE5B,aAAW,QAAQ,YAAY;AAC7B,UAAM,YAAY,MAAM,OAAO,YAAY,IAAI;AAC/C,QAAI,cAAc,QAAW;AAE3B;AAAA,IACF;AAEA,UAAM,gBAAgB,UAAU,MAAM,QAAQ;AAC9C,QAAI,kBAAkB,QAAW;AAE/B,cAAQ,KAAK,IAAI;AACjB;AAAA,IACF;AAGA,QAAI,OAAO,kBAAkB,WAAW;AACtC,cAAQ,KAAK,aAAa;AAC1B;AAAA,IACF;AAEA,UAAM,cAAc,cAAc,MAAM,MAAM;AAC9C,YAAQ;AAAA,MACN,uBAAuB;AAAA,QACrB,OAAO;AAAA,QACP,QAAQ,MAAM;AAAA,QACd;AAAA,QACA,MAAM,MAAM;AAAA,QACZ,cAAc,MAAM;AAAA,MACtB,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,SAAS,qBAAqB;AAAA,IAClC;AAAA,IACA,QAAQ,MAAM;AAAA,EAChB,CAAC;AAGD,MAAI,MAAM,eAAe;AACvB,QAAI,OAAO,WAAW,WAAW;AAC/B,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,eAAe,MAAM,UAAU,MAAM,MAAM;AAAA,MACvD;AAAA,IACF,OAAO;AACL,YAAM,cAAc,OAAO,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,EAAEA,EAAC,MAAMA,OAAM,KAAK;AACtE,UAAI,aAAa;AACf,cAAM,IAAI,eAAe,MAAM,UAAU,MAAM,QAAQ,YAAY,CAAC,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC5NO,SAAS,iBAAiB,OAKrB;AAEV,MAAI,MAAM,WAAW,QAAW;AAC9B,WAAO;AAAA,EACT;AAGA,MAAI,MAAM,UAAU,WAAW,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,IAAI,IAAI,MAAM,OAAO,KAAK;AAEhD,aAAW,QAAQ,MAAM,WAAW;AAClC,QAAI,CAAC,cAAc,IAAI,IAAI,EAAG;AAE9B,UAAM,YAAY,MAAM,OAAO,YAAY,IAAI;AAC/C,QAAI,cAAc,OAAW;AAE7B,UAAM,YAAa,UAAsC;AAGzD,QAAI,cAAc,OAAW;AAG7B,QAAI,OAAO,cAAc,WAAW;AAClC,UAAI,UAAW,QAAO;AACtB;AAAA,IACF;AAGA,QAAI,OAAO,cAAc,YAAY;AACnC,YAAM,gBAAqB,MAAM,iBAAiB,SAC9C,EAAE,MAAM,MAAM,MAAM,cAAc,MAAM,aAAa,IACrD,EAAE,MAAM,MAAM,KAAK;AACvB,UAAI,UAAU,aAAa,EAAG,QAAO;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;;;ACpCO,SAAS,kBAAkB,OAgBjB;AACf,QAAM,QACJ,MAAM,MAAM,aACZ,MAAM,MAAM,SACZ,MAAM,KAAK,aACX,MAAM,KAAK,QACX;AAEF,QAAM,cACJ,MAAM,MAAM,mBACZ,MAAM,KAAK,mBACX,MAAM,KAAK,eACX;AAEF,QAAM,UAAU,MAAM,MAAM,WAAW,MAAM,KAAK,WAAW;AAE7D,QAAM,gBAAgB,MAAM,KAAK,iBAAiB;AAKlD,MAAI,aAAa;AACjB,MACE,MAAM,eACN,CAAC,MAAM,SAAS,MAAM,WAAW,KACjC,UAAU,MAAM,KAAK,MACrB;AACA,iBAAa,QAAQ,MAAM;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AChEO,SAAS,wBAAwB,QAAoC;AAC1E,QAAM,EAAE,OAAO,QAAQ,SAAS,GAAG,KAAK,IAAI;AAE5C,SAAO;AAAA,IACL,GAAG;AAAA,IACH,aAAa,KAAK,YAAY,IAAI,CAAC,eAAe;AAChD,UAAI,CAAC,WAAW,OAAO,YAAa,QAAO;AAC3C,UAAI,OAAO,WAAW,MAAM,YAAY,QAAQ,SAAU,QAAO;AAIjE,aAAO;AAAA,QACL,GAAG;AAAA,QACH,OAAO;AAAA,UACL,GAAG,WAAW;AAAA,UACd,aAAa;AAAA,YACX,GAAG,WAAW,MAAM;AAAA,YACpB,KAAK;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,IACD,OAAO,QACH,EAAE,aAAa,MAAM,YAAY,IACjC;AAAA,EACN;AACF;AASO,SAAS,0BAA0B,QAAkG;AAC1I,QAAM,SAAwF,CAAC;AAE/F,aAAW,cAAc,OAAO,aAAa;AAC3C,QAAI,WAAW,OAAO,eAAe,OAAO,WAAW,MAAM,YAAY,QAAQ,YAAY;AAC3F,aAAO,WAAW,IAAI,IAAI,EAAE,KAAK,WAAW,MAAM,YAAY,IAAI;AAAA,IACpE;AAAA,EACF;AAEA,SAAO;AACT;;;ACtCO,SAAS,kBAAkB,OAGtB;AACV,MAAI,CAAC,MAAM,OAAO,OAAO,YAAa,QAAO;AAC7C,SAAO,MAAM,OAAO,MAAM,YAAY;AAAA,IACpC,CAAC,OAAO,GAAG,SAAS,MAAM,WAAW;AAAA,EACvC;AACF;;;ACGO,SAAS,kBAAkB,OAGJ;AAC5B,QAAM,EAAE,QAAQ,iBAAiB,MAAM,IAAI;AAC3C,QAAM,SAAoC,CAAC;AAE3C,aAAW,KAAK,OAAO,aAAa;AAClC,WAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,QAAQ,MAAM,aAAa,CAAC;AAAA,EACpE;AAEA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,KAAK,OAAO,MAAM,aAAa;AACxC,aAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,MAAI,CAAC,gBAAgB;AACnB,eAAW,KAAK,OAAO,SAAS;AAC9B,aAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,QAAQ,MAAM,SAAS,CAAC;AAAA,IAChE;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,qBAAqB,OAIF;AACjC,SAAO,kBAAkB,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI,KAAK;AACxE;;;ACvEO,SAAS,SAAS,SAA4D;AACnF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAI,SAAS,YAAY,SAAS,iBAAiB,SAC/C,EAAE,cAAc,MAAM,IACtB,CAAC;AAAA,IACL,GAAG;AAAA,EACL;AACF;;;ACVA,IAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,YAAY,OAAuB;AACjD,QAAM,QAAQ,MACX,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,UAAU,GAAG,EACrB,KAAK,EACL,MAAM,KAAK;AAEd,SAAO,MACJ,IAAI,CAAC,MAAM,MAAM;AAChB,UAAM,QAAQ,KAAK,YAAY;AAC/B,QAAI,IAAI,KAAK,YAAY,IAAI,KAAK,EAAG,QAAO;AAC5C,WAAO,MAAM,OAAO,CAAC,EAAE,YAAY,IAAI,MAAM,MAAM,CAAC;AAAA,EACtD,CAAC,EACA,KAAK,GAAG;AACb;;;ACpBO,SAAS,kBAAkB,OAGK;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,EAC5D;AACF;;;ACRO,SAAS,6BAA6B,OAOlC;AACT,MAAI,CAAC,MAAM,MAAM,UAAU;AACzB,WAAO,cAAc,MAAM,SAAS;AAAA,EACtC;AAEA,MAAI,CAAC,MAAM,uBAAuB;AAChC,QAAI,MAAM,MAAM,iBAAiB,QAAW;AAC1C,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AACA,QAAI,EAAE,OAAO,MAAM,MAAM,iBAAiB,MAAM,eAAe;AAC7D,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN,4CAA4C,MAAM,YAAY,eAAe,OAAO,MAAM,MAAM,YAAY;AAAA,MAC9G;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM;AACf;;;AC/CO,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;;;ACG3B,SAAS,0BAA0B,OAI/B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AACH;;;ACnBO,SAAS,OAAO,SAAwD;AAC7E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAI,SAAS,YAAY,SAAS,iBAAiB,SAC/C,EAAE,cAAc,EAAE,IAClB,CAAC;AAAA,IACL,GAAG;AAAA,EACL;AACF;;;ACEO,SAAS,gBAAgB,OAGO;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,QAAQ;AAAA,EAC7D;AACF;;;ACZO,SAAS,wBAAwB,OAI7B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AACH;;;ACbO,SAAS,OACd,SACmB;AACnB,SAAO,EAAE,MAAM,UAAU,GAAG,QAAQ;AACtC;;;AC2Dc;AAhEd,IAAM,uBAAuB;AAAA,EAC3B;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAcO,SAAS,gBAAgB,OAGO;AACrC,QAAM,YAAY,IAAI;AAAA,IACpB,MAAM,MAAM,QAAQ,IAAI,CAAC,KAAK,MAAM;AAAA,MAClC,IAAI;AAAA,MACJ;AAAA,QACE,OAAO,IAAI;AAAA,QACX,OAAO,IAAI,cAAc,qBAAqB,IAAI,qBAAqB,MAAM;AAAA,MAC/E;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,SACG,MAAM,MAAM,UACT,MAAM,MAAM,QAAQ,WACpB,MAAM,MAAM,UAAU,YAAY,MAAM,QAAQ;AAAA,IACtD,MAAM;AAAA,MACJ,OAAO,MAAM,MAAM,OAAO,iBAAiB;AAAA,MAC3C,YAAY;AAAA,IACd;AAAA,IACA,MAAM,CAAC,SAAS;AACd,YAAM,MAAM,KAAK,SAAS;AAC1B,YAAM,SAAS,MAAM,QAAQ,GAAG,IAC3B,MACD,OAAO,OACL,CAAC,OAAO,GAAG,CAAC,IACZ,CAAC;AAEP,UAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,aACE,oBAAC,SAAI,WAAU,iEACZ,iBAAO,IAAI,CAACC,OAAM;AACjB,cAAM,MAAM,UAAU,IAAIA,EAAC;AAC3B,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAO,EAAE,iBAAiB,KAAK,MAAM;AAAA,YAEpC,eAAK,SAASA;AAAA;AAAA,UAJVA;AAAA,QAKP;AAAA,MAEJ,CAAC,GACH;AAAA,IAEJ;AAAA,EACF;AACF;;;AC1EO,SAAS,wBAAwB,OAI7B;AACT,QAAM,WAAW,MAAM,MAAM,QAAQ,IAAI,CAAC,MAAM,cAAc,EAAE,KAAK,IAAI,EAAE,KAAK,GAAG;AAEnF,MAAI,MAAM,MAAM,SAAS;AACvB,WAAO,6BAA6B;AAAA,MAClC,OAAO,MAAM;AAAA,MACb,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM;AAAA,MACjB,cAAc;AAAA,MACd,WAAW,MAAM,MAAM,QAAQ,WAAW,IACtC,WAAW,QAAQ,MACnB,mBAAmB,QAAQ;AAAA,MAC/B,uBAAuB;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW,WAAW,QAAQ;AAAA,EAChC,CAAC;AACH;;;ACnCO,SAAS,KAAK,SAAoD;AACvE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAI,SAAS,YAAY,SAAS,iBAAiB,SAC/C,EAAE,cAAc,GAAG,IACnB,CAAC;AAAA,IACL,GAAG;AAAA,EACL;AACF;;;ACMO,SAAS,cAAc,OAGS;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,EAC5D;AACF;;;ACbO,SAAS,sBAAsB,OAI3B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AACH;;;ACtBO,SAAS,KAAK,SAAoD;AACvE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAI,SAAS,YAAY,SAAS,iBAAiB,SAC/C,EAAE,cAAc,EAAE,IAClB,CAAC;AAAA,IACL,GAAG;AAAA,EACL;AACF;;;ACEO,SAAS,cAAc,OAGS;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM;AAAA,MACJ,OAAO,MAAM,MAAM,OAAO,iBAAiB;AAAA,IAC7C;AAAA,IACA,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,SAAS,KAAM,QAAO;AAC1B,aAAO,IAAI,KAAK,KAAe,EAAE,mBAAmB;AAAA,IACtD;AAAA,EACF;AACF;;;ACjBO,SAAS,sBAAsB,OAI3B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AACH;;;ACrBO,SAAS,SAAS,SAA4D;AACnF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAI,SAAS,YAAY,SAAS,iBAAiB,SAC/C,EAAE,cAAc,GAAG,IACnB,CAAC;AAAA,IACL,GAAG;AAAA,EACL;AACF;;;ACgBQ,gBAAAC,YAAA;AAdD,SAAS,kBAAkB,OAGK;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,SAAS;AAAA,IAC5D,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,YAAM,OAAO,MAAM,MAAM,SAAS;AAClC,YAAM,SAAS,MAAM,MAAM,UAAU;AACrC,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAI;AAAA,UACJ,OAAO;AAAA,UACP;AAAA,UACA,WAAU;AAAA,UACV,OAAO,EAAE,OAAO,MAAM,OAAO;AAAA,UAC7B,SAAQ;AAAA,UACR,gBAAe;AAAA,UACf,SAAS,CAAC,MAAM;AACd,YAAC,EAAE,cAAsB,MAAM,UAAU;AAAA,UAC3C;AAAA;AAAA,MACF;AAAA,IAEJ;AAAA,EACF;AACF;;;AC/BO,SAAS,0BAA0B,OAI/B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AACH;;;ACfO,SAAS,aACd,SACsB;AACtB,SAAO,EAAE,MAAM,gBAAgB,GAAG,QAAQ;AAC5C;;;ACCO,SAAS,sBAAsB,OAGC;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,SAAS,MAAM,MAAM,UAAU,MAAM,MAAM,QAAQ,WAAW,MAAM,MAAM,UAAU,YAAY,MAAM,QAAQ;AAAA,IAC9G,MAAM,EAAE,MAAM,gBAAgB,IAAI,MAAM,MAAM,IAAI,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,IACpG,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,SAAS,KAAM,QAAO;AAC1B,UAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,GAAG,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG;AACrF,aAAO,OAAO,KAAK;AAAA,IACrB;AAAA,EACF;AACF;;;AChBO,SAAS,8BAA8B,OAInC;AACT,QAAM,SAAS,SAAS,MAAM,MAAM,EAAE;AACtC,QAAM,gBAAgB,MAAM,MAAM,UAAU,WAAW,MAAM,MAAM;AAEnE,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;AC1BO,SAAS,KAAK,SAAoD;AACvE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;;;ACKO,SAAS,cAAc,OAGS;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,IAC1D,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,SAAS,KAAM,QAAO;AAC1B,YAAM,MAAM,KAAK,UAAU,KAAK;AAChC,aAAO,IAAI,SAAS,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,IACtD;AAAA,EACF;AACF;;;AChBO,SAAS,sBAAsB,OAI3B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;ACtBO,SAAS,OAAO,SAAuD;AAC5E,SAAO,EAAE,MAAM,UAAU,GAAG,QAAQ;AACtC;;;ACKO,SAAS,wBAAwB,OAU7B;AACT,QAAM,eAAyB,CAAC;AAEhC,aAAW,CAAC,cAAc,QAAQ,KAAK,OAAO,QAAQ,MAAM,MAAM,MAAM,GAAG;AACzE,UAAM,YAAY,MAAM,kBAAkB;AAAA,MACxC,OAAO;AAAA,MACP,gBAAgB,MAAM;AAAA,MACtB,WAAW,GAAG,MAAM,SAAS,IAAI,YAAY;AAAA,IAC/C,CAAC;AACD,iBAAa,KAAK,GAAG,YAAY,KAAK,SAAS,EAAE;AAAA,EACnD;AAEA,QAAM,aAAa,aAAa,UAAU,IACtC,cAAc,aAAa,KAAK,IAAI,CAAC,QACrC;AAAA,EAAe,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA;AAEhE,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;ACnCO,SAAS,gBAAgB,OAGO;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,IAC1D,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,SAAS,KAAM,QAAO;AAC1B,YAAM,MAAM,KAAK,UAAU,KAAK;AAChC,aAAO,IAAI,SAAS,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,IACtD;AAAA,EACF;AACF;;;ACPO,SAAS,SAAS,SAA4D;AACnF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;;;ACPO,SAAS,0BAA0B,OAI/B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;AChBO,SAAS,kBAAkB,OAGK;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,IAC1D,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,SAAS,KAAM,QAAO;AAC1B,UAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO;AACvD,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AClBO,SAAS,OACd,SACgB;AAChB,SAAO,EAAE,MAAM,UAAU,GAAG,QAAQ;AACtC;;;ACAO,SAAS,wBAAwB,OAI7B;AACT,QAAM,SAAS,SAAS,MAAM,MAAM,EAAE;AACtC,QAAM,gBAAgB,MAAM,MAAM,UAAU,WAAW,MAAM,MAAM;AAEnE,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;AC1BO,SAAS,MAAM,SAAqD;AACzE,SAAO,EAAE,MAAM,SAAS,GAAG,QAAQ;AACrC;;;ACQO,SAAS,eAAe,OAGQ;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,IAC1D,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO;AACxD,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,aAAO,GAAG,MAAM,MAAM;AAAA,IACxB;AAAA,EACF;AACF;;;AChBO,SAAS,uBAAuB,OAS5B;AACT,QAAM,iBAAiB,MAAM,kBAAkB;AAAA,IAC7C,OAAO,MAAM,MAAM;AAAA,IACnB,gBAAgB,MAAM;AAAA,IACtB,WAAW,GAAG,MAAM,SAAS;AAAA,EAC/B,CAAC;AAGD,MAAI,YAAY;AAChB,MAAI,UAAU,WAAW,aAAa,GAAG;AAEvC,UAAM,QAAQ,UAAU,MAAM,cAAc,MAAM;AAElD,QAAI,MAAM,SAAS,GAAG,GAAG;AACvB,kBAAY,MAAM,MAAM,GAAG,EAAE;AAAA,IAC/B;AAAA,EACF;AACA,QAAM,YAAY,WAAW,SAAS;AAEtC,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;AC1BO,SAAS,OAAO,OASJ;AACjB,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,SAAS,MAAM,QAAQ;AAChC,QAAI,KAAK,IAAI,MAAM,IAAI,GAAG;AACxB,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,yBAAyB,MAAM,IAAI;AAAA,MACrC;AAAA,IACF;AACA,SAAK,IAAI,MAAM,IAAI;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM;AAAA,IACd,KAAK,MAAM;AAAA,IACX,KAAK,MAAM;AAAA,IACX,OAAO,MAAM;AAAA,IACb,aAAa,MAAM;AAAA,IACnB,UAAU,MAAM;AAAA,IAChB,OAAO,MAAM;AAAA,EACf;AACF;;;AChCO,SAAS,wBAAwB,OAW7B;AACT,QAAM,UAAU,MAAM,qBAAqB,oBAAI,IAAY;AAE3D,MAAI,MAAM,MAAM,OAAO,WAAW,GAAG;AACnC,WAAO,6BAA6B;AAAA,MAClC,OAAO,MAAM;AAAA,MACb,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM;AAAA,MACjB,cAAc;AAAA,MACd,WAAW;AAAA,MACX,uBAAuB;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,QAAM,cAAwB,CAAC;AAE/B,aAAW,SAAS,MAAM,MAAM,QAAQ;AACtC,QAAI,QAAQ,IAAI,MAAM,IAAI,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,6CAA6C,MAAM,IAAI;AAAA,MACzD;AAAA,IACF;AAEA,UAAM,eAAe,IAAI,IAAI,OAAO;AACpC,iBAAa,IAAI,MAAM,IAAI;AAE3B,UAAM,eAAyB;AAAA,MAC7B,yBAAyB,MAAM,IAAI;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AAC7D,YAAM,YAAY,MAAM,kBAAkB;AAAA,QACxC;AAAA,QACA,gBAAgB,MAAM;AAAA,QACtB,WAAW,GAAG,MAAM,SAAS,IAAI,MAAM,IAAI,IAAI,SAAS;AAAA,QACxD,mBAAmB;AAAA,MACrB,CAAC;AACD,mBAAa,KAAK,GAAG,SAAS,KAAK,SAAS,EAAE;AAAA,IAChD;AAEA,gBAAY;AAAA,MACV;AAAA,EAAe,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,YACJ,YAAY,WAAW,IACnB,YAAY,CAAC,IACb;AAAA,EAAa,YAAY,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA;AAE/D,QAAM,YAAY;AAAA,EAAa,SAAS;AAAA;AAExC,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB,CAAC;AACH;;;ACnFO,SAAS,gBAAgB,OAGO;AACrC,QAAM,WAAW,MAAM,MAAM,QAAQ,YAAY;AACjD,QAAM,SAAS,MAAM,MAAM,QAAQ,UAAU;AAE7C,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACvD,MAAM,EAAE,OAAO,MAAM,MAAM,OAAO,iBAAiB,OAAO;AAAA,IAC1D,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO,MAAM,MAAM;AACpE,UAAI,MAAM,WAAW,EAAG,QAAO,KAAK,QAAQ;AAC5C,aAAO,GAAG,MAAM,MAAM,IAAI,MAAM;AAAA,IAClC;AAAA,EACF;AACF;;;ACpBO,SAAS,MAAM,OAAoD;AACxE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,EACR;AACF;;;ACRO,SAAS,uBAAuB,OAI5B;AACT,SAAO,6BAA6B;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AACH;;;ACbO,SAAS,eAAe,OAGQ;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM,MAAM,SAAS,MAAM;AAAA,IACnC,MAAM;AAAA,IACN,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,CAAC,MAAO,QAAO;AACnB,aAAO;AAAA,IACT;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,IACR;AAAA,EACF;AACF;;;ACAO,SAAS,iBAAiB,OAKtB;AACT,QAAM,EAAE,OAAO,gBAAgB,UAAU,IAAI;AAC7C,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,sBAAsB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACnE,KAAK;AACH,aAAO,wBAAwB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACrE,KAAK;AACH,aAAO,0BAA0B,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACvE,KAAK;AACH,aAAO,wBAAwB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACrE,KAAK;AACH,aAAO,sBAAsB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACnE,KAAK;AACH,aAAO,0BAA0B,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACvE,KAAK;AACH,aAAO,8BAA8B,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IAC3E,KAAK;AACH,aAAO,wBAAwB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACrE,KAAK;AACH,aAAO,sBAAsB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACnE,KAAK;AACH,aAAO,wBAAwB;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA,mBAAmB;AAAA,MACrB,CAAC;AAAA,IACH,KAAK;AACH,aAAO,0BAA0B,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACvE,KAAK;AACH,aAAO,uBAAuB;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,QACA,mBAAmB;AAAA,MACrB,CAAC;AAAA,IACH,KAAK;AACH,aAAO,wBAAwB;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA,mBAAmB,CAAC,eAClB,iBAAiB;AAAA,UACf,OAAO,WAAW;AAAA,UAClB,gBAAgB,WAAW;AAAA,UAC3B,WAAW,WAAW;AAAA,UACtB,mBAAmB,WAAW;AAAA,QAChC,CAAC;AAAA,QACH,mBAAmB,MAAM;AAAA,MAC3B,CAAC;AAAA,IACH,KAAK;AACH,aAAO,uBAAuB,EAAE,OAAO,gBAAgB,UAAU,CAAC;AAAA,IACpE,KAAK;AAEH,aAAO;AAAA,IACT,KAAK;AACH,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,aAAa,SAAS,oBAAoB,cAAc;AAAA,MAC1D;AAAA,IACF;AACE,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,uBAAwB,MAAc,IAAI;AAAA,MAC5C;AAAA,EACJ;AACF;;;AClFO,SAAS,eAAe,OAAuD;AACpF,QAAM,EAAE,WAAW,IAAI;AACvB,QAAM,eAAe,oBAAI,IAA2B;AAEpD,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,WAAW,MAAM,GAA2B;AACzF,UAAM,YAAY,MAAM;AACxB,QAAI,WAAW;AACb,UAAI,aAAa,IAAI,SAAS,GAAG;AAC/B,cAAM,IAAI;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA,+BAA+B,SAAS;AAAA,QAC1C;AAAA,MACF;AACA,mBAAa,IAAI,WAAW,EAAE,MAAM,WAAW,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAAA,IACrE;AAAA,EACF;AAEA,aAAW,SAAS,QAAQ,CAAC,UAAU;AACrC,iBAAa,IAAI,MAAM,MAAM,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,OAAO,CAAC;AAAA,EACzE,CAAC;AAED,QAAM,aAAa,WAAW,OAAO;AACrC,MAAI,cAAc,eAAe,OAAO;AACtC,UAAM,WAAW,MAAM,UAAU;AACjC,QAAI,CAAC,aAAa,IAAI,QAAQ,GAAG;AAC/B,mBAAa,IAAI,UAAU,EAAE,MAAM,UAAU,QAAQ,CAAC,UAAU,EAAE,CAAC;AAAA,IACrE;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,aAAa,OAAO,CAAC;AACzC;;;AC/BO,SAAS,qBAAqB,OAA6D;AAChG,QAAM,EAAE,WAAW,IAAI;AACvB,QAAM,gBAAgB,oBAAI,IAAiC;AAE3D,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,WAAW,MAAM,GAA2B;AACzF,UAAM,cAAc,MAAM;AAC1B,QAAI,eAAe,YAAY,MAAM;AACnC,UAAI,cAAc,IAAI,YAAY,IAAI,GAAG;AACvC,cAAM,IAAI;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA,gCAAgC,YAAY,IAAI;AAAA,QAClD;AAAA,MACF;AACA,oBAAc,IAAI,YAAY,MAAM;AAAA,QAClC,MAAM,YAAY;AAAA,QAClB,aAAa;AAAA,QACb,cAAc,YAAY;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,aAAW,eAAe,QAAQ,CAAC,UAAU;AAC3C,kBAAc,IAAI,MAAM,MAAM;AAAA,MAC5B,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM,gBAAgB,CAAC;AAAA,IACvC,CAAC;AAAA,EACH,CAAC;AAED,QAAM,aAAa,WAAW,OAAO;AACrC,MAAI,cAAc,eAAe,OAAO;AACtC,UAAM,WAAW,UAAU,UAAU;AACrC,UAAM,iBAAiB,MAAM,KAAK,cAAc,OAAO,CAAC,EAAE;AAAA,MACxD,CAAC,OAAO,GAAG,gBAAgB;AAAA,IAC7B;AACA,QAAI,CAAC,kBAAkB,CAAC,cAAc,IAAI,QAAQ,GAAG;AACnD,oBAAc,IAAI,UAAU;AAAA,QAC1B,MAAM;AAAA,QACN,aAAa;AAAA,QACb,cAAc,CAAC;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,cAAc,OAAO,CAAC;AAC1C;;;ACfO,SAAS,sCAAsC,OAG3B;AACzB,QAAM,EAAE,gBAAgB,eAAe,IAAI;AAC3C,QAAM,SAAmC,CAAC;AAC1C,QAAM,cAAwB,CAAC;AAC/B,QAAM,WAAqB,CAAC;AAC5B,QAAM,WAAqB,CAAC;AAE5B,QAAM,aAAa,eAAe;AAClC,QAAM,aAAa,eAAe;AAClC,QAAM,gBAAgB,OAAO,KAAK,UAAU;AAC5C,QAAM,gBAAgB,OAAO,KAAK,UAAU;AAG5C,aAAW,YAAY,eAAe;AACpC,QAAI,cAAc,SAAS,QAAQ,GAAG;AACpC,kBAAY,KAAK,QAAQ;AAIzB,YAAM,YAAY,WAAW,QAAQ;AACrC,YAAM,YAAY,WAAW,QAAQ;AACrC,aAAO,QAAQ,IAAI;AAAA,QACjB,GAAG;AAAA,QACH,UAAU,UAAU;AAAA,QACpB,GAAK,UAAkB,iBAAiB,UAAa,EAAE,cAAe,UAAkB,aAAa;AAAA,MACvG;AAAA,IACF,OAAO;AACL,eAAS,KAAK,QAAQ;AACtB,aAAO,QAAQ,IAAI,WAAW,QAAQ;AAAA,IACxC;AAAA,EACF;AAGA,aAAW,YAAY,eAAe;AACpC,QAAI,cAAc,SAAS,QAAQ,EAAG;AACtC,aAAS,KAAK,QAAQ;AACtB,WAAO,QAAQ,IAAI,WAAW,QAAQ;AAAA,EACxC;AAGA,QAAM,UAA2B,CAAC;AAClC,QAAM,aAAa,oBAAI,IAAY;AAGnC,aAAW,OAAO,eAAe,WAAW,CAAC,GAAG;AAC9C,YAAQ,KAAK,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI,OAAmB,CAAC;AAC/D,eAAW,IAAI,IAAI,IAAI;AAAA,EACzB;AAGA,aAAW,OAAO,eAAe,WAAW,CAAC,GAAG;AAC9C,QAAI,CAAC,WAAW,IAAI,IAAI,IAAI,GAAG;AAC7B,cAAQ,KAAK,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI,OAAmB,CAAC;AAC/D,iBAAW,IAAI,IAAI,IAAI;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,iBACJ,eAAe,iBAAiB,CAAC,GACjC,IAAI,CAAC,QAAQ;AAAA,IACb,MAAM,GAAG;AAAA,IACT,aAAa,GAAG;AAAA,IAChB,cAAe,GAAG,gBAAgB,CAAC;AAAA,EACrC,EAAE;AAEF,SAAO,EAAE,QAAQ,SAAS,eAAe,aAAa,UAAU,SAAS;AAC3E;;;AC3GO,IAAM,eAAe;AAAA,EAC1B,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,QAAQ;AACV;AAiBO,IAAM,eAAN,MAAmB;AAAA,EAChB,gBAAgB,oBAAI,IAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqB1D,SAAS,OAIA;AACP,UAAM,WAAW,KAAK,cAAc,IAAI,MAAM,IAAI;AAClD,QAAI,UAAU;AAIZ,UACG,SAAS,WAAW,qBACnB,MAAM,WAAW,gBAClB,SAAS,WAAW,gBAAgB,MAAM,WAAW,mBACtD;AAEA,YAAI,MAAM,WAAW,mBAAmB;AACtC,eAAK,cAAc,IAAI,MAAM,MAAM;AAAA,YACjC,MAAM,MAAM;AAAA,YACZ,QAAQ,MAAM;AAAA,YACd,UAAU,MAAM;AAAA,UAClB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AACA,SAAK,cAAc,IAAI,MAAM,MAAM;AAAA,MACjC,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,UAAU,MAAM;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,SAA6B;AAC3B,WAAO,CAAC,GAAG,KAAK,cAAc,OAAO,CAAC;AAAA,EACxC;AACF;AAqBO,SAAS,kBAAkB,OAA4C;AAC5E,QAAM,WAAW,IAAI,aAAa;AAElC,aAAW,cAAc,MAAM,OAAO,aAAa;AACjD,aAAS,SAAS;AAAA,MAChB,MAAM,WAAW;AAAA,MACjB,QAAQ,aAAa;AAAA,MACrB,UAAU,cAAc,WAAW,IAAI;AAAA,IACzC,CAAC;AAAA,EACH;AAGA,MAAI,MAAM,OAAO,OAAO;AACtB,eAAW,cAAc,MAAM,OAAO,MAAM,aAAa;AACvD,eAAS,SAAS;AAAA,QAChB,MAAM,WAAW;AAAA,QACjB,QAAQ,aAAa;AAAA,QACrB,UAAU,oBAAoB,WAAW,IAAI;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,aAAW,UAAU,MAAM,OAAO,SAAS;AACzC,aAAS,SAAS;AAAA,MAChB,MAAM,OAAO;AAAA,MACb,QAAQ,aAAa;AAAA,MACrB,UAAU,UAAU,OAAO,IAAI;AAAA,IACjC,CAAC;AAAA,EACH;AAEA,aAAW,cAAc,MAAM,OAAO,KAAK,aAAa;AACtD,aAAS,SAAS;AAAA,MAChB,MAAM,WAAW;AAAA,MACjB,QAAQ,aAAa;AAAA,MACrB,UAAU,cAAc,WAAW,IAAI;AAAA,IACzC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACpJA,SAAS,aAAa,OAGoB;AACxC,QAAM,SAAgD,CAAC;AAEvD,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAA2B;AACrF,QAAI,MAAM,SAAS,KAAM;AAEzB,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,YAAY;AAClB,iBAAW,OAAO,UAAU,MAAM;AAChC,cAAM,cAAwB,CAAC;AAC/B,mBAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,IAAI,MAAM,GAA2B;AACxF,cAAI,WAAW,SAAS,KAAM;AAC9B,gBAAM,iBAAiB,iBAAiB;AAAA,YACtC,OAAO;AAAA,YACP,gBAAgB,MAAM;AAAA,YACtB,WAAW;AAAA,UACb,CAAC;AACD,sBAAY,KAAK,GAAG,SAAS,KAAK,cAAc,EAAE;AAAA,QACpD;AACA,YAAI,YAAY,SAAS,GAAG;AAC1B,iBAAO,KAAK;AAAA,YACV,MAAM,IAAI;AAAA,YACV,WAAW,yBAAyB,YAAY,KAAK,IAAI,CAAC;AAAA,UAC5D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,WAAW,iBAAiB;AAAA,UAC1B;AAAA,UACA;AAAA,UACA,gBAAgB,MAAM;AAAA,QACxB,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAiBO,SAAS,kBAAkB,OAAsC;AACtE,QAAM,SAAS,MAAM;AACrB,oBAAkB,EAAE,OAAO,CAAC;AAC5B,QAAM,oBAAoB,IAAI;AAAA,IAC5B,OAAO,KAAK,YAAY,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAAA,EAChD;AACA,QAAM,kBAAkB,oBAAI,IAAY;AAExC,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,IAAI,OAAO,uBAAuB,MAAM;AAAA,EACrD;AAEA,aAAW,cAAc,OAAO,aAAa;AAC3C,UAAM,iBAAiB,kBAAkB,IAAI,WAAW,IAAI;AAC5D,UAAM,SAAgD,CAAC;AACvD,UAAM,UAA2B,eAAe,EAAE,WAAW,CAAC;AAC9D,UAAM,gBAAuC,qBAAqB;AAAA,MAChE;AAAA,IACF,CAAC;AAED,QAAI,gBAAgB;AAClB,sBAAgB,IAAI,eAAe,IAAI;AACvC,YAAM,SAAS,sCAAsC;AAAA,QACnD;AAAA,QACA,gBAAgB;AAAA,MAClB,CAAC;AAGD,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AACzD,YAAI,MAAM,SAAS,KAAM;AACzB,eAAO,KAAK;AAAA,UACV;AAAA,UACA,WAAW,iBAAiB;AAAA,YAC1B;AAAA,YACA,gBAAgB,WAAW;AAAA,YAC3B,WAAW;AAAA,UACb,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAGA,iBAAW,SAAS,OAAO,SAAS;AAClC,YAAI,QAAQ,KAAK,CAACC,QAAOA,IAAG,SAAS,MAAM,IAAI,EAAG;AAClD,gBAAQ,KAAK,KAAK;AAAA,MACpB;AAGA,iBAAW,MAAM,OAAO,eAAe;AACrC,YAAI,cAAc,KAAK,CAAC,aAAa,SAAS,SAAS,GAAG,IAAI;AAC5D;AACF,sBAAc,KAAK,EAAE;AAAA,MACvB;AAAA,IACF,OAAO;AACL,aAAO,KAAK,GAAG,aAAa;AAAA,QAC1B,QAAQ,WAAW;AAAA,QACnB,gBAAgB,WAAW;AAAA,MAC7B,CAAC,CAAC;AAAA,IACJ;AAEA,UAAM;AAAA,MACJ;AAAA,MACA,gBAAgB,WAAW,aAAa,WAAW,IAAI;AAAA,IACzD;AACA,eAAW,KAAK,QAAQ;AACtB,YAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,SAAS,GAAG;AAAA,IAC3C;AAEA,UAAM,KAAK,gFAAgF;AAC3F,QAAI,WAAW,UAAU,QAAQ;AAC/B,YAAM,KAAK,wCAAwC;AACnD,YAAM,KAAK,4CAA4C;AAAA,IACzD;AACA,UAAM,KAAK,IAAI;AACf,eAAW,KAAK,SAAS;AACvB,YAAM,YAAY,EAAE,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACzD,YAAM,KAAK,aAAa,EAAE,IAAI,OAAO,SAAS,IAAI;AAAA,IACpD;AACA,eAAW,MAAM,eAAe;AAC9B,YAAM,aACJ,GAAG,aAAa,SAAS,IACrB,oBAAoB,GAAG,aAAa,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,MACnE;AACN,YAAM;AAAA,QACJ,mBAAmB,GAAG,IAAI,sBAAsB,GAAG,WAAW,IAAI,UAAU;AAAA,MAC9E;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,SAAS,OAAO,MAAM,YAAY,SAAS,GAAG;AACvD,UAAM,KAAK,IAAI,OAAO,wBAAwB,MAAM;AAEpD,eAAW,mBAAmB,OAAO,MAAM,aAAa;AACtD,YAAM,SAAgD,CAAC;AACvD,YAAM,UAA2B,eAAe,EAAE,YAAY,gBAAgB,CAAC;AAC/E,YAAM,gBAAuC,qBAAqB;AAAA,QAChE,YAAY;AAAA,MACd,CAAC;AAED,iBAAW,CAAC,WAAW,KAAK,KAAK,OAAO;AAAA,QACtC,gBAAgB;AAAA,MAClB,GAA2B;AACzB,YAAI,MAAM,SAAS,KAAM;AACzB,YAAI,cAAc,aAAa;AAE7B,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,WAAW,OAAO,MAAM,eAAe;AAAA,UACzC,CAAC;AAAA,QACH,OAAO;AACL,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,WAAW,iBAAiB;AAAA,cAC1B;AAAA,cACA;AAAA,cACA,gBAAgB,gBAAgB;AAAA,YAClC,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM;AAAA,QACJ;AAAA,QACA,gBAAgB,gBAAgB,aAAa,gBAAgB,IAAI;AAAA,MACnE;AACA,iBAAW,KAAK,QAAQ;AACtB,cAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,SAAS,GAAG;AAAA,MAC3C;AACA,YAAM,KAAK,IAAI;AACf,iBAAW,KAAK,SAAS;AACvB,cAAM,YAAY,EAAE,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACzD,cAAM,KAAK,aAAa,EAAE,IAAI,OAAO,SAAS,IAAI;AAAA,MACpD;AACA,iBAAW,MAAM,eAAe;AAC9B,cAAM,aACJ,GAAG,aAAa,SAAS,IACrB,oBAAoB,GAAG,aAAa,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,MACnE;AACN,cAAM;AAAA,UACJ,mBAAmB,GAAG,IAAI,sBAAsB,GAAG,WAAW,IAAI,UAAU;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,0BAA0B,OAAO,KAAK,YAAY;AAAA,IACtD,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,IAAI;AAAA,EACpC;AAEA,MAAI,wBAAwB,SAAS,GAAG;AACtC,UAAM,KAAK,IAAI,OAAO,kBAAkB,MAAM;AAAA,EAChD;AAEA,aAAW,kBAAkB,yBAAyB;AACpD,UAAM,UAA2B,eAAe;AAAA,MAC9C,YAAY;AAAA,IACd,CAAC;AACD,UAAM;AAAA,MACJ;AAAA,MACA,gBAAgB,eAAe,aAAa,eAAe,IAAI;AAAA,IACjE;AACA,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,eAAe,MAAM,GAA2B;AACzF,YAAM;AAAA,QACJ,KAAK,IAAI,KAAK,iBAAiB;AAAA,UAC7B;AAAA,UACA,gBAAgB,eAAe;AAAA,UAC/B,WAAW;AAAA,QACb,CAAC,CAAC;AAAA,MACJ;AAAA,IACF;AACA,UAAM,KAAK,IAAI;AACf,eAAW,KAAK,SAAS;AACvB,YAAM,YAAY,EAAE,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACzD,YAAM,KAAK,aAAa,EAAE,IAAI,OAAO,SAAS,IAAI;AAAA,IACpD;AAAA,EACF;AAEA,aAAW,UAAU,OAAO,SAAS;AACnC,UAAM,SAAgD,CAAC;AACvD,UAAM,UAA2B,eAAe,EAAE,YAAY,OAAO,CAAC;AACtE,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC9D,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,WAAW,iBAAiB;AAAA,UAC1B;AAAA,UACA;AAAA,UACA,gBAAgB,OAAO;AAAA,QACzB,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,UAAM;AAAA,MACJ;AAAA,MACA,gBAAgB,OAAO,aAAa,OAAO,IAAI;AAAA,IACjD;AACA,eAAW,KAAK,QAAQ;AACtB,YAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,SAAS,GAAG;AAAA,IAC3C;AAEA,UAAM,KAAK,gFAAgF;AAC3F,QAAK,OAAe,UAAU,QAAQ;AACpC,YAAM,KAAK,wCAAwC;AACnD,YAAM,KAAK,4CAA4C;AAAA,IACzD;AACA,UAAM,KAAK,IAAI;AACf,eAAW,KAAK,SAAS;AACvB,YAAM,YAAY,EAAE,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACzD,YAAM,KAAK,aAAa,EAAE,IAAI,OAAO,SAAS,IAAI;AAAA,IACpD;AAAA,EACF;AAIA;AACE,UAAM,KAAK,IAAI,OAAO,wBAAwB,MAAM;AACpD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,2CAA2C;AACtD,UAAM,KAAK,2BAA2B;AACtC,UAAM,KAAK,2BAA2B;AACtC,UAAM,KAAK,wBAAwB;AACnC,UAAM,KAAK,oBAAoB;AAC/B,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,6BAA6B;AACxC,UAAM,KAAK,4BAA4B;AACvC,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,MAAM;AACjB,UAAM,KAAK,sBAAsB;AACjC,UAAM,KAAK,0BAA0B;AACrC,UAAM,KAAK,sCAAsC;AACjD,UAAM,KAAK,4BAA4B;AACvC,UAAM,KAAK,yCAAyC;AACpD,UAAM,KAAK,IAAI;AACf,UAAM,KAAK,uDAAuD;AAClE,UAAM,KAAK,0EAA0E;AACrF,UAAM,KAAK,2EAA2E;AACtF,UAAM,KAAK,wEAAwE;AACnF,UAAM,KAAK,qEAAqE;AAAA,EAClF;AAEA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;;;AC/TA,SAAS,mBAAyC;AA6C3C,SAAS,YAGd,OAGyC;AACzC,QAAM,EAAE,UAAU,IAAI,MAAM;AAE5B,MAAI,WAAW,YAAY;AAAA,IACzB,GAAG,UAAU;AAAA,IACb,GAAG,MAAM;AAAA,EACX,CAAC;AAGD,aAAW,OAAO,MAAM,MAAM,UAAU,EAAE,GAAG;AAC3C,eAAW,SAAS;AAAA,MAClB,IAAI;AAAA,MACJ,IAAI;AAAA,IACN;AAAA,EACF;AAGA,QAAM,SAAS,MAAM;AAErB,aAAW,OAAO,OAAO,iBAAiB,CAAC,GAAG;AAC5C,eAAW,SAAS,YAAY,IAAI,iBAAiB;AAAA,MACnD,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI;AAAA,IACpB,CAAQ;AAAA,EACV;AAEA,aAAW,OAAO,OAAO,iBAAiB,CAAC,GAAG;AAC5C,eAAW,SAAS,YAAY,IAAI,iBAAiB;AAAA,MACnD,aAAa,IAAI;AAAA,MACjB,YAAY,IAAI;AAAA,MAChB,cAAc,IAAI;AAAA,IACpB,CAAQ;AAAA,EACV;AAEA,SAAO;AACT;;;ACzEO,SAAS,gBAAgB,OAGO;AACrC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,SAAS,MAAM,MAAM,UAAU,MAAM,MAAM,QAAQ,WAAW,MAAM,MAAM,UAAU,YAAY,MAAM,QAAQ;AAAA,IAC9G,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,IAAI,MAAM,MAAM;AAAA,MAChB,YAAY;AAAA,IACd;AAAA,IACA,MAAM,CAAC,SAAS;AACd,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACLO,SAAS,gBAAgB,OAGS;AACvC,QAAM,EAAE,YAAY,KAAK,IAAI;AAC7B,QAAM,UAAgD,CAAC;AACvD,QAAM,aAAa,WAAW,OAAO;AACrC,QAAM,iBAAiB,WAAW,OAAO;AAGzC,QAAM,SAAS,WAAW;AAG1B,QAAM,aAAuC,CAAC;AAC9C,MAAI,MAAM;AACR,UAAM,iBAAiB,KAAK,YAAY;AAAA,MACtC,CAAC,MAAqB,EAAE,SAAS,WAAW;AAAA,IAC9C;AACA,QAAI,gBAAgB;AAClB,iBAAW,CAAC,GAAGC,EAAC,KAAK,OAAO,QAAQ,eAAe,MAAM,GAGpD;AACH,mBAAW,CAAC,IAAIA;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB;AAClB,eAAW,YAAY,gBAAgB;AACrC,UAAI,aAAa,OAAO;AACtB,gBAAQ,KAAK,EAAE,aAAa,OAAO,QAAQ,KAAK,CAAC;AACjD;AAAA,MACF;AAEA,YAAM,QAAS,OAAO,QAAQ,KAAK,WAAW,QAAQ;AAItD,UAAI,CAAC,OAAO;AACV,gBAAQ,KAAK,EAAE,aAAa,UAAU,QAAQ,YAAY,QAAQ,EAAE,CAAC;AACrE;AAAA,MACF;AAEA,UAAI,MAAM,OAAO,OAAQ;AACzB,UAAI,MAAM,SAAS,QAAQ,MAAM,SAAS,OAAQ;AAElD,YAAM,MAAM,eAAe,UAAU,KAAK;AAE1C,UAAI,cAAc,aAAa,YAAY;AACzC,YAAI,OAAO,EAAE,GAAG,IAAI,MAAM,SAAS,KAAK;AAAA,MAC1C;AAGA,UAAI,MAAM,OAAO,YAAY,MAAM;AACjC,YAAI,OAAO;AAAA,UACT,GAAG,IAAI;AAAA,UACP,YAAY,MAAM,MAAM,WAAW;AAAA,UACnC,UAAU;AAAA,QACZ;AAAA,MACF;AAEA,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF,OAAO;AACL,YAAQ,KAAK,EAAE,aAAa,OAAO,QAAQ,KAAK,CAAC;AAGjD,UAAM,eAAe,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC;AAChD,eAAW,KAAK,OAAO,KAAK,UAAU,GAAG;AACvC,mBAAa,IAAI,CAAC;AAAA,IACpB;AAEA,eAAW,YAAY,cAAc;AACnC,YAAM,QAAS,OAAO,QAAQ,KAAK,WAAW,QAAQ;AACtD,UAAI,MAAM,OAAO,OAAQ;AACzB,UAAI,MAAM,SAAS,QAAQ,MAAM,SAAS,OAAQ;AAElD,YAAM,MAAM,eAAe,UAAU,KAAK;AAE1C,UAAI,cAAc,aAAa,YAAY;AACzC,YAAI,OAAO,EAAE,GAAG,IAAI,MAAM,SAAS,KAAK;AAAA,MAC1C;AAGA,UAAI,MAAM,OAAO,YAAY,MAAM;AACjC,YAAI,OAAO;AAAA,UACT,GAAG,IAAI;AAAA,UACP,YAAY,MAAM,MAAM,WAAW;AAAA,UACnC,UAAU;AAAA,QACZ;AAAA,MACF;AAEA,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eACP,UACA,OACoC;AACpC,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,cAAc,EAAE,UAAU,MAAM,CAAC;AAAA,IAC1C,KAAK;AACH,aAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC5C,KAAK;AACH,aAAO,kBAAkB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC9C,KAAK;AACH,aAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC5C,KAAK;AACH,aAAO,cAAc,EAAE,UAAU,MAAM,CAAC;AAAA,IAC1C,KAAK;AACH,aAAO,kBAAkB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC9C,KAAK;AACH,aAAO,sBAAsB,EAAE,UAAU,MAAM,CAAC;AAAA,IAClD,KAAK;AACH,aAAO,cAAc,EAAE,UAAU,MAAM,CAAC;AAAA,IAC1C,KAAK;AACH,aAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC5C,KAAK;AACH,aAAO,kBAAkB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC9C,KAAK;AACH,aAAO,eAAe,EAAE,UAAU,MAAM,CAAC;AAAA,IAC3C,KAAK;AACH,aAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC5C,KAAK;AACH,aAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;AAAA,IAC5C,KAAK;AACH,aAAO,eAAe,EAAE,UAAU,MAAM,CAAC;AAAA,IAC3C;AACE,aAAO;AAAA,QACL,aAAa;AAAA,QACb,QAAQ,YAAY,QAAQ;AAAA,MAC9B;AAAA,EACJ;AACF;;;ACrKA,SAAS,SAA0B;AAW5B,SAAS,mBAAmB,OAES;AAC1C,QAAM,QAAoC,CAAC;AAE3C,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AAC7D,QAAI,MAAM,OAAO,OAAQ;AACzB,QAAI,MAAM,SAAS,KAAM;AAGzB,QAAI,MAAM,SAAS,QAAQ;AACzB,iBAAW,OAAO,MAAM,MAAM;AAC5B,cAAM,YAAwC,CAAC;AAC/C,mBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,IAAI,MAAM,GAAG;AAC5D,cAAI,SAAS,SAAS,KAAM;AAC5B,cAAI,eAAe,eAAe,EAAE,OAAO,SAAS,CAAC;AACrD,cAAI,CAAC,SAAS,SAAU,gBAAe,aAAa,SAAS;AAC7D,oBAAU,OAAO,IAAI;AAAA,QACvB;AACA,cAAM,IAAI,IAAI,IAAI,EAAE,OAAO,SAAS,EAAE,SAAS;AAAA,MACjD;AACA;AAAA,IACF;AAEA,QAAI,YAAY,eAAe,EAAE,MAAM,CAAC;AAExC,QAAI,CAAC,MAAM,UAAU;AACnB,kBAAY,UAAU,SAAS;AAAA,IACjC;AAEA,UAAM,SAAS,IAAI;AAAA,EACrB;AAEA,SAAO,EAAE,OAAO,KAAK;AACvB;AASO,SAAS,eAAe,OAAwC;AACrE,UAAQ,MAAM,MAAM,MAAM;AAAA,IACxB,KAAK,QAAQ;AACX,UAAI,SAAS,EAAE,OAAO;AACtB,UAAI,MAAM,MAAM,aAAa,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,SAAS;AAC5E,UAAI,MAAM,MAAM,aAAa,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,SAAS;AAC5E,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,UAAU;AACb,UAAI,SAAS,EAAE,OAAO;AACtB,UAAI,MAAM,MAAM,OAAO,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,GAAG;AAChE,UAAI,MAAM,MAAM,OAAO,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,GAAG;AAChE,aAAO;AAAA,IACT;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,QAAQ;AAAA,IAEnB,KAAK,UAAU;AACb,YAAM,SAAS,MAAM,MAAM,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK;AACrD,UAAI,OAAO,WAAW,EAAG,QAAO,EAAE,OAAO;AACzC,YAAM,aAAa,EAAE,KAAK,MAA+B;AACzD,UAAI,MAAM,MAAM,SAAS;AACvB,eAAO,EAAE,MAAM,UAAU;AAAA,MAC3B;AACA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,OAAO;AAAA,IAElB,KAAK;AACH,aAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AAAA,IAE1C,KAAK,gBAAgB;AACnB,UAAI,MAAM,MAAM,SAAS;AACvB,eAAO,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,MAC3B;AACA,aAAO,EAAE,OAAO;AAAA,IAClB;AAAA,IAEA,KAAK,UAAU;AACb,UAAI,MAAM,MAAM,SAAS;AACvB,eAAO,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,MAC3B;AACA,aAAO,EAAE,OAAO;AAAA,IAClB;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,IAAI;AAAA,IAEf,KAAK,UAAU;AACb,YAAM,QAAoC,CAAC;AAC3C,iBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,MAAM,MAAM,MAAM,GAAG;AACpE,YAAI,eAAe,eAAe,EAAE,OAAO,SAAqB,CAAC;AACjE,YAAI,CAAE,SAAsB,SAAU,gBAAe,aAAa,SAAS;AAC3E,cAAM,OAAO,IAAI;AAAA,MACnB;AACA,aAAO,EAAE,OAAO,KAAK;AAAA,IACvB;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,IAAI;AAAA,IAEf,KAAK;AACH,aAAO,EAAE,OAAO;AAAA,IAElB,KAAK;AAEH,aAAO,EAAE,IAAI;AAAA,IAEf,KAAK,SAAS;AACZ,UAAI,SAAS,EAAE,MAAM,eAAe,EAAE,OAAO,MAAM,MAAM,MAAM,CAAC,CAAC;AACjE,UAAI,MAAM,MAAM,OAAO,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,GAAG;AAChE,UAAI,MAAM,MAAM,OAAO,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,GAAG;AAChE,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,UAAU;AACb,YAAM,eAAe,MAAM,MAAM,OAAO,IAAI,CAAC,aAAa;AACxD,cAAM,QAAoC;AAAA,UACxC,WAAW,EAAE,QAAQ,SAAS,IAAI;AAAA,UAClC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,UAC/B,MAAM,EAAE,OAAO;AAAA,QACjB;AACA,mBAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,SAAS,MAAM,GAAG;AAChE,cAAI,YAAY,eAAe,EAAE,MAAyB,CAAC;AAC3D,cAAI,CAAE,MAAmB,UAAU;AACjC,wBAAY,UAAU,SAAS;AAAA,UACjC;AACA,gBAAM,SAAS,IAAI;AAAA,QACrB;AACA,eAAO,EAAE,OAAO,KAAK;AAAA,MACvB,CAAC;AAED,UAAI,aAAa,WAAW,GAAG;AAC7B,YAAIC,UAAS,EAAE,MAAM,EAAE,IAAI,CAAC;AAC5B,YAAI,MAAM,MAAM,OAAO,KAAM,CAAAA,UAASA,QAAO,IAAI,MAAM,MAAM,GAAG;AAChE,YAAI,MAAM,MAAM,OAAO,KAAM,CAAAA,UAASA,QAAO,IAAI,MAAM,MAAM,GAAG;AAChE,eAAOA;AAAA,MACT;AAEA,YAAM,QACJ,aAAa,WAAW,IACpB,aAAa,CAAC,IACd,EAAE;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEN,UAAI,SAAS,EAAE,MAAM,KAAK;AAC1B,UAAI,MAAM,MAAM,OAAO,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,GAAG;AAChE,UAAI,MAAM,MAAM,OAAO,KAAM,UAAS,OAAO,IAAI,MAAM,MAAM,GAAG;AAChE,aAAO;AAAA,IACT;AAAA,IAEA;AACE,aAAO,EAAE,IAAI;AAAA,EACjB;AACF;;;ACzKA,SAAS,oBAAoB,OAAqC;AAChE,UAAQ,MAAM,MAAM,MAAM;AAAA,IACxB,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,UAAI,MAAM,MAAM,SAAS;AACvB,eAAO,MAAM,MAAM,eAAe,CAAC,MAAM,MAAM,YAAY,IAAI,CAAC;AAAA,MAClE;AACA,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,MAAM,UAAU,CAAC,IAAI;AAAA,IACpC,KAAK;AACH,aAAO,MAAM,MAAM,UAAU,CAAC,IAAI;AAAA,IACpC,KAAK;AACH,aAAO,CAAC;AAAA,IACV,KAAK,UAAU;AACb,YAAM,WAAoC,CAAC;AAC3C,iBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,MAAM,MAAM,MAAM,GAAG;AACpE,iBAAS,OAAO,IAAI,oBAAoB,EAAE,OAAO,SAAS,CAAC;AAAA,MAC7D;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,aAAO,CAAC;AAAA,IACV,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB;AAAA,IACrC,KAAK;AACH,aAAO,CAAC;AAAA,IACV,KAAK;AACH,aAAO,MAAM,MAAM,gBAAgB,CAAC;AAAA,IACtC,KAAK;AACH,aAAO,CAAC;AAAA,IACV,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AASO,SAAS,0BAA0B,OAEd;AAC1B,QAAM,SAAkC,CAAC;AAEzC,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AAC7D,QAAI,MAAM,OAAO,OAAQ;AACzB,QAAI,MAAM,SAAS,KAAM;AAGzB,QAAI,MAAM,SAAS,QAAQ;AACzB,iBAAW,OAAO,MAAM,MAAM;AAC5B,cAAM,cAAuC,CAAC;AAC9C,mBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,IAAI,MAAM,GAAG;AAC5D,cAAI,SAAS,SAAS,KAAM;AAC5B,sBAAY,OAAO,IAAI,oBAAoB,EAAE,OAAO,SAAS,CAAC;AAAA,QAChE;AACA,eAAO,IAAI,IAAI,IAAI;AAAA,MACrB;AACA;AAAA,IACF;AAEA,WAAO,SAAS,IAAI,oBAAoB,EAAE,MAAM,CAAC;AAAA,EACnD;AAEA,SAAO;AACT;;;ACrDO,SAAS,GAAG,OAQJ;AACb,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,MAAM;AAAA,IACb,aAAa,MAAM;AAAA,IACnB,OAAO,MAAM;AAAA,EACf;AACF;;;AClCO,SAAS,KACd,OACqB;AACrB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,EACR;AACF;;;AC+fO,IAAM,6BAA6B,CAAC,aAAa,aAAa,QAAQ,aAAa;;;ACvfnF,SAAS,YAAsD,OAMhD;AACpB,MAAI,CAAC,MAAM,QAAQ,CAAC,2BAA2B,KAAK,MAAM,IAAI,GAAG;AAC/D,UAAM,IAAI;AAAA,MACR,MAAM,QAAQ;AAAA,MACd,uBAAuB,MAAM,IAAI;AAAA,IACnC;AAAA,EACF;AAEA,aAAW,aAAa,OAAO,KAAK,MAAM,MAAM,GAAG;AACjD,QAAK,2BAAiD,SAAS,SAAS,GAAG;AACzE,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,eAAe,SAAS,uDAAuD,2BAA2B,KAAK,IAAI,CAAC;AAAA,MACtH;AAAA,IACF;AAAA,EACF;AAGA,QAAM,oBAAoB,CAAC,aAAa,QAAQ,UAAU,OAAO;AAEjE,MAAI,MAAM,OAAO,eAAe,MAAM,MAAM,gBAAgB,MAAM;AAChE,QAAI,CAAC,MAAM,QAAQ,MAAM,MAAM,WAAW,GAAG;AAC3C,YAAM,IAAI;AAAA,QACR,MAAM;AAAA,QACN,wEAAwE,OAAO,MAAM,MAAM,WAAW;AAAA,MACxG;AAAA,IACF;AACA,eAAW,QAAQ,MAAM,MAAM,aAAa;AAC1C,UAAI,CAAC,kBAAkB,SAAS,IAAI,GAAG;AACrC,cAAM,IAAI;AAAA,UACR,MAAM;AAAA,UACN,uBAAuB,IAAI,wCAAwC,kBAAkB,KAAK,IAAI,CAAC;AAAA,QACjG;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,OAAO,MAAM;AAAA,IACb,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM;AAAA,IACb,eAAe,MAAM;AAAA,EACvB;AACF;;;ACjEO,IAAM,kBAAiC;AAAA,EAC5C,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,MAAM;AAAA,EACtC,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,iBAAiB;AAAA,EACrD,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,gBAAgB;AAAA,EAChD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,iBAAiB;AAAA,EACrD,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,eAAe;AAAA,EAC/C,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,iBAAiB;AAAA,EACjD,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,cAAc;AAAA,EAC9C,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,iBAAiB;AAAA,EACjD,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,gBAAgB;AAAA,EAChD,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,cAAc;AAAA,EAC9C,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,gBAAgB;AAAA,EAClD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,cAAc;AAAA,EAChD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,cAAc;AAAA,EAChD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,cAAc;AAAA,EAChD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,cAAc;AAClD;AAMO,IAAM,oBAAmC;AAAA,EAC9C,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,iBAAiB;AAAA,EACnD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,kBAAkB;AAAA,EACpD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,cAAc;AAAA,EACpD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,kBAAkB;AAAA,EACpD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,iBAAiB;AAAA,EACnD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,gBAAgB;AAAA,EACpD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,kBAAkB;AAAA,EACtD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,iBAAiB;AAAA,EACrD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,cAAc;AACpD;AAMO,IAAM,sBAAqC;AAAA,EAChD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,MAAM;AAAA,EAC5C,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,MAAM;AAAA,EAC9C,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,MAAM;AAAA,EAChD,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,MAAM;AAAA,EAChD,EAAE,OAAO,YAAY,OAAO,YAAY,MAAM,MAAM;AAAA,EACpD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,MAAM;AAAA,EAC5C,EAAE,OAAO,aAAa,OAAO,cAAc,MAAM,MAAM;AACzD;AAMO,IAAM,wBAAuC;AAAA,EAClD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,MAAM;AAAA,EAC5C,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,iBAAiB;AAAA,EACnD,EAAE,OAAO,WAAW,OAAO,WAAW,MAAM,gBAAgB;AAAA,EAC5D,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,iBAAiB;AAAA,EACnD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,eAAe;AAAA,EACjD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,iBAAiB;AAAA,EACnD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,cAAc;AAAA,EAClD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,gBAAgB;AAAA,EACpD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,SAAS;AACjD;AAMO,IAAM,qBAAoC;AAAA,EAC/C,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,YAAY;AAAA,EAClD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,QAAQ;AAAA,EAC1C,EAAE,OAAO,WAAW,OAAO,WAAW,MAAM,SAAS;AAAA,EACrD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,SAAS;AAAA,EAC3C,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,QAAQ;AAAA,EAC1C,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,cAAc;AAAA,EAChD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,WAAW;AACjD;AAMO,IAAM,kBAAiC;AAAA,EAC5C,EAAE,OAAO,KAAK,OAAO,MAAM,MAAM,YAAY;AAAA,EAC7C,EAAE,OAAO,KAAK,OAAO,MAAM,MAAM,GAAG;AAAA,EACpC,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,GAAG;AAAA,EACtC,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,GAAG;AAAA,EACtC,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,GAAG;AAAA,EACtC,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,GAAG;AAAA,EACtC,EAAE,OAAO,OAAO,OAAO,QAAQ,MAAM,gBAAgB;AACvD;AAMO,IAAM,gBAA+B;AAAA,EAC1C,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,OAAO;AAAA,EAC7C,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,OAAO;AAAA,EAC7C,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,QAAQ;AAAA,EAClD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,MAAM;AAAA,EAC1C,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,SAAS;AAAA,EAC7C,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,SAAS;AAAA,EAC7C,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,MAAM;AAAA,EAC1C,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,MAAM;AAAA,EAC1C,EAAE,OAAO,OAAO,OAAO,eAAe,MAAM,cAAc;AAAA,EAC1D,EAAE,OAAO,OAAO,OAAO,eAAe,MAAM,cAAc;AAC5D;AAMO,IAAM,oBAAmC;AAAA,EAC9C,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,WAAW;AAAA,EACjD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,gBAAgB;AAAA,EAClD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,gBAAgB;AAAA,EAClD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,gBAAgB;AAAA,EAClD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,gBAAgB;AAAA,EAClD,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,gBAAgB;AAAA,EAClD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,gBAAgB;AAAA,EACpD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,gBAAgB;AAAA,EACpD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,gBAAgB;AAAA,EACpD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,iBAAiB;AAAA,EACrD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,iBAAiB;AAAA,EACrD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,iBAAiB;AAAA,EACrD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,OAAO;AAAA,EAC7C,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,QAAQ;AACpD;AAMO,IAAM,sBAAqC;AAAA,EAChD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,IAAI;AAAA,EAC1C,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,OAAO;AAAA,EAC/C,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,QAAQ;AAAA,EAC9C,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,MAAM;AAAA,EAChD,EAAE,OAAO,WAAW,OAAO,WAAW,MAAM,QAAQ;AAAA,EACpD,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,IAAI;AAC9C;AAMO,IAAM,yBAAwC;AAAA,EACnD,EAAE,OAAO,WAAW,OAAO,WAAW,MAAM,UAAU;AAAA,EACtD,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,WAAW;AAAA,EACnD,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,MAAM;AAAA,EAChD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,UAAU;AAAA,EAChD,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,SAAS;AAAA,EACjD,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,QAAQ;AACpD;AAMO,IAAM,uBAAsC;AAAA,EACjD,EAAE,OAAO,KAAK,OAAO,QAAQ,MAAM,MAAM;AAAA,EACzC,EAAE,OAAO,WAAW,OAAO,WAAW,MAAM,MAAM;AAAA,EAClD,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,MAAM;AAAA,EACtC,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,MAAM;AAAA,EACtC,EAAE,OAAO,KAAK,OAAO,KAAK,MAAM,MAAM;AACxC;AAMO,IAAM,uBAAsC;AAAA,EACjD,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,OAAO;AAAA,EAC7C,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,QAAQ;AAAA,EAClD,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,SAAS;AAAA,EACjD,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,QAAQ;AAAA,EAC5C,EAAE,OAAO,OAAO,OAAO,OAAO,MAAM,QAAQ;AAC9C;;;ACzLA,IAAM,qBAGF;AAAA;AAAA,EAEF,QAAQ,CAACC,OAAM,KAAKA,EAAC;AAAA,EACrB,WAAW,CAACA,OAAM,MAAMA,EAAC;AAAA,EACzB,aAAa,CAACA,OAAM,MAAMA,EAAC;AAAA,EAC3B,cAAc,CAACA,OAAM,MAAMA,EAAC;AAAA,EAC5B,YAAY,CAACA,OAAM,MAAMA,EAAC;AAAA,EAC1B,SAAS,CAACA,OAAM,KAAKA,EAAC;AAAA,EACtB,YAAY,CAACA,OAAM,MAAMA,EAAC;AAAA,EAC1B,cAAc,CAACA,OAAM,MAAMA,EAAC;AAAA,EAC5B,eAAe,CAACA,OAAM,MAAMA,EAAC;AAAA,EAC7B,aAAa,CAACA,OAAM,MAAMA,EAAC;AAAA;AAAA,EAG3B,OAAO,CAACA,OAAM,KAAKA,EAAC;AAAA,EACpB,UAAU,CAACA,OAAM,SAASA,EAAC;AAAA;AAAA,EAG3B,iBAAiB,CAACA,OAAM;AACtB,QACEA,GAAE,WAAW,MAAM,KACnBA,GAAE,WAAW,GAAG,KAChBA,GAAE,WAAW,KAAK,KAClBA,GAAE,WAAW,KAAK,KAClBA,GAAE,WAAW,OAAO,GACpB;AACA,aAAO,OAAOA,EAAC;AAAA,IACjB;AACA,WAAO,MAAMA,EAAC;AAAA,EAChB;AAAA;AAAA,EAGA,aAAa,CAACA,OAAOA,OAAM,YAAY,WAAW,UAAUA,EAAC;AAAA,EAC7D,aAAa,CAACA,OAAM;AAClB,QACEA,GAAE,WAAW,MAAM,KACnBA,GAAE,WAAW,GAAG,KAChBA,GAAE,WAAW,KAAK,KAClBA,GAAE,WAAW,KAAK,KAClBA,GAAE,WAAW,OAAO,GACpB;AACA,aAAO,WAAWA,EAAC;AAAA,IACrB;AACA,WAAO,UAAUA,EAAC;AAAA,EACpB;AAAA,EACA,aAAa,CAACA,OAAM,UAAUA,EAAC;AAAA,EAC/B,cAAc,CAACA,OAAOA,OAAM,YAAY,YAAY,WAAWA,EAAC;AAAA;AAAA,EAGhE,WAAW,CAACA,OAAOA,OAAM,YAAY,WAAW,UAAUA,EAAC;AAAA,EAC3D,SAAS,CAACA,OAAM,WAAWA,EAAC;AAAA;AAAA,EAG5B,SAAS,CAACA,OAAM;AACd,QAAIA,OAAM,cAAe,QAAO;AAChC,WAAOA;AAAA,EACT;AAAA,EACA,UAAU,CAACA,OAAM,YAAYA,EAAC;AAAA;AAAA,EAG9B,WAAW,CAACA,OAAM,QAAQA,EAAC;AAAA,EAC3B,UAAU,CAACA,OAAM,QAAQA,EAAC;AAAA,EAC1B,YAAY,CAACA,OAAM,QAAQA,EAAC;AAAA,EAC5B,OAAO,CAACA,OAAM;AACZ,QACEA,GAAE,WAAW,MAAM,KACnBA,GAAE,WAAW,GAAG,KAChBA,GAAE,WAAW,KAAK,KAClBA,GAAE,WAAW,KAAK,KAClBA,GAAE,WAAW,OAAO,GACpB;AACA,aAAO,SAASA,EAAC;AAAA,IACnB;AACA,WAAO,QAAQA,EAAC;AAAA,EAClB;AAAA,EACA,YAAY,CAACA,OAAM,WAAWA,EAAC;AAAA,EAC/B,eAAe,CAACA,OAAM,YAAYA,EAAC;AAAA;AAAA,EAGnC,KAAK,CAACA,OAAM,OAAOA,EAAC;AAAA,EACpB,eAAe,CAACA,OAAM;AACpB,UAAM,MAA8B;AAAA,MAClC,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,kBAAkB;AAAA,IACpB;AACA,WAAO,IAAIA,EAAC,KAAK,QAAQA,EAAC;AAAA,EAC5B;AAAA,EACA,YAAY,CAACA,OAAM,SAASA,EAAC;AAAA,EAC7B,gBAAgB,CAACA,OAAM,WAAWA,EAAC;AAAA,EACnC,UAAU,CAACA,OAAM,QAAQA,EAAC;AAAA;AAAA,EAG1B,WAAW,CAACA,OAAM,UAAUA,EAAC;AAAA,EAC7B,aAAa,CAACA,OAAM,UAAUA,EAAC;AAAA,EAC/B,gBAAgB,CAACA,OAAM,UAAUA,EAAC;AACpC;AAKA,SAAS,gBAAgB,OAA+C;AACtE,QAAM,UAAoB,CAAC;AAE3B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AACvD,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,GAAI;AAE3D,UAAM,SAAS,mBAAmB,GAA6B;AAC/D,QAAI,CAAC,OAAQ;AAEb,YAAQ,KAAK,OAAO,OAAO,KAAK,CAAC,CAAC;AAAA,EACpC;AAEA,SAAO;AACT;AAmBO,SAAS,sBAAsB,OAE3B;AACT,MAAI,CAAC,MAAM,gBAAiB,QAAO;AAEnC,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,MAAM,MAAM,eAAe;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,SAAmB,CAAC;AAG1B,MAAI,KAAK,MAAM;AACb,WAAO,KAAK,GAAG,gBAAgB,EAAE,QAAQ,KAAK,KAAK,CAAC,CAAC;AAAA,EACvD;AAGA,QAAM,iBAAiB,OAAO,KAAK,IAAI,EACpC,OAAO,CAAC,MAAM,MAAM,MAAM,EAC1B,KAAK;AAER,aAAW,MAAM,gBAAgB;AAC/B,UAAM,UAAU,gBAAgB,EAAE,QAAQ,KAAK,EAAE,EAAE,CAAC;AACpD,eAAW,OAAO,SAAS;AACzB,aAAO,KAAK,GAAG,EAAE,IAAI,GAAG,EAAE;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO,OAAO,KAAK,GAAG;AACxB;;;ACzKO,SAAS,oBAAoB,OAAiC;AACnE,SAAO,MAAM,KACV,QAAQ,UAAU,GAAG,EACrB,QAAQ,mBAAmB,OAAO,EAClC,MAAM,KAAK,EACX,OAAO,OAAO,EACd,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC,EAAE,YAAY,CAAC,EACrE,KAAK,EAAE;AACZ;;;ACJO,SAAS,kBAAkB,OAGvB;AACT,UAAQ,MAAM,MAAM,MAAM;AAAA,IACxB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IAET,KAAK,UAAU;AACb,YAAM,SAAS,MAAM,MAAM,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK;AACrD,UAAI,OAAO,WAAW,EAAG,QAAO;AAChC,YAAM,QAAQ,OAAO,IAAI,CAACC,OAAM,IAAIA,EAAC,GAAG,EAAE,KAAK,KAAK;AACpD,UAAI,MAAM,MAAM,SAAS;AACvB,eAAO,IAAI,KAAK;AAAA,MAClB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,gBAAgB;AACnB,YAAM,SAAS,OAAO,MAAM,MAAM,EAAE;AACpC,aAAO,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO;AAAA,IAC/C;AAAA,IAEA,KAAK,UAAU;AACb,YAAM,SAAS,OAAO,MAAM,MAAM,EAAE;AACpC,aAAO,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO;AAAA,IAC/C;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,QAAQ,kBAAkB;AAAA,QAC9B,OAAO,MAAM,MAAM;AAAA,QACnB,qBAAqB,MAAM;AAAA,MAC7B,CAAC;AACD,YAAM,cAAc,MAAM,SAAS,GAAG;AACtC,aAAO,cAAc,IAAI,KAAK,QAAQ,GAAG,KAAK;AAAA,IAChD;AAAA,IAEA,KAAK,UAAU;AACb,YAAM,QAAQ,MAAM,MAAM,OAAO,IAAI,CAAC,MAAM;AAC1C,YAAI,MAAM,qBAAqB,IAAI,EAAE,IAAI,GAAG;AAC1C,iBAAO,MAAM,oBAAoB,IAAI,EAAE,IAAI;AAAA,QAC7C;AACA,eAAO,EAAE,iBAAiB,oBAAoB,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,MAChE,CAAC;AACD,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,UAAI,MAAM,WAAW,EAAG,QAAO,GAAG,MAAM,CAAC,CAAC;AAC1C,aAAO,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,IAC9B;AAAA,IAEA;AACE,aAAO;AAAA,EACX;AACF;;;ACpEO,SAAS,iBAAiB,OAAsC;AACrE,QAAM,SAAS,MAAM;AACrB,QAAM,QAAkB,CAAC;AAIzB,QAAM,eAAe,oBAAI,IAAsB;AAC/C,QAAM,sBAAsB,oBAAI,IAAoB;AAEpD,WAAS,cAAc,QAAkC;AACvD,eAAW,SAAS,OAAO,OAAO,MAAM,GAAG;AACzC,UAAI,MAAM,SAAS,UAAU;AAC3B,mBAAW,SAAS,MAAM,QAAQ;AAChC,cAAI,CAAC,aAAa,IAAI,MAAM,IAAI,GAAG;AACjC,yBAAa,IAAI,MAAM,MAAM,KAAK;AAClC,0BAAc,MAAM,MAAkC;AAAA,UACxD;AAAA,QACF;AAAA,MACF,WAAW,MAAM,SAAS,QAAQ;AAChC,mBAAW,OAAQ,MAAuB,MAAM;AAC9C,wBAAc,IAAI,MAAkC;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,aAAW,OAAO,OAAO,aAAa;AACpC,kBAAc,IAAI,MAAkC;AAAA,EACtD;AACA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,OAAO,OAAO,MAAM,aAAa;AAC1C,oBAAc,IAAI,MAAkC;AAAA,IACtD;AAAA,EACF;AACA,aAAW,KAAK,OAAO,SAAS;AAC9B,kBAAc,EAAE,MAAkC;AAAA,EACpD;AAEA,aAAW,CAAC,MAAM,KAAK,KAAK,cAAc;AACxC,wBAAoB;AAAA,MAClB;AAAA,MACA,MAAM,iBAAiB,oBAAoB,EAAE,KAAK,CAAC;AAAA,IACrD;AAAA,EACF;AAIA,QAAM,WAAW,oBAAI,IAAoB;AAEzC,WAAS,aAAa,MAAc,QAAgB;AAClD,QAAI,SAAS,IAAI,IAAI,GAAG;AACtB,YAAM,IAAI;AAAA,QACR,6BAA6B,IAAI,oBAAe,SAAS,IAAI,IAAI,CAAC,QAAQ,MAAM;AAAA,MAElF;AAAA,IACF;AACA,aAAS,IAAI,MAAM,MAAM;AAAA,EAC3B;AAEA,QAAM,kBAAkB,oBAAI,IAAoB;AAChD,aAAW,OAAO,OAAO,aAAa;AACpC,UAAM,OAAO,IAAI,iBAAiB,oBAAoB,EAAE,MAAM,IAAI,KAAK,CAAC;AACxE,iBAAa,MAAM,eAAe,IAAI,IAAI,GAAG;AAC7C,oBAAgB,IAAI,IAAI,MAAM,IAAI;AAAA,EACpC;AAEA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,OAAO,OAAO,MAAM,aAAa;AAC1C,YAAM,OAAO,IAAI,iBAAiB,oBAAoB,EAAE,MAAM,IAAI,KAAK,CAAC;AACxE,mBAAa,MAAM,qBAAqB,IAAI,IAAI,GAAG;AACnD,sBAAgB,IAAI,IAAI,MAAM,IAAI;AAAA,IACpC;AAAA,EACF;AAGA,QAAM,oBAAoB,IAAI;AAAA,IAC5B,OAAO,KAAK,YAAY,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAAA,EAChD;AACA,QAAM,sBAAsB,IAAI,IAAI,OAAO,YAAY,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACzE,QAAM,aAAa,IAAI;AAAA,KACpB,OAAO,OAAO,eAAe,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EACrD;AACA,aAAW,WAAW,OAAO,KAAK,aAAa;AAC7C,QAAI,CAAC,oBAAoB,IAAI,QAAQ,IAAI,KAAK,CAAC,WAAW,IAAI,QAAQ,IAAI,GAAG;AAC3E,YAAM,OAAO,QAAQ,iBAAiB,oBAAoB,EAAE,MAAM,QAAQ,KAAK,CAAC;AAChF,mBAAa,MAAM,oBAAoB,QAAQ,IAAI,GAAG;AACtD,sBAAgB,IAAI,QAAQ,MAAM,IAAI;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,cAAc,oBAAI,IAAoB;AAC5C,aAAW,KAAK,OAAO,SAAS;AAC9B,UAAM,OAAO,EAAE,iBAAiB,oBAAoB,EAAE,MAAM,EAAE,KAAK,CAAC;AACpE,iBAAa,MAAM,WAAW,EAAE,IAAI,GAAG;AACvC,gBAAY,IAAI,EAAE,MAAM,IAAI;AAAA,EAC9B;AAEA,aAAW,CAAC,MAAM,IAAI,KAAK,qBAAqB;AAC9C,iBAAa,MAAM,UAAU,IAAI,GAAG;AAAA,EACtC;AAIA,MAAI,gBAAgB;AACpB,WAAS,iBAAiB,QAAkC;AAC1D,eAAW,SAAS,OAAO,OAAO,MAAM,GAAG;AACzC,UAAI,MAAM,SAAS,kBAAkB,MAAM,SAAS,UAAU;AAC5D,wBAAgB;AAAA,MAClB,WAAW,MAAM,SAAS,QAAQ;AAChC,mBAAW,OAAQ,MAAuB,MAAM;AAC9C,2BAAiB,IAAI,MAAkC;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,aAAW,OAAO,OAAO,aAAa;AACpC,qBAAiB,IAAI,MAAkC;AAAA,EACzD;AACA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,OAAO,OAAO,MAAM,aAAa;AAC1C,uBAAiB,IAAI,MAAkC;AAAA,IACzD;AAAA,EACF;AACA,aAAW,KAAK,OAAO,SAAS;AAC9B,qBAAiB,EAAE,MAAkC;AAAA,EACvD;AACA,aAAW,SAAS,aAAa,OAAO,GAAG;AACzC,qBAAiB,MAAM,MAAkC;AAAA,EAC3D;AAEA,MAAI,OAAO,YAAY,SAAS,MAAM,OAAO,OAAO,aAAa,UAAU,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC9G,oBAAgB;AAAA,EAClB;AAGA,MAAI,sBAAsB;AAC1B,WAAS,uBAAuB,QAAkC;AAChE,eAAW,SAAS,OAAO,OAAO,MAAM,GAAG;AACzC,UAAI,MAAM,SAAS,YAAY;AAC7B,8BAAsB;AAAA,MACxB,WAAW,MAAM,SAAS,QAAQ;AAChC,mBAAW,OAAQ,MAAuB,MAAM;AAC9C,iCAAuB,IAAI,MAAkC;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,aAAW,OAAO,OAAO,aAAa;AACpC,2BAAuB,IAAI,MAAkC;AAAA,EAC/D;AACA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,OAAO,OAAO,MAAM,aAAa;AAC1C,6BAAuB,IAAI,MAAkC;AAAA,IAC/D;AAAA,EACF;AACA,aAAW,KAAK,OAAO,SAAS;AAC9B,2BAAuB,EAAE,MAAkC;AAAA,EAC7D;AACA,aAAW,SAAS,aAAa,OAAO,GAAG;AACzC,2BAAuB,MAAM,MAAkC;AAAA,EACjE;AAIA,QAAM,KAAK,2EAAkD;AAC7D,QAAM,KAAK,EAAE;AACb,MAAI,eAAe;AACjB,UAAM,KAAK,mDAAmD;AAAA,EAChE;AACA,MAAI,qBAAqB;AACvB,UAAM,KAAK,uDAAuD;AAAA,EACpE;AACA,MAAI,iBAAiB,qBAAqB;AACxC,UAAM,KAAK,EAAE;AAAA,EACf;AAIA,QAAM,mBAAmB,CAAC,GAAG,aAAa,KAAK,CAAC,EAAE,KAAK;AACvD,aAAW,QAAQ,kBAAkB;AACnC,UAAM,QAAQ,aAAa,IAAI,IAAI;AACnC,UAAM,OAAO,oBAAoB,IAAI,IAAI;AACzC,UAAM,KAAK,uBAAuB,EAAE,OAAO,MAAM,oBAAoB,CAAC,CAAC;AACvE,UAAM,KAAK,EAAE;AAAA,EACf;AAIA,aAAW,OAAO,OAAO,aAAa;AACpC,UAAM,OAAO,gBAAgB,IAAI,IAAI,IAAI;AACzC,UAAM,UAAU,kBAAkB,IAAI,IAAI,IAAI;AAC9C,QAAI;AAEJ,QAAI,SAAS;AACX,YAAM,SAAS,sCAAsC;AAAA,QACnD,gBAAgB;AAAA,QAChB,gBAAgB;AAAA,MAClB,CAAC;AACD,eAAS,OAAO;AAAA,IAClB,OAAO;AACL,eAAS,IAAI;AAAA,IACf;AAEA,UAAM,cAAc,CAAC,CAAE,IAAY,UAAU;AAC7C,UAAM;AAAA,MACJ,4BAA4B;AAAA,QAC1B;AAAA,QACA,MAAM,IAAI;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,aAAW,WAAW,OAAO,KAAK,aAAa;AAC7C,QAAI,oBAAoB,IAAI,QAAQ,IAAI,KAAK,WAAW,IAAI,QAAQ,IAAI,EAAG;AAC3E,UAAM,OAAO,gBAAgB,IAAI,QAAQ,IAAI;AAC7C,UAAM;AAAA,MACJ,4BAA4B;AAAA,QAC1B;AAAA,QACA,MAAM,QAAQ;AAAA,QACd,QAAQ,QAAQ;AAAA,QAChB,aAAa;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,OAAO,OAAO,MAAM,aAAa;AAC1C,YAAM,OAAO,gBAAgB,IAAI,IAAI,IAAI;AACzC,YAAM;AAAA,QACJ,iCAAiC;AAAA,UAC/B;AAAA,UACA,MAAM,IAAI;AAAA,UACV,YAAY,IAAI;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACH;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAIA,aAAW,KAAK,OAAO,SAAS;AAC9B,UAAM,OAAO,YAAY,IAAI,EAAE,IAAI;AACnC,UAAM;AAAA,MACJ,wBAAwB;AAAA,QACtB;AAAA,QACA,MAAM,EAAE;AAAA,QACR,WAAW,EAAE,aAAa,EAAE;AAAA,QAC5B,QAAQ,EAAE;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAIA,MAAI,gBAAgB,OAAO,GAAG;AAC5B,UAAM,UAAU,CAAC,GAAG,gBAAgB,QAAQ,CAAC,EAC1C,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EACrC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,EAC3C,KAAK,IAAI;AACZ,UAAM,KAAK;AAAA,EAA0C,OAAO;AAAA,EAAK;AACjE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,YAAY,OAAO,GAAG;AACxB,UAAM,UAAU,CAAC,GAAG,YAAY,QAAQ,CAAC,EACtC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EACrC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,EAC3C,KAAK,IAAI;AACZ,UAAM,KAAK;AAAA,EAAsC,OAAO;AAAA,EAAK;AAC7D,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAIA,SAAS,uBAAuB,OAIrB;AACT,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,oBAAoB,MAAM,IAAI,IAAI;AAC7C,QAAM,KAAK,iBAAiB,MAAM,MAAM,IAAI,IAAI;AAChD,QAAM,KAAK,uBAAuB;AAClC,QAAM,KAAK,iBAAiB;AAE5B,QAAM,KAAK,GAAG,mBAAmB,EAAE,QAAQ,MAAM,MAAM,QAAoC,qBAAqB,MAAM,oBAAoB,CAAC,CAAC;AAE5I,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,4BAA4B,OAM1B;AACT,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,oBAAoB,MAAM,IAAI,IAAI;AAC7C,QAAM,KAAK,cAAc,MAAM,IAAI,KAAK;AACxC,QAAM,KAAK,0BAA0B;AAErC,MAAI,MAAM,aAAa;AACrB,UAAM,KAAK,uCAAuC;AAClD,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,6BAA6B;AAAA,EAC1C;AAEA,QAAM,KAAK,GAAG,mBAAmB,EAAE,QAAQ,MAAM,QAAQ,qBAAqB,MAAM,oBAAoB,CAAC,CAAC;AAE1G,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,iCAAiC,OAK/B;AACT,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,oBAAoB,MAAM,IAAI,IAAI;AAC7C,QAAM,KAAK,cAAc,MAAM,IAAI,KAAK;AACxC,QAAM,KAAK,0BAA0B;AAGrC,QAAM,KAAK,sBAAsB;AACjC,QAAM,KAAK,qBAAqB;AAChC,QAAM,KAAK,qBAAqB;AAChC,QAAM,KAAK,iBAAiB;AAG5B,QAAM,KAAK,iBAAiB;AAC5B,QAAM,KAAK,mBAAmB;AAC9B,QAAM,KAAK,oBAAoB;AAG/B,QAAM,YAAY,oBAAI,IAAI,CAAC,GAAG,qBAAqB,GAAG,wBAAwB,CAAC;AAC/E,QAAM,iBAA2C,CAAC;AAClD,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,UAAU,GAAG;AACjE,QAAI,UAAU,IAAI,SAAgB,EAAG;AACrC,mBAAe,SAAS,IAAI;AAAA,EAC9B;AACA,QAAM,KAAK,GAAG,mBAAmB,EAAE,QAAQ,gBAAgB,qBAAqB,MAAM,oBAAoB,CAAC,CAAC;AAE5G,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,wBAAwB,OAMtB;AACT,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,oBAAoB,MAAM,IAAI,IAAI;AAC7C,QAAM,KAAK,cAAc,MAAM,SAAS,KAAK;AAC7C,QAAM,KAAK,0BAA0B;AAErC,QAAM,KAAK,GAAG,mBAAmB,EAAE,QAAQ,MAAM,QAAQ,qBAAqB,MAAM,oBAAoB,CAAC,CAAC;AAE1G,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAOA,SAAS,mBAAmB,OAGf;AACX,QAAM,QAAkB,CAAC;AAEzB,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AAC7D,UAAM,IAAI;AACV,QAAI,EAAE,SAAS,KAAM;AAErB,QAAI,EAAE,SAAS,QAAQ;AACrB,YAAM,YAAY;AAClB,iBAAW,OAAO,UAAU,MAAM;AAChC,cAAM,aAAuB,CAAC;AAC9B,mBAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,IAAI,MAAM,GAA2B;AACxF,cAAI,WAAW,SAAS,KAAM;AAC9B,gBAAM,gBAAgB,WAAW,WAAW,KAAK;AACjD,gBAAM,eAAe,kBAAkB;AAAA,YACrC,OAAO;AAAA,YACP,qBAAqB,MAAM;AAAA,UAC7B,CAAC;AACD,qBAAW,KAAK,GAAG,SAAS,GAAG,aAAa,KAAK,YAAY,EAAE;AAAA,QACjE;AACA,YAAI,WAAW,SAAS,GAAG;AACzB,gBAAM,KAAK,KAAK,IAAI,IAAI,QAAQ,WAAW,KAAK,IAAI,CAAC,KAAK;AAAA,QAC5D;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,QAAQ,EAAE;AAChB,UAAI,MAAO,OAAM,KAAK,SAAS,KAAK,KAAK;AACzC,YAAM,WAAW,EAAE,WAAW,KAAK;AACnC,YAAM,UAAU,kBAAkB;AAAA,QAChC,OAAO;AAAA,QACP,qBAAqB,MAAM;AAAA,MAC7B,CAAC;AACD,YAAM,KAAK,KAAK,SAAS,GAAG,QAAQ,KAAK,OAAO,GAAG;AAAA,IACrD;AAAA,EACF;AAEA,SAAO;AACT;;;ACtbO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AACF;AAMO,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA,GAAG;AACL,CAAC;AAKM,IAAM,+BAA+B;AAKrC,IAAM,4BAA4B;;;ACjBlC,SAAS,kBAAkB,OAEN;AAC1B,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,QAAQ,GAAG;AACzD,QAAI,CAAC,kBAAkB,IAAI,GAAG,GAAG;AAC/B,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;;;ACVO,SAAS,kBAAkB,OAIvB;AACT,MAAI,OAAO,MAAM,OAAO,QAAQ,UAAU;AACxC,WAAO,MAAM,OAAO;AAAA,EACtB;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,IAAI,MAAM,GAAG;AACzC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR,0DAA0D,MAAM,IAAI,GAAG;AAAA,MACzE;AAAA,IACF;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,MAAM,gBAAgB,QAAW;AACnC,aAAO,MAAM;AAAA,IACf;AACA,UAAM;AAAA,EACR;AACF;;;ACzBO,SAAS,gBAAgB,OAGpB;AACV,MAAI,MAAM,OAAO,mBAAmB,QAAW;AAC7C,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,OAAO,eAAe,WAAW,GAAG;AAC5C,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,cAAc;AAAA,IAAK,CAAC,UAC/B,MAAM,OAAO,eAAgB,SAAS,KAAK;AAAA,EAC7C;AACF;;;ACtBO,IAAM,sBAA+C;AAAA,EAC1D,EAAE,OAAO,UAAU,OAAO,KAAK,QAAQ,KAAK,MAAM,aAAa;AAAA,EAC/D,EAAE,OAAO,UAAU,OAAO,KAAK,QAAQ,MAAM,MAAM,SAAS;AAAA,EAC5D,EAAE,OAAO,UAAU,OAAO,MAAM,QAAQ,KAAK,MAAM,SAAS;AAAA,EAC5D,EAAE,OAAO,WAAW,OAAO,MAAM,QAAQ,MAAM,MAAM,UAAU;AACjE;AAKO,IAAM,+BAA+B;;;ACA5C,eAAsB,sBAA0D,OAK9D;AAChB,QAAM,WAAW,MAAO,MAAM,IAAI,GAC/B,MAAM,cAAc,EACpB;AAAA,IAAU;AAAA,IAAsB,CAAC,MAChC,EACG,GAAG,cAAc,MAAM,UAAU,EACjC,GAAG,cAAc,MAAM,UAAU,EACjC,GAAG,UAAU,iBAAiB;AAAA,EACnC,EACC,MAAM;AAET,MAAI,UAAU;AACZ,UAAO,MAAM,IAAI,GAAW,MAAM,SAAS,KAAK;AAAA,MAC9C,UAAU,MAAM;AAAA,MAChB,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH,OAAO;AACL,UAAO,MAAM,IAAI,GAAW,OAAO,gBAAgB;AAAA,MACjD,YAAY,MAAM;AAAA,MAClB,YAAY,MAAM;AAAA,MAClB,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,UAAU,MAAM;AAAA,MAChB,WAAW,KAAK,IAAI;AAAA,MACpB,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AACF;AAUA,eAAsB,sBAA0D,OAI9D;AAChB,QAAM,UAAU,MAAO,MAAM,IAAI,GAC9B,MAAM,cAAc,EACpB;AAAA,IAAU;AAAA,IAAsB,CAAC,MAChC,EACG,GAAG,cAAc,MAAM,UAAU,EACjC,GAAG,cAAc,MAAM,UAAU,EACjC,GAAG,UAAU,iBAAiB;AAAA,EACnC,EACC,QAAQ;AAEX,aAAW,SAAS,SAAS;AAC3B,UAAO,MAAM,IAAI,GAAW,OAAO,MAAM,GAAG;AAAA,EAC9C;AACF;AAeA,eAAsB,mBAAuD,OAIjC;AAE1C,QAAM,eAAe,MAAO,MAAM,IAAI,GACnC,MAAM,cAAc,EACpB;AAAA,IAAU;AAAA,IAAsB,CAAC,MAChC,EACG,GAAG,cAAc,MAAM,UAAU,EACjC,GAAG,cAAc,MAAM,UAAU,EACjC,GAAG,UAAU,iBAAiB;AAAA,EACnC,EACC,MAAM;AAET,MAAI,cAAc;AAChB,WAAO,aAAa;AAAA,EACtB;AAGA,QAAM,cAAc,MAAO,MAAM,IAAI,GAClC,MAAM,cAAc,EACpB;AAAA,IAAU;AAAA,IAAe,CAAC,MACzB,EAAE,GAAG,cAAc,MAAM,UAAU,EAAE,GAAG,cAAc,MAAM,UAAU;AAAA,EACxE,EACC,QAAQ;AAEX,MAAI,gBAAgD;AACpD,MAAI,aAAa;AACjB,aAAWC,MAAK,aAAa;AAC3B,QAAIA,GAAE,WAAW,qBAAqBA,GAAE,WAAW,WAAY;AAC/D,UAAM,MAAMA,GAAE;AACd,QAAI,MAAM,YAAY;AACpB,mBAAa;AACb,sBAAgBA;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,eAAe;AACjB,WAAQ,cAAsB;AAAA,EAChC;AAGA,SAAO;AACT;;;ACtIA;AAAA,EACE;AAAA,OAKK;AACP,SAAS,SAAmD;AA2B5D,SAAS,YACP,SACA;AACA,SAAO,OAAO,KAA2B,SAAwC;AAC/E,UAAM,EAAE,YAAY,GAAG,SAAS,IAAI;AAEpC,UAAM,SAAwB,eAAe,SACxC,aACD;AAEJ,UAAM,SAAS,OAAO;AAAA,MACpB,OAAO,OAAO,OAAO,eAAe,GAAG,CAAC;AAAA,MACxC;AAAA,MACA,EAAE,OAAO;AAAA,IACX;AAEA,WAAO,QAAQ,QAAQ,QAA4B;AAAA,EACrD;AACF;AAwCO,SAAS,eACd,eACA;AACA,SAAO,CAA0C,UAM4D;AAC3G,UAAM,aAAa;AAAA,MACjB,GAAG,MAAM;AAAA,MACT,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,UAAU,GAAG,EAAE,QAAQ,CAAC,CAAC;AAAA,IACpE;AAEA,WAAO,aAAa;AAAA,MAClB,MAAM;AAAA,MACN,SAAS,YAAqC,MAAM,OAAO;AAAA,IAC7D,CAAC;AAAA,EACH;AACF;AAQO,SAAS,SAAkD,OAMwC;AACxG,QAAM,aAAa;AAAA,IACjB,GAAG,MAAM;AAAA,IACT,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,UAAU,GAAG,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpE;AAEA,SAAO,aAAa;AAAA,IAClB,MAAM;AAAA,IACN,SAAS,YAAY,MAAM,OAAO;AAAA,EACpC,CAAC;AACH;;;AChIA,SAAS,mBAAmB;AAM5B,eAAe,kBACb,KACA,KACA;AACA,MAAI,KAAK,cAAc,CAAC,IAAI,OAAO,IAAI,QAAQ,KAAK;AAClD,UAAM,MAAM,MAAM,IAAI,QAAQ,OAAO,IAAI,SAAS;AAClD,QAAI,IAAK,QAAO,EAAE,GAAG,KAAK,IAAI;AAAA,EAChC;AACA,SAAO;AACT;AAEA,eAAsB,cAAkD,OAOrE;AACD,QAAM,EAAE,MAAM,IAAI,IAAI;AACtB,QAAM,IAAI,KAAK,UAAU,SACrB,IAAI,GAAG,MAAM,KAAK,cAAc,EAAE,MAAM,MAAM,IAC9C,IAAI,GAAG,MAAM,KAAK,cAAc;AACpC,QAAM,SAAS,MAAM,EAAE,SAAS,KAAK,cAAc;AACnD,QAAM,eAAe,MAAM,QAAQ;AAAA,IACjC,OAAO,KAAK,IAAI,CAAC,QAAa,kBAAkB,KAAK,GAAG,CAAC;AAAA,EAC3D;AACA,SAAO,EAAE,GAAG,QAAQ,MAAM,aAAa;AACzC;AASA,eAAsB,YAAgD,OAQnE;AACD,QAAM,MAAM,MAAM,MAAM,IAAI,GAAG,IAAI,MAAM,KAAK,UAAiB;AAC/D,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,WAAW,MAAM,kBAAkB,MAAM,KAAK,GAAG;AAGvD,MAAI,MAAM,KAAK,SAAS;AACtB,UAAM,WAAW,MAAM,mBAA8B;AAAA,MACnD,KAAK,MAAM;AAAA,MACX,YAAY,MAAM,KAAK;AAAA,MACvB,YAAY,MAAM,KAAK;AAAA,IACzB,CAAC;AACD,QAAI,UAAU;AACZ,aAAO,EAAE,GAAG,UAAU,GAAG,SAAS;AAAA,IACpC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,eAAmD,OAQtE;AACD,QAAM,IAAI,EAAE,GAAG,MAAM,KAAK,OAAO;AAGjC,MAAI,EAAE,aAAa,EAAE,QAAQ,IAAI;AAC/B,UAAM,MAAM,MAAM,MAAM,IAAI,QAAQ,OAAO,EAAE,SAAgB;AAC7D,QAAI,IAAK,GAAE,MAAM;AAAA,EACnB;AAEA,QAAM,SAAS,mBAAmB;AAAA,IAChC,QAAQ,MAAM,KAAK;AAAA,EACrB,CAAC,EAAE,QAAQ;AAEX,QAAM,SAAS,OAAO,UAAU,CAAC;AACjC,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS;AAAA,MACT,QAAQ,OAAO,MAAM,QAAQ;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,QAAM,MAAM,IAAI,GAAG,MAAM,MAAM,KAAK,YAAmB,OAAO,IAAW;AACzE,SAAO,MAAM,KAAK;AACpB;AAEA,eAAsB,eAAmD,OAQrD;AAClB,MAAI,MAAM,KAAK,SAAS,UAAU;AAChC,UAAM,WAAW,MAAM,MAAM,IAAI,GAAG,MAAM,MAAM,KAAK,cAAc,EAAE,MAAM;AAC3E,QAAI,UAAU;AACZ,YAAM,IAAI;AAAA,QACR,WAAW,MAAM,KAAK,cAAc;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,mBAAmB;AAAA,IAChC,QAAQ,MAAM,KAAK;AAAA,EACrB,CAAC;AAED,QAAM,SAAS,OAAO,UAAU,MAAM,KAAK,MAAM;AACjD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS;AAAA,MACT,QAAQ,OAAO,MAAM,QAAQ;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,QAAM,KAAK,MAAM,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,gBAAuB,OAAO,IAAW;AACzF,SAAO;AACT;AAEA,eAAsB,eAAmD,OAOvD;AAChB,MAAI,MAAM,KAAK,SAAS,UAAU;AAChC,UAAM,WAAW,MAAM,MAAM,IAAI,GAAG,IAAI,MAAM,KAAK,UAAiB;AACpE,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR,WAAW,MAAM,KAAK,cAAc;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,UAAiB;AACxD;AAcA,eAAsB,gBAAoD,OAQvE;AACD,QAAM,EAAE,MAAM,IAAI,IAAI;AACtB,QAAM,OAAO,MAAO,IAAI,GAAG,MAAM,KAAK,cAAc,EACjD,gBAAgB,KAAK,iBAAiB,CAAC,MAAW,EAAE,OAAO,KAAK,aAAa,KAAK,KAAK,CAAC,EACxF,KAAK,EAAE;AACV,SAAO,QAAQ,IAAI,KAAK,IAAI,CAAC,QAAa,kBAAkB,KAAK,GAAG,CAAC,CAAC;AACxE;;;AC7LO,IAAM,mBACX;AAiCK,SAAS,0BAA0B,OAGvB;AACjB,QAAM,EAAE,QAAQ,QAAQ,IAAI;AAC5B,QAAM,SAAyB,CAAC;AAChC,QAAM,QAAkB,CAAC;AAGzB,aAAW,cAAc,OAAO,aAAa;AAC3C,UAAM,EAAE,SAAS,UAAU,IAAI,uBAAuB;AAAA,MACpD;AAAA,MACA,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AACD,WAAO,OAAO,WAAW,IAAI,KAAK,IAAI;AACtC,WAAO,aAAa,WAAW,IAAI,KAAK,IAAI;AAC5C,UAAM,KAAK,WAAW,IAAI;AAAA,EAC5B;AAGA,MAAI,OAAO,OAAO,aAAa;AAC7B,eAAW,cAAc,OAAO,MAAM,aAAa;AACjD,YAAM,EAAE,SAAS,UAAU,IAAI,uBAAuB;AAAA,QACpD;AAAA,QACA,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,aAAO,OAAO,WAAW,IAAI,KAAK,IAAI;AACtC,aAAO,aAAa,WAAW,IAAI,KAAK,IAAI;AAC5C,YAAM,KAAK,WAAW,IAAI;AAAA,IAC5B;AAAA,EACF;AAGA,MAAI,OAAO,SAAS;AAClB,eAAW,UAAU,OAAO,SAAS;AACnC,UAAI,MAAM,SAAS,OAAO,IAAI,EAAG;AACjC,YAAM,aAAa;AAAA,QACjB,MAAM,OAAO;AAAA,QACb,WAAW,OAAO,aAAa,OAAO;AAAA,QACtC,QAAQ,OAAO;AAAA,QACf,eAAe;AAAA,MACjB;AACA,YAAM,EAAE,SAAS,UAAU,IAAI,uBAAuB;AAAA,QACpD;AAAA,QACA,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,aAAO,OAAO,OAAO,IAAI,KAAK,IAAI;AAClC,aAAO,aAAa,OAAO,IAAI,KAAK,IAAI;AACxC,YAAM,KAAK,OAAO,IAAI;AAAA,IACxB;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,aAAa;AAC5B,eAAW,cAAc,OAAO,KAAK,aAAa;AAChD,UAAI,CAAC,WAAW,YAAa;AAE7B,UAAI,MAAM,SAAS,WAAW,IAAI,EAAG;AACrC,YAAM,EAAE,SAAS,UAAU,IAAI,uBAAuB;AAAA,QACpD;AAAA,QACA,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,aAAO,OAAO,WAAW,IAAI,KAAK,IAAI;AACtC,aAAO,aAAa,WAAW,IAAI,KAAK,IAAI;AAC5C,YAAM,KAAK,WAAW,IAAI;AAAA,IAC5B;AAAA,EACF;AAGA,SAAO,cAAc,IAAI,kBAAkB,EAAE,MAAM,CAAC;AAEpD,SAAO;AACT;AAOO,SAAS,uBAAuB,OAII;AACzC,QAAM,EAAE,YAAY,SAAS,QAAQ,IAAI;AACzC,QAAM,OAAO,WAAW;AACxB,QAAM,YAAY,WAAW,aAAa,WAAW;AACrD,QAAM,mBAAmB,WAAW,gBAAgB,CAAC,KAAK;AAE1D,QAAM,YAAY,kBAAkB,EAAE,MAAM,WAAW,SAAS,kBAAkB,QAAQ,CAAC;AAC3F,QAAM,UAAU,gBAAgB,EAAE,MAAM,WAAW,SAAS,kBAAkB,QAAQ,CAAC;AAEvF,SAAO,EAAE,SAAS,UAAU;AAC9B;AAIO,SAAS,kBAAkB,OAMvB;AACT,QAAM,EAAE,WAAW,SAAS,kBAAkB,QAAQ,IAAI;AAC1D,QAAM,QAAkB,CAAC;AAGzB,QAAM,cAAc,CAAC,oBAAoB;AACzC,MAAI,CAAC,SAAS;AACZ,gBAAY,KAAK,oBAAoB;AAAA,EACvC;AAEA,QAAM,kBAA4B,CAAC,gBAAgB;AACnD,MAAI,CAAC,SAAS;AACZ,oBAAgB,KAAK,UAAU;AAAA,EACjC;AAEA,QAAM,qBAAqB,gBAAgB,SAAS,IAChD;AAAA,gBAAmB,gBAAgB,KAAK,IAAI,CAAC,2BAC7C;AAEJ,QAAM,oBAAoB,UAAU,KAAK;AAAA;AAEzC,QAAM,KAAK,GAAG,gBAAgB;AAAA,gCACA,QAAQ,qBAAqB;AAAA,8CACf,QAAQ,qBAAqB,WAAW,iBAAiB;AAAA;AAAA,WAE5F,YAAY,KAAK,IAAI,CAAC,yBAAyB,kBAAkB,EAAE;AAG5E,QAAM,KAAK,sBAAsB,EAAE,UAAU,CAAC,CAAC;AAG/C,QAAM,KAAK,wBAAwB,EAAE,UAAU,CAAC,CAAC;AAGjD,MAAI,CAAC,SAAS;AACZ,UAAM,KAAK,yBAAyB,EAAE,UAAU,CAAC,CAAC;AAAA,EACpD;AAGA,MAAI,CAAC,SAAS;AACZ,UAAM,KAAK,yBAAyB,EAAE,UAAU,CAAC,CAAC;AAAA,EACpD;AAGA,QAAM,KAAK,yBAAyB,EAAE,UAAU,CAAC,CAAC;AAGlD,MAAI,kBAAkB;AACpB,UAAM,KAAK,0BAA0B;AAAA,MACnC;AAAA,MACA,iBAAiB,iBAAiB;AAAA,MAClC,aAAa,iBAAiB;AAAA,IAChC,CAAC,CAAC;AAAA,EACJ;AAEA,SAAO,MAAM,KAAK,MAAM,IAAI;AAC9B;AAEO,SAAS,sBAAsB,OAAsC;AAC1E,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA;AAAA,oBAEW,SAAS;AAAA;AAAA,mBAEV,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAOP,SAAS;AAAA;AAAA;AAAA;AAAA,+CAIiB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAMxD;AAEO,SAAS,wBAAwB,OAAsC;AAC5E,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAMmB,SAAS;AAAA,4BACT,SAAS;AAAA;AAAA;AAGrC;AAEO,SAAS,yBAAyB,OAAsC;AAC7E,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,kBAKS,SAAS;AAAA;AAAA,iDAEsB,SAAS;AAAA;AAAA,wCAElB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAYX,SAAS,uCAAuC,SAAS;AAAA;AAE/F;AAEO,SAAS,yBAAyB,OAAsC;AAC7E,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA;AAAA;AAAA,oBAGW,SAAS;AAAA;AAAA,kBAEX,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2EAOgD,SAAS;AAAA;AAAA;AAGpF;AAEO,SAAS,yBAAyB,OAAsC;AAC7E,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA;AAAA,oBAEW,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAMW,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAMjD;AAEO,SAAS,0BAA0B,OAI/B;AACT,QAAM,EAAE,WAAW,iBAAiB,YAAY,IAAI;AACpD,SAAO;AAAA;AAAA;AAAA,mBAGU,SAAS;AAAA,qCACS,SAAS;AAAA,wBACtB,eAAe,uBAAuB,WAAW;AAAA;AAAA;AAGzE;AAIO,SAAS,gBAAgB,OAMrB;AACT,QAAM,EAAE,MAAM,WAAW,SAAS,kBAAkB,QAAQ,IAAI;AAChE,QAAM,QAAkB,CAAC;AAGzB,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA,GAAI,UAAU,CAAC,IAAI,CAAC,kBAAkB,gBAAgB;AAAA,IACtD;AAAA,IACA,GAAI,mBAAmB,CAAC,iBAAiB,IAAI,CAAC;AAAA,EAChD;AAEA,QAAM,KAAK,GAAG,gBAAgB;AAAA;AAAA;AAAA;AAAA,mCAIG,QAAQ,mBAAmB;AAAA,8CAChB,QAAQ,mBAAmB;AAAA;AAAA,2BAE9C,QAAQ,WAAW;AAAA,yBACrB,QAAQ,gBAAgB;AAAA,WACtC,SAAS,KAAK,IAAI,CAAC,yBAAyB,IAAI,GAAG;AAG5D,QAAM,KAAK,iBAAiB,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhC;AAGA,QAAM,KAAK,oBAAoB,EAAE,UAAU,CAAC,CAAC;AAG7C,QAAM,KAAK,sBAAsB,EAAE,UAAU,CAAC,CAAC;AAG/C,MAAI,CAAC,SAAS;AACZ,UAAM,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC,CAAC;AAAA,EACxD;AAGA,MAAI,CAAC,SAAS;AACZ,UAAM,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC,CAAC;AAAA,EACxD;AAGA,QAAM,KAAK,uBAAuB,EAAE,UAAU,CAAC,CAAC;AAGhD,MAAI,kBAAkB;AACpB,UAAM,KAAK,wBAAwB,CAAC;AAAA,EACtC;AAEA,SAAO,MAAM,KAAK,MAAM,IAAI;AAC9B;AAEO,SAAS,oBAAoB,OAAsC;AACxE,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA;AAAA,gBAEO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BzB;AAEO,SAAS,sBAAsB,QAAuC;AAC3E,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BT;AAEO,SAAS,uBAAuB,QAG5B;AACT,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBT;AAEO,SAAS,uBAAuB,OAG5B;AACT,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA,sBACa,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqB/B;AAEO,SAAS,uBAAuB,OAAsC;AAC3E,QAAM,EAAE,UAAU,IAAI;AACtB,SAAO;AAAA,sBACa,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkB/B;AAEO,SAAS,0BAAkC;AAChD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBT;AAOO,SAAS,kBAAkB,OAAoC;AACpE,QAAM,SAAS,CAAC,GAAG,MAAM,KAAK,EAAE,KAAK;AACrC,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,mBAAmB;AAAA,EAC5B;AACA,QAAM,UAAU,OACb,IAAI,CAAC,SAAS,eAAe,IAAI,YAAY,IAAI,GAAG,EACpD,KAAK,IAAI;AACZ,SAAO,GAAG,gBAAgB;AAAA,EAAK,OAAO;AAAA;AACxC;;;ACjgBA,SAAS,YAAY,QAA0C;AAC7D,QAAM,SAAS,oBAAI,IAAyB;AAC5C,MAAI,CAAC,OAAO,KAAK,EAAG,QAAO;AAG3B,QAAM,aACJ;AAEF,MAAI;AACJ,UAAQ,QAAQ,WAAW,KAAK,MAAM,OAAO,MAAM;AACjD,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,SAAS,oBAAI,IAAwD;AAI3E,UAAM,aAAa;AACnB,QAAI;AACJ,YAAQ,aAAa,WAAW,KAAK,IAAI,OAAO,MAAM;AACpD,YAAM,YAAY,WAAW,CAAC;AAC9B,YAAM,YAAY,WAAW,CAAC,EAAG,QAAQ,SAAS,EAAE;AACpD,YAAM,aAAa,UAAU,WAAW,aAAa;AACrD,aAAO,IAAI,WAAW,EAAE,WAAW,WAAW,CAAC;AAAA,IACjD;AAEA,WAAO,IAAI,MAAM,EAAE,MAAM,OAAO,CAAC;AAAA,EACnC;AAEA,SAAO;AACT;AAWO,SAAS,WAAW,WAAmB,WAA+B;AAC3E,QAAM,YAAY,YAAY,SAAS;AACvC,QAAM,YAAY,YAAY,SAAS;AAEvC,QAAM,gBAAmC,CAAC;AAC1C,QAAM,gBAAmC,CAAC;AAC1C,QAAM,cAAiC,CAAC;AACxC,QAAM,gBAAoC,CAAC;AAE3C,aAAW,CAAC,WAAW,QAAQ,KAAK,WAAW;AAC7C,UAAM,WAAW,UAAU,IAAI,SAAS;AAExC,eAAW,CAAC,WAAW,QAAQ,KAAK,SAAS,QAAQ;AACnD,YAAM,OAAwB;AAAA,QAC5B,OAAO;AAAA,QACP,OAAO;AAAA,QACP,WAAW,SAAS;AAAA,QACpB,YAAY,SAAS;AAAA,MACvB;AAEA,UAAI,CAAC,UAAU;AAEb,YAAI,SAAS,YAAY;AACvB,wBAAc,KAAK,IAAI;AAAA,QACzB,OAAO;AACL,wBAAc,KAAK,IAAI;AAAA,QACzB;AAAA,MACF,OAAO;AACL,cAAM,WAAW,SAAS,OAAO,IAAI,SAAS;AAC9C,YAAI,CAAC,UAAU;AAEb,cAAI,SAAS,YAAY;AACvB,0BAAc,KAAK,IAAI;AAAA,UACzB,OAAO;AACL,0BAAc,KAAK,IAAI;AAAA,UACzB;AAAA,QACF,WAAW,SAAS,cAAc,CAAC,SAAS,YAAY;AAEtD,sBAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,CAAC,WAAW,QAAQ,KAAK,WAAW;AAC7C,UAAM,WAAW,UAAU,IAAI,SAAS;AACxC,QAAI,CAAC,SAAU;AAEf,eAAW,CAAC,WAAW,QAAQ,KAAK,SAAS,QAAQ;AACnD,UAAI,CAAC,SAAS,OAAO,IAAI,SAAS,GAAG;AACnC,sBAAc,KAAK;AAAA,UACjB,OAAO;AAAA,UACP,OAAO;AAAA,UACP,WAAW,SAAS;AAAA,UACpB,aAAa,SAAS;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,CAAC,GAAG,eAAe,GAAG,eAAe,GAAG,WAAW;AAAA,EACrE;AACF;AAQO,SAAS,mBACd,QACA,QACQ;AACR,MAAI,SAAS;AAEb,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,WAAY;AAItB,UAAM,UAAU,MAAM,MAAM,QAAQ,uBAAuB,MAAM;AACjE,UAAM,UAAU,IAAI;AAAA,MAClB,QAAQ,OAAO,UAAU,MAAM,UAAU,QAAQ,uBAAuB,MAAM,CAAC;AAAA,IACjF;AACA,aAAS,OAAO,QAAQ,SAAS,oBAAoB;AAAA,EACvD;AAEA,SAAO;AACT;AASO,SAAS,2BACd,QACA,QACQ;AACR,MAAI,SAAS;AAGb,QAAM,UAAU,oBAAI,IAAgC;AACpD,aAAW,KAAK,QAAQ;AACtB,UAAM,OAAO,QAAQ,IAAI,EAAE,KAAK,KAAK,CAAC;AACtC,SAAK,KAAK,CAAC;AACX,YAAQ,IAAI,EAAE,OAAO,IAAI;AAAA,EAC3B;AAEA,aAAW,CAAC,WAAW,WAAW,KAAK,SAAS;AAE9C,UAAM,eAAe,IAAI;AAAA,MACvB,uBAAuB,SAAS;AAAA,IAClC;AACA,UAAM,aAAa,OAAO,MAAM,YAAY;AAC5C,QAAI,CAAC,WAAY;AAGjB,UAAM,aAAa,YAAY,IAAI,CAAC,MAAM;AACxC,YAAM,eAAe,EAAE,cACnB,EAAE,YACF,cAAc,EAAE,SAAS;AAC7B,aAAO,KAAK,EAAE,KAAK,KAAK,YAAY;AAAA,IACtC,CAAC;AAGD,aAAS,OAAO;AAAA,MACd;AAAA,MACA,KAAK,WAAW,KAAK,IAAI,CAAC;AAAA;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;;;ACjNO,SAAS,cAAc,OAGZ;AAChB,QAAM,EAAE,MAAM,OAAO,IAAI;AAEzB,MAAI,KAAK,eAAe,WAAW,EAAG,QAAO,CAAC;AAG9C,QAAM,iBAAiB,oBAAI,IAGzB;AAEF,aAAW,cAAc,OAAO,aAAa;AAC3C,mBAAe,IAAI,WAAW,MAAM,WAAW,MAAM;AAAA,EACvD;AAEA,aAAW,UAAU,OAAO,SAAS;AACnC,mBAAe,IAAI,OAAO,MAAM,OAAO,MAAM;AAAA,EAC/C;AAEA,QAAM,MAAqB,CAAC;AAE5B,aAAW,aAAa,KAAK,gBAAgB;AAC3C,UAAM,mBAAmB,eAAe,IAAI,UAAU,KAAK;AAE3D,QAAI,CAAC,kBAAkB;AAErB;AAAA,IACF;AAEA,UAAM,QAAQ,iBAAiB,UAAU,KAAK;AAC9C,QAAI,CAAC,OAAO;AAEV;AAAA,IACF;AAEA,QAAI,CAAC,MAAM,UAAU;AAEnB;AAAA,IACF;AACA,UAAM,eAAgB,MAAc;AACpC,QAAI,iBAAiB,QAAW;AAE9B;AAAA,IACF;AAEA,QAAI,KAAK;AAAA,MACP,OAAO,UAAU;AAAA,MACjB,OAAO,UAAU;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":["v","v","jsx","ui","v","schema","v","v","v"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/collections/utils.ts","../src/fields/blocks/types.ts","../src/fields/text/config.ts","../src/fields/validators/utils.ts","../src/fields/text/validator.ts","../src/fields/number/config.ts","../src/fields/number/validator.ts","../src/fields/checkbox/config.ts","../src/fields/checkbox/validator.ts","../src/fields/date/config.ts","../src/fields/date/validator.ts","../src/fields/select/config.ts","../src/fields/select/validator.ts","../src/fields/url/config.ts","../src/fields/url/validator.ts","../src/fields/color/config.ts","../src/fields/color/convert.ts","../src/fields/color/utils.ts","../src/fields/color/validator.ts","../src/fields/relationship/config.ts","../src/fields/relationship/validator.ts","../src/fields/array/config.ts","../src/fields/array/validator.ts","../src/fields/utils.ts","../src/fields/group/config.ts","../src/fields/group/validator.ts","../src/fields/blocks/config.ts","../src/fields/blocks/validator.ts","../src/fields/upload/config.ts","../src/fields/upload/validator.ts","../src/fields/validators/index.ts","../src/fields/interfaceGen.ts","../src/collections/config.ts","../src/collections/constants.ts","../src/collections/validator.ts","../src/collections/interfaceGen.ts","../src/globals/config.ts","../src/globals/interfaceGen.ts","../src/framework.ts","../src/access/validateAccessConstraints.ts","../src/auth/types.ts","../src/auth/mergeCollections.ts","../src/collections/internal/index.ts","../src/media/types.ts","../src/media/validators.ts","../src/media/config.ts","../src/access/config.ts","../src/access/canAccessAdminPanel.ts","../src/access/buildChecks.ts","../src/media/api/mutations.ts","../src/media/api/queries.ts","../src/media/api/server.ts","../src/media/utils.ts","../src/config/config.ts","../src/config/sanitizeConfig.ts","../src/schema/generateVexSchema.ts","../src/schema/migrate.ts","../src/collections/indexFields.ts","../src/types/generateVexTypes.ts"],"sourcesContent":["import type { icons } from \"lucide-react\";\n\n/**\n * Valid Lucide icon name string (e.g. `\"FileText\"`, `\"Users\"`, `\"Settings\"`).\n *\n * Derived from the `icons` map exported by `lucide-react` — the same map the\n * `Icon` component in `@vexcms/react` indexes at render time. This is\n * deliberately narrower than the set of names `lucide-react` exports as\n * components: alias exports (`AlertCircle` → `CircleAlert`), the `*Icon`\n * suffixed duplicates (`UsersIcon`), and non-icon exports (`createLucideIcon`,\n * `icons`, `Icon`) are absent from the map and would render nothing.\n *\n * Use the canonical PascalCase name as listed on the Lucide site.\n * @see https://lucide.dev/icons\n *\n * @example\n * ```ts\n * const icon: LucideIconName = \"CircleAlert\"; // ✅ canonical, renders\n * const alias: LucideIconName = \"AlertCircle\"; // ❌ alias export, not in `icons`\n * const bad: LucideIconName = \"NotAnIcon\"; // ❌ not an icon at all\n * ```\n *\n * @see the `Icon` component from `@vexcms/react` that renders a `LucideIconName`\n */\nexport type LucideIconName = keyof typeof icons;\n\nconst MINOR_WORDS = new Set([\n \"a\",\n \"an\",\n \"and\",\n \"as\",\n // \"at\",\n \"but\",\n \"by\",\n \"for\",\n \"if\",\n \"in\",\n \"nor\",\n \"of\",\n \"on\",\n \"or\",\n \"so\",\n \"the\",\n \"to\",\n \"up\",\n \"yet\",\n]);\n\n/**\n * Converts a string to title case, handling camelCase, snake_case, and kebab-case inputs.\n * Minor words (e.g. \"a\", \"and\", \"the\") are lowercased unless they appear at the start.\n *\n * @param input - The string to convert.\n * @returns The title-cased string.\n */\nexport function toTitleCase(input: string): string {\n const words = input\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .replace(/[_-]+/g, \" \")\n .trim()\n .split(/\\s+/);\n\n return words\n .map((word, i) => {\n const lower = word.toLowerCase();\n if (i > 0 && MINOR_WORDS.has(lower)) return lower;\n return lower.charAt(0).toUpperCase() + lower.slice(1);\n })\n .join(\" \");\n}\n\n/**\n * Returns the plural form of an English word using common suffix rules.\n *\n * Handles the most common cases: words ending in s/x/z/ch/sh, consonant+y,\n * and f/fe. Falls back to appending \"s\" for everything else.\n *\n * @param word - The singular word to pluralise (e.g. `\"Post\"`, `\"Category\"`)\n * @returns The pluralised word (e.g. `\"Posts\"`, `\"Categories\"`)\n *\n * @example\n * ```ts\n * plural(\"Post\") // \"Posts\"\n * plural(\"Category\") // \"Categories\"\n * plural(\"Leaf\") // \"Leaves\"\n * ```\n */\nexport function plural(word: string): string {\n if (/[sxz]$/i.test(word) || /[cs]h$/i.test(word)) {\n return word + \"es\";\n }\n if (/[^aeiou]y$/i.test(word)) {\n return word.slice(0, -1) + \"ies\";\n }\n if (/fe?$/i.test(word)) {\n return word.replace(/fe?$/i, \"ves\");\n }\n return word + \"s\";\n}\n\n/**\n * Ensures a string starts with a `/`, prepending one if it is absent.\n *\n * @param text - The path string to normalise.\n * @returns The path with a guaranteed leading slash (e.g. `\"admin\"` → `\"/admin\"`).\n */\nexport function addLeadingSlash(text: string): string {\n if (text.charAt(0) !== \"/\") {\n return `/${text}`;\n }\n return text;\n}\n","import { z, type ZodType } from \"zod\";\nimport type { CollectionConfig } from \"./types\";\nimport { adminFieldToInputSchema } from \"../fields\";\nimport type { TDocument } from \"../api/convex\";\n\n/**\n * Builds the `defaultValues` object for a TanStack Form instance from a collection.\n *\n * When `document` is provided, uses the document's field values (edit mode).\n * When omitted, falls back to each field's `defaultValue` (create mode).\n * The returned object's keys match the collection field keys.\n *\n * @param props - Input props.\n * @param props.collection - The collection whose fields define the form shape.\n * @param props.document - Optional existing document to populate values from when editing.\n * @returns A `Record<fieldKey, value>` ready to pass to `useForm({ defaultValues })`.\n *\n * @example\n * ```ts\n * // New document — uses field defaults\n * getCollectionDefaultValues({ collection: postsCollection })\n * // → { title: \"\", slug: \"\" }\n *\n * // Existing document — uses document values\n * getCollectionDefaultValues({ collection: postsCollection, document: doc })\n * // → { title: \"Hello world\", slug: \"hello-world\" }\n * ```\n */\nexport function getCollectionDefaultValues(props: {\n collection: CollectionConfig;\n document?: TDocument | null;\n}) {\n const res: Record<string, unknown> = {};\n for (const [fieldKey, fieldDef] of Object.entries(props.collection.fields)) {\n if (fieldDef.admin.hidden) {\n continue;\n }\n if (props.document && Boolean(props.document[fieldKey])) {\n res[fieldKey] = props.document[fieldKey];\n } else {\n res[fieldKey] = fieldDef.defaultValue;\n }\n }\n return res;\n}\n\n/**\n * Builds a Zod object schema for validating all fields in a collection.\n *\n * Calls `adminFieldToInputSchema` for each field and combines the results\n * into a `z.object({...})`. Used by `useCollectionForm` as the TanStack Form\n * `onSubmitAsync` / `onBlurAsync` validator.\n *\n * @param props - Input props.\n * @param props.collection - The collection whose fields define the schema shape.\n * @returns A `z.object` schema with one key per collection field.\n *\n * @example\n * ```ts\n * const schema = getCollectionInputSchema({ collection: postsCollection })\n * // → z.object({ title: z.string().min(1), slug: z.string().min(3).max(100) })\n * schema.parse({ title: \"Hello\", slug: \"hello\" }) // passes\n * ```\n */\nexport function getCollectionInputSchema(props: { collection: CollectionConfig }) {\n const res: Record<string, ZodType> = {};\n for (const [fieldKey, fieldDef] of Object.entries(props.collection.fields)) {\n if (fieldDef.admin.hidden) {\n continue;\n }\n res[fieldKey] = adminFieldToInputSchema({ field: fieldDef });\n }\n return z.object({ ...res });\n}\n\n/**\n * Converts a collection slug to a PascalCase identifier for use in type names.\n *\n * Splits on underscores and hyphens and capitalizes each segment.\n *\n * @param props - Input props.\n * @param props.slug - The collection slug, e.g. `\"blog_posts\"`, `\"authors\"`.\n * @returns PascalCase string, e.g. `\"BlogPosts\"`, `\"Authors\"`.\n *\n * @example\n * ```ts\n * slugToPascalCase({ slug: \"blog_posts\" }) // → \"BlogPosts\"\n * slugToPascalCase({ slug: \"authors\" }) // → \"Authors\"\n */\nexport function slugToPascalCase(props: { slug: string }): string {\n return props.slug\n .split(/[-_]/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\"\");\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport type { BaseField, BaseFieldInput, FieldAdminConfigInput } from \"../baseTypes\";\nimport type { AdminField } from \"../types\";\nimport { LucideIconName } from \"../../utils\";\nimport type { FieldAdminConfig } from \"../baseTypes\";\n\n/**\n * Field names reserved by the blocks system.\n *\n * These names are injected automatically on every block item stored in Convex\n * and cannot be used as user field names inside `defineBlock({ fields: { ... } })`.\n *\n * - `blockType` — discriminant identifying the block's definition (e.g. `\"heading\"`)\n * - `blockName` — user-editable label stored alongside the block data\n * - `id` — stable UUID assigned on creation; used as the React key and\n * pre-requisites drag-and-drop reorder\n */\nexport const RESERVED_BLOCK_FIELD_NAMES = [\n \"blockType\",\n \"blockName\",\n \"id\",\n] as const;\n\n/**\n * A Generic Block shape that all block data will follow coming out of Convex\n */\nexport interface GenericBlock extends Record<string, any> {\n id: string;\n blockType: string;\n blockName?: string;\n}\n\n/**\n * Admin UI configuration for a single block definition.\n *\n * @see {@link BlockConfigInput}\n */\nexport interface BlockAdminConfig {\n /**\n * Lucide icon name shown next to the block label in the picker dialog.\n *\n * Typed as `string` in `@vexcms/core` to avoid a React dependency.\n * Rendered via the existing `<Icon name={...}>` component in `@vexcms/react`.\n *\n * @example \"Sparkles\" | \"Puzzle\" | \"Megaphone\" | \"CreditCard\"\n */\n icon?: LucideIconName;\n /**\n * Whether this block starts expanded when the page loads.\n *\n * Default: `true` (block is open by default)\n *\n * Note: Controlled by the field-level `admin.defaultCollapsed` setting —\n * when that is `true`, all blocks start collapsed regardless of this value.\n */\n defaultCollapsed?: boolean;\n}\n\n/**\n * Configuration input for a single block type, passed to `defineBlock()`.\n *\n * A block definition describes one variant in a blocks field — its stored\n * discriminant (`slug`), its display name in the admin picker (`label`), the\n * fields that make up its data shape, and optional admin UI config (icon).\n * Three fields are injected automatically on every block item and must not\n * appear in `fields`: `blockType`, `blockName`, and `id`.\n *\n * **Defaults applied by `defineBlock()`:**\n * ```ts\n * {\n * interfaceName: slugToPascalCase(slug) + \"Block\", // e.g. \"heading\" → \"HeadingBlock\"\n * }\n * ```\n *\n * @example\n * ```ts\n * const headingBlock = defineBlock({\n * slug: \"heading\",\n * label: \"Heading\",\n * admin: { icon: \"heading\" },\n * fields: {\n * level: select({ options: [{ label: \"H1\", value: \"h1\" }] }),\n * text: text({ required: true }),\n * },\n * })\n * ```\n *\n * @see {@link BlockConfig} for the resolved output type\n * @see {@link defineBlock} for the config function that produces this type\n */\nexport interface BlockConfigInput {\n /**\n * Unique identifier for this block type.\n *\n * Stored as `blockType: \"slug\"` on every block item. Used as the Convex\n * `v.literal()` discriminant and Zod `z.literal()` key. Must start with a\n * letter and contain only letters, numbers, hyphens, and underscores\n * (`/^[a-zA-Z][a-zA-Z0-9_-]*$/`).\n */\n slug: string;\n name?: string;\n /** Display label shown in the admin block-type picker and as the block header. */\n label?: string;\n /**\n * Fields that make up this block's data shape.\n *\n * Accepts any `AdminField`, including nested `group()` or `array()`.\n * `blockType`, `blockName`, and `id` are injected automatically — do not\n * include them here. `defineBlock()` throws if any reserved name is used.\n */\n fields: Record<string, AdminField>;\n /** Admin UI configuration (picker icon). */\n admin?: BlockAdminConfig;\n /**\n * Custom TypeScript interface name for this block type.\n *\n * Defaults to `${slugToPascalCase(slug)}Block` (e.g. `\"heading\"` → `\"HeadingBlock\"`).\n */\n interfaceName?: string;\n}\n\n/**\n * Resolved block type definition, after `defineBlock()` applies all defaults.\n *\n * @see {@link BlockConfigInput} for the user-facing input type\n * @see {@link defineBlock} for the config function that produces this type\n */\nexport interface BlockConfig<TBlockMeta extends {} = {}> {\n /** Unique discriminant value stored as `blockType` on every block item. */\n blockType: string;\n blockName?: string;\n id: string;\n /** Display label shown in the admin block-type picker. */\n label?: string;\n /** Fields that make up this block's data shape. */\n fields: Record<string, AdminField>;\n /** Admin UI configuration. */\n admin?: BlockAdminConfig;\n /**\n * TypeScript interface name for this block type.\n *\n * Always set after `defineBlock()`. Defaults to `${slugToPascalCase(slug)}Block`.\n */\n interfaceName: string;\n /**\n * Computed TypeScript object-type string including all three framework keys.\n *\n * E.g. `{ blockType: \"heading\"; blockName?: string; id: string; text: string }`.\n * Used by `getFieldInterfaces` to emit the block's `export type` declaration.\n */\n interfaceType: string;\n metadata?: TBlockMeta;\n}\n\n/**\n * Configuration input for a `blocks()` field.\n *\n * Blocks fields store an ordered, heterogeneous list of typed objects. Each item\n * carries `blockType` (which block definition it matches), `id` (stable UUID),\n * `blockName` (user-editable label), plus the fields from that block's definition.\n *\n * **Defaults applied by `blocks()`:**\n * ```ts\n * {\n * type: \"blocks\",\n * label: \"\", // inferred from field key by defineCollection\n * required: false,\n * defaultValue: [],\n * labels: { singular: \"block\", plural: \"blocks\" },\n * admin: {\n * hidden: false, readOnly: false, position: \"main\", width: \"full\",\n * cellAlignment: \"left\",\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * body: blocks({\n * label: \"Body\",\n * blocks: [headingBlock, paragraphBlock],\n * })\n * ```\n *\n * @example\n * ```ts\n * // Named union alias + min/max constraints\n * body: blocks({\n * label: \"Body\",\n * interfaceName: \"PageBlock\",\n * blocks: [headingBlock, paragraphBlock],\n * min: 1,\n * max: 20,\n * labels: { singular: \"section\", plural: \"sections\" },\n * })\n * ```\n *\n * @see {@link BlocksField} for the resolved output type\n * @see {@link blocks} for the config function that produces this type\n */\nexport interface BlocksFieldInput<TFieldMeta extends {} = {}> extends Omit<\n BaseFieldInput<TFieldMeta>,\n \"admin\"\n> {\n admin?: FieldAdminConfigInput & {\n defaultCollapsed?: boolean;\n };\n /** Block type definitions that are allowed in this field. */\n blocks: BlockConfig<TFieldMeta>[];\n /**\n * Optional TypeScript union alias name.\n *\n * When set, emits `export type PageBlock = HeadingBlock | ParagraphBlock` and\n * the collection interface uses `PageBlock[]` instead of the inline union.\n */\n interfaceName?: string;\n /**\n * Minimum number of block items.\n *\n * Enforced by the Zod inputSchema (form validation), not the Convex schema.\n * Does not affect the generated `vex.schema.ts`.\n */\n min?: number;\n /**\n * Maximum number of block items.\n *\n * Enforced by the Zod inputSchema. When the max is reached, the \"Add\" button\n * is disabled in the admin UI.\n */\n max?: number;\n /** Singular/plural display labels used in the admin UI. Defaults to `{ singular: \"block\", plural: \"blocks\" }`. */\n labels?: { singular: string; plural: string };\n /** Pre-filled value when creating a new document. Defaults to `[]`. */\n defaultValue?: Record<string, unknown>[];\n}\n\n/**\n * Resolved configuration for a `blocks()` field, after all defaults are applied.\n *\n * @see {@link BlocksFieldInput} for the user-facing input type\n * @see {@link blocks} for the config function that produces this type\n */\nexport interface BlocksField<\n TFieldMeta extends {} = {},\n> extends BaseField<TFieldMeta> {\n readonly type: typeof ADMIN_FIELDS.blocks.type;\n admin: FieldAdminConfig & {\n defaultCollapsed: boolean;\n };\n /** Block type definitions allowed in this field. */\n blocks: BlockConfig<TFieldMeta>[];\n /** Optional TypeScript union alias name. */\n interfaceName?: string;\n /** Minimum number of block items (Zod-enforced). */\n min?: number;\n /** Maximum number of block items (Zod-enforced). */\n max?: number;\n /** Singular/plural display labels for the admin UI. */\n labels: { singular: string; plural: string };\n /** Pre-filled value when creating a new document. */\n defaultValue: Record<string, unknown>[];\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { TextFieldInput, TextField } from \"./types\";\n\n/**\n * Creates a text field with all defaults applied.\n *\n * Text fields store short, single-line string values.\n * Common uses: titles, names, slugs, URLs, email addresses.\n *\n * Accepts {@link TextFieldInput} (all optional) and returns {@link TextField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Text field configuration. All properties are optional.\n * @returns Resolved text field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { text, defineCollection } from '@vexcms/core'\n *\n * posts: defineCollection({\n * fields: {\n * // Minimal — label inferred from key (\"Title\")\n * title: text(),\n *\n * // Required slug with length validation and a database index\n * slug: text({ required: true, min: { value: 3 }, max: { value: 100 }, index: \"by_slug\" }),\n *\n * // Author name with a placeholder hint in the admin form\n * authorName: text({\n * required: true,\n * admin: { width: \"half\", placeholder: \"e.g. Jane Smith\" },\n * }),\n * }\n * })\n * ```\n *\n * @see {@link TextFieldInput} for the full input type\n * @see {@link TextField} for the resolved output type\n */\nexport function text<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options?: TextFieldInput<TFieldMeta>,\n): TextField<TFieldMeta> {\n return {\n type: ADMIN_FIELDS.text.type,\n interfaceType: ADMIN_FIELDS.text.interfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.text.defaultValue,\n ...options,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { AdminField } from \"../types\";\n\n/**\n * Wraps a Convex validator string in `v.optional()` when the field is not required.\n *\n * Used during schema generation to apply the correct Convex validator based on\n * whether the field is marked as required in its config.\n *\n * @param props - handleOptionalValidators() input props\n * @param props.field - The resolved field definition, used to check `required`\n * @param props.validator - A Convex validator expression string (e.g. `\"v.string()\"`)\n * @returns The validator string, wrapped in `v.optional(...)` if the field is optional\n *\n * @example\n * ```ts\n * handleOptionalValidators({ field: textField, validator: \"v.string()\" })\n * // required field → \"v.string()\"\n * // optional field → \"v.optional(v.string())\"\n * ```\n */\nexport function applyBaseValidators(props: {\n field: AdminField;\n validator: string;\n}): string {\n if (props.field.required) {\n return props.validator;\n }\n return `v.optional(${props.validator})`;\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { TextField } from \"./types\";\n\n/**\n * Converts a text field definition to a Convex schema validator.\n *\n * Generates the appropriate v.string() or v.optional(v.string()) code\n * for the Convex schema based on the field's required property.\n *\n * **Important notes:**\n * - `min`/`max` are runtime validation constraints, NOT schema constraints\n * - They don't affect the generated Convex value type\n * - Validation happens in the admin panel and mutation handlers\n * - The index property is handled separately by index collection logic\n *\n * This function is used by the CLI during schema generation to build\n * the Convex schema file.\n *\n * @param props - textFieldToValidator() input props\n * @param props.field - The text field definition\n * @returns Convex value type string: \"v.string()\" or \"v.optional(v.string())\"\n *\n * @example\n * ```ts\n * const field1 = text({ required: true })\n * textToValidatorString({ field: field1 }) // \"v.string()\"\n *\n * const field2 = text({ required: false })\n * textToValidatorString({ field: field2 }) // \"v.optional(v.string())\"\n *\n * const field3 = text({ min: { value: 3 }, max: { value: 100 } })\n * textToValidatorString({ field: field3 }) // \"v.optional(v.string())\"\n * // Note: Length constraints don't affect schema, handled at validation layer\n * ```\n *\n * @internal - Used by schema generation, not typically called by users\n */\nexport function textFieldToValidator(props: { field: TextField }): string {\n return applyBaseValidators({\n field: props.field,\n validator: ADMIN_FIELDS.text.validator,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport type { NumberFieldInput, NumberField } from \"./types\";\n\n/**\n * Creates a number field with all defaults applied.\n *\n * Number fields store numeric values.\n * Common uses: prices, quantities, ratings, ages, counts.\n *\n * Accepts {@link NumberFieldInput} (all optional) and returns {@link NumberField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Number field configuration. All properties are optional.\n * @returns Resolved number field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { number, defineCollection } from '@vexcms/core'\n *\n * products: defineCollection({\n * fields: {\n * // Minimal — label inferred from key (\"Price\")\n * price: number(),\n *\n * // Required quantity with a minimum of 1 and a database index\n * quantity: number({ required: true, min: { value: 1 }, index: \"by_quantity\" }),\n *\n * // Rating capped between 0 and 5\n * rating: number({\n * min: { value: 0, error: \"Rating cannot be negative\" },\n * max: { value: 5, error: \"Rating cannot exceed 5\" },\n * admin: { width: \"half\" },\n * }),\n * }\n * })\n * ```\n *\n * @see {@link NumberFieldInput} for the full input type\n * @see {@link NumberField} for the resolved output type\n */\nexport function number<TFieldMeta extends {} = {}>(\n options?: NumberFieldInput<TFieldMeta>,\n): NumberField<TFieldMeta> {\n if (options?.min?.value && options?.max?.value) {\n if (options.min.value >= options.max.value) {\n // TODO. setup errors that throw in development upon invalid configuration\n throw new Error(`Min value must be lower than the Max value`);\n }\n }\n return {\n type: ADMIN_FIELDS.number.type,\n interfaceType: ADMIN_FIELDS.number.interfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.number.defaultValue,\n ...options,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { NumberField } from \"./types\";\n\n/**\n * Converts a number field definition to a Convex schema validator.\n *\n * Generates the appropriate v.number() or v.optional(v.number()) code\n * for the Convex schema based on the field's required property.\n *\n * **Important notes:**\n * - min/max are runtime validation constraints, NOT schema constraints\n * - They don't affect the generated Convex value type\n * - Validation happens in the admin panel and mutation handlers\n * - The index property is handled separately by index collection logic\n *\n * This function is used by the CLI during schema generation to build\n * the Convex schema file.\n *\n * @param props - numberFieldToValidator() input props\n * @param props.field - The number field definition\n * @returns Convex value type string: \"v.number()\" or \"v.optional(v.number())\"\n *\n * @example\n * ```ts\n * const field1 = number({ required: true })\n * numberFieldToValidator({ field: field1 }) // \"v.number()\"\n *\n * const field2 = number({ required: false })\n * numberFieldToValidator({ field: field2 }) // \"v.optional(v.number())\"\n *\n * const field3 = number({ min: { value: 0 }, max: { value: 100 } })\n * numberFieldToValidator({ field: field3 }) // \"v.optional(v.number())\"\n * // Note: Range constraints don't affect schema, handled at validation layer\n * ```\n *\n * @internal - Used by schema generation, not typically called by users\n */\nexport function numberFieldToValidator(props: { field: NumberField }): string {\n return applyBaseValidators({\n field: props.field,\n validator: ADMIN_FIELDS.number.validator\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { CheckboxFieldInput, CheckboxField } from \"./types\";\n\n/**\n * Creates a checkbox field with all defaults applied.\n *\n * Checkbox fields store boolean values — feature flags, opt-in toggles,\n * published states, visibility flags, and similar on/off settings.\n *\n * Accepts {@link CheckboxFieldInput} (all optional) and returns {@link CheckboxField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `defaultValue` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Checkbox field configuration. All properties are optional.\n * @returns Resolved checkbox field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { checkbox, defineCollection } from '@vexcms/core'\n *\n * posts: defineCollection({\n * fields: {\n * // Minimal — label inferred from key (\"Published\")\n * published: checkbox(),\n *\n * // Required field, checked by default when creating a new document\n * featured: checkbox({ defaultValue: true, admin: { width: \"half\" } }),\n *\n * // Indexed flag for fast admin queries\n * archived: checkbox({ index: \"by_archived\" }),\n * }\n * })\n * ```\n *\n * @see {@link CheckboxFieldInput} for the full input type\n * @see {@link CheckboxField} for the resolved output type\n */\nexport function checkbox<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options?: CheckboxFieldInput<TFieldMeta>,\n): CheckboxField<TFieldMeta> {\n return {\n type: ADMIN_FIELDS.checkbox.type,\n interfaceType: ADMIN_FIELDS.checkbox.interfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.checkbox.defaultValue,\n ...options,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { CheckboxField } from \"./types\";\n\n/**\n * Converts a checkbox field definition to a Convex schema validator.\n *\n * Generates the appropriate `v.boolean()` or `v.optional(v.boolean())` code\n * for the Convex schema based on the field's `required` property.\n *\n * **Important notes:**\n * - The `required` flag is the only property that affects the generated validator.\n * - `index` is handled separately by collection index logic.\n * - This function is used by the CLI during schema generation to build the Convex schema file.\n *\n * @param props - checkboxFieldToValidator() input props\n * @param props.field - The checkbox field definition\n * @returns Convex value type string: `\"v.boolean()\"` or `\"v.optional(v.boolean())\"`\n *\n * @example\n * ```ts\n * const field1 = checkbox({ required: true })\n * checkboxFieldToValidator({ field: field1 }) // \"v.boolean()\"\n *\n * const field2 = checkbox({ required: false })\n * checkboxFieldToValidator({ field: field2 }) // \"v.optional(v.boolean())\"\n *\n * const field3 = checkbox()\n * checkboxFieldToValidator({ field: field3 }) // \"v.optional(v.boolean())\"\n * ```\n *\n * @internal - Used by schema generation, not typically called by users\n */\nexport function checkboxFieldToValidator(props: {\n field: CheckboxField;\n}): string {\n return applyBaseValidators({\n field: props.field,\n validator: ADMIN_FIELDS.checkbox.validator,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { DateFieldInput, DateField } from \"./types\";\n\n/**\n * Creates a date field with all defaults applied.\n *\n * Date fields store a Unix timestamp in milliseconds.\n * Common uses: published dates, expiry dates, event times, timestamps.\n *\n * Accepts {@link DateFieldInput} (all optional) and returns {@link DateField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `time.hidden` — `false` (time picker is visible)\n * - `time.use12HourFormat` — `true` (AM/PM format)\n * - `time.timePicker.hour` — `true`\n * - `time.timePicker.minute` — `true`\n * - `time.timePicker.second` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Date field configuration. All properties are optional.\n * @returns Resolved date field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { date, defineCollection } from '@vexcms/core'\n *\n * posts: defineCollection({\n * fields: {\n * // Minimal — label inferred from key (\"Published At\")\n * publishedAt: date(),\n *\n * // Required event date with a database index\n * eventDate: date({ required: true, index: \"by_event_date\" }),\n *\n * // Date-only picker (hide the time UI)\n * expiresOn: date({ time: { hidden: true } }),\n *\n * // Appointment in 24-hour format, shown in the sidebar\n * appointmentAt: date({\n * required: true,\n * time: { use12HourFormat: false },\n * admin: { position: \"sidebar\", width: \"half\" },\n * }),\n * }\n * })\n * ```\n *\n * @see {@link DateFieldInput} for the full input type\n * @see {@link DateField} for the resolved output type\n */\nexport function date<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options?: DateFieldInput<TFieldMeta>,\n): DateField<TFieldMeta> {\n return {\n type: ADMIN_FIELDS.date.type,\n interfaceType: ADMIN_FIELDS.date.interfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.date.defaultValue,\n ...options,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n placeholder: \"\",\n ...options?.admin,\n },\n\n time: {\n hidden: false,\n use12HourFormat: true,\n ...options?.time,\n timePicker: {\n hour: true,\n minute: true,\n second: false,\n ...options?.time?.timePicker,\n },\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { DateField } from \"./types\";\n\n/**\n * Converts a date field definition to a Convex schema validator.\n *\n * Generates the appropriate `v.number()` or `v.optional(v.number())` code\n * for the Convex schema based on the field's required property.\n * Date values are stored as Unix timestamps in milliseconds.\n *\n * **Important notes:**\n * - The `time` property is a UI concern only — it does NOT affect the schema type\n * - The index property is handled separately by index collection logic\n *\n * This function is used by the CLI during schema generation to build\n * the Convex schema file.\n *\n * @param props - dateFieldToValidator() input props\n * @param props.field - The date field definition\n * @returns Convex value type string: `\"v.number()\"` or `\"v.optional(v.number())\"`\n *\n * @example\n * ```ts\n * const field1 = date({ required: true })\n * dateFieldToValidator({ field: field1 }) // \"v.number()\"\n *\n * const field2 = date({ required: false })\n * dateFieldToValidator({ field: field2 }) // \"v.optional(v.number())\"\n * ```\n *\n * @internal - Used by schema generation, not typically called by users\n */\nexport function dateFieldToValidator(props: { field: DateField }): string {\n return applyBaseValidators({\n field: props.field,\n validator: ADMIN_FIELDS.date.validator,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { SelectFieldInput, SelectField } from \"./types\";\n\n/**\n * Creates a select field with all defaults applied.\n *\n * Select fields store an array of chosen option values — suitable for status\n * labels, categories, tags, or any enumerable choice set. Set `hasMany: false`\n * to restrict to a single selection.\n *\n * Accepts {@link SelectFieldInput} (all optional) and returns {@link SelectField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `defaultValue` — `[]`\n * - `options` — `[]`\n * - `hasMany` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Select field configuration. All properties are optional.\n * @returns Resolved select field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { select, defineCollection } from '@vexcms/core'\n *\n * posts: defineCollection({\n * fields: {\n * // Single-select status field\n * status: select({\n * required: true,\n * options: [\n * { label: \"Draft\", value: \"draft\" },\n * { label: \"Published\", value: \"published\" },\n * ],\n * }),\n *\n * // Multi-select tag field\n * tags: select({\n * hasMany: true,\n * options: [\n * { label: \"News\", value: \"news\" },\n * { label: \"Tutorial\", value: \"tutorial\" },\n * { label: \"Release\", value: \"release\" },\n * ],\n * }),\n * }\n * })\n * ```\n *\n * @see {@link SelectFieldInput} for the full input type\n * @see {@link SelectField} for the resolved output type\n */\nexport function select<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options?: SelectFieldInput<TFieldMeta>,\n): SelectField<TFieldMeta> {\n return {\n type: ADMIN_FIELDS.select.type,\n interfaceType: ADMIN_FIELDS.select.interfaceType,\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.select.defaultValue,\n options: [],\n hasMany: false,\n ...options,\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { applyBaseValidators } from \"../validators/utils\";\nimport type { SelectField } from \"./types\";\n\n/**\n * Converts a select field definition to a Convex schema validator string.\n *\n * Generates a `v.array(v.union(...))` validator where each union member is a\n * `v.literal(\"value\")` for each configured option. Wraps in `v.optional()`\n * when the field is not required.\n *\n * This function is used by the CLI during schema generation to build the Convex schema file.\n *\n * @param props - selectFieldToValidator() input props\n * @param props.field - The resolved select field definition\n * @returns Convex value type string, e.g. `v.array(v.union(v.literal(\"draft\"), v.literal(\"published\")))`\n *\n * @example\n * ```ts\n * const field1 = select({ required: true, options: [{ label: \"Draft\", value: \"draft\" }, { label: \"Published\", value: \"published\" }] })\n * selectFieldToValidator({ field: field1 })\n * // → 'v.array(v.union(v.literal(\"draft\"), v.literal(\"published\")))'\n *\n * const field2 = select({ required: false, options: [{ label: \"Active\", value: \"active\" }] })\n * selectFieldToValidator({ field: field2 })\n * // → 'v.optional(v.array(v.union(v.literal(\"active\"))))'\n * ```\n *\n * @internal - Used by schema generation, not typically called by users\n */\nexport function selectFieldToValidator(props: { field: SelectField }): string {\n const { field } = props;\n const optionLiterals = field.options\n .map((o) => `v.literal(\"${o.value}\")`)\n .join(\", \");\n const validator = `v.array(v.union(${optionLiterals}))`;\n return applyBaseValidators({ field, validator });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { UrlFieldInput, UrlField } from \"./types\";\n\n/**\n * Creates a URL field with all defaults applied.\n *\n * URL fields store absolute URLs as strings and render them as clickable\n * links in the admin data table. Common uses: website links, canonical\n * URLs, external resource references, social profile URLs.\n *\n * Accepts {@link UrlFieldInput} (all optional) and returns {@link UrlField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - URL field configuration. All properties are optional.\n * @returns Resolved URL field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { url, defineCollection } from '@vexcms/core'\n *\n * pages: defineCollection({\n * fields: {\n * // Minimal — label inferred from key (\"Canonical Url\")\n * canonicalUrl: url(),\n *\n * // Required website URL with a length cap and database index\n * website: url({ required: true, max: { value: 2048 }, index: \"by_website\" }),\n *\n * // Social profile URL with a placeholder hint\n * twitterUrl: url({\n * required: false,\n * admin: { width: \"half\", placeholder: \"https://twitter.com/username\" },\n * }),\n * }\n * })\n * ```\n *\n * @see {@link UrlFieldInput} for the full input type\n * @see {@link UrlField} for the resolved output type\n */\nexport function url<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options?: UrlFieldInput<TFieldMeta>,\n): UrlField<TFieldMeta> {\n return {\n type: ADMIN_FIELDS.url.type,\n interfaceType: ADMIN_FIELDS.url.interfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.url.defaultValue,\n ...options,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { UrlField } from \"./types\";\n\n/**\n * Converts a URL field definition to a Convex schema validator string.\n *\n * URL fields are stored as plain strings in Convex — the URL format is\n * enforced at the admin form layer, not in the database schema. This\n * function generates only the type constraint.\n *\n * Length constraints (`min`, `max`) are runtime validation — they do not\n * affect the generated Convex validator string. Index configuration is\n * handled separately by the collection schema builder.\n *\n * @param props - Input props.\n * @param props.field - The resolved URL field definition.\n * @returns Convex validator string: `\"v.string()\"` for required fields,\n * `\"v.optional(v.string())\"` for optional fields.\n *\n * @example\n * ```ts\n * const field1 = url({ required: true })\n * urlFieldToValidator({ field: field1 }) // \"v.string()\"\n *\n * const field2 = url({ required: false })\n * urlFieldToValidator({ field: field2 }) // \"v.optional(v.string())\"\n *\n * const field3 = url({ min: { value: 10 }, max: { value: 2048 } })\n * urlFieldToValidator({ field: field3 }) // \"v.optional(v.string())\"\n * // Length constraints don't affect schema — handled at validation layer\n * ```\n *\n * @see {@link urlFieldToInputSchema} for the admin-form Zod schema with URL format and length validation\n * @internal Used by schema generation, not typically called directly.\n */\nexport function urlFieldToValidator(props: { field: UrlField }): string {\n return applyBaseValidators({\n field: props.field,\n validator: ADMIN_FIELDS.url.validator,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport { COLOR_FORMATS } from \"./formats\";\nimport type { ColorFieldInput, ColorField } from \"./types\";\n\n/**\n * Creates a colour field with all defaults applied.\n *\n * Colour fields store a CSS colour string and render a swatch picker in the\n * admin form. Common uses: theme palettes, per-document accent colours, block\n * background overrides.\n *\n * Accepts {@link ColorFieldInput} (all optional) and returns {@link ColorField} with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `defaultValue` — `\"\"`\n * - `format` — `\"hex\"`\n * - `themeColors` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Colour field configuration. All properties are optional.\n * @returns Resolved colour field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { color, defineCollection } from '@vexcms/core'\n *\n * themes: defineCollection({\n * fields: {\n * // Minimal — label inferred from key (\"Brand Color\"), stored as hex\n * brandColor: color(),\n *\n * // Stored as oklch so the front end can interpolate it directly\n * primaryLight: color({ format: \"oklch\", required: true }),\n *\n * // Offer the host app's design tokens as a second picker tab\n * overlayTint: color({ themeColors: true, admin: { width: \"half\" } }),\n * }\n * })\n * ```\n *\n * @see {@link ColorFieldInput} for the full input type\n * @see {@link ColorField} for the resolved output type\n */\nexport function color<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options?: ColorFieldInput<TFieldMeta>,\n): ColorField<TFieldMeta> {\n return {\n type: ADMIN_FIELDS.color.type,\n interfaceType: ADMIN_FIELDS.color.interfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: ADMIN_FIELDS.color.defaultValue,\n ...options,\n\n // Resolved after `...options` so both are always defined.\n format: options?.format ?? COLOR_FORMATS.hex.format,\n themeColors: options?.themeColors ?? false,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { COLOR_FORMATS, type ColorFormat } from \"./formats\";\n\n/**\n * A colour in 8-bit sRGB with straight (non-premultiplied) alpha.\n *\n * This is the pivot representation for every notation: parsing produces one,\n * serialising consumes one. sRGB rather than HSV because HSV is a *picker's*\n * working model — `@uiw/react-color-sketch` happens to use it — while sRGB is\n * what every CSS notation converts to and from.\n *\n * @example\n * ```ts\n * const ember: ColorValue = { r: 232, g: 98, b: 42, a: 1 };\n * ```\n */\nexport interface ColorValue {\n /** Red channel, `0`–`255`. */\n r: number;\n /** Green channel, `0`–`255`. */\n g: number;\n /** Blue channel, `0`–`255`. */\n b: number;\n /** Alpha, `0`–`1`. `1` is fully opaque. */\n a: number;\n}\n\n/** A colour in the OKLCh polar form: lightness 0–1, chroma, hue in degrees. */\ninterface OklchColor {\n l: number;\n c: number;\n h: number;\n}\n\n/** A colour in the HSL cylindrical form: hue in degrees, saturation and lightness 0–100. */\ninterface HslColor {\n h: number;\n s: number;\n l: number;\n}\n\n/**\n * Decimal places used when serialising each notation.\n *\n * Chosen by measurement, not taste. `convert.test.ts` sweeps a 4096-colour\n * lattice through serialise → parse and requires an exact 8-bit match; these are\n * the coarsest values that reach zero drift. The measured cliff for OKLCh:\n *\n * | precision | colours that drift |\n * | --- | --- |\n * | L1 C3 H1 (shadcn's hand-authored style) | 869 |\n * | L1 C4 H1 | 251 |\n * | L2 C4 H2 | 5 |\n * | **L2 C5 H2** | **0** |\n *\n * Trailing zeros are dropped when serialising, so a grey still reads\n * `oklch(14.51% 0 0)` rather than `oklch(14.51% 0.00000 0.0)` — the extra\n * digits appear only on colours that need them.\n *\n * For comparison, `@uiw/color-convert`'s `hsvaToHslString` rounds saturation\n * and lightness to whole percents, which turns `#E8622A` into `#E9632B` in one\n * round trip.\n */\nconst PRECISION = {\n hslHue: 1,\n hslPercent: 1,\n oklchLightness: 2,\n oklchChroma: 5,\n oklchHue: 2,\n alpha: 3,\n} as const;\n\n/** `#RRGGBB` or `#RRGGBBAA`, captured in two-digit groups. */\nconst HEX_STRING = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})?$/;\n\n/** `rgb(232, 98, 42)` / `rgba(232, 98, 42, 0.5)`. */\nconst RGB_STRING =\n /^rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)$/;\n\n/** `hsl(17.7, 80.5%, 53.7%)` / `hsla(17.7, 80.5%, 53.7%, 0.5)`. */\nconst HSL_STRING =\n /^hsla?\\(\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(\\d+(?:\\.\\d+)?)%\\s*,\\s*(\\d+(?:\\.\\d+)?)%\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)$/;\n\n/** `oklch(65.7% 0.1793 40.9)` / `oklch(0.657 0.1793 40.9 / 0.5)`. */\nconst OKLCH_STRING =\n /^oklch\\(\\s*(\\d+(?:\\.\\d+)?)(%?)\\s+(\\d+(?:\\.\\d+)?)\\s+(-?\\d+(?:\\.\\d+)?)\\s*(?:\\/\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)$/;\n\n/**\n * Clamps a value into a closed range.\n *\n * @param props - Input props.\n * @param props.value - The value to clamp.\n * @param props.min - Lower bound, inclusive.\n * @param props.max - Upper bound, inclusive.\n * @returns The value, bounded.\n */\nfunction clamp(props: { value: number; min: number; max: number }): number {\n return Math.min(props.max, Math.max(props.min, props.value));\n}\n\n/**\n * Rounds to a fixed number of decimals, dropping trailing zeros.\n *\n * Used for alpha so `0.5` serialises as `0.5` rather than `0.500`.\n *\n * @param props - Input props.\n * @param props.value - The value to round.\n * @param props.decimals - Maximum decimal places to keep.\n * @returns The rounded value.\n */\nfunction round(props: { value: number; decimals: number }): number {\n return Number(props.value.toFixed(props.decimals));\n}\n\n/**\n * Converts a gamma-encoded sRGB channel to its linear-light value.\n *\n * @param props - Input props.\n * @param props.channel - Channel in the 0–1 range.\n * @returns The linear-light channel value.\n */\nfunction srgbToLinear(props: { channel: number }): number {\n const c = props.channel;\n return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n}\n\n/**\n * Converts a linear-light channel back to gamma-encoded sRGB.\n *\n * @param props - Input props.\n * @param props.channel - Linear-light channel in the 0–1 range.\n * @returns The gamma-encoded channel value.\n */\nfunction linearToSrgb(props: { channel: number }): number {\n const c = props.channel;\n return c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;\n}\n\n/**\n * Converts sRGB to OKLCh.\n *\n * Uses Björn Ottosson's sRGB→OKLab matrices — the same transform browsers\n * implement for the `oklch()` notation, verified against Chromium's own output\n * to the byte. Hand-rolled rather than pulled from a colour library: it is\n * twenty lines of closed-form arithmetic, and the alternative (`culori`) would\n * become a runtime dependency of `@vexcms/core`.\n *\n * @param props - Input props.\n * @param props.color - The sRGB colour. Alpha is ignored.\n * @returns The equivalent OKLCh colour. Hue is `0` for achromatic input.\n */\nfunction rgbToOklch(props: { color: ColorValue }): OklchColor {\n const lr = srgbToLinear({ channel: props.color.r / 255 });\n const lg = srgbToLinear({ channel: props.color.g / 255 });\n const lb = srgbToLinear({ channel: props.color.b / 255 });\n\n const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\n const lightness = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;\n const a = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;\n const b = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;\n\n const chroma = Math.sqrt(a * a + b * b);\n // Below this chroma the hue angle is numerical noise — pin it to 0 so grey\n // serialises as `oklch(14.5% 0 0)` rather than an arbitrary angle.\n const hue = chroma < 1e-6 ? 0 : ((Math.atan2(b, a) * 180) / Math.PI + 360) % 360;\n\n return { l: lightness, c: chroma, h: hue };\n}\n\n/**\n * Converts OKLCh to sRGB, clamping to the sRGB gamut.\n *\n * OKLCh describes colours sRGB cannot show; those clamp per channel rather than\n * failing, which matches what a browser paints for an out-of-gamut `oklch()`.\n *\n * @param props - Input props.\n * @param props.oklch - The OKLCh colour.\n * @param props.alpha - Alpha to carry onto the result, `0`–`1`.\n * @returns The equivalent sRGB colour.\n */\nfunction oklchToRgb(props: { oklch: OklchColor; alpha: number }): ColorValue {\n const radians = (props.oklch.h * Math.PI) / 180;\n const a = props.oklch.c * Math.cos(radians);\n const b = props.oklch.c * Math.sin(radians);\n\n const lCube = (props.oklch.l + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const mCube = (props.oklch.l - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const sCube = (props.oklch.l - 0.0894841775 * a - 1.291485548 * b) ** 3;\n\n const toChannel = (linear: number) =>\n clamp({ value: Math.round(linearToSrgb({ channel: linear }) * 255), min: 0, max: 255 });\n\n return {\n r: toChannel(4.0767416621 * lCube - 3.3077115913 * mCube + 0.2309699292 * sCube),\n g: toChannel(-1.2684380046 * lCube + 2.6097574011 * mCube - 0.3413193965 * sCube),\n b: toChannel(-0.0041960863 * lCube - 0.7034186147 * mCube + 1.707614701 * sCube),\n a: props.alpha,\n };\n}\n\n/**\n * Converts sRGB to HSL.\n *\n * @param props - Input props.\n * @param props.color - The sRGB colour. Alpha is ignored.\n * @returns Hue in degrees, saturation and lightness as percentages.\n */\nfunction rgbToHsl(props: { color: ColorValue }): HslColor {\n const r = props.color.r / 255;\n const g = props.color.g / 255;\n const b = props.color.b / 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const lightness = (max + min) / 2;\n\n if (max === min) return { h: 0, s: 0, l: lightness * 100 };\n\n const delta = max - min;\n const saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);\n\n let hue: number;\n if (max === r) hue = ((g - b) / delta) % 6;\n else if (max === g) hue = (b - r) / delta + 2;\n else hue = (r - g) / delta + 4;\n\n return { h: ((hue * 60) % 360 + 360) % 360, s: saturation * 100, l: lightness * 100 };\n}\n\n/**\n * Converts HSL to sRGB.\n *\n * @param props - Input props.\n * @param props.hsl - Hue in degrees, saturation and lightness as percentages.\n * @param props.alpha - Alpha to carry onto the result, `0`–`1`.\n * @returns The equivalent sRGB colour.\n */\nfunction hslToRgb(props: { hsl: HslColor; alpha: number }): ColorValue {\n const h = ((props.hsl.h % 360) + 360) % 360 / 360;\n const s = clamp({ value: props.hsl.s / 100, min: 0, max: 1 });\n const l = clamp({ value: props.hsl.l / 100, min: 0, max: 1 });\n\n if (s === 0) {\n const grey = Math.round(l * 255);\n return { r: grey, g: grey, b: grey, a: props.alpha };\n }\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const toChannel = (offset: number) => {\n let t = h + offset;\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n return {\n r: Math.round(toChannel(1 / 3) * 255),\n g: Math.round(toChannel(0) * 255),\n b: Math.round(toChannel(-1 / 3) * 255),\n a: props.alpha,\n };\n}\n\n/**\n * Serialises a colour into one of the supported CSS notations.\n *\n * Alpha is emitted only when the colour is not fully opaque, so an opaque\n * colour produces `#e8622a` rather than `#e8622aff` and `rgb(...)` rather than\n * `rgba(..., 1)`.\n *\n * @param props - Input props.\n * @param props.color - The colour to write.\n * @param props.format - The notation to write it in.\n * @returns A CSS colour string in `format`.\n * @throws An Error if an unrecognised format is given. Reaching this is a\n * compile error: the default arm binds the exhausted union to `never`.\n *\n * @example\n * ```ts\n * const ember = { r: 232, g: 98, b: 42, a: 1 };\n * serializeColor({ color: ember, format: \"hex\" }) // \"#e8622a\"\n * serializeColor({ color: ember, format: \"oklch\" }) // \"oklch(65.7% 0.1793 40.9)\"\n * ```\n */\nexport function serializeColor(props: { color: ColorValue; format: ColorFormat }): string {\n const { color } = props;\n const isOpaque = color.a >= 1;\n const alpha = round({ value: color.a, decimals: PRECISION.alpha });\n\n switch (props.format) {\n case COLOR_FORMATS.hex.format: {\n const pair = (channel: number) =>\n clamp({ value: Math.round(channel), min: 0, max: 255 })\n .toString(16)\n .padStart(2, \"0\");\n const rgb = `#${pair(color.r)}${pair(color.g)}${pair(color.b)}`;\n return isOpaque ? rgb : `${rgb}${pair(color.a * 255)}`;\n }\n case COLOR_FORMATS.rgb.format: {\n const channels = `${Math.round(color.r)}, ${Math.round(color.g)}, ${Math.round(color.b)}`;\n return isOpaque ? `rgb(${channels})` : `rgba(${channels}, ${alpha})`;\n }\n case COLOR_FORMATS.hsl.format: {\n const hsl = rgbToHsl({ color });\n const h = round({ value: hsl.h, decimals: PRECISION.hslHue });\n const s = round({ value: hsl.s, decimals: PRECISION.hslPercent });\n const l = round({ value: hsl.l, decimals: PRECISION.hslPercent });\n return isOpaque ? `hsl(${h}, ${s}%, ${l}%)` : `hsla(${h}, ${s}%, ${l}%, ${alpha})`;\n }\n case COLOR_FORMATS.oklch.format: {\n const oklch = rgbToOklch({ color });\n const l = round({ value: oklch.l * 100, decimals: PRECISION.oklchLightness });\n const c = round({ value: oklch.c, decimals: PRECISION.oklchChroma });\n const h = round({ value: oklch.h, decimals: PRECISION.oklchHue });\n return `oklch(${l}% ${c} ${h}${isOpaque ? \"\" : ` / ${alpha}`})`;\n }\n default: {\n const unhandled: never = props.format;\n throw new Error(`unsupported colour format: ${JSON.stringify(unhandled)}`);\n }\n }\n}\n\n/**\n * Parses a stored colour value into a {@link ColorValue}.\n *\n * Accepts every notation {@link serializeColor} can emit, regardless of the\n * field's current `format` — so a field whose format changed still reads its\n * stored colour instead of resetting. Values with no literal colour\n * (`var(--token)`, the empty string) return `null`.\n *\n * @param props - Input props.\n * @param props.value - The stored field value.\n * @returns The parsed colour, or `null` when the value is empty, a theme-token\n * reference, or not a recognised notation.\n *\n * @example\n * ```ts\n * parseColor({ value: \"oklch(65.7% 0.1793 40.9)\" }) // { r: 232, g: 98, b: 42, a: 1 }\n * parseColor({ value: \"var(--primary)\" }) // null\n * ```\n */\nexport function parseColor(props: { value: string }): ColorValue | null {\n const value = props.value.trim();\n if (!value) return null;\n\n const hex = HEX_STRING.exec(value);\n if (hex) {\n return {\n r: parseInt(hex[1], 16),\n g: parseInt(hex[2], 16),\n b: parseInt(hex[3], 16),\n a: hex[4] === undefined ? 1 : parseInt(hex[4], 16) / 255,\n };\n }\n\n const rgb = RGB_STRING.exec(value);\n if (rgb) {\n const channels = [rgb[1], rgb[2], rgb[3]].map(Number);\n if (channels.some((channel) => channel > 255)) return null;\n return {\n r: channels[0],\n g: channels[1],\n b: channels[2],\n a: rgb[4] === undefined ? 1 : clamp({ value: Number(rgb[4]), min: 0, max: 1 }),\n };\n }\n\n const hsl = HSL_STRING.exec(value);\n if (hsl) {\n return hslToRgb({\n hsl: { h: Number(hsl[1]), s: Number(hsl[2]), l: Number(hsl[3]) },\n alpha: hsl[4] === undefined ? 1 : clamp({ value: Number(hsl[4]), min: 0, max: 1 }),\n });\n }\n\n const oklch = OKLCH_STRING.exec(value);\n if (oklch) {\n const lightness = Number(oklch[1]);\n return oklchToRgb({\n oklch: {\n l: oklch[2] ? lightness / 100 : lightness,\n c: Number(oklch[3]),\n h: Number(oklch[4]),\n },\n alpha: oklch[5] === undefined ? 1 : clamp({ value: Number(oklch[5]), min: 0, max: 1 }),\n });\n }\n\n return null;\n}\n","/**\n * Theme field key → CSS custom property, for the 32 shadcn design tokens.\n *\n * This map is the theming system's contract. `themeColorFields` derives the\n * collection's colour fields from it, and `buildThemeCss` emits one declaration\n * per entry — so a token cannot exist in the stored document without also being\n * applied, or vice versa. The names are exactly the custom properties shadcn\n * components consume and exactly the set tweakcn exports, so a preset maps\n * across with no gaps.\n */\nexport const THEME_COLOR_TOKENS = {\n background: \"--background\",\n foreground: \"--foreground\",\n card: \"--card\",\n cardForeground: \"--card-foreground\",\n popover: \"--popover\",\n popoverForeground: \"--popover-foreground\",\n primary: \"--primary\",\n primaryForeground: \"--primary-foreground\",\n secondary: \"--secondary\",\n secondaryForeground: \"--secondary-foreground\",\n muted: \"--muted\",\n mutedForeground: \"--muted-foreground\",\n accent: \"--accent\",\n accentForeground: \"--accent-foreground\",\n destructive: \"--destructive\",\n destructiveForeground: \"--destructive-foreground\",\n border: \"--border\",\n input: \"--input\",\n ring: \"--ring\",\n chart1: \"--chart-1\",\n chart2: \"--chart-2\",\n chart3: \"--chart-3\",\n chart4: \"--chart-4\",\n chart5: \"--chart-5\",\n sidebar: \"--sidebar\",\n sidebarForeground: \"--sidebar-foreground\",\n sidebarPrimary: \"--sidebar-primary\",\n sidebarPrimaryForeground: \"--sidebar-primary-foreground\",\n sidebarAccent: \"--sidebar-accent\",\n sidebarAccentForeground: \"--sidebar-accent-foreground\",\n sidebarBorder: \"--sidebar-border\",\n sidebarRing: \"--sidebar-ring\",\n} as const;\n\n/** One of the 32 shadcn colour-token keys, camelCased: `\"cardForeground\"`, `\"chart1\"`. */\nexport type ThemeColorTokenKey = keyof typeof THEME_COLOR_TOKENS;\n\n/**\n * Scheme-independent fields, read from the theme document root.\n *\n * `--font-sans` is commonly also set by the host's font loader (e.g.\n * `next/font`) as a class on `<html>`; both are specificity (0,1,0), so the\n * later declaration wins. A stack naming a font the app has not loaded degrades\n * to the next entry rather than breaking.\n */\nexport const THEME_SHARED_TOKENS = {\n radius: \"--radius\",\n fontFamily: \"--font-sans\",\n} as const;\n\n/** Where a theme's CSS applies. */\nexport type ThemeScope = \"admin\" | \"site\";\n\n/**\n * Stark × Ember — this repo's house palette, lifted verbatim from the `:root`\n * block of `globals.css`. A freshly created theme starts from these values, so\n * \"new theme\" means \"fork the current look\", not \"32 empty pickers\".\n */\nexport const EMBER_LIGHT: Record<ThemeColorTokenKey, string> = {\n background: \"oklch(96.1% 0 0)\",\n foreground: \"oklch(13.7% 0 0)\",\n card: \"oklch(100% 0 0)\",\n cardForeground: \"oklch(13.7% 0 0)\",\n popover: \"oklch(100% 0 0)\",\n popoverForeground: \"oklch(13.7% 0 0)\",\n primary: \"oklch(60.5% 0.175 42)\",\n primaryForeground: \"oklch(100% 0 0)\",\n secondary: \"oklch(98% 0 0)\",\n secondaryForeground: \"oklch(13.7% 0 0)\",\n muted: \"oklch(98% 0 0)\",\n mutedForeground: \"oklch(50.5% 0 0)\",\n accent: \"oklch(96% 0.025 42)\",\n accentForeground: \"oklch(52% 0.180 40)\",\n destructive: \"oklch(57.7% 0.198 27)\",\n destructiveForeground: \"oklch(98% 0 0)\",\n border: \"oklch(85% 0 0)\",\n input: \"oklch(54.6% 0 0)\",\n ring: \"oklch(60.5% 0.175 42)\",\n chart1: \"oklch(60.5% 0.175 42)\",\n chart2: \"oklch(45% 0 0)\",\n chart3: \"oklch(72% 0.100 60)\",\n chart4: \"oklch(60% 0.040 30)\",\n chart5: \"oklch(78% 0 0)\",\n sidebar: \"oklch(98% 0 0)\",\n sidebarForeground: \"oklch(13.7% 0 0)\",\n sidebarPrimary: \"oklch(60.5% 0.175 42)\",\n sidebarPrimaryForeground: \"oklch(100% 0 0)\",\n sidebarAccent: \"oklch(96.1% 0 0)\",\n sidebarAccentForeground: \"oklch(13.7% 0 0)\",\n sidebarBorder: \"oklch(85% 0 0)\",\n sidebarRing: \"oklch(60.5% 0.175 42)\",\n};\n\n/** Stark × Ember dark-mode values, from `globals.css`'s `.dark` block. */\nexport const EMBER_DARK: Record<ThemeColorTokenKey, string> = {\n background: \"oklch(13.7% 0 0)\",\n foreground: \"oklch(95% 0 0)\",\n card: \"oklch(17.4% 0 0)\",\n cardForeground: \"oklch(95% 0 0)\",\n popover: \"oklch(17.4% 0 0)\",\n popoverForeground: \"oklch(95% 0 0)\",\n primary: \"oklch(72% 0.175 50)\",\n primaryForeground: \"oklch(13.7% 0 0)\",\n secondary: \"oklch(20% 0 0)\",\n secondaryForeground: \"oklch(95% 0 0)\",\n muted: \"oklch(20% 0 0)\",\n mutedForeground: \"oklch(70% 0 0)\",\n accent: \"oklch(72% 0.175 50 / 0.12)\",\n accentForeground: \"oklch(72% 0.175 50)\",\n destructive: \"oklch(63% 0.210 27)\",\n destructiveForeground: \"oklch(95% 0 0)\",\n border: \"oklch(25% 0 0)\",\n input: \"oklch(40% 0 0)\",\n ring: \"oklch(72% 0.175 50)\",\n chart1: \"oklch(72% 0.175 50)\",\n chart2: \"oklch(78% 0 0)\",\n chart3: \"oklch(78% 0.120 65)\",\n chart4: \"oklch(60% 0.060 30)\",\n chart5: \"oklch(45% 0 0)\",\n sidebar: \"oklch(7% 0 0)\",\n sidebarForeground: \"oklch(95% 0 0)\",\n sidebarPrimary: \"oklch(72% 0.175 50)\",\n sidebarPrimaryForeground: \"oklch(13.7% 0 0)\",\n sidebarAccent: \"oklch(20% 0 0)\",\n sidebarAccentForeground: \"oklch(95% 0 0)\",\n sidebarBorder: \"oklch(25% 0 0)\",\n sidebarRing: \"oklch(72% 0.175 50)\",\n};\n\n/**\n * Builds one CSS declaration block.\n *\n * @param props - Input props.\n * @param props.values - Field key → stored value.\n * @param props.tokens - Field key → custom property name.\n * @returns Newline-joined `--token: value;` declarations, or `\"\"` when none apply.\n */\nfunction buildDeclarations(props: {\n values: Record<string, unknown> | undefined;\n tokens: Record<string, string>;\n}): string {\n if (!props.values) return \"\";\n const declarations: string[] = [];\n for (const [fieldKey, cssVar] of Object.entries(props.tokens)) {\n const value = props.values[fieldKey];\n if (typeof value === \"string\" && value) declarations.push(` ${cssVar}: ${value};`);\n }\n return declarations.join(\"\\n\");\n}\n\n/**\n * Builds the stylesheet text applying a theme document at a scope.\n *\n * Values are written through verbatim — a `color()` field storing\n * `oklch(60.5% 0.175 42)` needs no conversion, because custom properties accept\n * any colour notation. `.dark` is assumed to sit on `<html>`, which *is*\n * `:root`, so the dark selector is a compound, never a descendant.\n *\n * The two scopes form a specificity ladder that no injection order can upset:\n * site light `:root` (0,1,0) < site dark `.dark` (0,1,0, later) < admin light\n * `:root:root` (0,2,0) < admin dark `.dark:root:root` (0,3,0). Emit the site\n * theme once for the whole document and the admin theme from the admin route\n * only, and the admin block wins exactly where it renders.\n *\n * @param props - Input props.\n * @param props.theme - The theme document — `light`/`dark` colour groups plus\n * root-level `radius` and `fontFamily`, i.e. the shape `themeColorFields`\n * stores.\n * @param props.scope - `\"site\"` emits `:root`; `\"admin\"` emits `:root:root`.\n * @returns The stylesheet text, or `\"\"` when the theme sets nothing.\n *\n * @example\n * ```ts\n * const css = buildThemeCss({ theme, scope: \"site\" });\n * // \":root {\\n --background: oklch(96.1% 0 0);\\n …\\n}\\n\\n.dark {\\n …\\n}\"\n * ```\n */\nexport function buildThemeCss(props: {\n theme: Record<string, unknown>;\n scope: ThemeScope;\n}): string {\n const selector = props.scope === \"admin\" ? \":root:root\" : \":root\";\n const darkSelector = props.scope === \"admin\" ? \".dark:root:root\" : \".dark\";\n\n const light = [\n buildDeclarations({\n values: props.theme.light as Record<string, unknown> | undefined,\n tokens: THEME_COLOR_TOKENS,\n }),\n buildDeclarations({ values: props.theme, tokens: THEME_SHARED_TOKENS }),\n ]\n .filter(Boolean)\n .join(\"\\n\");\n const dark = buildDeclarations({\n values: props.theme.dark as Record<string, unknown> | undefined,\n tokens: THEME_COLOR_TOKENS,\n });\n\n return [light && `${selector} {\\n${light}\\n}`, dark && `${darkSelector} {\\n${dark}\\n}`]\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { ColorField } from \"./types\";\n\n/**\n * Converts a colour field definition to a Convex schema validator string.\n *\n * Colour fields are stored as plain strings in Convex — the notation (and the\n * `var(--token)` alternative allowed by `themeColors`) is enforced at the admin\n * form layer, not in the database schema. This function generates only the type\n * constraint, so changing `format` never triggers a schema migration.\n *\n * @param props - Input props.\n * @param props.field - The resolved colour field definition.\n * @returns Convex validator string: `\"v.string()\"` for required fields,\n * `\"v.optional(v.string())\"` for optional fields.\n *\n * @example\n * ```ts\n * colorFieldToValidator({ field: color({ required: true }) }) // \"v.string()\"\n * colorFieldToValidator({ field: color({ required: false }) }) // \"v.optional(v.string())\"\n * ```\n *\n * @see {@link colorFieldToInputSchema} for the admin-form Zod schema that enforces the notation\n * @internal Used by schema generation, not typically called directly.\n */\nexport function colorFieldToValidator(props: { field: ColorField }): string {\n return applyBaseValidators({\n field: props.field,\n validator: ADMIN_FIELDS.color.validator,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport type { RelationshipFieldInput, RelationshipField } from \"./types\";\nimport type { CollectionSlug } from \"../../types/generated\";\nimport { ComponentHKT } from \"../baseTypes\";\nimport { BaseFieldMeta } from \"../types\";\n\n/**\n * Creates a relationship field with all defaults applied.\n *\n * Stores Convex `Id` references pointing to documents in another registered collection.\n * The generated Convex schema **always** emits `v.array(v.id(\"collection\"))` regardless\n * of `hasMany` — `hasMany` is a UI-only hint that controls whether the admin picker allows\n * one or multiple selections; it does not change the stored Convex type.\n * A `.index(\"by_<fieldKey>\", [\"<fieldKey>\"])` is auto-generated for every relationship\n * field — no explicit `index` property needed.\n *\n * `TCollectionSlug` is inferred from `options.collection`. After running `vex generate`,\n * passing an unregistered slug is a compile-time error.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from field key by `defineCollection`)\n * - `required` — `false`\n * - `hasMany` — `false`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @typeParam TCollectionSlug - Inferred from `options.collection`.\n * @param options - Relationship field config. `collection` is required.\n * @returns Resolved relationship field definition with all defaults applied.\n *\n * @example\n * ```ts\n * // Single reference — stores Id<\"authors\">\n * author: relationship({ collection: { slug: \"authors\" } })\n *\n * // Multi-reference — stores Id<\"tags\">[]\n * tags: relationship({ collection: { slug: \"tags\" }, hasMany: true, required: false })\n * ```\n *\n * @see {@link RelationshipFieldInput} for the full input type\n * @see {@link RelationshipField} for the resolved output type\n */\nexport function relationship<\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n TCollectionSlug extends CollectionSlug = CollectionSlug,\n TComponent extends ComponentHKT = ComponentHKT,\n>(\n options: RelationshipFieldInput<TFieldMeta, TCollectionSlug, TComponent>,\n): RelationshipField<TFieldMeta, TCollectionSlug, TComponent> {\n return {\n label: \"\",\n required: false,\n hasMany: false,\n ...options,\n type: ADMIN_FIELDS.relationship.type,\n // Per-field override of the static `ADMIN_FIELDS.relationship.interfaceType`\n // (`Id<CollectionSlug>[]`): emitting the target slug as a literal is what\n // lets `RelationshipTargetOf` recover it, so `populate`/`depth` can narrow\n // the populated field to `Doc<target>[]` instead of a union of every doc.\n interfaceType: `Id<\"${options.collection.slug}\">[]`,\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n placeholder: \"\",\n components: {},\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n","import { applyBaseValidators } from \"../validators/utils\";\nimport type { RelationshipField } from \"./types\";\n\n/**\n * Converts a relationship field definition to a Convex schema validator string.\n *\n * Emits `v.id(\"collection\")` for single references and\n * `v.array(v.id(\"collection\"))` for multi-references. Wraps in `v.optional()`\n * when `field.required` is `false`.\n *\n * @param props - Input props.\n * @param props.field - The resolved relationship field definition.\n * @returns Convex validator string.\n *\n * @example\n * ```ts\n * relationshipFieldToValidator({ field: relationship({ collection: { slug: \"authors\" }, required: true }) })\n * // → 'v.array(v.id(\"authors\"))'\n *\n * relationshipFieldToValidator({ field: relationship({ collection: { slug: \"tags\" }, hasMany: true }) })\n * // → 'v.optional(v.array(v.id(\"tags\")))'\n * ```\n *\n * @internal\n */\nexport function relationshipFieldToValidator(props: {\n field: RelationshipField;\n}): string {\n const { field } = props;\n const validator = `v.array(v.id(\"${field.collection.slug}\"))`;\n return applyBaseValidators({ field, validator });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { ArrayFieldInput, ArrayField, ArrayType } from \"./types\";\n\n/**\n * Creates an array field with all defaults applied.\n *\n * Array fields store ordered lists of values — strings, numbers, booleans,\n * or nested objects. Items are validated by a nested field definition\n * (`items`) which supports any VexCMS field type including nested arrays.\n *\n * Accepts {@link ArrayFieldInput} (all optional) and returns {@link ArrayField}\n * with all defaults applied.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `labels.singular` — `\"Item\"`\n * - `labels.plural` — `\"Items\"`\n * - `required` — `false`\n * - `defaultValue` — `[]`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Array field configuration. All properties are optional.\n * @returns Resolved array field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { array, text, defineCollection } from '@vexcms/core'\n *\n * posts: defineCollection({\n * fields: {\n * // Simple string tags array\n * tags: array({\n * items: text(),\n * }),\n *\n * // Number array with a min length\n * scores: array({\n * items: number(),\n * min: { value: 1 },\n * }),\n *\n * // Nested array — array of arrays of numbers\n * matrix: array({\n * items: array({ items: number() }),\n * }),\n * }\n * })\n * ```\n *\n * @see {@link ArrayFieldInput} for the full input type\n * @see {@link ArrayField} for the resolved output type\n */\nexport function array<\n TArrayType extends ArrayType = string,\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n>(options: ArrayFieldInput<TArrayType, TFieldMeta>): ArrayField<TArrayType, TFieldMeta> {\n // If the items field is a named group, reference its name in the array\n // type rather than inlining the full object type. This keeps generated\n // interfaces readable and lets the named group's own type alias do the work.\n const itemsInterfaceType =\n options.items.type === ADMIN_FIELDS.group.type && options.items.interfaceName\n ? options.items.interfaceName\n : options.items.interfaceType;\n\n return {\n type: ADMIN_FIELDS.array.type,\n interfaceType: `${itemsInterfaceType}[]`,\n\n // Core properties with defaults\n label: \"\",\n labels: {\n singular: \"Item\",\n plural: \"Items\",\n },\n required: false,\n defaultValue: [],\n ...options,\n\n items: {\n ...options.items,\n required: true,\n },\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n // Optional admin properties (no defaults)\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options.meta,\n } as TFieldMeta,\n };\n}\n","import { adminFieldToValidator } from \"../validators\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { ArrayField, ArrayType } from \"./types\";\n\n/**\n * Converts an array field definition to a Convex schema validator.\n *\n * Generates `v.array(itemValidator)` wrapped in `v.optional(…)` if the field\n * is not required. The item validator is derived from the nested `field.items`\n * field definition using `adminFieldToValidator`.\n *\n * @param props - Input props\n * @param props.field - The array field definition\n * @returns Convex value type string: `\"v.array(v.string())\"` or `\"v.optional(v.array(v.string()))\"`\n *\n * @example\n * ```ts\n * const field1 = array({ items: text(), required: true })\n * arrayFieldToValidator({ field: field1 }) // \"v.array(v.string())\"\n *\n * const field2 = array({ items: number(), required: false })\n * arrayFieldToValidator({ field: field2 }) // \"v.optional(v.array(v.number()))\"\n *\n * const field3 = array({ items: array({ items: number() }) })\n * arrayFieldToValidator({ field: field3 }) // \"v.array(v.array(v.number()))\"\n * ```\n *\n * @internal - Used by CLI schema generation\n */\nexport function arrayFieldToValidator<\n TArrayType extends ArrayType = ArrayType,\n TFieldMeta extends {} = {},\n>(props: { field: ArrayField<TArrayType, TFieldMeta> }): string {\n const itemValidator = adminFieldToValidator({ field: props.field.items });\n return applyBaseValidators({\n field: props.field,\n validator: `v.array(${itemValidator})`,\n });\n}\n","import { AdminField } from \"./types\";\n\n/**\n * Wraps a string into lines that do not exceed `maxLen` characters, splitting\n * on word boundaries.\n *\n * Used by `adminFieldToJSDocComment` to keep JSDoc comment lines within the\n * conventional 80-character limit before emitting them into generated source files.\n *\n * @param props - Input props.\n * @param props.text - The string to wrap.\n * @param props.maxLen - Maximum character length per line.\n * @returns An array of strings, each no longer than `maxLen` characters.\n *\n * @example\n * ```ts\n * wrapLines({ text: \"This is a long description that should wrap.\", maxLen: 20 })\n * // → [\"This is a long\", \"description that\", \"should wrap.\"]\n * ```\n */\nexport function wrapLines(props: { text: string; maxLen: number }): string[] {\n const words = props.text.split(\" \");\n const lines: string[] = [];\n let current = \"\";\n for (const word of words) {\n if (current && current.length + 1 + word.length > props.maxLen) {\n lines.push(current);\n current = word;\n } else {\n current = current ? `${current} ${word}` : word;\n }\n }\n if (current) lines.push(current);\n return lines;\n}\n\n/**\n * Builds a tab-indented JSDoc comment block for a field's description.\n *\n * Reads `field.interfaceDescription` first, falling back to `field.description`.\n * Returns an empty string when neither is set. The output is ready to insert\n * directly above a property line in a generated TypeScript interface — lines are\n * wrapped at 80 characters via `wrapLines`.\n *\n * @param props - Input props.\n * @param props.field - The resolved field definition to extract the description from.\n * @returns A tab-indented JSDoc block string ready to splice into generated\n * TypeScript source, or an empty string if the field has no description.\n *\n * @example\n * ```ts\n * const field = text({ description: \"Page title shown in browser tabs.\" })\n * adminFieldToJSDocComment({ field })\n * // Returns a multi-line JSDoc block wrapping the description text\n * ```\n */\nexport function adminFieldToJSDocComment(props: { field: AdminField }): string {\n let jsdocComment = \"\";\n const jsdoc = props.field.interfaceDescription ?? props.field.description;\n if (jsdoc) {\n const linesArray = wrapLines({\n text: jsdoc,\n maxLen: 80,\n });\n jsdocComment = `\\t/**\\n${linesArray.map((l) => `\\t * ${l}`).join(\"\\n\")}\\n\\t */\\n`;\n }\n return jsdocComment;\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport { adminFieldToJSDocComment } from \"../utils\";\nimport type { GroupFieldInput, GroupField } from \"./types\";\n\n/**\n * Creates a group field with all defaults applied.\n *\n * Group fields store a named set of sub-fields as a single nested Convex\n * `v.object({...})`. Each sub-field respects its own `required` setting —\n * required sub-fields emit bare validators (e.g. `v.string()`); optional\n * ones emit `v.optional(v.string())`.\n *\n * **Defaults applied:**\n * - `label` — `\"\"` (inferred from the field key by `defineCollection`)\n * - `required` — `false`\n * - `defaultValue` — `{}`\n * - `admin.hidden` — `false`\n * - `admin.readOnly` — `false`\n * - `admin.position` — `\"main\"`\n * - `admin.width` — `\"full\"`\n * - `admin.cellAlignment` — `\"left\"`\n *\n * @param options - Group field configuration. `fields` is required; all other\n * properties are optional.\n * @returns Resolved group field definition with all defaults applied.\n *\n * @example\n * ```ts\n * import { group, text, url } from \"@vexcms/core\"\n *\n * posts: defineCollection({\n * fields: {\n * seo: group({\n * label: \"SEO\",\n * fields: {\n * title: text({ required: true }),\n * description: text(),\n * ogImage: url(),\n * },\n * }),\n * },\n * })\n * ```\n *\n * @see {@link GroupFieldInput} for the full input type\n * @see {@link GroupField} for the resolved output type\n */\nexport function group<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options: GroupFieldInput<TFieldMeta>,\n): GroupField<TFieldMeta> {\n // Compute the TypeScript interface type string from sub-fields so that\n // generateVexTypes emits accurate per-field types rather than `object`.\n const computedInterfaceType = buildInterfaceType(options.fields);\n\n return {\n type: ADMIN_FIELDS.group.type,\n interfaceType: computedInterfaceType,\n\n // Core properties with defaults\n label: \"\",\n required: false,\n defaultValue: {},\n defaultOpen: true,\n ...options,\n\n // Admin config with all defaults applied\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options?.meta,\n } as TFieldMeta,\n };\n}\n\n/**\n * Builds a TypeScript object-type string from a record of sub-fields.\n *\n * Used by `group()` to compute `GroupField.interfaceType`.\n *\n * @param fields - The sub-field record from the group config.\n * @returns A TypeScript type string, e.g. `\"{ title: string; description?: string }\"`.\n */\nfunction buildInterfaceType(fields: GroupFieldInput[\"fields\"]): string {\n const entries = Object.entries(fields)\n .map(([key, field]) => {\n const jsdocComment = adminFieldToJSDocComment({ field });\n const typeStr =\n field.type === ADMIN_FIELDS.group.type && field.interfaceName\n ? field.interfaceName\n : field.interfaceType;\n return `\\n${jsdocComment}${key}${field.required ? \"\" : \"?\"}: ${typeStr}`;\n })\n .join(\"; \");\n return `{ ${entries} }`;\n}\n","import { adminFieldToValidator } from \"../validators\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { GroupField } from \"./types\";\n\n/**\n * Converts a group field definition to a Convex schema validator string.\n *\n * Generates `v.object({ key: validator, ... })` where each sub-field's\n * validator is built by the existing `adminFieldToValidator` dispatch.\n * Sub-fields respect their own `required` setting — required sub-fields\n * emit bare validators; optional ones emit `v.optional(...)`.\n *\n * The outer object is wrapped in `v.optional(...)` when `field.required`\n * is `false`.\n *\n * @param props - Input props.\n * @param props.field - The resolved group field definition.\n * @returns A Convex validator string.\n *\n * @example\n * ```ts\n * const field = group({\n * fields: { title: text({ required: true }), body: text() },\n * })\n * groupFieldToValidator({ field })\n * // → 'v.optional(v.object({ title: v.string(), body: v.optional(v.string()) }))'\n * ```\n *\n * @example\n * ```ts\n * const field = group({\n * required: true,\n * fields: { score: number({ required: true }) },\n * })\n * groupFieldToValidator({ field })\n * // → 'v.object({ score: v.number() })'\n * ```\n *\n * @internal — Used by CLI schema generation via `adminFieldToValidator`.\n */\nexport function groupFieldToValidator<TFieldMeta extends {} = {}>(props: {\n field: GroupField<TFieldMeta>;\n}): string {\n const { field } = props;\n\n const subValidators = Object.entries(field.fields)\n .map(\n ([key, subField]) =>\n `${key}: ${adminFieldToValidator({ field: subField })}`,\n )\n .join(\", \");\n\n return applyBaseValidators({\n field,\n validator: `v.object({ ${subValidators} })`,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { slugToPascalCase } from \"../../collections/utils\";\nimport type { BlockConfigInput, BlockConfig, BlocksFieldInput, BlocksField } from \"./types\";\nimport { RESERVED_BLOCK_FIELD_NAMES } from \"./types\";\nimport { nanoid } from \"nanoid\";\nimport { BaseFieldMeta } from \"../types\";\n\n/**\n * Defines a single block type for use in a `blocks()` field.\n *\n * Validates that the slug is a valid identifier and that no field name\n * collides with framework-reserved names (`blockType`, `blockName`, `id`).\n * Computes `interfaceType` — the TypeScript object-type string including\n * all three framework keys plus user fields.\n *\n * @param options - Block definition. `slug`, `label`, and `fields` are required.\n * @returns Resolved `BlockDef` with all defaults applied.\n *\n * @throws {Error} If `slug` does not match `/^[a-zA-Z][a-zA-Z0-9_-]*$/`.\n * @throws {Error} If any field name is in `RESERVED_BLOCK_FIELD_NAMES`.\n *\n * @example\n * ```ts\n * const headingBlock = defineBlock({\n * slug: \"heading\",\n * label: \"Heading\",\n * admin: { icon: \"heading\" },\n * fields: { text: text({ required: true }) },\n * })\n * ```\n *\n * @see {@link BlockConfigInput} for the full input type\n * @see {@link BlockConfig} for the resolved output type\n */\nexport function defineBlock(options: BlockConfigInput): BlockConfig {\n // Validate slug format — must generate a valid Convex v.literal() string\n if (!options.slug || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(options.slug)) {\n throw new Error(\n `Invalid block slug \"${options.slug}\". Slugs must start with a letter and contain only letters, numbers, hyphens, and underscores.`,\n );\n }\n\n // Prevent field name collisions with framework-injected keys\n for (const fieldName of Object.keys(options.fields)) {\n if ((RESERVED_BLOCK_FIELD_NAMES as readonly string[]).includes(fieldName)) {\n throw new Error(\n `Block \"${options.slug}\": field name \"${fieldName}\" is reserved. Reserved names: ${RESERVED_BLOCK_FIELD_NAMES.join(\", \")}`,\n );\n }\n }\n\n const interfaceName = options.interfaceName ?? `${slugToPascalCase({ slug: options.slug })}Block`;\n\n return {\n id: nanoid(),\n blockType: options.slug,\n blockName: options.name,\n label: options.label,\n fields: options.fields,\n admin: options.admin,\n interfaceName,\n interfaceType: buildBlockInterfaceType({\n slug: options.slug,\n fields: options.fields,\n }),\n };\n}\n\n/**\n * Creates a blocks field with all defaults applied.\n *\n * Validates that all block slugs are unique within this field. Each item\n * stored in Convex carries `blockType`, `blockName`, and `id` in addition\n * to the block's own fields.\n *\n * @param options - Blocks field configuration. `blocks` is required.\n * @returns Resolved blocks field definition.\n *\n * @throws {Error} If two or more block definitions share the same slug.\n *\n * @example\n * ```ts\n * const heading = defineBlock({ slug: \"heading\", label: \"Heading\", fields: { text: text({ required: true }) } })\n * const paragraph = defineBlock({ slug: \"paragraph\", label: \"Paragraph\", fields: { content: text({ required: true }) } })\n *\n * defineCollection({\n * fields: {\n * body: blocks({\n * label: \"Body\",\n * blocks: [heading, paragraph],\n * labels: { singular: \"section\", plural: \"sections\" },\n * }),\n * },\n * })\n * ```\n *\n * @see {@link BlocksFieldInput} for the full input type\n * @see {@link BlocksField} for the resolved output type\n */\nexport function blocks<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options: BlocksFieldInput<TFieldMeta>,\n): BlocksField<TFieldMeta> {\n // Validate unique slugs\n const seen = new Set<string>();\n for (const block of options.blocks) {\n if (seen.has(block.blockType)) {\n throw new Error(\n `Duplicate block slug \"${block.blockType}\" in blocks() call. Each block must have a unique slug.`,\n );\n }\n seen.add(block.blockType);\n }\n\n return {\n type: ADMIN_FIELDS.blocks.type,\n interfaceType: buildBlocksInterfaceType({\n blocks: options.blocks,\n interfaceName: options.interfaceName,\n }),\n label: options.label ?? \"\",\n required: options.required ?? false,\n defaultValue: options.defaultValue ?? [],\n labels: options.labels ?? { singular: \"Block\", plural: \"Blocks\" },\n blocks: options.blocks,\n interfaceName: options.interfaceName,\n min: options.min,\n max: options.max,\n admin: {\n defaultCollapsed: options.admin?.defaultCollapsed ?? false,\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n placeholder: \"\",\n ...options?.admin,\n },\n meta: {\n ...options.meta,\n } as TFieldMeta,\n };\n}\n\n/**\n * Builds the TypeScript object-type string for a block definition.\n *\n * Always includes the three framework keys first (`blockType` literal, `blockName?`,\n * `id`), followed by user fields. Named group sub-fields are referenced by\n * `interfaceName` rather than inlined.\n *\n * @param props - The block properties.\n * @param props.slug - The block slug used for the `blockType` literal.\n * @param props.fields - The block's field definitions.\n * @returns The TypeScript object-type string.\n * @internal\n */\nfunction buildBlockInterfaceType(props: {\n slug: string;\n fields: BlockConfigInput[\"fields\"];\n}): string {\n const frameworkKeys = `blockType: \"${props.slug}\"; blockName?: string; id: string`;\n const userEntries = Object.entries(props.fields)\n .map(([key, field]) => {\n const typeStr =\n field.type === ADMIN_FIELDS.group.type && field.interfaceName\n ? field.interfaceName\n : field.interfaceType;\n return `${key}${field.required ? \"\" : \"?\"}: ${typeStr}`;\n })\n .join(\"; \");\n return userEntries ? `{ ${frameworkKeys}; ${userEntries} }` : `{ ${frameworkKeys} }`;\n}\n\n/**\n * Builds the TypeScript array-type string for a blocks field.\n *\n * Uses `interfaceName` for the named union alias when set, otherwise\n * builds an inline union of all block interface names.\n *\n * @param props - The blocks field properties.\n * @param props.blocks - The block definitions for this field.\n * @param props.interfaceName - Optional union alias name.\n * @returns The TypeScript array-type string.\n * @internal\n */\nfunction buildBlocksInterfaceType(props: {\n blocks: BlockConfig[];\n interfaceName?: string;\n}): string {\n if (props.interfaceName) return `${props.interfaceName}[]`;\n const names = props.blocks.map((b) => b.interfaceName);\n if (names.length === 0) return \"Record<string, unknown>[]\";\n if (names.length === 1) return `${names[0]}[]`;\n return `(${names.join(\" | \")})[]`;\n}\n","import { adminFieldToValidator } from \"../validators\";\nimport { applyBaseValidators } from \"../validators/utils\";\nimport type { BlocksField } from \"./types\";\n\n/**\n * Converts a blocks field definition to a Convex schema validator string.\n *\n * Each block type becomes a `v.object()` with three framework keys first —\n * `blockType: v.literal(slug)`, `blockName: v.optional(v.string())`,\n * `id: v.string()` — followed by the block's own field validators. Multiple\n * block types are combined with `v.union()`; a single block type uses a bare\n * `v.object()`. The whole thing is wrapped in `v.array()`, then `v.optional()`\n * when `field.required` is `false`.\n *\n * @param props - Input props.\n * @param props.field - The resolved blocks field definition.\n * @returns A Convex validator string.\n *\n * @example\n * ```ts\n * const heading = defineBlock({ slug: \"heading\", fields: { text: text({ required: true }) } })\n * const paragraph = defineBlock({ slug: \"paragraph\", fields: { content: text() } })\n * blocksFieldToValidator({ field: blocks({ blocks: [heading, paragraph] }) })\n * // → 'v.optional(v.array(v.union(\n * // v.object({ blockType: v.literal(\"heading\"), blockName: v.optional(v.string()), id: v.string(), text: v.string() }),\n * // v.object({ blockType: v.literal(\"paragraph\"), blockName: v.optional(v.string()), id: v.string(), content: v.optional(v.string()) }),\n * // )))'\n * ```\n *\n * @internal — Used by CLI schema generation via `adminFieldToValidator`.\n */\nexport function blocksFieldToValidator<TFieldMeta extends {} = {}>(props: {\n field: BlocksField<TFieldMeta>;\n}): string {\n const { field } = props;\n\n const blockObjects = field.blocks.map((block) => {\n const subValidators = Object.entries(block.fields)\n .map(\n ([key, subField]) =>\n `${key}: ${adminFieldToValidator({ field: subField })}`,\n )\n .join(\", \");\n\n const frameworkEntries = [\n `blockType: v.literal(\"${block.blockType}\")`,\n `blockName: v.optional(v.string())`,\n `id: v.string()`,\n ].join(\", \");\n\n const allEntries = subValidators\n ? `${frameworkEntries}, ${subValidators}`\n : frameworkEntries;\n\n return `v.object({ ${allEntries} })`;\n });\n\n const itemValidator =\n blockObjects.length === 1\n ? blockObjects[0]!\n : `v.union(\\n${blockObjects.map((o) => ` ${o}`).join(\",\\n\")}\\n)`;\n\n return applyBaseValidators({\n field,\n validator: `v.array(${itemValidator})`,\n });\n}\n","import { ADMIN_FIELDS } from \"../constants\";\nimport { BaseFieldMeta } from \"../types\";\nimport type { UploadFieldInput, UploadField } from \"./types\";\n\n/**\n * Creates an upload field that stores a reference to a media document.\n *\n * The `to` parameter specifies which media collection receives uploaded files.\n * At config validation time, the `to` slug is checked against the media\n * collections returned by all configured storage adapters.\n *\n * @param options — Upload field configuration. `to` is required.\n * @returns Resolved upload field definition.\n *\n * @throws {Error} If `to` is empty or not a valid slug (`/^[a-zA-Z][a-zA-Z0-9_-]*$/`).\n *\n * @example\n * ```ts\n * defineCollection({\n * fields: {\n * featuredImage: upload({ to: \"images\", label: \"Featured Image\" }),\n * },\n * });\n */\nexport function upload<TFieldMeta extends BaseFieldMeta = BaseFieldMeta>(\n options: UploadFieldInput<TFieldMeta>,\n): UploadField<TFieldMeta> {\n if (!options.to || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(options.to)) {\n throw new Error(`upload(): \"to\" must be a valid collection slug. Got \"${options.to}\".`);\n }\n\n return {\n label: \"\",\n required: false,\n hasMany: false,\n min: 0,\n accept: \"\",\n ...options,\n type: ADMIN_FIELDS.upload.type,\n // Per-field override of the static `ADMIN_FIELDS.upload.interfaceType`\n // (`Id<MediaCollectionSlug>[]`). `to` is validated as a slug above; emitting\n // it as a literal keeps the populated type narrow once more than one media\n // collection is registered (a single-member union masks the difference).\n interfaceType: `Id<\"${options.to}\">[]`,\n admin: {\n hidden: false,\n readOnly: false,\n position: \"main\",\n width: \"full\",\n cellAlignment: \"left\",\n placeholder: \"\",\n ...options.admin,\n },\n meta: {\n ...options.meta,\n } as TFieldMeta,\n };\n}\n","import { applyBaseValidators } from \"../validators/utils\";\nimport type { UploadField } from \"./types\";\n\n/**\n * Generates the Convex schema validator for an upload field.\n *\n * Stores a media document ID: `v.id(\"<to-slug>\")`. The `to` slug is the\n * media collection name — schema generation validates that the collection exists.\n *\n * @param props — Validator generation options.\n * @param props.field — The resolved upload field definition.\n * @returns Convex validator string, e.g. `\"v.id(\\\"images\\\")\"` or\n * `\"v.optional(v.id(\\\"images\\\"))\"`.\n */\nexport function uploadFieldToValidator(props: { field: UploadField }): string {\n const validator = `v.array(v.id(\"${props.field.to}\"))`;\n return applyBaseValidators({ field: props.field, validator });\n}\n","import { ADMIN_FIELDS, type AdminFieldType } from \"../constants\";\nimport { AdminField } from \"../types\";\nimport { textFieldToValidator } from \"../text\";\nimport { numberFieldToValidator } from \"../number\";\nimport { checkboxFieldToValidator } from \"../checkbox\";\nimport { dateFieldToValidator } from \"../date\";\nimport { selectFieldToValidator } from \"../select\";\nimport { urlFieldToValidator } from \"../url\";\nimport { colorFieldToValidator } from \"../color\";\nimport { relationshipFieldToValidator } from \"../relationship\";\nimport { arrayFieldToValidator } from \"../array\";\nimport { groupFieldToValidator } from \"../group\";\nimport { blocksFieldToValidator } from \"../blocks\";\nimport { uploadFieldToValidator } from \"../upload\";\n\n/**\n * Converts any field definition to its Convex schema validator string.\n *\n * Dispatches to the field-type-specific validator function based on `field.type`.\n * Used by the CLI during schema generation to build the Convex schema file.\n *\n * @param props Input props\n * @param props.field - The resolved field definition to convert\n * @returns A Convex validator string (e.g. `\"v.string()\"`, `\"v.optional(v.boolean())\"`)\n * @throws An Error if an unrecognized field type is given. Reaching this is a\n * compile error: the default arm binds the exhausted union to `never`, so a new\n * member of `AdminField` fails typecheck here until a case is added\n *\n * @see {@link textFieldToValidator} for the text field implementation\n * @see {@link numberFieldToValidator} for the number field implementation\n * @see {@link checkboxFieldToValidator} for the checkbox field implementation\n * @internal\n */\nexport function adminFieldToValidator<TFieldMeta extends {} = {}>(props: {\n field: AdminField<TFieldMeta>;\n}) {\n // Captured before the switch narrows `props.field`: inside the default arm the\n // union is exhausted to `never`, and `never.type` is not a usable string.\n const fieldType: AdminFieldType = props.field.type;\n\n switch (props.field.type) {\n case ADMIN_FIELDS.text.type:\n return textFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.number.type:\n return numberFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.checkbox.type:\n return checkboxFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.date.type:\n return dateFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.select.type:\n return selectFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.url.type:\n return urlFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.color.type:\n return colorFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.relationship.type:\n return relationshipFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.array.type:\n return arrayFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.group.type:\n return groupFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.blocks.type:\n return blocksFieldToValidator({ field: props.field });\n case ADMIN_FIELDS.upload.type:\n return uploadFieldToValidator({ field: props.field });\n default: {\n const unhandled: never = props.field;\n throw new Error(\n `unrecognized field type: ${fieldType} — ${JSON.stringify(unhandled)}`,\n );\n }\n }\n}\n","import { CollectionConfig } from \"../types\";\nimport { ADMIN_FIELDS } from \"./constants\";\n\n/**\n * Recursively collects `export type` declarations for every group field that\n * carries an `interfaceName`, at any depth in the field tree.\n *\n * Traversal is depth-first so nested named types are always declared before\n * the parent types that reference them. Both direct group sub-fields and\n * group items inside array fields are visited.\n *\n * @param fields - The field map to walk (collection-level or group sub-fields).\n * @returns Ordered list of `export type Name = ...` strings, ready to prepend\n * to the generated interface block.\n */\nexport function getFieldInterfaces(fields: CollectionConfig[\"fields\"]): string[] {\n const declarations: string[] = [];\n\n for (const field of Object.values(fields)) {\n if (field.type === ADMIN_FIELDS.group.type) {\n // Depth-first: collect nested declarations before this one so that\n // sub-group named types are declared before any type that references them.\n declarations.push(...getFieldInterfaces(field.fields));\n\n if (field.interfaceName) {\n declarations.push(`export type ${field.interfaceName} = ${field.interfaceType}`);\n }\n } else if (field.type === ADMIN_FIELDS.array.type) {\n // Array items may themselves be groups — visit their fields too.\n if (field.items.type === ADMIN_FIELDS.group.type) {\n declarations.push(...getFieldInterfaces(field.items.fields));\n\n if (field.items.interfaceName) {\n declarations.push(\n `export type ${field.items.interfaceName} = ${field.items.interfaceType}`,\n );\n }\n }\n } else if (field.type === ADMIN_FIELDS.blocks.type) {\n // Depth-first: recurse into each block's fields for any named sub-groups,\n // then emit each block's own type declaration.\n for (const block of field.blocks) {\n declarations.push(...getFieldInterfaces(block.fields));\n declarations.push(`export type ${block.interfaceName} = ${block.interfaceType}`);\n }\n // Named union alias — emitted after all individual block types.\n if (field.interfaceName) {\n const union = field.blocks.map((b) => b.interfaceName).join(\" | \");\n declarations.push(`export type ${field.interfaceName} = ${union}`);\n }\n }\n }\n\n return declarations;\n}\n","import { AdminField, CollectionFieldMeta, ComponentHKT } from \"../fields\";\nimport { CollectionSlug } from \"../types\";\nimport { toTitleCase, plural } from \"../utils\";\nimport { CollectionConfigInput, CollectionConfig } from \"./types\";\nimport { slugToPascalCase } from \"./utils\";\n\nfunction populateCollectionFieldMeta<\n TFieldMeta extends {} = {},\n TCollectionMeta extends {} = {},\n TCollectionSlug extends CollectionSlug = CollectionSlug,\n TFieldSlug extends string = string,\n TComponent extends ComponentHKT = ComponentHKT,\n>({\n config,\n}: {\n config: CollectionConfigInput<\n TFieldMeta,\n TCollectionMeta,\n TCollectionSlug,\n TFieldSlug,\n TComponent\n >;\n}): Record<TFieldSlug, AdminField<TFieldMeta & CollectionFieldMeta>> {\n const fields: Record<\n TFieldSlug,\n AdminField<TFieldMeta & { collectionSlug: string }>\n > = {} as Record<TFieldSlug, AdminField<TFieldMeta & CollectionFieldMeta>>;\n Object.entries(config.fields).forEach((value) => {\n const fieldSlug = value[0] as TFieldSlug;\n const field = value[1] as AdminField<TFieldMeta & CollectionFieldMeta>;\n fields[fieldSlug] = {\n ...field,\n meta: {\n ...field?.meta,\n collectionSlug: config.slug,\n },\n };\n });\n return fields;\n}\n\n/**\n * Resolves a raw collection config input into a fully-populated `CollectionConfig`.\n *\n * Fills in any missing `labels` by deriving them from the `slug` — converting it\n * to title case for `singular` and further pluralising it for `plural`.\n *\n * @param config - The raw collection configuration supplied by the caller.\n * @returns The resolved `CollectionConfig` with all defaults applied.\n *\n * @example\n * ```ts\n * defineCollection({\n * slug: \"posts\",\n * fields: {\n * title: text({ required: true }),\n * },\n * });\n * // → { slug: \"posts\", admin: { useAsTitle: \"_id\" }, labels: { singular: \"Post\", plural: \"Posts\" }, fields: { ... } }\n * ```\n *\n * @see {@link CollectionConfigInput} for the user-facing input type\n * @see {@link CollectionConfig} for the resolved return type\n */\nexport function defineCollection<\n TFieldMeta extends {} = {},\n TCollectionMeta extends {} = {},\n TCollectionSlug extends CollectionSlug = CollectionSlug,\n TFieldSlug extends string = string,\n TComponent extends ComponentHKT = ComponentHKT,\n>(\n config: CollectionConfigInput<\n TFieldMeta,\n TCollectionMeta,\n TCollectionSlug,\n TFieldSlug,\n TComponent\n >,\n): CollectionConfig<\n TFieldMeta & CollectionFieldMeta,\n TCollectionMeta,\n TCollectionSlug,\n TFieldSlug,\n TComponent\n> {\n const fields = populateCollectionFieldMeta({ config });\n return {\n interfaceName: slugToPascalCase({ slug: config.slug }) + \"Document\",\n ...config,\n fields,\n admin: {\n useAsTitle: \"_id\",\n components: {},\n ...config.admin,\n table: {\n defaultPageSize: 10,\n serverPageSize: 100,\n pageSizeOptions: [10, 25, 50, 100],\n defaultColumns: [],\n ...config.admin?.table,\n bulkActions: {\n delete: true,\n ...config.admin?.table?.bulkActions,\n },\n defaultSort: {\n field: \"_createdAt\",\n order: \"desc\",\n ...config.admin?.table?.defaultSort,\n },\n },\n },\n labels: {\n singular: toTitleCase(config.slug),\n plural: plural(toTitleCase(config.slug)),\n ...config.labels,\n },\n meta: {\n ...config.meta,\n } as TCollectionMeta,\n };\n}\n","/**\n * Built-in Convex system fields that are present on every document.\n *\n * Maps logical names to their Convex database field slugs. These slugs are\n * always valid values for `useAsTitle` in a collection's admin config,\n * regardless of the collection's own field definitions.\n */\nexport const CORE_ADMIN_FIELDS = {\n /** The document's unique identifier, stored as `_id` in Convex. */\n id: {\n slug: \"_id\",\n },\n /** The document's creation timestamp, stored as `_creationTime` in Convex. */\n createdAt: {\n slug: \"_creationTime\",\n },\n} as const;\n\n/**\n * Union of the field slugs for all built-in Convex system fields.\n *\n * Resolves to `\"_id\" | \"_creationTime\"`. Use this type wherever a value must\n * refer to a core system field rather than a user-defined collection field.\n *\n * @see {@link CORE_ADMIN_FIELDS} for the full map of logical names to slugs\n */\nexport type CoreAdminField =\n (typeof CORE_ADMIN_FIELDS)[keyof typeof CORE_ADMIN_FIELDS][\"slug\"];\n","import { ADMIN_FIELDS } from \"../fields/constants\";\nimport { adminFieldToValidator } from \"../fields/validators\";\nimport { CollectionConfig } from \"./types\";\nimport type { VexConfig } from \"../config\";\nimport { CORE_ADMIN_FIELDS } from \"./constants\";\n\n/**\n * Describes a relationship field in another collection that points to a given collection.\n *\n * Used by `collectionConfigToVexSchema` to detect whether a search index should be\n * auto-generated on the current collection's `useAsTitle` field.\n *\n * @see {@link getIncomingRelationships}\n */\nexport interface IncomingRelationship {\n /** The slug of the collection that holds the relationship field. */\n fromSlug: string;\n /** The field key of the relationship field in that collection. */\n fieldKey: string;\n}\n\n/**\n * Returns all relationship fields in other collections that point to `collection`.\n *\n * Iterates every collection in `config` (excluding `collection` itself) and collects\n * any field with `type === \"relationship\"` whose `collection` matches\n * `props.collection.slug`.\n *\n * @param props - Input props.\n * @param props.collection - The collection being checked for incoming relationships.\n * @param props.config - The full resolved VexCMS configuration.\n * @returns An array of `IncomingRelationship` descriptors, empty if none found.\n *\n * @example\n * ```ts\n * // posts has: author: relationship({ collection: \"authors\" })\n * getIncomingRelationships({ collection: authorsCollection, config })\n * // → [{ fromSlug: \"posts\", fieldKey: \"author\" }]\n */\nexport function getIncomingRelationships(props: {\n collection: CollectionConfig;\n config: VexConfig;\n}): IncomingRelationship[] {\n const relationships: IncomingRelationship[] = [];\n // NOTE: self-references are intentionally INCLUDED. A collection that has\n // a relationship pointing to itself (e.g. `posts.parent: relationship({\n // slug: \"posts\" })`) still needs `.searchIndex(\"search_<useAsTitle>\", …)`\n // so the relationship picker can search the same collection it lives in.\n // Skipping self-refs left the picker stuck on the loading state because\n // the picker query targeted an index that was never generated.\n for (const collection of props.config.collections) {\n Object.entries(collection.fields)\n\n .filter(([_fieldKey, field]) => {\n if (field.type === ADMIN_FIELDS.relationship.type) {\n return field.collection.slug === props.collection.slug;\n }\n if (field.type === ADMIN_FIELDS.upload.type) {\n return field.to === props.collection.slug;\n }\n return false;\n })\n\n .forEach(([fieldKey, _field]) => {\n relationships.push({\n fieldKey,\n fromSlug: collection.slug,\n });\n });\n }\n return relationships;\n}\n\n/**\n * Converts a resolved `CollectionConfig` to a Convex `defineTable(...)` source string.\n *\n * Iterates the collection's fields, builds each field's Convex validator via\n * `adminFieldToValidator`, and appends index chains:\n * - `.index()` for fields with an explicit `field.index` property\n * - `.index(\"by_<fieldKey>\", [\"<fieldKey>\"])` auto-generated for every relationship field\n * - `.searchIndex()` for text fields with `field.searchIndex` configured\n * - `.searchIndex(\"search_<useAsTitle>\", { searchField: \"<useAsTitle>\", filterFields: [] })`\n * auto-generated when another collection has a relationship pointing HERE and\n * `useAsTitle` is not a Convex system field (`_id`, `_creationTime`), provided\n * no manually configured search index already has that name.\n *\n * @param props - Input props.\n * @param props.collection - The resolved collection definition to convert.\n * @param props.config - The full resolved VexCMS config, needed for cross-collection relationship detection.\n * @returns A TypeScript source string declaring the Convex table.\n *\n * @example\n * ```ts\n * const posts = defineCollection({\n * slug: \"posts\",\n * fields: { author: relationship({ collection: \"authors\", required: true }) },\n * });\n * collectionConfigToVexSchema({ collection: posts, config });\n * // → 'export const posts = defineTable({...})\\n\\t.index(\"by_author\", [\"author\"])'\n *\n * @see {@link generateVexSchema} for the full-file generator that wraps this function\n * @see {@link getIncomingRelationships} for the cross-collection helper\n */\nexport function collectionConfigToVexSchema(props: {\n collection: CollectionConfig;\n config: VexConfig;\n}): string {\n const fieldsBlock = [];\n const indexes = [];\n const searchIndexes: string[] = [];\n for (const index of props.collection.indexes ?? []) {\n indexes.push(`\\t.index(\"${index.name}\", ${JSON.stringify(index.fields)})`);\n }\n\n for (const [fieldKey, field] of Object.entries(props.collection.fields)) {\n const validator = adminFieldToValidator({ field });\n fieldsBlock.push(`\\t${fieldKey}: ${validator},`);\n\n const fieldIndexName = field.index\n ? field.index\n : field.type === ADMIN_FIELDS.relationship.type\n ? `by_${fieldKey}`\n : undefined;\n // collection indexes preferred since they can be compound indexes\n if (fieldIndexName && !props.collection.indexes?.find((i) => i.name === fieldIndexName)) {\n indexes.push(`\\t.index(\"${fieldIndexName}\", [\"${fieldKey}\"])`);\n }\n\n if (field.type === ADMIN_FIELDS.text.type && field.searchIndex) {\n searchIndexes.push(`\\t.searchIndex(\"${field.searchIndex.name}\", {\\n\n searchField: \"${fieldKey}\",\n filterFields: ${JSON.stringify(field.searchIndex.filterFields)}\\n\n })`);\n }\n }\n const relationships = getIncomingRelationships({\n collection: props.collection,\n config: props.config,\n });\n relationships.forEach(() => {\n const useAsTitle = props.collection.admin.useAsTitle;\n const coreAdminFields: string[] = Object.values(CORE_ADMIN_FIELDS).map((f) => f.slug);\n if (coreAdminFields.includes(useAsTitle)) return;\n const searchIndex = searchIndexes.find((si) =>\n si.includes(`.searchIndex(\"search_${useAsTitle}\", {`),\n );\n if (searchIndex !== undefined) return;\n searchIndexes.push(`\\t.searchIndex(\"search_${useAsTitle}\", {\\n\n searchField: \"${useAsTitle}\",\\n\n filterFields: []\n })`);\n });\n return `export const ${props.collection.slug} = defineTable({\\n${fieldsBlock.join(\"\\n\")}\\n\n })${indexes.length > 0 ? `\\n${indexes.join(\"\\n\")}` : \"\"}${\n searchIndexes.length > 0 ? `\\n${searchIndexes.join(\"\\n\")}` : \"\"\n }\n `;\n}\n","import { ADMIN_FIELDS, wrapLines, getFieldInterfaces } from \"../fields\";\nimport { CollectionConfig } from \"./types\";\nimport { slugToPascalCase } from \"./utils\";\n\n/**\n * Converts a resolved `CollectionConfig` to a TypeScript `export interface` source string.\n *\n * Each generated interface extends `VexDocument` (inheriting `_id` and `_creationTime`)\n * and overrides `_id` with the branded Convex `Id<\"slug\">` type for that collection.\n * Optional fields (`field.required === false`) are emitted with the `?` modifier.\n * `select` fields with custom options emit a companion type alias above the interface,\n * named `<InterfaceName><FieldKey>Option` so the same field key on two collections does\n * not produce two aliases with one name. Override with the field's `optionInterfaceName`.\n *\n * @param props - Input props.\n * @param props.collection - The resolved collection definition to convert.\n * @returns A TypeScript source string for one document interface block.\n *\n * @example\n * ```ts\n * const collection = defineCollection({\n * slug: \"posts\",\n * fields: { title: text({ required: true }), excerpt: text({ required: false }) },\n * });\n * collectionConfigToInterface({ collection });\n * // → 'export interface PostsDocument extends VexDocument {\\n\\t_id: Id<\"posts\">\\n\\ttitle: string\\n\\texcerpt?: string\\n}'\n * ```\n *\n * @see {@link generateVexTypes} for the full-file generator that wraps this function\n */\nexport function collectionConfigToInterface(props: { collection: CollectionConfig }): string {\n const { collection } = props;\n const fieldInterfaces = getFieldInterfaces(collection.fields);\n const interfaceStart = `export interface ${collection.interfaceName} extends VexDocument {\\n\n \\t_id: Id<\"${collection.slug}\">`;\n\n const collectionSubTypes: string[] = [];\n const interfaceFields = Object.entries(collection.fields)\n .map(([fieldKey, field]) => {\n let fieldType = field.interfaceType;\n if (field.type === ADMIN_FIELDS.select.type) {\n // Qualified by the collection's interface name, not the field key alone.\n // The field key alone collides whenever two collections declare a `select`\n // under the same name — `status` on three content collections emitted three\n // `StatusOption` aliases and broke the generated file. Interface names are\n // already unique (two collections sharing one would collide on the interface\n // itself), so qualifying is sufficient without any cross-collection state.\n //\n // Safe to rename: this alias is deliberately NOT exported, so nothing outside\n // the generated file can reference it.\n const optionName =\n field.optionInterfaceName ??\n `${collection.interfaceName}${slugToPascalCase({ slug: fieldKey })}Option`;\n collectionSubTypes.push(\n `type ${optionName} = ${field.options.map((o) => `\"${o.value}\"`).join(\" | \")}`,\n );\n // `[]` matters: a `select` stores `v.array(...)` (see `ADMIN_FIELDS.select`,\n // whose own `interfaceType` is `string[]`), and substituting the bare union\n // name here used to drop it — so the generated interface promised a scalar\n // while the deployed schema rejected one. Inserting the documented value then\n // failed at runtime with a validator error, and an access constraint written\n // as `q.eq(\"status\", \"published\")` typechecked against a shape that can never\n // match a stored row.\n fieldType = `${optionName}[]`;\n }\n if (field.type === ADMIN_FIELDS.group.type && field.interfaceName) {\n fieldType = field.interfaceName;\n }\n if (field.type === ADMIN_FIELDS.blocks.type && field.interfaceName) {\n fieldType = `${field.interfaceName}[]`;\n }\n let jsdocComment = \"\";\n const jsdoc = field.interfaceDescription ?? field.description;\n if (jsdoc) {\n const linesArray = wrapLines({\n text: jsdoc,\n maxLen: 80,\n });\n jsdocComment = `\\t/**\\n${linesArray.map((l) => `\\t * ${l}`).join(\"\\n\")}\\n\\t */\\n`;\n }\n return `${jsdocComment}\\t${fieldKey}${field.required ? \"\" : \"?\"}: ${fieldType}`;\n })\n .join(\"\\n\");\n\n return [\n fieldInterfaces.join(\"\\n\\n\"),\n collectionSubTypes.join(\"\\n\"),\n interfaceStart,\n interfaceFields,\n \"}\",\n ].join(\"\\n\");\n}\n\n/**\n * Converts a resolved `CollectionConfig` to the TypeScript source string for its\n * `CollectionsFieldTypeMap` entry used in the `declare module '@vexcms/core'` block.\n *\n * The output maps each field type present in the collection to a union of that\n * collection's field keys of that type, plus a fixed `id: \"_id\"` entry. This\n * lets framework code look up field keys by type at the TypeScript level —\n * for example, finding all `text` fields on a given collection for search.\n *\n * @param props - Input props.\n * @param props.collection - The resolved collection definition to convert.\n * @returns A TypeScript source string for one `CollectionsFieldTypeMap` entry (without wrapping braces).\n *\n * @example\n * ```ts\n * const posts = defineCollection({\n * slug: \"posts\",\n * fields: { title: text({ required: true }), author: relationship({ collection: { slug: \"authors\" } }) },\n * });\n * collectionConfigToFieldTypeMap({ collection: posts });\n * // → '\\tposts: {\\n\\t\\tid: \"_id\"\\n\\t\\ttext: \"title\"\\n\\t\\trelationship: \"author\"\\n\\t}'\n * ```\n *\n * @see {@link generateVexTypes} for the full-file generator that wraps this function\n */\nexport function collectionConfigToFieldTypeMap(props: { collection: CollectionConfig }): string {\n const { collection } = props;\n const fieldTypeMap = Object.entries(collection.fields).reduce<Record<string, string[]>>(\n (acc, [fieldKey, field]) => {\n if (!acc[field.type]) acc[field.type] = [];\n acc[field.type]!.push(`\"${fieldKey}\"`);\n return acc;\n },\n {},\n );\n const interfaceBody = Object.entries(fieldTypeMap).reduce((acc, [fieldType, fields]) => {\n acc += `\\t\\t${fieldType}: ${fields.join(\" | \")}\\n`;\n return acc;\n }, \"\");\n // No synthetic `id: \"_id\"` entry: this map is a field-TYPE index, and `_id` is not a\n // field type. It was only ever here to inject `_id` into the flattened field-key\n // union that access checks used to consume. That union is gone with the field-mode\n // API; what survives derives field names from the DOCUMENT (`AccessDocFieldFor`),\n // which carries `_id` and `_creationTime` on its own. `FieldKeysOfType` bounds its\n // key to `AdminFieldType`, so this entry was unreachable through the public surface.\n return `\\t${collection.slug}: {\\n${interfaceBody}\\t}`;\n}\n","import type { ComponentHKT } from \"../fields\";\nimport { slugToPascalCase } from \"../collections/utils\";\nimport type { GlobalConfig, GlobalConfigInput, ReservedGlobalFieldKey } from \"./types\";\nimport type { GlobalSlug } from \"../types/generated\";\n\n/**\n * Defines a singleton global document for the VexCMS project.\n *\n * **Flat API:** `globals.get({ slug: \"siteSettings\" })` returns a flat document\n * where user fields (`siteName`, `activeTheme`, …) are at root level alongside\n * `_id`, `_creationTime`, and `_slug`. The DB stores data nested in a `data`\n * field; the VexCMS API layer handles flattening on read and re-nesting on write.\n *\n * **Reserved field keys:** `_id`, `_creationTime`, and `_slug` may not be used\n * as field names. A compile-time error is emitted on the offending field when\n * they are used. A runtime error is also thrown for JS consumers.\n *\n * @typeParam TFieldMeta - Metadata on each field definition.\n * @typeParam TGlobalMeta - Metadata on the global config itself.\n * @typeParam TGlobalSlug - The slug string literal (inferred by TypeScript).\n * @typeParam TFieldSlug - Union of field key string literals.\n * @typeParam TComponent - Framework HKT binding.\n * @param config - The raw global configuration.\n * @returns The resolved `GlobalConfig` with all defaults applied.\n * @throws {Error} When `config.fields` contains one of the reserved keys\n * `_id`, `_creationTime`, or `_slug`.\n *\n * @example\n * ```ts\n * export const siteSettings = defineGlobal({\n * slug: \"siteSettings\",\n * label: \"Site Settings\",\n * fields: {\n * siteName: text({ label: \"Site Name\", required: true }),\n * activeTheme: relationship({ label: \"Active Theme\", collection: \"themes\" }),\n * },\n * admin: { group: \"Site Builder\" },\n * });\n * ```\n *\n * @see {@link GlobalConfigInput} for the user-facing input type\n * @see {@link GlobalConfig} for the resolved return type\n */\nexport function defineGlobal<\n TFieldMeta extends {} = {},\n TGlobalMeta extends {} = {},\n TGlobalSlug extends GlobalSlug = GlobalSlug,\n TFieldSlug extends string = string,\n TComponent extends ComponentHKT = ComponentHKT,\n>(\n config: string extends TFieldSlug\n ? GlobalConfigInput<TFieldMeta, TGlobalMeta, TGlobalSlug, TFieldSlug, TComponent>\n : [TFieldSlug & ReservedGlobalFieldKey] extends [never]\n ? GlobalConfigInput<TFieldMeta, TGlobalMeta, TGlobalSlug, TFieldSlug, TComponent>\n : {\n fields: {\n [K in TFieldSlug &\n ReservedGlobalFieldKey]: \"Field name is reserved — cannot use _id, _creationTime, or _slug\";\n };\n },\n): GlobalConfig<TFieldMeta, TGlobalMeta, TGlobalSlug, TFieldSlug, TComponent> {\n // Runtime guard for JS consumers\n const reservedKeys: ReservedGlobalFieldKey[] = [\"_id\", \"_creationTime\", \"_slug\"];\n for (const key of reservedKeys) {\n if (key in (config as GlobalConfigInput).fields) {\n throw new Error(\n `defineGlobal: field key \"${key}\" is reserved and cannot be used in global \"${(config as GlobalConfigInput).slug}\". ` +\n `Reserved keys: ${reservedKeys.join(\", \")}.`,\n );\n }\n }\n\n const input = config as GlobalConfigInput<\n TFieldMeta,\n TGlobalMeta,\n TGlobalSlug,\n TFieldSlug,\n TComponent\n >;\n\n return {\n ...input,\n interfaceName: input.interfaceName ?? slugToPascalCase({ slug: input.slug }) + \"Global\",\n admin: {\n group: \"\",\n description: \"\",\n components: {},\n ...input.admin,\n },\n meta: (input.meta ?? {}) as TGlobalMeta,\n versions: {\n drafts: false,\n ...input.versions,\n },\n };\n}\n","import { ADMIN_FIELDS, wrapLines, getFieldInterfaces } from \"../fields\";\nimport type { GlobalConfig } from \"./types\";\n\n/**\n * Converts a resolved `GlobalConfig` to a TypeScript `export interface` source string.\n *\n * The generated interface extends `VexDocumentGlobal<\"slug\">` (which itself\n * extends `VexDocument`), adding user fields at root level. This produces the\n * flat shape returned by `globals.get` — no `data` wrapper.\n *\n * @param props.global - The resolved global definition to convert.\n * @returns TypeScript source string for one flat global interface block.\n *\n * @example\n * ```ts\n * globalConfigToInterface({ global: siteSettings });\n * // → 'export interface SiteSettingsGlobal extends VexDocumentGlobal<\"siteSettings\"> {\\n\\tsiteName: string\\n\\t...\\n}'\n * ```\n */\nexport function globalConfigToInterface(props: { global: GlobalConfig }): string {\n const { global: g } = props;\n const fieldInterfaces = getFieldInterfaces(g.fields);\n const interfaceStart = `export interface ${g.interfaceName} extends VexDocumentGlobal<\"${g.slug}\"> {`;\n\n const interfaceFields = Object.entries(g.fields)\n .map(([fieldKey, field]) => {\n let fieldType = field.interfaceType;\n if (field.type === ADMIN_FIELDS.group.type && field.interfaceName) {\n fieldType = field.interfaceName;\n }\n if (field.type === ADMIN_FIELDS.blocks.type && field.interfaceName) {\n fieldType = `${field.interfaceName}[]`;\n }\n let jsdocComment = \"\";\n const jsdoc = field.interfaceDescription ?? field.description;\n if (jsdoc) {\n const linesArray = wrapLines({ text: jsdoc, maxLen: 80 });\n jsdocComment = `\\t/**\\n${linesArray.map((l) => `\\t * ${l}`).join(\"\\n\")}\\n\\t */\\n`;\n }\n return `${jsdocComment}\\t${fieldKey}${field.required ? \"\" : \"?\"}: ${fieldType}`;\n })\n .join(\"\\n\");\n\n return [fieldInterfaces.join(\"\\n\\n\"), interfaceStart, interfaceFields, \"}\"].join(\"\\n\");\n}\n\n/**\n * Converts a resolved `GlobalConfig` to the TypeScript source string for its\n * `GlobalsFieldTypeMap` entry in the `declare module '@vexcms/core'` block.\n *\n * Powers `GlobalRelationshipKeysOf<TGlobalSlug>` for populate type narrowing.\n *\n * @param props.global - The resolved global definition.\n * @returns TypeScript source string for one `GlobalsFieldTypeMap` entry.\n */\nexport function globalConfigToFieldTypeMap(props: { global: GlobalConfig }): string {\n const { global: g } = props;\n const fieldTypeMap = Object.entries(g.fields).reduce<Record<string, string[]>>(\n (acc, [fieldKey, field]) => {\n if (!acc[field.type]) acc[field.type] = [];\n acc[field.type]!.push(`\"${fieldKey}\"`);\n return acc;\n },\n {},\n );\n const interfaceBody = Object.entries(fieldTypeMap)\n .map(([fieldType, fields]) => `\\t\\t${fieldType}: ${fields.join(\" | \")}`)\n .join(\"\\n\");\n // See `collectionConfigToFieldTypeMap` for why there is no synthetic `id` entry.\n return `\\t${g.slug}: {\\n${interfaceBody}\\n\\t}`;\n}\n","import { CollectionConfig } from \"./collections\";\nimport { ClientVexConfig } from \"./config\";\nimport type {\n AdminField,\n ApplyComponent,\n BaseFieldMeta,\n CellComponentProps,\n ComponentHKT,\n InputComponentProps,\n} from \"./fields\";\nimport type { VexDocument } from \"./api/convex\";\nimport { CollectionSlug, GlobalSlug, VexDocumentGlobal } from \"./types/generated\";\nimport { PaginationResult } from \"./api/types\";\nimport { GlobalConfig } from \"./globals\";\n\n/**\n * Maps every field type in the `AdminField` union to the framework's input component type\n * for that field.\n *\n * Keyed by `AdminField['type']` — as new field types are added to the union, TypeScript\n * automatically requires a matching component slot in this map.\n *\n * Each slot resolves to `ApplyComponent<F, InputComponentProps<MatchingFieldDef>>`, which\n * means the component must accept the input props for that specific field type. This gives\n * the component full autocomplete for field-specific properties (e.g. `fieldDef.max`\n * on the text slot).\n *\n * @see {@link CellComponentProps} for the data table cell props\n * @see {@link ComponentHKT} for how framework packages define their HKT\n * @see {@link ApplyComponent} for how the HKT resolves to a concrete component type\n */\nexport type FieldComponentMap<\n F extends ComponentHKT,\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n> = {\n [K in AdminField[\"type\"]]: {\n input: ApplyComponent<\n F,\n InputComponentProps<TFieldMeta, Extract<AdminField<TFieldMeta>, { type: K }>>\n >;\n cell: ApplyComponent<F, CellComponentProps<Extract<AdminField<TFieldMeta>, { type: K }>>>;\n };\n};\n\n/**\n * Props passed to the admin `Dashboard` view component.\n *\n * The Dashboard receives the full resolved VexCMS config and is responsible\n * for rendering the admin shell — navigation sidebar, header, and a slot for\n * the active view (collection list or edit form).\n *\n * @see {@link ViewComponentMap}\n */\nexport interface DashboardProps {\n /** The full resolved VexCMS configuration. */\n config: ClientVexConfig;\n}\n\n/**\n * Props passed to the `CollectionListView` component.\n *\n * `TCollectionSlug` is inferred from the `collection` prop and narrows the collection type\n * to a specific slug after `vex generate` runs. `TDoc` defaults to `VexDocument`\n * and can be narrowed to a generated document interface when the caller has a\n * typed initial data array.\n *\n * @see {@link ViewComponentMap}\n */\nexport interface CollectionListViewProps<\n TFieldMeta extends {} = {},\n TCollectionMeta extends {} = {},\n TCollectionSlug extends CollectionSlug = CollectionSlug,\n TDoc extends VexDocument = VexDocument,\n> {\n /** The resolved collection configuration for the collection being listed. */\n collection: CollectionConfig<TFieldMeta, TCollectionMeta, TCollectionSlug>;\n /**\n * Pre-fetched documents from the server. Passed as `initialData` to\n * the TanStack Query so the list renders immediately on first load.\n * Omit when rendering client-side only.\n */\n initialData?: PaginationResult<TDoc>;\n}\n\n/**\n * Props passed to the `CollectionEditView` component.\n *\n * `TCollectionSlug` is inferred from the `collection` prop. After `vex generate` runs,\n * passing a collection of the wrong slug is a compile-time error.\n *\n * @see {@link ViewComponentMap}\n */\nexport interface CollectionEditViewProps<\n TFieldMeta extends {} = {},\n TCollectionMeta extends {} = {},\n TCollectionSlug extends CollectionSlug = CollectionSlug,\n TDocument extends VexDocument = VexDocument,\n> {\n /** The resolved collection configuration whose fields will be rendered. */\n collection: CollectionConfig<TFieldMeta, TCollectionMeta, TCollectionSlug>;\n /**\n * The Convex document ID of the document being edited.\n * Omit for new document creation — the form will be empty.\n */\n documentId: VexDocument[\"_id\"];\n /**\n * Pre-fetched document from the server for SSR hydration.\n * `null` explicitly means \"no document found\". `undefined` means \"not loaded yet\".\n */\n initialData?: TDocument | null;\n}\n\n/**\n * Props passed to the `GlobalEditView` component.\n *\n * `TGlobalSlug` is inferred from the `global` prop. After `vex generate` runs,\n * passing a global config with an unregistered slug is a compile-time error.\n *\n * @see {@link ViewComponentMap}\n */\nexport interface GlobalEditViewProps<\n TFieldMeta extends {} = {},\n TGlobalMeta extends {} = {},\n TGlobalSlug extends GlobalSlug = GlobalSlug,\n TDocument extends VexDocumentGlobal = VexDocumentGlobal,\n> {\n /** The resolved global configuration whose fields will be rendered. */\n global: GlobalConfig<TFieldMeta, TGlobalMeta, TGlobalSlug>;\n /**\n * Pre-fetched document from the server for SSR hydration.\n * `null` explicitly means \"no document found\". `undefined` means \"not loaded yet\".\n */\n initialData?: TDocument | null;\n}\n\n/**\n * Maps the three required admin views to their framework component types.\n *\n * All three are required — omitting any one causes a TypeScript error at the\n * `defineFrameworkAdapter` call site.\n *\n * @see {@link FrameworkAdapterInput}\n */\nexport type ViewComponentMap<F extends ComponentHKT> = {\n /** Admin shell component receiving the full VexCMS config. */\n dashboard: ApplyComponent<F, DashboardProps>;\n /** Collection list view — renders a list of documents for a collection. */\n collectionListView: ApplyComponent<F, CollectionListViewProps>;\n /** Collection edit form — renders all field inputs for a collection. */\n collectionEditView: ApplyComponent<F, CollectionEditViewProps>;\n};\n\n/**\n * Input type for `defineFrameworkAdapter()`.\n *\n * Framework packages pass this to register their component implementations.\n * TypeScript enforces that every field type in the `AdminField` union has both\n * an input component (`fields`) and a cell component (`cells`), and that each\n * component accepts the correct props for its field type.\n *\n * **What the HKT does:**\n * The `F` parameter is the framework's HKT — a type-level function that maps\n * a props type to the framework's component type. For React:\n * ```ts\n * interface ReactHKT extends ComponentHKT {\n * component: ComponentType<this['_props']>;\n * }\n * ```\n * Passing `ReactHKT` as `F` means every slot in `fields` and `cells` resolves to\n * `ComponentType<CorrectProps>`, giving the component full prop autocomplete.\n *\n * @example\n * ```ts\n * // In @vexcms/react\n * import { defineFrameworkAdapter, ComponentHKT } from '@vexcms/core';\n * import { ComponentType } from 'react';\n *\n * interface ReactHKT extends ComponentHKT {\n * component: ComponentType<this['_props']>;\n * }\n *\n * export const reactAdapter = defineFrameworkAdapter<ReactHKT>({\n * name: 'react',\n * version: '0.1.0',\n * fields: {\n * text: TextInputComponent, // must accept InputComponentProps<TextField>\n * },\n * cells: {\n * text: TextCellComponent, // must accept CellComponentProps<TextField>\n * },\n * });\n * ```\n *\n * @see {@link FrameworkAdapter} for the resolved type returned by `defineFrameworkAdapter`\n * @see {@link FieldComponentMap} for the field component slot types\n * @see {@link CellComponentProps} for the cell component props\n */\nexport interface FrameworkAdapterInput<\n F extends ComponentHKT,\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n> {\n /** Framework name used for identification (e.g. `\"react\"`, `\"solid\"`). */\n name: string;\n /** Adapter version — should match the framework package version. */\n version: string;\n /**\n * Input components for each field type, rendered in the document edit form.\n * Every type in the `AdminField` union must have a corresponding component.\n */\n fields: FieldComponentMap<F, TFieldMeta>;\n /**\n * Admin view components — required for rendering the admin panel.\n * All three must be provided; TypeScript enforces completeness.\n */\n views: ViewComponentMap<F>;\n}\n\n/**\n * Resolved framework adapter returned by `defineFrameworkAdapter()`.\n *\n * @see {@link FrameworkAdapterInput} for the user-facing input type\n * @see {@link defineFrameworkAdapter} for the function that produces this type\n */\nexport type FrameworkAdapter<\n F extends ComponentHKT,\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n> = FrameworkAdapterInput<F, TFieldMeta>;\n\n/**\n * Registers a framework adapter, enforcing that all field and cell components are\n * implemented and typed correctly.\n *\n * This is a zero-runtime identity function — it returns the adapter unchanged.\n * All enforcement happens at the TypeScript level via the `F` HKT parameter:\n * missing components cause a type error, and each component gets autocomplete\n * for its field-specific props.\n *\n * @param adapter - The framework adapter implementation.\n * @returns The same adapter, verified by TypeScript.\n *\n * @example\n * ```ts\n * import { defineFrameworkAdapter, ComponentHKT } from '@vexcms/core';\n * import { ComponentType } from 'react';\n *\n * interface ReactHKT extends ComponentHKT {\n * component: ComponentType<this['_props']>;\n * }\n *\n * export const reactAdapter = defineFrameworkAdapter<ReactHKT>({\n * name: 'react',\n * version: '0.1.0',\n * fields: {\n * text: MyTextInput, // TS error if missing or wrong props\n * },\n * cells: {\n * text: MyTextCell,\n * },\n * });\n * ```\n *\n * @see {@link FrameworkAdapterInput} for the full input type\n * @see {@link FrameworkAdapter} for the resolved return type\n */\nexport function defineFrameworkAdapter<\n F extends ComponentHKT,\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n>(adapter: FrameworkAdapterInput<F, TFieldMeta>): FrameworkAdapter<F, TFieldMeta> {\n return adapter;\n}\n","import { type GenericDocument } from \"convex/server\";\nimport type { AccessConditionResult, AccessIndexConstraint } from \"./constraintTypes\";\nimport { AccessResource, VexAccessConfig, VexAccessConfigError } from \"./types\";\nimport { ADMIN_FIELDS } from \"../fields\";\nimport { createAccessQueryBuilder, readAccessCondition } from \"./createAccessQueryBuilder\";\n\n/**\n * Declared Convex index name → field tuple for one resource, read the same\n * way `collectIndexNames` (`types/generateVexTypes.ts`) builds `.index()`\n * calls: one index per `field.index`, or an auto `by_<fieldKey>` for\n * relationship fields. Every declared index is single-field today; this\n * returns single-element tuples accordingly and stays correct if a\n * compound-index authoring mechanism lands later. @internal\n * @param resource @see {@link AccessResource} the collection / resource\n * @returns Record<string, readonly string[]> A record of indexes to fields\n */\nfunction collectResourceIndexFields(resource: AccessResource): Record<string, readonly string[]> {\n const indexFields: Record<string, readonly string[]> = {};\n for (const [fieldKey, field] of Object.entries(resource.fields)) {\n if (field.index) {\n indexFields[field.index] = [fieldKey];\n } else if (field.type === ADMIN_FIELDS.relationship.type) {\n indexFields[`by_${fieldKey}`] = [fieldKey];\n }\n }\n return indexFields;\n}\n\n/**\n *\n * Validates all access config options during runtime for\n * any constraints that would result in invalid convex queries\n *\n * @param props VexAccessConfig @see {@link VexAccessConfig}\n *\n * @throws {VexAccessConfigError} When the named index is not declared, when the\n * constraint fields are not an\n * in-order prefix of a declared index, when an `eq` follows a bound, when\n * a second lower bound appears, when anything follows an upper bound, or\n * when a lower/upper bound pair targets different fields — naming the\n * role, resource, action, and the 1-based position of the offending\n * constraint.\n */\nexport function validateAccessConfig(props?: VexAccessConfig) {\n if (!props) return;\n const resourcesBySlug = new Map<string, AccessResource>(\n props.resources.map((resource) => [resource.slug, resource]),\n );\n for (const [role, subjects] of Object.entries(props.permissions)) {\n if (typeof subjects !== \"object\" || subjects === null) continue;\n for (const [resourceSlug, actions] of Object.entries(subjects as Record<string, unknown>)) {\n const resource = resourcesBySlug.get(resourceSlug);\n // Custom resources and admin subjects carry no declared indexes and\n // are skipped here — see `validateAccessConstraints`'s edge cases.\n if (resource === undefined || typeof actions !== \"object\" || actions === null) continue;\n for (const [action, check] of Object.entries(actions as Record<string, unknown>)) {\n // The action-level wildcard IS resolved here, unlike the role-level one\n // (boolean-only). Its `q` is an `AccessPredicateBuilder`, so it can never\n // name an index and `validateAccessConstraints` will have nothing to check —\n // but running the callback is still worth it, because that is what turns a\n // rule that throws into a `VexAccessConfigError` at module load rather than\n // at query time. Skipping it made the wildcard the one place a broken\n // constraint stayed hidden until a request hit it.\n if (typeof check !== \"object\" || check === null) continue;\n if (!(\"constraints\" in check)) continue;\n let outcome: boolean | AccessConditionResult;\n try {\n outcome = (\n check as {\n constraints: (\n callbackProps: Record<string, unknown>,\n ) => boolean | AccessConditionResult;\n }\n ).constraints({\n user: {},\n organization: {},\n q: createAccessQueryBuilder(),\n });\n } catch (error) {\n // Resolving a rule means RUNNING its callback at module load, so a rule\n // that reached past its types — `as any`, a hand-built object, a method\n // the builder does not have — surfaces here as whatever it threw. Rethrow\n // as a config error so every `defineAccess` failure has one shape and\n // names the offending rule, instead of leaking a bare `TypeError` with no\n // indication of which role or action produced it.\n throw new VexAccessConfigError(\n `role \"${role}\" on ${resourceSlug}.${action}: the constraints callback threw ` +\n `while being resolved — ${error instanceof Error ? error.message : String(error)}. ` +\n `Constraints must be a pure chain on the supplied \"q\"; they run once at ` +\n `config time with no documents and no database access.`,\n );\n }\n // A rule that short-circuits to a flat allow/deny has no condition to check.\n if (typeof outcome === \"boolean\") continue;\n const condition = readAccessCondition<GenericDocument>(outcome);\n // Anything built through `q` is readable here. An unreadable value therefore\n // means the callback never touched the builder and returned something else —\n // a bare object, `undefined`, a number. Previously that fell through the\n // `condition?.index === undefined` guard below and was accepted as \"excludes\n // nothing\", which is the most dangerous possible default for an access rule:\n // the author believes they wrote a restriction and the config silently has\n // none. `resolveAccessRule` still fails SAFE for this shape at request time;\n // config time should fail LOUD.\n if (condition === undefined) {\n throw new VexAccessConfigError(\n `role \"${role}\" on ${resourceSlug}.${action}: the constraints callback did not ` +\n `return a constraint built from the supplied \"q\" (got ` +\n `${outcome === null ? \"null\" : typeof outcome}). Build a condition with ` +\n `q.withIndex(...) / q.filter(...), or return a boolean to allow or deny outright.`,\n );\n }\n // This validator enforces Convex's INDEX rules — the index name, field order\n // and operator sequencing — so it applies only when the rule chose an index. A\n // predicate compiles to `.filter()`, which imposes none of them.\n if (condition.index === undefined) continue;\n validateAccessConstraints({\n role,\n resource: resourceSlug,\n action,\n constraints: condition.index.constraints,\n indexFields: collectResourceIndexFields(resource),\n indexName: condition.index.name,\n });\n }\n }\n }\n}\n\n/**\n * Validates one rule's recorded constraint list against its resource's\n * declared Convex indexes. Called once per constraints-bearing rule from\n * `defineAccess`, so a malformed rule fails at module load.\n *\n * @param props - Input props.\n * @param props.role - Role name the rule belongs to (for the error message).\n * @param props.resource - Resource slug the rule guards (for the error message).\n * @param props.action - Action name the rule guards (for the error message).\n * @param props.constraints - The rule's recorded constraint list, already\n * produced by invoking its `constraints` callback with a fresh builder.\n * @param props.indexFields - The resource's declared indexes, index name →\n * field tuple in declaration order. The caller derives this from real\n * Convex index declarations (`defineAccess` reads it off `field.index` /\n * relationship auto-index the same way `collectIndexNames`,\n * `types/generateVexTypes.ts`, builds `.index()` calls) — every declared\n * index is single-field today, but this validator is written generically\n * and stays correct if compound indexes are ever declarable.\n * @returns Nothing; throws on violation.\n * @param props.indexName - The index the rule actually named, when known. Given, it\n * must be declared by the resource and is the only tuple the fields may prefix.\n * @throws {VexAccessConfigError} When the named index is not declared, when the\n * constraint fields are not an\n * in-order prefix of a declared index, when an `eq` follows a bound, when\n * a second lower bound appears, when anything follows an upper bound, or\n * when a lower/upper bound pair targets different fields — naming the\n * role, resource, action, and the 1-based position of the offending\n * constraint.\n */\nexport function validateAccessConstraints<\n TDocument extends GenericDocument = GenericDocument,\n>(props: {\n role: string;\n resource: string;\n action: string;\n constraints: readonly AccessIndexConstraint<string, TDocument>[];\n indexFields: Readonly<Record<string, readonly string[]>>;\n indexName?: string;\n}): void {\n const where = `role \"${props.role}\" on ${props.resource}.${props.action}`;\n\n // ── 0. The named index must exist ──────────────────────────────────────────\n // Checked before the empty-constraints bail: `q.withIndex(\"nope\", (ix) => ix)`\n // records no constraints but still names an index Convex will reject at query\n // time. Without this, the field-sequence check below was the only gate, and it\n // only inspects the declared tuples' VALUES — so any field order that happened\n // to match SOME index passed regardless of the name actually written.\n if (props.indexName !== undefined && !(props.indexName in props.indexFields)) {\n const declared = Object.keys(props.indexFields);\n throw new VexAccessConfigError(\n `${where}: names index \"${props.indexName}\", which ${props.resource} does not declare ` +\n `(declared: ${declared.length > 0 ? declared.join(\", \") : \"none\"})`,\n );\n }\n\n if (props.constraints.length === 0) return;\n\n // ── 1. Field sequence ──────────────────────────────────────────────────────\n // A lower bound immediately followed by an upper bound on the SAME field is the\n // only case Convex allows two constraints to share one index position, so the\n // pair collapses to a single logical field. Every other constraint is its own\n // position.\n const fields: string[] = [];\n for (let i = 0; i < props.constraints.length; i += 1) {\n const current = props.constraints[i]!;\n const next = props.constraints[i + 1];\n fields.push(current.field);\n if (\n isLowerBound(current.op) &&\n next !== undefined &&\n isUpperBound(next.op) &&\n next.field === current.field\n ) {\n i += 1;\n }\n }\n\n // ── 2. In-order prefix of some declared index ──────────────────────────────\n // When the rule named an index, that index's tuple is the ONLY one its fields may\n // prefix — matching a sibling index's shape is not permission to use this name.\n const candidates =\n props.indexName !== undefined\n ? [props.indexFields[props.indexName] ?? []]\n : Object.values(props.indexFields);\n const matchesSomeIndex = candidates.some(\n (tuple) => tuple.length >= fields.length && fields.every((field, at) => tuple[at] === field),\n );\n if (!matchesSomeIndex) {\n throw new VexAccessConfigError(\n props.indexName !== undefined\n ? `${where}: constraint fields [${fields.join(\", \")}] are not an in-order prefix of index \"${props.indexName}\" ([${(props.indexFields[props.indexName] ?? []).join(\", \")}])`\n : `${where}: constraint fields [${fields.join(\", \")}] are not an in-order prefix of any declared index`,\n );\n }\n\n // ── 3. Convex's operator rule ──────────────────────────────────────────────\n // Check ORDER is load-bearing: one constraint can violate several rules at\n // once, and the most specific diagnosis must win. `eq` after `lt` breaks both\n // \"nothing follows an upper bound\" and \"eq precedes every bound\"; the former is\n // the more precise complaint, so it is tested first. Likewise a second lower\n // bound on a different field would also read as a mismatched bound pair, so the\n // second-bound check precedes the same-field check. Reordering these silently\n // changes which message an author sees — `validateAccessConstraints.test.ts`\n // pins each one exactly.\n let lowerBoundSeen = false;\n let upperBoundSeen = false;\n let lastBoundField: string | undefined;\n\n for (const [index, constraint] of props.constraints.entries()) {\n const position = index + 1;\n const at = `${where}: constraint ${position} (\"${constraint.field}\")`;\n\n if (upperBoundSeen) {\n throw new VexAccessConfigError(`${at} follows an upper bound — nothing may follow lt/lte`);\n }\n if (constraint.op === \"eq\" && (lowerBoundSeen || upperBoundSeen)) {\n throw new VexAccessConfigError(\n `${at} uses \"eq\" after a bound — eq must precede every gt/gte/lt/lte`,\n );\n }\n if (isLowerBound(constraint.op) && lowerBoundSeen) {\n throw new VexAccessConfigError(\n `${at} is a second lower bound — at most one gt/gte is allowed`,\n );\n }\n if (\n isUpperBound(constraint.op) &&\n lastBoundField !== undefined &&\n lastBoundField !== constraint.field\n ) {\n throw new VexAccessConfigError(\n `${at} is a bound on a different field than the prior bound (\"${lastBoundField}\") — bounds must pin the same field`,\n );\n }\n\n if (isLowerBound(constraint.op)) {\n lowerBoundSeen = true;\n lastBoundField = constraint.field;\n } else if (isUpperBound(constraint.op)) {\n upperBoundSeen = true;\n lastBoundField = constraint.field;\n }\n }\n}\n\n/**\n * Whether `op` opens a range from below.\n *\n * @param op - A recorded constraint's operator.\n * @returns `true` for `gt`/`gte`.\n */\nfunction isLowerBound(op: AccessIndexConstraint<string, GenericDocument>[\"op\"]): boolean {\n return op === \"gt\" || op === \"gte\";\n}\n\n/**\n * Whether `op` closes a range from above.\n *\n * @param op - A recorded constraint's operator.\n * @returns `true` for `lt`/`lte`.\n */\nfunction isUpperBound(op: AccessIndexConstraint<string, GenericDocument>[\"op\"]): boolean {\n return op === \"lt\" || op === \"lte\";\n}\n","import { CollectionConfig } from \"../collections\";\nimport { ComponentHKT } from \"../fields\";\nimport { CollectionSlug } from \"../types\";\n\n/**\n * Metadata attached to auth fields to control merge behavior during\n * auth collection merging.\n *\n * When `locked: true`, the field definition from the auth adapter is\n * preserved and cannot be overridden by a user-defined collection.\n * Unlocked fields can be extended or replaced by the user.\n *\n * @see {@link mergeAuthCollections} for the merge logic that respects this flag\n * @see {@link better-auth/src!betterAuthAdapter} for the adapter that sets `locked` on system fields\n */\nexport interface AuthFieldMeta {\n /** When `true`, this field cannot be overridden by user-defined collections. */\n locked: boolean;\n}\n\n/**\n * Metadata attached to auth collections to control merge behavior with\n * user-defined collections.\n *\n * Auth adapters mark collections as `protected` to prevent accidental\n * overrides that could break authentication.\n */\nexport type AuthCollectionMeta = {\n /**\n * When `true`, this auth collection cannot be overridden by a user-defined\n * collection with the same slug. Attempting to do so throws a\n * {@link VexAuthConfigError}.\n *\n * When `false` or omitted, user-defined collections can extend or\n * override this auth collection (unlocked fields can still be overridden,\n * but locked fields are preserved — see {@link AuthFieldMeta}).\n */\n protected?: boolean;\n};\n\n/**\n * Auth collection config — extends `CollectionConfig` with field-level\n * locking so auth adapters can protect fields that must not be overridden.\n */\nexport type AuthCollectionConfig<\n TCollectionSlug extends CollectionSlug = CollectionSlug,\n TFieldSlug extends string = string,\n TComponent extends ComponentHKT = ComponentHKT,\n> = CollectionConfig<\n AuthFieldMeta,\n AuthCollectionMeta,\n TCollectionSlug,\n TFieldSlug,\n TComponent\n>;\n\n/**\n * Auth adapter returned by an auth provider package (e.g. `@vexcms/better-auth`).\n *\n * The adapter exposes auth collections as standard Vex `CollectionConfig[]`\n * so that schema generation, admin navigation, and CRUD views treat them\n * identically to user-defined collections.\n *\n * @see {@link better-auth/src!betterAuthAdapter} — the Better Auth implementation\n */\nexport interface VexAuthAdapter {\n /** Provider identifier for debugging and telemetry. */\n readonly name: string;\n\n /**\n * Auth collections to register alongside user-defined collections.\n *\n * These are merged into `VexConfig.collections` automatically by\n * `defineConfig()`. Each collection uses standard Vex field builders\n * (`text()`, `relationship()`, etc.) and may carry `admin.readOnly`\n * defaults on system fields.\n */\n readonly collections: AuthCollectionConfig[];\n\n /**\n * The slug of the collection that stores user documents.\n *\n * Used by the admin panel to resolve user references and by auth-aware\n * components to look up the current user collection.\n */\n readonly userCollection: CollectionSlug;\n}\n\n/**\n * Error thrown when auth configuration is invalid or when a user-defined\n * collection attempts to override a protected auth collection.\n *\n * @see {@link mergeAuthCollections} for the merge logic that throws this error\n */\nexport class VexAuthConfigError extends Error {\n /**\n * @param message — Human-readable description of the configuration error.\n */\n constructor(message: string) {\n super(message);\n this.name = \"VexAuthConfigError\";\n }\n}\n","import type { CollectionConfig } from \"../collections\";\nimport {\n VexAuthConfigError,\n type AuthCollectionConfig,\n AuthFieldMeta,\n} from \"./types\";\nimport type { AdminField } from \"../fields\";\n\n/**\n * Merges auth collections with user-defined collections, respecting\n * `protected` at the collection level and `meta.locked` on individual fields.\n *\n * Merge rules:\n * 1. User collections that match a `protected` auth slug throw an error.\n * 2. Iterate remaining user collections in their declared order.\n * 3. If a user collection's slug matches an auth collection:\n * - Auth fields with `meta.locked === true` are preserved.\n * - All other fields: user field wins (override or extend).\n * - Admin config: user collection wins.\n * - The merged collection appears at the user's declared position.\n * 4. Auth collections with no matching user collection are appended at the end.\n * 5. User collections with no matching auth collection are added as-is.\n *\n * @param props — authCollections, userCollections\n * @param props.authCollections — Collections from the auth adapter.\n * @param props.userCollections — Collections defined by the user.\n * @throws VexAuthConfigError when users pass a protected collection slug.\n * @returns Merged collections array for `VexConfig`.\n */\nexport function mergeAuthCollections(props: {\n authCollections: AuthCollectionConfig[];\n userCollections: CollectionConfig[];\n}): CollectionConfig[] {\n const { authCollections, userCollections } = props;\n const protectedSlugs = new Set(\n authCollections.filter((c) => c.meta?.protected).map((c) => c.slug),\n );\n for (const userCol of userCollections) {\n if (protectedSlugs.has(userCol.slug)) {\n throw new VexAuthConfigError(\n `Collection slug \"${userCol.slug}\" is protected by the auth adapter and cannot be overridden.`,\n );\n }\n }\n\n const authBySlug = new Map(authCollections.map((c) => [c.slug, c]));\n const merged: CollectionConfig[] = [];\n const consumedAuthSlugs = new Set<string>();\n\n for (const userCol of userCollections) {\n const authCol = authBySlug.get(userCol.slug);\n if (authCol) {\n merged.push(mergeSingleCollection(authCol, userCol));\n consumedAuthSlugs.add(userCol.slug);\n } else {\n merged.push(userCol);\n }\n }\n\n for (const authCol of authCollections) {\n if (!consumedAuthSlugs.has(authCol.slug)) {\n // Strip AuthCollectionConfig-only properties before exposing\n const { protected: _, ...clean } = authCol as AuthCollectionConfig & {\n protected?: boolean;\n };\n merged.push(clean as CollectionConfig);\n }\n }\n\n return merged;\n}\n\nfunction isFieldLocked(field: AdminField<AuthFieldMeta>): boolean {\n return field?.meta?.locked === true;\n}\n\nfunction mergeSingleCollection(\n authCol: AuthCollectionConfig,\n userCol: CollectionConfig,\n): CollectionConfig {\n // Start with all auth fields\n const fields: (CollectionConfig | AuthCollectionConfig)[\"fields\"] = {\n ...authCol.fields,\n };\n\n // User fields override unless the auth field is meta-locked\n for (const [fieldName, userField] of Object.entries(userCol.fields)) {\n const authField = authCol.fields[fieldName];\n if (!authField || !isFieldLocked(authField)) {\n fields[fieldName] = userField;\n }\n }\n\n // TODO fix: currently stripping all collection metadata which may post a problem later\n // Strip AuthCollectionConfig-only properties from the returned object\n const { meta: _, ...authBase } = authCol;\n\n return {\n ...authBase,\n ...userCol,\n fields,\n };\n}\n","export const internalCollections = [];\n","import type { GenericDataModel, GenericMutationCtx, GenericQueryCtx } from \"convex/server\";\nimport type { CollectionConfig, CollectionConfigInput } from \"../collections\";\nimport type { BaseFieldMeta, ComponentHKT } from \"../fields\";\nimport type { MediaCollectionSlug, StorageAdapterSlug } from \"../types\";\n\n/**\n * Metadata attached to every media collection linking it to a specific storage adapter.\n *\n * Set by `defineMediaCollection()` and tagged onto each collection by the\n * adapter when it processes its `mediaCollections` array. Core uses\n * `storageAdapter` to route upload, delete, and URL operations to the\n * correct adapter at runtime.\n */\nexport type MediaCollectionMeta = {\n /**\n * Which storage adapter this collection is linked to specifically. \"convex\" supported by default\n */\n storageAdapter: StorageAdapterSlug;\n};\n\n/**\n * Configuration input for a `defineMediaCollection()` call.\n *\n * Identical to `CollectionConfigInput` except `fields` is omitted — media\n * collections have a fixed set of system fields (`alt`, `filename`, `mimeType`,\n * `size`, `storageId`, `deleted`, `convexUrl`, `width`, `height`) that\n * `defineMediaCollection()` always injects. Pass extra custom fields via the\n * `fields` override on `defineMediaCollection()`.\n *\n * @example\n * ```ts\n * const images = defineMediaCollection({\n * slug: \"images\",\n * labels: { singular: \"Image\", plural: \"Images\" },\n * });\n * ```\n *\n * @see {@link MediaCollectionConfig} for the resolved type after defaults are applied\n * @see {@link file-storage-convex/src!defineMediaCollection} from `@vexcms/file-storage-convex`\n */\nexport type MediaCollectionConfigInput<\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n TCollectionMeta extends MediaCollectionMeta = MediaCollectionMeta,\n TCollectionSlug extends MediaCollectionSlug = MediaCollectionSlug,\n TFieldSlug extends string = string,\n TComponent extends ComponentHKT = ComponentHKT,\n> = Omit<\n CollectionConfigInput<TFieldMeta, TCollectionMeta, TCollectionSlug, TFieldSlug, TComponent>,\n \"fields\"\n>;\n\n/**\n * Resolved media collection configuration after `defineMediaCollection()` applies system fields and defaults.\n *\n * Structurally identical to `CollectionConfig` — all schema generation, admin\n * panel rendering, and query helpers work against this type. Media collections\n * are stored in `VexConfig.mediaCollections` separately from user-defined\n * `collections` and appear under a dedicated \"Media\" section in the admin panel.\n *\n * @see {@link MediaCollectionConfigInput} for the user-facing input type\n * @see {@link file-storage-convex/src!defineMediaCollection} from `@vexcms/file-storage-convex`\n */\nexport type MediaCollectionConfig<\n TFieldMeta extends BaseFieldMeta = BaseFieldMeta,\n TCollectionMeta extends MediaCollectionMeta = MediaCollectionMeta,\n TCollectionSlug extends MediaCollectionSlug = MediaCollectionSlug,\n TFieldSlug extends string = string,\n TComponent extends ComponentHKT = ComponentHKT,\n> = CollectionConfig<TFieldMeta, TCollectionMeta, TCollectionSlug, TFieldSlug, TComponent>;\n\n/**\n * Error thrown when storage configuration is invalid.\n *\n * Covers: missing required fields on media collections, slug collisions\n * (between collections and media collections, or across adapters), upload\n * fields referencing non-existent media collections, or `upload()` used\n * without a configured storage adapter.\n */\nexport class VexStorageConfigError extends Error {\n /**\n * @param message — Human-readable description of the configuration error.\n */\n constructor(message: string) {\n super(message);\n this.name = \"VexStorageConfigError\";\n }\n}\n\n/** Protocol type for file upload methods. */\nexport const STORAGE_ADAPTER_PROTOCOLS = {\n presignedUrl: \"presigned-url\",\n // directUpload: \"direct-upload\",\n // streaming: \"streaming\",\n} as const;\n/** Protocol type for file upload methods. */\nexport type StorageAdapterProtocol =\n (typeof STORAGE_ADAPTER_PROTOCOLS)[keyof typeof STORAGE_ADAPTER_PROTOCOLS];\n\n/**\n * Return type for `getUrl` — either a resolved URL or an error message, never both.\n */\nexport type GetUrlReturn = { url: string; error?: never } | { url?: never; error: string };\n/**\n * Shared interface implemented by all storage adapters.\n *\n * Defines the minimum contract — `name`, `type`, `mediaCollections`, and the\n * four lifecycle methods (`createMediaDocument`, `deleteMedia`, `getUrl`,\n * `uploadFile`) — that every adapter must satisfy regardless of protocol.\n *\n * @see {@link StorageAdapterPresignedUrlInterface} for the presigned-URL sub-interface\n * @see {@link StorageAdapterPresignedUrl} for the abstract base class\n */\nexport interface StorageAdapterBaseInterface {\n /** Protocol name — tells the admin panel what the identifier of this storage adapter is. */\n readonly name: StorageAdapterSlug;\n /** Protocol type — tells the admin panel how to upload files. */\n readonly type: StorageAdapterProtocol;\n\n /**\n * Processed media collections ready for schema generation and admin panel.\n *\n * The adapter validates, augments, and returns these collections. Each\n * collection is tagged with `meta.storageAdapterName` equal to this adapter's\n * `name`. Core merges all collections from all adapters into\n * `VexConfig.mediaCollections` — separate from user-defined `collections`.\n */\n mediaCollections: MediaCollectionConfig[];\n\n admin: {\n /**\n * When `true`, delete operations set `deleted: true` on the media document\n * instead of physically removing the file. The file remains in storage until\n * a scheduled cleanup job purges it.\n *\n * @default false\n */\n softDelete: boolean;\n };\n\n /**\n * Creates a media document in Convex after the file is uploaded.\n * All adapters must use this exact signature.\n */\n createMediaDocument<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericMutationCtx<TDataModel>,\n args: {\n collectionSlug: string;\n storageId: string;\n filename: string;\n mimeType: string;\n size: number;\n alt?: string;\n adapterFields?: Record<string, unknown>;\n },\n ): Promise<string>;\n\n /**\n * Deletes a media document and its file from storage.\n * All adapters must use this exact signature.\n */\n deleteMedia<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericMutationCtx<TDataModel>,\n args: { collectionSlug: string; mediaId: string; softDelete?: boolean },\n ): Promise<boolean>;\n\n /**\n * Returns a URL for a media file.\n * All adapters must use this exact signature.\n */\n getUrl<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericQueryCtx<TDataModel>,\n args: { collectionSlug: string; mediaId: string },\n ): Promise<GetUrlReturn>;\n\n /**\n * Uploads a file to the storage backend and returns the storage ID.\n *\n * This is a pure JS function that can be called from any framework\n * (React, Next.js, Svelte, etc.) or even directly in the browser.\n *\n * @param file - The file to upload\n * @param uploadUrl - The presigned URL from generateUploadUrl\n * @returns Promise resolving to { storageId, url, ... } with adapter-specific fields\n *\n * @example\n * ```ts\n * // React component\n * const { storageId } = await adapter.uploadFile(file, uploadUrl);\n * await createMediaDocument({ storageId, ... });\n * ```\n */\n uploadFile(\n file: any,\n uploadUrl: string,\n ): Promise<{\n storageId: string;\n url?: string;\n [key: string]: unknown; // Adapter-specific fields\n }>;\n}\n\n/**\n * Return type for `generateUploadUrl` — the upload URL and an optional adapter-assigned storage ID.\n */\nexport type GenerateUploadUrlReturn = {\n url: string;\n storageId?: string;\n};\n/**\n * Return type for `uploadFile` — the adapter-assigned storage ID, an optional public URL,\n * and any adapter-specific fields (e.g. Cloudinary `public_id`, S3 `key`).\n */\nexport type UploadFileReturn = {\n storageId: string;\n url?: string;\n [key: string]: unknown; // Adapter-specific fields\n};\n/**\n * Storage adapter interface for the presigned-URL upload protocol.\n *\n * Extends `StorageAdapterBaseInterface` with `generateUploadUrl` — the client\n * requests a short-lived URL from the server, POSTs the file directly to\n * storage, then calls `createMediaDocument` with the returned `storageId`.\n *\n * @see {@link StorageAdapterBaseInterface} for the shared base contract\n * @see {@link StorageAdapterPresignedUrl} for the abstract base class to extend\n */\nexport interface StorageAdapterPresignedUrlInterface extends StorageAdapterBaseInterface {\n readonly type: (typeof STORAGE_ADAPTER_PROTOCOLS)[\"presignedUrl\"];\n\n /**\n * Generates a URL to upload a file to. Returns different shapes per protocol:\n * - presigned-url: `{ url: string }` — POST the file to this URL\n * - direct-upload: `{ url: string; storageId?: string }` — PUT the file to this URL\n * - streaming: `{ url: string; storageId?: string }` — resumable upload session\n */\n generateUploadUrl<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericMutationCtx<TDataModel>,\n ): Promise<GenerateUploadUrlReturn>;\n\n /**\n * Uploads a file to the storage backend and returns the storage ID.\n *\n * This is a pure JS function that can be called from any framework\n * (React, Next.js, Svelte, etc.) or even directly in the browser.\n *\n * @param file - The file to upload\n * @param uploadUrl - The presigned URL from generateUploadUrl\n * @returns Promise resolving to { storageId, url, ... } with adapter-specific fields\n *\n * @example\n * ```ts\n * // React component\n * const { storageId } = await adapter.uploadFile(file, uploadUrl);\n * await createMediaDocument({ storageId, ... });\n * ```\n */\n uploadFile(file: any, uploadUrl: string): Promise<UploadFileReturn>;\n}\n\n/**\n * Base class for storage adapters.\n *\n * All file storage adapters must extend this class to ensure consistent\n * behavior in the admin panel. Adapters override methods to implement\n * adapter-specific logic (e.g., different storage backends).\n *\n * @example\n * ```ts\n * // In file-storage-convex/src/adapter/index.ts\n * import { BaseStorageAdapter } from \"@vexcms/core\";\n *\n * export class ConvexStorageAdapter extends BaseStorageAdapter {\n * readonly name = \"convex\";\n *\n * async generateUploadUrl(ctx) {\n * const url = await ctx.storage.generateUploadUrl();\n * return { url };\n * }\n *\n * // Override other methods as needed...\n * }\n * ```\n */\nexport abstract class StorageAdapterPresignedUrl implements StorageAdapterPresignedUrlInterface {\n /** Protocol name — tells the admin panel what the identifier of this storage adapter is. */\n abstract readonly name: StorageAdapterSlug;\n /** Protocol type — tells the admin panel how to upload files. */\n abstract readonly type: StorageAdapterProtocol;\n\n abstract mediaCollections: MediaCollectionConfig[];\n\n abstract admin: { softDelete: boolean };\n\n /**\n * Generates a URL to upload a file to.\n * Override in subclass for adapter-specific implementation.\n */\n abstract generateUploadUrl<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericMutationCtx<TDataModel>,\n ): Promise<{ url: string; storageId?: string }>;\n\n /**\n * Creates a media document in Convex after the file is uploaded.\n * Override in subclass for adapter-specific implementation.\n */\n abstract createMediaDocument<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericMutationCtx<TDataModel>,\n args: {\n collectionSlug: string;\n storageId: string;\n filename: string;\n mimeType: string;\n size: number;\n alt?: string;\n adapterFields?: Record<string, unknown>;\n },\n ): Promise<string>;\n\n /**\n * Deletes a media document and its file from storage.\n * Override in subclass for adapter-specific implementation.\n */\n abstract deleteMedia<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericMutationCtx<TDataModel>,\n args: {\n collectionSlug: string;\n mediaId: string;\n softDelete?: boolean;\n },\n ): Promise<boolean>;\n\n /**\n * Returns a URL for a media file.\n * Override in subclass for adapter-specific implementation.\n */\n abstract getUrl<TDataModel extends GenericDataModel = GenericDataModel>(\n ctx: GenericQueryCtx<TDataModel>,\n args: {\n collectionSlug: string;\n mediaId: string;\n },\n ): Promise<{ url: string; error?: never } | { url?: never; error: string }>;\n\n /**\n * Uploads a file to the storage backend and returns the storage ID.\n *\n * This is a pure JS function that can be called from any framework\n * (React, Next.js, Svelte, etc.) or even directly in the browser.\n *\n * @param file - The file to upload\n * @param uploadUrl - The presigned URL from generateUploadUrl\n * @returns Promise resolving to { storageId, url, ... } with adapter-specific fields\n *\n * @example\n * ```ts\n * // React component\n * const { storageId } = await adapter.uploadFile(file, uploadUrl);\n * await createMediaDocument({ storageId, ... });\n * ```\n */\n abstract uploadFile(\n file: any,\n uploadUrl: string,\n ): Promise<{\n storageId: string;\n url?: string;\n [key: string]: unknown; // Adapter-specific fields\n }>;\n}\n\n/**\n * Union of all supported storage adapter interface types.\n *\n * Currently only presigned-URL adapters are supported. Extend this union\n * as new upload protocols are added.\n *\n * @see {@link StorageAdapterPresignedUrlInterface}\n */\nexport type VexStorageAdapter = StorageAdapterPresignedUrlInterface;\n","import { v } from \"convex/values\";\n\n/**\n * Convex validator for `createMediaDocument` arguments.\n * Every storage adapter must use this in its `createMediaDocument` mutation.\n */\nexport const createMediaDocumentArgs = v.object({\n collectionSlug: v.string(),\n storageId: v.string(),\n fileName: v.string(),\n mimeType: v.string(),\n size: v.number(),\n alt: v.optional(v.string()),\n adapterFields: v.optional(v.record(v.string(), v.any())),\n});\n\n/**\n * Convex validator for `createMediaDocument` return value.\n * Returns the created media document ID.\n */\nexport const createMediaDocumentReturn = v.string();\n\n/**\n * Convex validator for `deleteMedia` arguments.\n * Every storage adapter must use this in its `deleteMedia` mutation.\n */\nexport const deleteMediaArgs = v.object({\n collectionSlug: v.string(),\n mediaId: v.string(),\n});\n\n/**\n * Convex validator for `deleteMedia` return value.\n */\nexport const deleteMediaReturn = v.boolean();\n\n/**\n * Convex validator for `getUrl` arguments.\n * Every storage adapter must use this in its `getUrl` query.\n */\nexport const getUrlArgs = v.object({\n collectionSlug: v.string(),\n mediaId: v.string(),\n});\n\n/**\n * Convex validator for `getUrl` return value.\n */\nexport const getUrlReturn = v.object({\n url: v.string(),\n});\n","import type { CollectionConfig } from \"../collections\";\nimport { ADMIN_FIELDS } from \"../fields/constants\";\nimport { MediaCollectionSlug } from \"../types\";\nimport { VexStorageConfigError } from \"./types\";\nimport type { MediaCollectionConfig, VexStorageAdapter } from \"./types\";\n\ninterface StorageValidationInput {\n collections: CollectionConfig[];\n storageAdapters?: VexStorageAdapter[];\n}\n\ninterface StorageValidationOutput {\n mediaCollections: MediaCollectionConfig[];\n}\n\n/**\n * Validates storage adapter configuration and merges media collections.\n *\n * Checks:\n * 1. `upload()` fields only exist when storage adapters are configured.\n * 2. Every `upload().to` slug matches a media collection slug.\n * 3. No slug collisions between regular collections and media collections.\n * 4. No duplicate media collection slugs across adapters.\n *\n * @param input — Validation input containing collections and adapters.\n * @returns Merged media collections with `meta.storageAdapterName` set.\n * @throws {VexStorageConfigError} On any validation failure.\n */\nexport function validateAndMergeStorageConfig(\n input: StorageValidationInput,\n): StorageValidationOutput {\n const { collections, storageAdapters } = input;\n\n // Check if any collection uses upload fields\n const uploadFields: {\n collectionSlug: string;\n fieldName: string;\n to: MediaCollectionSlug;\n }[] = [];\n for (const collection of collections) {\n for (const [fieldName, field] of Object.entries(collection.fields)) {\n if (field.type === ADMIN_FIELDS.upload.type) {\n uploadFields.push({\n collectionSlug: collection.slug,\n fieldName,\n to: field.to,\n });\n }\n }\n }\n\n // Edge: upload fields without storage adapters\n if (uploadFields.length > 0 && (!storageAdapters || storageAdapters.length === 0)) {\n const fieldList = uploadFields.map((f) => `${f.collectionSlug}.${f.fieldName}`).join(\", \");\n throw new VexStorageConfigError(\n `upload() fields require a configured storage adapter. Fields without adapter: ${fieldList}. ` +\n `Add a storage adapter to defineConfig({ storageAdapters: [convexFileStorage({...})] }).`,\n );\n }\n\n // Merge media collections from all adapters\n const mediaCollections: MediaCollectionConfig[] = [];\n const seenMediaSlugs = new Map<string, string>(); // slug -> adapterName\n\n if (storageAdapters) {\n for (const adapter of storageAdapters) {\n for (const collection of adapter.mediaCollections) {\n // Check for duplicate media collection slugs across adapters\n if (seenMediaSlugs.has(collection.slug)) {\n const otherAdapter = seenMediaSlugs.get(collection.slug);\n throw new VexStorageConfigError(\n `Duplicate media collection slug \"${collection.slug}\" defined by both ` +\n `\"${otherAdapter}\" and \"${adapter.name}\" adapters. Media collection slugs must be unique across all adapters.`,\n );\n }\n seenMediaSlugs.set(collection.slug, adapter.name);\n\n // Tag with storageAdapterName\n const taggedCollection: MediaCollectionConfig = {\n ...collection,\n meta: {\n ...collection.meta,\n storageAdapter: adapter.name,\n },\n };\n mediaCollections.push(taggedCollection);\n }\n }\n }\n\n // Check for slug collisions between regular collections and media collections\n const collectionSlugs = new Set(collections.map((c) => c.slug));\n for (const mediaCollection of mediaCollections) {\n if (collectionSlugs.has(mediaCollection.slug)) {\n throw new VexStorageConfigError(\n `Slug collision: \"${mediaCollection.slug}\" is defined as both a collection and a media collection. ` +\n `Collection and media collection slugs must be unique.`,\n );\n }\n }\n\n // Validate upload field references\n if (uploadFields.length > 0) {\n const mediaSlugs = new Set(mediaCollections.map((c) => c.slug));\n const missing = new Set<string>();\n\n for (const uploadField of uploadFields) {\n if (!mediaSlugs.has(uploadField.to)) {\n missing.add(uploadField.to);\n }\n }\n\n if (missing.size > 0) {\n throw new VexStorageConfigError(\n `upload() fields reference missing media collections: ${[...missing].join(\", \")}. ` +\n `Define these collections via a storage adapter's defineMediaCollection(). ` +\n `Available media collections: ${[...mediaSlugs].join(\", \") || \"none\"}.`,\n );\n }\n }\n\n return { mediaCollections };\n}\n","import { CollectionSlug } from \"../types/generated\";\nimport { PERMISSION_MODES, ADMIN_CUSTOM_SUBJECTS, WILDCARD_KEY } from \"./constants\";\nimport {\n CustomActionsInput,\n VexAccessConfigError,\n type AccessResource,\n type CustomResourceInput,\n type SubjectMap,\n type VexAccessConfig,\n type VexAccessConfigInput,\n} from \"./types\";\n\n/**\n * Defines the RBAC configuration for a VexCMS project.\n *\n * Builder in the `defineCollection`/`defineGlobal` family: infers the\n * per-subject action/data/field registry (`SubjectMap`) from `resources` and\n * `customResources` so `hasPermission()` calls against the returned config are\n * fully typed; validates the matrix in dev; returns a frozen `VexAccessConfig`\n * for `defineConfig({ access })`.\n *\n * @typeParam TRoles - Tuple of role name literals.\n * @typeParam TResources - Tuple of collection/global configs contributing subjects.\n * @typeParam TCustomResources - Custom subject declarations (`{ actions, data? }`).\n * @typeParam TUserSlug - Slug literal of the user collection; drives the callback\n * `user` type via the generated registry.\n * @typeParam TOrgSlug - Slug literal of the organization collection, when\n * multi-tenant. Presence gates the `organization` callback key; `undefined`\n * when single-tenant.\n * @param props - The access configuration.\n * @param props.roles - All role names the matrix may reference.\n * @param props.resources - Collections/globals to expose as subjects, keyed by slug.\n * @param props.customResources - Non-resource subjects, keyed by name.\n * @param props.userCollectionSlug - Slug of the collection whose documents are\n * `user` in callbacks. A plain string — the merged user collection\n * (auth-adapter fields included) does not exist yet at authoring time; the\n * document type resolves from the generated registry by slug.\n * @param props.userRolesField - Field on the user document holding role(s)\n * (`string` or `string[]` value); `hasPermission` reads roles from it.\n * @param props.orgCollectionSlug - Optional org collection slug enabling\n * org-scoped callbacks.\n * @param props.permissions - Role → subject → check matrix (see `RolePermissions`).\n * @returns Frozen `VexAccessConfig` carrying the `SubjectMap` phantom for inference.\n * @throws {VexAccessConfigError} When `userCollectionSlug` or `userRolesField` is\n * empty, when a `customResources` key collides with a resource slug, or when a\n * `customResources` entry declares an empty `actions` array. Also when a rule's\n * recorded constraints are not an in-order prefix of a declared index or violate\n * Convex's operator rule (see `validateAccessConstraints`), and when a\n * `constraints` callback throws while being recorded — every rule's callback runs\n * once here, at module load, so a rule that reached past its types surfaces as a\n * config error naming the role, resource and action rather than as a bare\n * `TypeError` from whichever method was missing.\n * @example\n * ```ts\n * export const access = defineAccess({\n * roles: [\"admin\", \"editor\"],\n * resources: [pages, users],\n * customResources: { apiKeys: { actions: [\"create\", \"revoke\"] } },\n * userCollectionSlug: \"users\",\n * userRolesField: \"roles\",\n * permissions: {\n * admin: { [WILDCARD_KEY]: true },\n * editor: { pages: { read: true, update: true }, apiKeys: false },\n * },\n * });\n * ```\n *\n * @see {@link VexAccessConfigInput} for the input type\n * @see {@link VexAccessConfig} for the resolved return type\n */\nexport function defineAccess<\n const TRoles extends readonly string[],\n const TResources extends readonly AccessResource[],\n const TCustomResources extends Record<string, CustomResourceInput> = {},\n const TUserSlug extends CollectionSlug = CollectionSlug,\n const TOrgSlug extends CollectionSlug | undefined = undefined,\n const TCustomActions extends Partial<\n Record<TResources[number][\"slug\"] | TUserSlug | Extract<TOrgSlug, string>, CustomActionsInput>\n > = {},\n>(\n props: VexAccessConfigInput<\n TRoles,\n TResources,\n TCustomResources,\n TUserSlug,\n TOrgSlug,\n TCustomActions\n >,\n): VexAccessConfig<\n SubjectMap<TResources, TCustomResources, TUserSlug, TOrgSlug, TCustomActions>,\n TResources,\n TUserSlug,\n TOrgSlug,\n TCustomActions\n> {\n // Hard errors — always run, regardless of NODE_ENV. The user collection\n // itself cannot be validated here (auth-adapter fields merge later, inside\n // `defineConfig`), so validation is limited to the config's own shape.\n if (props.userCollectionSlug.length === 0) {\n throw new VexAccessConfigError(`userCollectionSlug cannot be empty`);\n }\n if (props.userRolesField.length === 0) {\n throw new VexAccessConfigError(`userRolesField cannot be empty`);\n }\n if (props.anonRole !== undefined && props.anonRole.length === 0) {\n throw new VexAccessConfigError(`anonRole must not be empty if provided`);\n }\n\n const resourceSlugs = new Set<string>(\n props.resources\n .map((resource) => resource.slug)\n .concat(\n props.orgCollectionSlug\n ? [props.userCollectionSlug, props.orgCollectionSlug]\n : [props.userCollectionSlug],\n ),\n );\n for (const [key, customResource] of Object.entries(props.customResources ?? {})) {\n if (resourceSlugs.has(key)) {\n throw new VexAccessConfigError(`customResources \"${key}\" collides with a resource slug`);\n }\n if (customResource.actions.length === 0) {\n throw new VexAccessConfigError(`customResources \"${key}\" must declare at least one action`);\n }\n }\n\n // Dev-only validation warnings — a typo'd role or subject would otherwise\n // silently resolve via `defaultPermissionMode` at runtime.\n if (process.env.NODE_ENV !== \"production\") {\n const knownSubjects = new Set<string>([\n ...resourceSlugs,\n props.userCollectionSlug,\n ...(props.orgCollectionSlug ? [props.orgCollectionSlug] : []),\n ...Object.keys(props.customResources ?? {}),\n ...Object.keys(ADMIN_CUSTOM_SUBJECTS),\n ]);\n const roleSet = new Set<string>(props.roles);\n for (const [role, subjects] of Object.entries(props.permissions)) {\n if (!roleSet.has(role)) {\n console.warn(`permission role \"${role}\" not in roles array`);\n continue;\n }\n for (const subjectKey of Object.keys(subjects as Record<string, unknown>)) {\n if (subjectKey !== WILDCARD_KEY && !knownSubjects.has(subjectKey)) {\n console.warn(\n `permission subject \"${subjectKey}\" not found in resources, customResources, or adminPanel`,\n );\n }\n }\n }\n if (props.orgCollectionSlug !== undefined && props.orgCollectionSlug.length === 0) {\n console.warn(`orgCollectionSlug must not be empty`);\n }\n }\n\n return Object.freeze({\n anonRole: props.anonRole,\n enabled: props.enabled ?? true,\n roles: props.roles,\n resources: props.resources,\n customActions: props.customActions,\n // Pinned, not defaulted: an allow posture applies at two different fallthrough\n // points (one of which never consults the role wildcard), which made it an\n // invisible global grant. Use a role-level `\"*\": true` instead.\n defaultPermissionMode: PERMISSION_MODES.deny,\n userCollectionSlug: props.userCollectionSlug,\n userRolesField: props.userRolesField,\n orgCollectionSlug: props.orgCollectionSlug,\n permissions: props.permissions,\n });\n}\n","import { ADMIN_CUSTOM_SUBJECTS, PERMISSION_SCOPES } from \"./constants\";\nimport { hasPermission } from \"./hasPermission\";\nimport type { VexAccessConfig } from \"./types\";\n\n/**\n * Props for {@link canAccessAdminPanel}.\n */\nexport interface CanAccessAdminPanelProps {\n /**\n * The resolved config from `defineAccess()`. `undefined` means RBAC is not\n * configured, which grants access — the same escape hatch `hasPermission`\n * uses, so a project without an access matrix keeps working.\n */\n access?: VexAccessConfig;\n /**\n * The authenticated caller. `null`/`{}` (unauthenticated) resolves to an empty\n * role list and therefore denies.\n */\n user: Record<string, unknown> | null;\n /** The caller's active organization, forwarded to permission callbacks. */\n organization?: Record<string, unknown>;\n}\n\n/**\n * Answers whether a caller may open the admin panel at all — the\n * `adminPanel.access` gate.\n *\n * This is the coarse entry check. It is deliberately separate from the\n * per-collection checks: a caller who fails this should never reach the panel,\n * whereas a caller who passes it may still be denied individual collections.\n *\n * Call it in the host app's admin route (a server component, layout, or\n * middleware) and redirect on `false`. It never throws: the `adminPanel.access`\n * subject carries no document, so it is evaluated with\n * `scope: \"any\"` — a permission callback that only reads `user`/`organization`\n * resolves normally, and one that reaches for a document resolves to `true`\n * rather than throwing, since \"can this caller use the panel\" is inherently a\n * subject-level question.\n *\n * Prefer this over hand-writing `hasPermission({ resource: \"adminPanel\", … })`\n * so the subject key and action are never spelled by hand.\n *\n * @param props - The access config plus the resolved caller.\n * @returns `true` when the caller may open the admin panel; `false` to deny.\n * Also `true` when `access` is `undefined` (RBAC not configured).\n * @example\n * ```tsx\n * // app/admin/[[...path]]/page.tsx\n * const auth = await fetchAuthQuery(api.auth.api.getUserOrg, {});\n * if (!canAccessAdminPanel({ access, user: auth.user, organization: auth.organization })) {\n * redirect(\"/unauthorized\");\n * }\n * ```\n * @see {@link hasPermission} for the general check this delegates to\n */\nexport function canAccessAdminPanel(props: CanAccessAdminPanelProps): boolean {\n return hasPermission({\n access: props.access,\n user: props.user,\n organization: props.organization,\n resource: ADMIN_CUSTOM_SUBJECTS.adminPanel.key,\n action: ADMIN_CUSTOM_SUBJECTS.adminPanel.actions[0],\n scope: PERMISSION_SCOPES.any,\n });\n}\n","import type { AccessConditionResult, AccessQueryBuilder } from \"./constraintTypes\";\nimport type {\n AccessCheck,\n AccessDocFieldFor,\n AccessDocFor,\n AccessFieldValueFor,\n AccessIndexedFieldFor,\n AccessIndexNameFor,\n AccessMutationCheck,\n AccessResourceRef,\n} from \"./types\";\nimport type { AuthUserDocument } from \"../types/generated\";\nimport { ADMIN_FIELDS } from \"../fields/constants\";\n\n/**\n * Builders for the common composable access checks.\n *\n * These exist to own the unavoidable casts. A helper generic over a resource slug `S`\n * and a field `F` cannot hand a concrete value to `AccessFieldValueFor<S, F>` or call\n * `ix.eq(field, …)` against `AccessIndexFieldsFor<S>[N]`, because both are unresolved\n * while `S` and `F` are unbound — TypeScript will not accept a value against a\n * conditional or indexed-access type it cannot reduce, even when a bound plainly\n * guarantees it. The casts are therefore inherent to writing such a helper at all.\n *\n * What is NOT inherent is where they live. Written once here, behind functions whose\n * public signatures are fully checked, a project's own checks need none. Call sites\n * stay completely type-safe: the field must lead an index, the value must match the\n * field, and the returned check is branded to its resource.\n */\n\n/**\n * The runtime index-range builder, reached past the generic parameters.\n *\n * This is the ONE cast these builders cannot type away. `q.withIndex` is satisfied by\n * typing the resolved index name ({@link AccessIndexNameFor}), but the range callback's\n * builder is `ConstraintBuilder<AccessIndexFieldsFor<S>[N], …>` — an indexed access on\n * an unresolved type while `S` and `F` are unbound — so no argument can be checked\n * against its `eq`. Reducing that would require TypeScript to evaluate a generic\n * indexed access, which it does not do.\n *\n * @internal\n */\ntype RawRange = { eq: (field: string, value: unknown) => never };\n\n/**\n * Resolves the index whose leading field is `field`.\n *\n * @param resource - The resource config the caller passed.\n * @param field - A field the types already guaranteed leads an index.\n * @returns The Convex index name.\n * @throws {Error} When no index leads with `field`. Unreachable through the typed\n * surface; worth failing loudly because the alternative is a silent full scan with\n * the caller believing their check was pushed down.\n */\nfunction indexNameFor<S extends string, F>(\n resource: AccessResourceRef<S>,\n field: F & string,\n): AccessIndexNameFor<S, F> {\n const declared = resource.fields[field]?.index;\n if (declared) return declared as AccessIndexNameFor<S, F>;\n throw new Error(\n `[vexcms] \"${field}\" on \"${resource.slug}\" leads no declared index; ` +\n `an indexed access check cannot narrow on it.`,\n );\n}\n\n/**\n * Reads a field's owner value off a document, tolerating both storage shapes.\n *\n * Relationship fields generate `Id<slug>[]` regardless of `hasMany`, so ownership is\n * usually a one-element array; a plain text or id column is a scalar. Checking the\n * value rather than the schema keeps this correct for both.\n *\n * @param owner - The field's stored value.\n * @param userId - The requesting user's id.\n * @returns True when the value names this user.\n */\nfunction ownerMatches(owner: unknown, userId: unknown): boolean {\n return Array.isArray(owner) ? owner.includes(userId) : owner === userId;\n}\n\n/**\n * Builds a read check narrowed to `field === value`, pushed into that field's index.\n *\n * @typeParam S - Resource slug, inferred from `props.resource`.\n * @typeParam F - Field name, constrained to `S`'s index-leading fields.\n * @param props - Input props.\n * @param props.resource - The resource this check governs.\n * @param props.field - Field to compare, completed from `S`'s indexed fields.\n * @param props.value - Value to match, typed from `S`'s document.\n * @returns A check assignable to `permissions[role][S].read`.\n */\nexport function indexedEqCheck<S extends string, F extends AccessIndexedFieldFor<S>>(props: {\n field: F;\n resource: AccessResourceRef<S>;\n value: AccessFieldValueFor<S, F>;\n}): AccessCheck<S> {\n const index = indexNameFor(props.resource, props.field);\n return {\n constraints: ({ q }: { q: AccessQueryBuilder<never, never> }): AccessConditionResult =>\n q.withIndex(index, (ix) => (ix as unknown as RawRange).eq(props.field, props.value)),\n } as unknown as AccessCheck<S>;\n}\n\n/**\n * Builds a read check narrowed to rows the requesting user owns, pushed into the owner\n * field's index.\n *\n * The comparison value is built per request from `user`, and its shape follows the\n * field's declared type: a relationship column stores `Id[]`, so the value is\n * `[user._id]`; anything else compares the id directly. That decision needs the\n * resource config, which is why this is a distinct builder rather than a call to\n * {@link indexedEqCheck}.\n *\n * @typeParam S - Resource slug, inferred from `props.resource`.\n * @typeParam F - Owner field, constrained to `S`'s index-leading fields.\n * @param props - Input props.\n * @param props.resource - The resource this check governs.\n * @param props.field - The owner field, e.g. `\"authorId\"`.\n * @returns A check assignable to `permissions[role][S].read`.\n */\nexport function indexedOwnerCheck<S extends string, F extends AccessIndexedFieldFor<S>>(props: {\n field: F;\n resource: AccessResourceRef<S>;\n}): AccessCheck<S> {\n const index = indexNameFor(props.resource, props.field);\n const isRelationship =\n props.resource.fields[props.field]?.type === ADMIN_FIELDS.relationship.type;\n return {\n constraints: ({\n q,\n user,\n }: {\n q: AccessQueryBuilder<never, never>;\n user: AuthUserDocument;\n }): AccessConditionResult => {\n return q.withIndex(index, (ix) =>\n (ix as unknown as RawRange).eq(props.field, isRelationship ? [user._id] : user._id),\n );\n },\n } as unknown as AccessCheck<S>;\n}\n\n/**\n * Builds a single-document check that passes only when `field` names the requesting\n * user.\n *\n * A per-document predicate rather than an index range: `create`/`update`/`delete`\n * authorize one document, so there is nothing to narrow (DD 14). `field` is therefore\n * any readable field, not only an indexed one.\n *\n * @typeParam S - Resource slug, inferred from `props.resource`.\n * @typeParam F - Owner field on `S`.\n * @param props - Input props.\n * @param props.resource - The resource this check governs.\n * @param props.field - The owner field, e.g. `\"authorId\"`.\n * @returns A check assignable to a non-query action on `S`.\n */\nexport function ownerPredicateCheck<S extends string, F extends AccessDocFieldFor<S>>(props: {\n field: F;\n resource: AccessResourceRef<S>;\n}): AccessMutationCheck<S> {\n return ((callbackProps: { data?: AccessDocFor<S>; user: AuthUserDocument }) => {\n const owner = callbackProps.data?.[props.field];\n return ownerMatches(owner, callbackProps.user._id);\n }) as AccessMutationCheck<S>;\n}\n","import { GenericDataModel } from \"convex/server\";\nimport { VexStorageConfigError } from \"../types\";\nimport type {\n CreateMediaDocumentServerArgs,\n DeleteMediaServerArgs,\n GenerateUploadUrlServerArgs,\n} from \"./types\";\nimport { CRUD_ACTIONS, hasPermission } from \"../../access\";\nimport { resolveAccessCall, resolveCollectionSlug } from \"../../api/utils\";\nimport { type GenericId } from \"convex/values\";\nimport { CollectionSlug } from \"../../types\";\n\n/**\n * Generates a URL to upload a file to the storage adapter.\n * Server-side only — call inside a Convex mutation handler.\n *\n * Looks up the adapter by name from `args.config.storage?.adapters` and\n * calls `adapter.generateUploadUrl(ctx)`.\n *\n * Import from `@vexcms/core/server`.\n *\n * @typeParam DataModel - Convex data model (inferred from `args.ctx`).\n * @param args - `{ ctx, config, adapter }`.\n * @returns Promise resolving to `{ url: string }` — the upload URL.\n * @example\n * ```ts\n * import { generateUploadUrl } from \"@vexcms/core/server\";\n *\n * export const uploadFile = mutation({\n * args: { adapter: v.string() },\n * handler: (ctx, args) =>\n * generateUploadUrl({ ctx, config: myConfig, adapter: args.adapter }),\n * });\n */\nexport async function generateUploadUrl<TDataModel extends GenericDataModel = GenericDataModel>(\n args: GenerateUploadUrlServerArgs<TDataModel>,\n): Promise<{ url: string }> {\n if (args.config.access !== undefined) {\n const { access, action, resource } = resolveAccessCall({\n config: args.config,\n access: args.access,\n defaultAction: CRUD_ACTIONS.create,\n resource: args.collection,\n });\n hasPermission({\n throwOnDenied: true,\n user: args.auth?.user ?? {},\n organization: args.auth?.organization,\n access,\n resource,\n action,\n });\n }\n const adapter = args.config.storage?.adapters.find((a) => a.name === args.adapter);\n if (!adapter) {\n throw new VexStorageConfigError(`Storage adapter \"${args.adapter}\" not found`);\n }\n return await adapter.generateUploadUrl(args.ctx);\n}\n\n/**\n * Creates a media document in the storage adapter after the file is uploaded.\n * Server-side only — call inside a Convex mutation handler.\n *\n * Looks up the adapter by name from `args.config.storage?.adapters` and\n * calls `adapter.createMediaDocument(ctx, args)`.\n *\n * Import from `@vexcms/core/server`.\n *\n * @typeParam DataModel - Convex data model (inferred from `args.ctx`).\n * @param args - `{ ctx, config, adapter, collectionSlug, storageId, filename, mimeType, size, alt?, adapterFields? }`.\n * @returns Promise resolving to the new media document's ID as a string.\n * @example\n * ```ts\n * import { createMediaDocument } from \"@vexcms/core/server\";\n *\n * export const saveMedia = mutation({\n * args: { data: v.any() },\n * handler: (ctx, args) =>\n * createMediaDocument({ ctx, config: myConfig, ...args.data }),\n * });\n * ```\n */\nexport async function createMediaDocument<TDataModel extends GenericDataModel = GenericDataModel>(\n args: CreateMediaDocumentServerArgs<TDataModel>,\n): Promise<string> {\n if (args.config.access !== undefined) {\n const { access, action, resource } = resolveAccessCall({\n config: args.config,\n access: args.access,\n defaultAction: CRUD_ACTIONS.create,\n resource: args.collection,\n });\n hasPermission({\n throwOnDenied: true,\n access,\n user: args.auth?.user ?? {},\n organization: args.auth?.organization,\n resource,\n action,\n });\n }\n const adapter = args.config.storage?.adapters.find((a) => a.name === args.adapter);\n if (!adapter) {\n throw new VexStorageConfigError(`Storage adapter \"${args.adapter}\" not found`);\n }\n return await adapter.createMediaDocument(args.ctx, {\n collectionSlug: args.collection,\n storageId: args.storageId,\n filename: args.filename,\n mimeType: args.mimeType,\n size: args.size,\n alt: args.alt,\n adapterFields: args.adapterFields,\n });\n}\n\n/**\n * Deletes a media document and its file from storage.\n * Server-side only — call inside a Convex mutation handler.\n *\n * Looks up the adapter by name from `args.config.storage?.adapters` and\n * calls `adapter.deleteMedia(ctx, args)`.\n *\n * Import from `@vexcms/core/server`.\n *\n * @typeParam DataModel - Convex data model (inferred from `args.ctx`).\n * @param args - `{ ctx, config, adapter, mediaId, softDelete? }`.\n * @returns Promise resolving to `true` if the document was deleted.\n * @example\n * ```ts\n * import { deleteMedia } from \"@vexcms/core/server\";\n *\n * export const removeMedia = mutation({\n * args: { mediaId: v.string() },\n * handler: (ctx, args) =>\n * deleteMedia({ ctx, config: myConfig, adapter: \"convex\", mediaId: args.mediaId }),\n * });\n * ```\n */\nexport async function deleteMedia<TDataModel extends GenericDataModel = GenericDataModel>(\n args: DeleteMediaServerArgs<TDataModel>,\n): Promise<boolean> {\n if (args.config.access !== undefined) {\n const resource = resolveCollectionSlug({\n ctx: args.ctx,\n config: args.config,\n id: args.mediaId as GenericId<CollectionSlug>,\n });\n const { access, action } = resolveAccessCall({\n config: args.config,\n access: args.access,\n defaultAction: CRUD_ACTIONS.delete,\n resource,\n });\n // Pass the stored media document: a per-document delete rule cannot be\n // evaluated without it, and omitting it makes such a rule unsatisfiable\n // (the capability probe trips and the default `all` scope resolves `false`).\n const doc = await args.ctx.db.get(args.mediaId as GenericId<CollectionSlug>);\n hasPermission({\n throwOnDenied: true,\n access,\n user: args.auth?.user ?? {},\n organization: args.auth?.organization,\n resource,\n action,\n data: doc ?? undefined,\n });\n }\n const adapter = args.config.storage?.adapters.find((a) => a.name === args.adapter);\n if (!adapter) {\n throw new VexStorageConfigError(`Storage adapter \"${args.adapter}\" not found`);\n }\n return await adapter.deleteMedia(args.ctx, {\n collectionSlug: \"\",\n mediaId: args.mediaId,\n softDelete: args.softDelete,\n });\n}\n","import type { GenericDataModel } from \"convex/server\";\n\nimport { GetUrlReturn } from \"../types\";\nimport type { GetUrlServerArgs } from \"./types\";\nimport { CRUD_ACTIONS, hasPermission } from \"../../access\";\nimport { resolveAccessCall, resolveCollectionSlug } from \"../../api/utils\";\nimport { GenericId } from \"convex/values\";\nimport { CollectionSlug } from \"../../types\";\n\n/**\n * Returns a URL for a media file.\n * Server-side only — call inside a Convex query handler.\n *\n * Looks up the adapter by name from `args.config.storage?.adapters` and\n * calls `adapter.getUrl(ctx, args)`.\n *\n * Import from `@vexcms/core/server`.\n *\n * @typeParam DataModel - Convex data model (inferred from `args.ctx`).\n * @param args - `{ ctx, config, adapter, mediaId }`.\n * @returns Promise resolving to `{ url: string }` or `{ url: null, error: string }`.\n * @example\n * ```ts\n * import { getUrl } from \"@vexcms/core/server\";\n *\n * export const getMediaUrl = query({\n * args: { mediaId: v.string() },\n * handler: (ctx, args) =>\n * getUrl({ ctx, config: myConfig, adapter: \"convex\", mediaId: args.mediaId }),\n * });\n * ```\n */\nexport async function getUrl<TDataModel extends GenericDataModel = GenericDataModel>(\n args: GetUrlServerArgs<TDataModel>,\n): Promise<GetUrlReturn> {\n if (args.config.access !== undefined) {\n const resource = resolveCollectionSlug({\n ctx: args.ctx,\n config: args.config,\n id: args.mediaId as GenericId<CollectionSlug>,\n });\n const { access, action } = resolveAccessCall({\n config: args.config,\n access: args.access,\n defaultAction: CRUD_ACTIONS.read,\n resource,\n });\n hasPermission({\n throwOnDenied: true,\n access,\n user: args.auth?.user ?? {},\n organization: args.auth?.organization ?? {},\n resource: resource,\n action,\n });\n }\n const adapter = args.config.storage?.adapters.find((a) => a.name === args.adapter);\n if (!adapter) {\n return {\n error: `Adapter \"${args.adapter}\" not found`,\n };\n }\n return await adapter.getUrl(args.ctx, {\n collectionSlug: \"\",\n mediaId: args.mediaId,\n });\n}\n","import {\n type MutationBuilder,\n type QueryBuilder,\n type FunctionVisibility,\n type GenericDataModel,\n GenericMutationCtx,\n GenericQueryCtx,\n} from \"convex/server\";\nimport { v } from \"convex/values\";\nimport type { VexConfig } from \"../../config\";\nimport { generateUploadUrl, createMediaDocument, deleteMedia, getUrl } from \"./index\";\nimport { VexApiAuth } from \"../../api/types\";\nimport { resolveGetAuth } from \"../../api/server\";\n\n/**\n * Registers `getUrl` as a convex query endpoint.\n * Registers `generateUploadUrl`, `createMediaDocument`, and `deleteMedia` as Convex mutation endpoints.\n *\n * Call in the user's `convex/vex/media.ts`. The factory wraps\n * the server functions in `mutation()` with `v.args()` schemas so Convex\n * exposes them at `api.vex.media.generateUploadUrl`, `api.vex.media.createMediaDocument`, etc.\n *\n * `vexConvexApi.media.generateUploadUrl`, `vexConvexApi.media.createMediaDocument`, etc. in\n * `@vexcms/core/src/convex/index.ts` point at these paths.\n *\n * @returns Registered `getUrl` Convex query, `generateUploadUrl` / `createMediaDocument` / `deleteMedia` Convex mutations.\n * @example\n * ```ts\n * // apps/test/convex/vex/media.ts\n * import { createGetAuth } from \"@vexcms/better-auth\"\n * import { mediaApi } from \"@vexcms/core/convex\";\n * import { mutation, query } from \"../_generated/server\";\n * import config from \"../../src/vex.config\";\n *\n * export const { getUrl, generateUploadUrl, createMediaDocument, deleteMedia } = mediaApi({ config, query, mutation, getAuth: createGetAuth({...}) });\n * ```\n */\nexport function mediaApi<\n TDataModel extends GenericDataModel = GenericDataModel,\n Visibility extends FunctionVisibility = \"public\",\n>({\n config,\n query,\n mutation,\n getAuth,\n}: {\n /** The user's resolved `VexConfig`. */\n config: VexConfig;\n /** Convex `query` builder from `_generated/server` (or an internal builder to keep endpoints private). */\n query: QueryBuilder<TDataModel, Visibility>;\n /** Convex `mutation` builder from `_generated/server` (or an internal builder to keep endpoints private). */\n mutation: MutationBuilder<TDataModel, Visibility>;\n /**\n * Server-side resolver for the current caller: receives the handler's ctx and\n * returns `{ user, organization? }` (or `undefined` when unauthenticated).\n * Called once per request, and only when `config.access` is configured.\n * Never exposed to clients.\n */\n getAuth?: (\n ctx: GenericQueryCtx<TDataModel> | GenericMutationCtx<TDataModel>,\n ) => Promise<VexApiAuth | undefined>;\n}) {\n return {\n getUrl: query({\n args: {\n adapter: v.string(),\n mediaId: v.string(),\n },\n returns: v.union(\n v.object({\n url: v.string(),\n }),\n v.object({\n error: v.string(),\n }),\n ),\n handler: async (ctx, args) => {\n const auth = await resolveGetAuth({ ctx, config, getAuth });\n return await getUrl({\n auth,\n ctx,\n config,\n adapter: args.adapter,\n mediaId: args.mediaId,\n });\n },\n }),\n\n // MUTATIONS\n generateUploadUrl: mutation({\n args: {\n adapter: v.string(),\n collection: v.string(),\n },\n returns: v.object({ url: v.string() }),\n handler: async (ctx, args) => {\n const auth = await resolveGetAuth({ ctx, config, getAuth });\n return await generateUploadUrl({\n auth,\n ctx: ctx,\n collection: args.collection,\n config,\n adapter: args.adapter,\n });\n },\n }),\n\n createMediaDocument: mutation({\n args: {\n adapter: v.string(),\n collectionSlug: v.string(),\n storageId: v.string(),\n filename: v.string(),\n mimeType: v.string(),\n size: v.number(),\n alt: v.optional(v.string()),\n adapterFields: v.optional(v.any()),\n },\n returns: v.string(),\n handler: async (ctx, args) => {\n const auth = await resolveGetAuth({ ctx, config, getAuth });\n return await createMediaDocument({\n auth,\n ctx,\n config,\n adapter: args.adapter,\n collection: args.collectionSlug,\n storageId: args.storageId,\n filename: args.filename,\n mimeType: args.mimeType,\n size: args.size,\n alt: args.alt,\n adapterFields: args.adapterFields,\n });\n },\n }),\n\n deleteMedia: mutation({\n args: {\n adapter: v.string(),\n mediaId: v.string(),\n softDelete: v.optional(v.boolean()),\n },\n returns: v.boolean(),\n handler: async (ctx, args) => {\n const auth = await resolveGetAuth({ ctx, config, getAuth });\n return await deleteMedia({\n auth,\n ctx,\n config,\n adapter: args.adapter,\n mediaId: args.mediaId,\n softDelete: args.softDelete,\n });\n },\n }),\n };\n}\n","/**\n * Formats byte count into human-readable file size.\n *\n * Converts raw byte count into appropriate units (B, KB, MB, GB, TB)\n * with sensible precision for each scale.\n *\n * @param bytes - File size in bytes\n * @returns Formatted string with unit (e.g. \"248 KB\", \"1.4 MB\")\n *\n * @example\n * ```ts\n * formatBytes(1024) // \"1 KB\"\n * formatBytes(1536) // \"1.5 KB\"\n * formatBytes(1048576) // \"1 MB\"\n * formatBytes(248000) // \"242.2 KB\"\n * ```\n */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n if (bytes < 1024 * 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n return `${(bytes / (1024 * 1024 * 1024 * 1024)).toFixed(1)} TB`;\n}\n\n/**\n * Formats MIME type into short display name.\n *\n * Extracts the subtype from a MIME type and normalizes common variants.\n *\n * @param mimeType - Full MIME type (e.g. \"image/jpeg\")\n * @returns Uppercase short name (e.g. \"JPG\")\n *\n * @example\n * ```ts\n * formatMimeType(\"image/jpeg\") // \"JPG\"\n * formatMimeType(\"image/svg+xml\") // \"SVG\"\n * formatMimeType(\"application/pdf\") // \"PDF\"\n * ```\n */\nexport function formatMimeType(mimeType: string): string {\n return (mimeType.split(\"/\")[1] || mimeType)\n .toUpperCase()\n .replace(\"SVG+XML\", \"SVG\")\n .replace(\"JPEG\", \"JPG\");\n}\n","import { AccessResource } from \"../access\";\nimport { validateAccessConfig } from \"../access/validateAccessConstraints\";\nimport { mergeAuthCollections } from \"../auth/mergeCollections\";\nimport { internalCollections } from \"../collections/internal\";\nimport { validateAndMergeStorageConfig } from \"../media\";\nimport { VexConfig, VexConfigInput } from \"./types\";\n\n/**\n * Resolves a raw Vex config input into a fully-populated `VexConfig`.\n *\n * Applies defaults for any omitted properties — an absent `collections`\n * array is replaced with an empty array so downstream consumers can always\n * iterate without null-checking.\n *\n * When an `auth` adapter is provided, its collections are merged with\n * user-defined collections via {@link mergeAuthCollections}. Protected\n * auth collections cannot be overridden, and locked fields are preserved.\n *\n * @param config - The raw Vex configuration supplied by the caller.\n * @returns The resolved `VexConfig` with all defaults applied.\n *\n * @example\n * ```ts\n * // Basic config with user-defined collections only\n * defineConfig({\n * collections: [\n * defineCollection({ slug: \"posts\", fields: { title: text() } }),\n * ],\n * });\n * ```\n *\n * @example\n * ```ts\n * // Config with Better Auth integration\n * import { betterAuthAdapter } from \"@vexcms/better-auth\";\n *\n * defineConfig({\n * auth: betterAuthAdapter(authOptions),\n * collections: [posts, authors],\n * });\n * ```\n *\n * @see {@link VexConfigInput} for the user-facing input type\n * @see {@link VexConfig} for the resolved return type\n * @see {@link mergeAuthCollections} for auth collection merge logic\n * @see {@link better-auth/src!betterAuthAdapter} for the Better Auth adapter\n */\nexport function defineConfig(config?: VexConfigInput): VexConfig {\n const userCollections = config?.collections ?? [];\n const authCollections = config?.authAdapter?.collections ?? [];\n const collections = mergeAuthCollections({\n authCollections,\n userCollections,\n }).concat(internalCollections);\n\n const { mediaCollections } = validateAndMergeStorageConfig({\n collections: collections,\n storageAdapters: config?.storage?.adapters,\n });\n\n if (config?.access) {\n const allResources: AccessResource[] = (\n collections.concat(mediaCollections) as AccessResource[]\n ).concat(config?.globals ?? []);\n validateAccessConfig({\n ...config.access,\n resources: allResources,\n });\n }\n\n return {\n basePath: \"/admin\",\n ...config,\n access: config?.access,\n auth: config?.authAdapter,\n storage: {\n adapters: config?.storage?.adapters ?? [],\n },\n collections,\n globals: config?.globals ?? [],\n mediaCollections,\n admin: {\n ...config?.admin,\n sidebar: {\n side: \"left\",\n collapsible: \"offcanvas\",\n ...config?.admin?.sidebar,\n },\n },\n schema: {\n outputPath: \"/convex/vex.schema.ts\",\n ...config?.schema,\n },\n types: {\n outputPath: \"/src/vex.types.ts\",\n ...config?.types,\n },\n };\n}\n","import type { VexConfig } from \"./types\";\n\n/**\n * A version of `VexConfig` safe to pass across RSC / JSON serialization\n * boundaries. All non-serializable values (functions, React components, class\n * instances, symbols) are replaced with `null`. The shape is otherwise\n * identical to `VexConfig` — serializable fields retain their types.\n *\n * Produced by {@link sanitizeConfigForClient}.\n *\n * @see {@link VexConfig} for the full server-side config\n * @see {@link sanitizeConfigForClient} for the sanitization function\n */\nexport type ClientVexConfig = Sanitized<Omit<VexConfig, \"access\">>;\n\n/**\n * Recursively replaces all non-serializable values in a type with `null`.\n *\n * - Functions → `null`\n * - Symbols → `null`\n * - Class instances → `null`\n * - Arrays → element type recursively sanitized\n * - Plain objects → property types recursively sanitized\n * - Primitives (string, number, boolean, null, undefined) → unchanged\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Sanitized<T> = T extends (...args: any[]) => any\n ? null\n : T extends symbol\n ? null\n : T extends Array<infer U>\n ? Sanitized<U>[]\n : T extends object\n ? { [K in keyof T]: Sanitized<T[K]> }\n : T;\n\n// ─── Runtime helpers ─────────────────────────────────────────────────────────\n\n/**\n * Returns `true` if `value` is a plain object (created via `{}` or\n * `Object.create(null)`). Class instances, arrays, null, and functions all\n * return `false`.\n *\n * @internal\n * @param value - object to check\n * @returns boolean\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n/**\n * Recursively strips all non-serializable values from an arbitrary value tree.\n *\n * Rules:\n * - `null` / `undefined` → `null`\n * - `function` → `null` (covers React components and callbacks)\n * - `symbol` → `null`\n * - Primitive (string, number, boolean) → returned as-is\n * - Array → each element recursively processed\n * - Plain object (`{}`) → each property recursively processed\n * - Class instance (non-plain object) → `null`\n *\n * This function is intentionally exhaustive so that new non-serializable\n * properties added anywhere in `VexConfig` are stripped automatically without\n * requiring manual additions to `sanitizeConfigForClient`.\n *\n * @param value - Any value to sanitize.\n * @returns A JSON-serializable version of `value`, with non-serializable\n * leaves replaced by `null`.\n *\n * @internal\n */\nexport function stripNonSerializable(value: unknown): unknown {\n if (value === null || value === undefined) return null;\n if (typeof value === \"function\") return null;\n if (typeof value === \"symbol\") return null;\n if (typeof value === \"bigint\") return null;\n\n // Primitives are already serializable\n if (typeof value !== \"object\") return value;\n\n if (Array.isArray(value)) {\n // Recurse into every element — primitives pass through unchanged,\n // class instances become null, nested objects/arrays are processed recursively.\n return value.map((item) => stripNonSerializable(item));\n }\n\n // Only recurse into plain objects — class instances (React elements, Zod\n // schemas, etc.) are treated as opaque and replaced with null.\n if (!isPlainObject(value)) return null;\n\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[k] = stripNonSerializable(v);\n }\n return result;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Strips all non-serializable values from a `VexConfig` for safe passage\n * across RSC / JSON serialization boundaries (e.g. server layout →\n * client component).\n *\n * Uses {@link stripNonSerializable} to recursively walk the entire config\n * tree, replacing functions, React components, class instances, and symbols\n * with `null`. Adding a new non-serializable property anywhere in the config\n * is handled automatically — no manual additions needed here.\n *\n * The `access` config is always omitted from the client version — it is\n * never needed client-side and contains permission functions that cannot\n * be serialized.\n *\n * @param config - The fully resolved server-side VexCMS config.\n * @returns A deeply sanitized copy safe to pass to client components.\n *\n * @example\n * ```ts\n * // In a Next.js server component (e.g. AdminLayout):\n * import vexConfig from \"~/convex/vex.config\";\n * import { sanitizeConfigForClient } from \"@vexcms/core\";\n *\n * const clientConfig = sanitizeConfigForClient(vexConfig);\n * return <AdminShell config={clientConfig} />;\n * ```\n *\n * @see {@link ClientVexConfig} for the sanitized type\n * @see {@link stripNonSerializable} for the recursive sanitizer\n */\nexport function sanitizeConfigForClient(config: VexConfig): ClientVexConfig {\n // Drop storage adapters (class instances) and the access config up front.\n // Access is deliberately server-only: its callbacks cannot serialize (a\n // nulled matrix would misresolve in hasPermission), client checks are\n // advisory at best, and permission policy should not ship to the browser.\n const { storage, access, ...rest } = config;\n return stripNonSerializable(rest) as ClientVexConfig;\n}\n","import type { VexConfig } from \"../config/types\";\nimport { collectionConfigToVexSchema } from \"../collections\";\n\nfunction fail(contents: string) {\n return { update: false, contents };\n}\n\nfunction success(contents: string) {\n return { update: true, contents };\n}\n\n/**\n * Generates the full contents of `vex.schema.ts` from a resolved `VexConfig`.\n *\n * Returns `{ update: false, contents }` when there are no collections — the output\n * contains only the auto-generated header and no imports or table declarations.\n * Returns `{ update: true, contents }` when collections are present — the output\n * includes the header, `convex/server` and `convex/values` imports, and one\n * `export const` block per collection.\n *\n * @param props - Input props.\n * @param props.config - The fully resolved Vex configuration.\n * @returns An object with `update` (whether the file should be written to disk) and `contents` (the file string).\n *\n * @example\n * ```ts\n * const config = defineConfig({\n * collections: [\n * defineCollection({ slug: \"posts\", fields: { title: text() } }),\n * ],\n * });\n * const { update, contents } = generateVexSchema({ config });\n * // update → true\n * // contents → '// ⚠️ AUTO-GENERATED BY VEX CMS ...\\nimport { defineTable } from \"convex/server\"\\n...'\n * ```\n *\n * @see {@link collectionConfigToVexSchema} for the per-collection string builder\n * @see {@link VexConfig} for the resolved config shape\n */\nexport function generateVexSchema(props: { config: VexConfig }): {\n update: boolean;\n contents: string;\n} {\n let header = `// ⚠️ AUTO-GENERATED BY VEX CMS — DO NOT EDIT ⚠️\\n// Run 'vex dev' or 'vex generate' to update this file.\\n`;\n if (props.config.collections.length < 1 && props.config.globals.length < 1) {\n return fail(header);\n }\n\n let imports = `import { defineTable } from \"convex/server\"\\nimport { v } from \"convex/values\"\\n`;\n const allCollections = props.config.collections.concat(props.config.mediaCollections);\n let collectionSchemas = allCollections\n .map((collection) => {\n return collectionConfigToVexSchema({ collection, config: props.config });\n })\n .join(\"\\n\");\n\n let globalsTable = \"\";\n if (props.config.globals.length > 0) {\n globalsTable = [\n \"\",\n \"/**\",\n \" * VEX GLOBALS — singleton documents, one row per registered global slug\",\n \" **/\",\n \"\",\n \"export const vex_globals = defineTable({\",\n \" slug: v.string(),\",\n \" data: v.any(),\",\n \"})\",\n ' .index(\"by_slug\", [\"slug\"])',\n ].join(\"\\n\");\n }\n\n return success([header, imports, collectionSchemas, globalsTable].join(\"\\n\"));\n}\n","import type { VexConfig } from \"../config/types\";\n\n/** A field that needs migration when its schema changes. */\nexport interface NeedsMigrationField {\n table: string;\n field: string;\n isOptional: boolean;\n}\n\n/** Metadata about a field that was removed from the config. */\nexport interface RemovedFieldInfo {\n table: string;\n field: string;\n}\n\n/** Diff result between two schema strings. */\nexport interface SchemaDiff {\n needsMigration: NeedsMigrationField[];\n removedFields: RemovedFieldInfo[];\n}\n\n/** A single field backfill operation produced by `planMigration`. */\nexport type MigrationOp = {\n table: string;\n field: string;\n defaultValue: unknown;\n};\n\n/**\n * Computes a diff between two schema strings, identifying fields that now\n * need migration and fields that were removed. Stub — always returns an\n * empty diff; schema-string diffing is not yet implemented.\n *\n * @param _previous - The prior schema source string. Currently unused;\n * placeholder for the not-yet-implemented diffing logic.\n * @param _next - The new schema source string. Currently unused;\n * placeholder for the not-yet-implemented diffing logic.\n * @returns An empty {@link SchemaDiff} until diffing is implemented.\n */\nexport function diffSchema(_previous: string, _next: string): SchemaDiff {\n return { needsMigration: [], removedFields: [] };\n}\n\n/**\n * Returns a copy of the schema string with the given fields made optional.\n * Stub — currently returns `schema` unchanged; the rewrite is not yet\n * implemented.\n *\n * @param schema - The schema source string to rewrite.\n * @param _fields - The fields that should be made optional. Currently\n * unused; placeholder for the not-yet-implemented rewrite.\n * @returns The schema string, unchanged until this is implemented.\n */\nexport function makeFieldsOptional(\n schema: string,\n _fields: NeedsMigrationField[],\n): string {\n return schema;\n}\n\n/**\n * Returns a copy of the schema string with previously removed fields\n * re-added as optional. Stub — currently returns `schema` unchanged; the\n * rewrite is not yet implemented.\n *\n * @param schema - The schema source string to rewrite.\n * @param _removedFields - The fields that were removed from the config and\n * should be re-added as optional. Currently unused; placeholder for the\n * not-yet-implemented rewrite.\n * @returns The schema string, unchanged until this is implemented.\n */\nexport function addRemovedFieldsAsOptional(\n schema: string,\n _removedFields: RemovedFieldInfo[],\n): string {\n return schema;\n}\n\n/**\n * Plans backfill operations from a schema diff. Stub — always returns an\n * empty array; migration planning is not yet implemented.\n *\n * @param _props - The schema diff and resolved config to plan backfills\n * from. Currently unused; placeholder for the not-yet-implemented\n * planning logic.\n * @returns An empty list of {@link MigrationOp}s until planning is\n * implemented.\n */\nexport function planMigration(_props: {\n diff: SchemaDiff;\n config: VexConfig;\n}): MigrationOp[] {\n return [];\n}\n","import { ADMIN_FIELDS } from \"../fields\";\nimport { CollectionConfig } from \"./types\";\n\n/**\n * Groups a collection's index-bearing fields by declared index name, in\n * field declaration order — the same computation `collectionConfigToVexSchema`\n * uses for its `.index()` chain (`collections/validator.ts:114-118`): an\n * explicit `field.index`, or an auto `by_<fieldKey>` for every relationship\n * field. Search indexes are excluded — `withIndex` never targets those.\n * Two fields declaring the SAME `field.index` value group into one compound\n * entry, fields in the order they appear on the collection.\n *\n * @param props - Input props.\n * @param props.collection - The collection to read index-bearing fields from.\n * @returns Map of index name → field keys, in declaration order. Empty when\n * the collection declares no indexed fields.\n * @internal\n */\nexport function collectionConfigToIndexFields(props: {\n collection: CollectionConfig;\n}): Map<string, string[]> {\n const fields = new Map<string, string[]>();\n for (const [fieldKey, field] of Object.entries(props.collection.fields)) {\n let indexName: string;\n if (field.index) {\n indexName = field.index;\n } else if (field.type === ADMIN_FIELDS.relationship.type) {\n indexName = `by_${fieldKey}`;\n } else {\n continue;\n }\n\n const existing = fields.get(indexName);\n if (existing) {\n existing.push(fieldKey);\n } else {\n fields.set(indexName, [fieldKey]);\n }\n }\n return fields;\n}\n","import {\n collectionConfigToFieldTypeMap,\n collectionConfigToInterface,\n} from \"../collections/interfaceGen\";\nimport type { VexConfig } from \"../config/types\";\nimport { globalConfigToFieldTypeMap, globalConfigToInterface } from \"../globals\";\nimport { STORAGE_ADAPTER_PROTOCOLS } from \"../media\";\nimport { collectionConfigToIndexFields } from \"../collections/indexFields\";\nimport { CustomActionsInput } from \"../access\";\n\n/**\n * Formats one collection's `IndexFieldsBySlug` entry: a `readonly`\n * field-tuple per declared index name, or `{}` when the collection\n * declares none — the edge case `IndexNameFor` (`types/generated.ts`)\n * depends on: `keyof {}` still resolves to `never`, so an index-less slug\n * widens identically to the old `never`-union form while staying a valid\n * object type `IndexFieldsFor` can index into.\n *\n * @param props - Input props.\n * @param props.slug - The collection slug this entry is keyed under.\n * @param props.indexFields - This collection's `collectIndexFields()` result.\n * @returns One `\\t<slug>: { ... }` (or `\\t<slug>: {}`) line for the\n * `IndexFieldsBySlug` block of the `declare module` augmentation.\n * @internal\n */\nfunction formatIndexFieldsEntry(props: {\n slug: string;\n indexFields: Map<string, string[]>;\n}): string {\n // `{}` rather than `never` for an index-less collection: `keyof {}` is\n // `never`, so `IndexNameFor` still widens correctly, while `{}` stays a\n // valid object type that `IndexFieldsFor` can index into.\n if (props.indexFields.size === 0) return `\\t${props.slug}: {}`;\n\n // Map iteration follows insertion order, which is field declaration order,\n // so each tuple is positionally correct. Emitted as a `readonly` TUPLE, not\n // a union — the tuple IS the field-order encoding `ConstraintBuilder`\n // narrows against, so a single-field index stays a 1-tuple.\n const entries = [...props.indexFields.entries()]\n .map(\n ([indexName, fieldKeys]) =>\n `${indexName}: readonly [${fieldKeys.map((f) => `\"${f}\"`).join(\", \")}]`,\n )\n .join(\"; \");\n return `\\t${props.slug}: { ${entries} }`;\n}\n\n/**\n * Generates the full contents of `vex.types.ts` from a resolved `VexConfig`.\n *\n * When there are no collections, returns only the auto-generated header.\n * When collections are present, the output contains:\n * - Imports for `Id` (from `@convex/_generated/dataModel`) and `VexDocument` (from `@vexcms/core`)\n * - One `export interface` per collection, extending `VexDocument` with a branded `Id<\"slug\">` for `_id`\n * - `export type CollectionSlug` — union of all collection slugs\n * - `export type DocumentBySlug` — map of slug to document interface\n * - `declare module '@vexcms/core'` block that augments `GeneratedVexTypes`, narrowing\n * `CollectionSlug` and `DocumentBySlug` inside `@vexcms/core` itself\n *\n * @param props - Input props.\n * @param props.config - The fully resolved Vex configuration.\n * @returns The complete TypeScript source string to write to `vex.types.ts`.\n *\n * @example\n * ```ts\n * const config = defineConfig({\n * collections: [\n * defineCollection({ slug: \"posts\", fields: { title: text({ required: true }) } }),\n * ],\n * });\n * const contents = generateVexTypes({ config });\n * // Writes to vex.types.ts:\n * // import type { Id } from \"@convex/_generated/dataModel\"\n * // import type { VexDocument } from \"@vexcms/core\"\n * // export interface PostsDocument extends VexDocument { _id: Id<\"posts\">; title: string }\n * // export type CollectionSlug = \"posts\"\n * // export type DocumentBySlug = { posts: PostsDocument }\n * // declare module \"@vexcms/core\" { interface GeneratedVexTypes { ... } }\n * ```\n *\n * @see {@link collectionConfigToInterface} for the per-collection interface builder\n * @see {@link VexConfig} for the resolved config shape\n */\nexport function generateVexTypes(props: { config: VexConfig }): string {\n const { config } = props;\n const typesHeader = `// ⚠️ AUTO-GENERATED BY VEX CMS — DO NOT EDIT ⚠️\n // Run 'vex dev' or 'vex generate' to update this file.\\n\n /* eslint-disable perfectionist/sort-union-types */\n /* eslint-disable perfectionist/sort-interfaces */\n /* eslint-disable perfectionist/sort-modules */\\n\\n\n import type { Id } from \"@convex/_generated/dataModel\"\n import type { VexDocument, VexDocumentGlobal } from \"@vexcms/core\"\\n\n `;\n\n const allCollections = config.collections.concat(config.mediaCollections);\n const hasCollections = allCollections.length > 0;\n const hasGlobals = config.globals.length > 0;\n\n const interfaceBlocks = allCollections\n .map((collection) => collectionConfigToInterface({ collection }))\n .concat(config.globals.map((global) => globalConfigToInterface({ global })));\n\n const collectionSlugs = !hasCollections\n ? \"never\"\n : allCollections.map((c) => `\"${c.slug}\"`).join(\" | \");\n const collectionSlugType = `export type CollectionSlug = ${collectionSlugs}`;\n\n const mediaCollectionSlugs = !hasCollections\n ? `\"\"`\n : config.mediaCollections.map((mc) => `\"${mc.slug}\"`).join(\" | \");\n const mediaCollectionSlugType = `export type MediaCollectionSlug = ${mediaCollectionSlugs}`;\n\n const globalSlugs = !hasGlobals ? \"never\" : config.globals.map((g) => `\"${g.slug}\"`).join(\" | \");\n const globalSlugType = `export type GlobalSlug = ${globalSlugs}`;\n\n const globalDocumentsBySlug = config.globals\n .map((g) => `\\t${g.slug}: ${g.interfaceName}`)\n .join(\"\\n\");\n const globalDocumentBySlugType = !hasGlobals\n ? undefined\n : `export type GlobalDocumentBySlug = {\\n${globalDocumentsBySlug}\\n}`;\n\n const documentsBySlug = allCollections.map((c) => `\\t${c.slug}: ${c.interfaceName}`).join(\"\\n\");\n const documentBySlugType = `export type DocumentBySlug = {\\n${documentsBySlug}\\n}`;\n\n const collectionsFieldTypeMap = allCollections\n .map((c) => collectionConfigToFieldTypeMap({ collection: c }))\n .join(\"\\n\");\n\n const globalsFieldTypeMap = config.globals\n .map((g) => globalConfigToFieldTypeMap({ global: g }))\n .join(\"\\n\");\n\n const storageAdapterSlugs =\n config.storage?.adapters\n .filter((a) => a.type === STORAGE_ADAPTER_PROTOCOLS.presignedUrl)\n .map((a) => `\"${a.name}\"`)\n .join(\" | \") ?? \"never\";\n const storageAdapterSlugType = `export type StorageAdapterSlug = ${storageAdapterSlugs}`;\n\n // The slugs `defineAccess` was configured with. Emitting them lets core resolve the\n // project's user/organization DOCUMENT types on its own, so a project's access\n // helpers can name a check type without threading those two types by hand.\n // `never` when unset: `AccessCheck` falls back to the wide shapes, exactly as it\n // does before `vex generate` has run at all.\n const userSlug = config.access?.userCollectionSlug;\n const orgSlug = config.access?.orgCollectionSlug;\n const authSlugs = [\n `\\t\\t\\tuser: ${userSlug ? `\"${userSlug}\"` : \"never\"}`,\n `\\t\\t\\torganization: ${orgSlug ? `\"${orgSlug}\"` : \"never\"}`,\n ].join(\"\\n\");\n\n const indexFieldsBySlug = allCollections\n .map((c) =>\n formatIndexFieldsEntry({\n slug: c.slug,\n indexFields: collectionConfigToIndexFields({ collection: c }),\n }),\n )\n .join(\"\\n\");\n\n const customActionsBySlug = Object.entries(config.access?.customActions ?? {})\n .map(([slug, actions]) => {\n const query =\n ((actions as Partial<CustomActionsInput>).query ?? []).map((a) => `\"${a}\"`).join(\" | \") ||\n \"never\";\n const mutation =\n ((actions as Partial<CustomActionsInput>).mutation ?? [])\n .map((a) => `\"${a}\"`)\n .join(\" | \") || \"never\";\n return `\\t\\t\\t${slug}: { query: ${query}; mutation: ${mutation} }`;\n })\n .join(\"\\n\");\n\n const declareModule = `declare module \"@vexcms/core\" {\n \\tinterface GeneratedVexTypes {\n \\t\\tCollectionSlug: ${collectionSlugs}\n \\t\\tGlobalSlug: ${globalSlugs}\n \\t\\tMediaCollectionSlug: ${mediaCollectionSlugs}\n \\t\\tStorageAdapterSlug: ${storageAdapterSlugs}\n \\t\\tDocumentBySlug: {\\n${documentsBySlug}\\n}\n \\t\\tGlobalDocumentBySlug: {\\n${globalDocumentsBySlug}\\n}\n \\t\\tCollectionsFieldTypeMap: {\\n${collectionsFieldTypeMap}\\n}\n \\t\\tGlobalsFieldTypeMap: {\\n${globalsFieldTypeMap}\\n}\n \\t\\tIndexFieldsBySlug: {\\n${indexFieldsBySlug}\\n}\n \\t\\tCustomActionsBySlug: {\\n${customActionsBySlug}\\n}\n \\t\\tAuthSlugs: {\\n${authSlugs}\\n}\n \\t}\n \\n}`;\n\n return [\n typesHeader,\n \"\",\n ...interfaceBlocks,\n \"\",\n collectionSlugType,\n \"\",\n globalSlugType,\n \"\",\n mediaCollectionSlugType,\n \"\",\n storageAdapterSlugType,\n \"\",\n documentBySlugType,\n \"\",\n globalDocumentBySlugType,\n \"\",\n declareModule,\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":["text","color","v","v","v"]}