convex-cms 0.0.2 → 0.0.3

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 (265) hide show
  1. package/admin-dist/nitro.json +15 -0
  2. package/admin-dist/public/assets/CmsEmptyState-CRswfTzk.js +5 -0
  3. package/admin-dist/public/assets/CmsPageHeader-CirpXndm.js +1 -0
  4. package/admin-dist/public/assets/CmsStatusBadge-CbEUpQu-.js +1 -0
  5. package/admin-dist/public/assets/CmsToolbar-BI2nZOXp.js +1 -0
  6. package/admin-dist/public/assets/ContentEntryEditor-CBeCyK_m.js +4 -0
  7. package/admin-dist/public/assets/ErrorState-BIVaWmom.js +1 -0
  8. package/admin-dist/public/assets/TaxonomyFilter-ChaY6Y_x.js +1 -0
  9. package/admin-dist/public/assets/_contentTypeId-DQ8k_Rvw.js +1 -0
  10. package/admin-dist/public/assets/_entryId-CKU_glsK.js +1 -0
  11. package/admin-dist/public/assets/alert-BXjTqrwQ.js +1 -0
  12. package/admin-dist/public/assets/badge-hvUOzpVZ.js +1 -0
  13. package/admin-dist/public/assets/circle-check-big-CF_pR17r.js +1 -0
  14. package/admin-dist/public/assets/command-DU82cJlt.js +1 -0
  15. package/admin-dist/public/assets/content-_LXl3pp7.js +1 -0
  16. package/admin-dist/public/assets/content-types-KjxaXGxY.js +2 -0
  17. package/admin-dist/public/assets/globals-CS6BZ0zp.css +1 -0
  18. package/admin-dist/public/assets/index-DNGIZHL-.js +1 -0
  19. package/admin-dist/public/assets/label-KNtpL71g.js +1 -0
  20. package/admin-dist/public/assets/link-2-Bw2aI4V4.js +1 -0
  21. package/admin-dist/public/assets/list-sYepHjt_.js +1 -0
  22. package/admin-dist/public/assets/main-CKj5yfEi.js +97 -0
  23. package/admin-dist/public/assets/media-Bkrkffm7.js +1 -0
  24. package/admin-dist/public/assets/new._contentTypeId-C3LstjNs.js +1 -0
  25. package/admin-dist/public/assets/plus-DUn8v_Xf.js +1 -0
  26. package/admin-dist/public/assets/rotate-ccw-DJEoHcRI.js +1 -0
  27. package/admin-dist/public/assets/scroll-area-DfIlT0in.js +1 -0
  28. package/admin-dist/public/assets/search-MuAUDJKR.js +1 -0
  29. package/admin-dist/public/assets/select-BD29IXCI.js +1 -0
  30. package/admin-dist/public/assets/settings-DmMyn_6A.js +1 -0
  31. package/admin-dist/public/assets/switch-h3Rrnl5i.js +1 -0
  32. package/admin-dist/public/assets/tabs-imc8h-Dp.js +1 -0
  33. package/admin-dist/public/assets/taxonomies-dAsrT65H.js +1 -0
  34. package/admin-dist/public/assets/textarea-BTy7nwzR.js +1 -0
  35. package/admin-dist/public/assets/trash-SAWKZZHv.js +1 -0
  36. package/admin-dist/public/assets/triangle-alert-E52Vfeuh.js +1 -0
  37. package/admin-dist/public/assets/useBreadcrumbLabel-BECBMCzM.js +1 -0
  38. package/admin-dist/public/assets/usePermissions-Basjs9BT.js +1 -0
  39. package/admin-dist/public/favicon.ico +0 -0
  40. package/admin-dist/server/_chunks/_libs/@date-fns/tz.mjs +217 -0
  41. package/admin-dist/server/_chunks/_libs/@floating-ui/core.mjs +719 -0
  42. package/admin-dist/server/_chunks/_libs/@floating-ui/dom.mjs +622 -0
  43. package/admin-dist/server/_chunks/_libs/@floating-ui/react-dom.mjs +292 -0
  44. package/admin-dist/server/_chunks/_libs/@floating-ui/utils.mjs +320 -0
  45. package/admin-dist/server/_chunks/_libs/@radix-ui/number.mjs +6 -0
  46. package/admin-dist/server/_chunks/_libs/@radix-ui/primitive.mjs +11 -0
  47. package/admin-dist/server/_chunks/_libs/@radix-ui/react-arrow.mjs +23 -0
  48. package/admin-dist/server/_chunks/_libs/@radix-ui/react-avatar.mjs +119 -0
  49. package/admin-dist/server/_chunks/_libs/@radix-ui/react-checkbox.mjs +270 -0
  50. package/admin-dist/server/_chunks/_libs/@radix-ui/react-collection.mjs +69 -0
  51. package/admin-dist/server/_chunks/_libs/@radix-ui/react-compose-refs.mjs +39 -0
  52. package/admin-dist/server/_chunks/_libs/@radix-ui/react-context.mjs +137 -0
  53. package/admin-dist/server/_chunks/_libs/@radix-ui/react-dialog.mjs +325 -0
  54. package/admin-dist/server/_chunks/_libs/@radix-ui/react-direction.mjs +9 -0
  55. package/admin-dist/server/_chunks/_libs/@radix-ui/react-dismissable-layer.mjs +210 -0
  56. package/admin-dist/server/_chunks/_libs/@radix-ui/react-dropdown-menu.mjs +253 -0
  57. package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-guards.mjs +29 -0
  58. package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-scope.mjs +206 -0
  59. package/admin-dist/server/_chunks/_libs/@radix-ui/react-id.mjs +14 -0
  60. package/admin-dist/server/_chunks/_libs/@radix-ui/react-label.mjs +23 -0
  61. package/admin-dist/server/_chunks/_libs/@radix-ui/react-menu.mjs +812 -0
  62. package/admin-dist/server/_chunks/_libs/@radix-ui/react-popover.mjs +300 -0
  63. package/admin-dist/server/_chunks/_libs/@radix-ui/react-popper.mjs +286 -0
  64. package/admin-dist/server/_chunks/_libs/@radix-ui/react-portal.mjs +16 -0
  65. package/admin-dist/server/_chunks/_libs/@radix-ui/react-presence.mjs +128 -0
  66. package/admin-dist/server/_chunks/_libs/@radix-ui/react-primitive.mjs +141 -0
  67. package/admin-dist/server/_chunks/_libs/@radix-ui/react-roving-focus.mjs +224 -0
  68. package/admin-dist/server/_chunks/_libs/@radix-ui/react-scroll-area.mjs +721 -0
  69. package/admin-dist/server/_chunks/_libs/@radix-ui/react-select.mjs +1163 -0
  70. package/admin-dist/server/_chunks/_libs/@radix-ui/react-separator.mjs +28 -0
  71. package/admin-dist/server/_chunks/_libs/@radix-ui/react-slot.mjs +601 -0
  72. package/admin-dist/server/_chunks/_libs/@radix-ui/react-switch.mjs +152 -0
  73. package/admin-dist/server/_chunks/_libs/@radix-ui/react-tabs.mjs +189 -0
  74. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-callback-ref.mjs +11 -0
  75. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-controllable-state.mjs +69 -0
  76. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-effect-event.mjs +1 -0
  77. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-escape-keydown.mjs +17 -0
  78. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-is-hydrated.mjs +15 -0
  79. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-layout-effect.mjs +6 -0
  80. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-previous.mjs +14 -0
  81. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-size.mjs +39 -0
  82. package/admin-dist/server/_chunks/_libs/@radix-ui/react-visually-hidden.mjs +33 -0
  83. package/admin-dist/server/_chunks/_libs/@tanstack/history.mjs +409 -0
  84. package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +1711 -0
  85. package/admin-dist/server/_chunks/_libs/@tanstack/react-store.mjs +56 -0
  86. package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +4829 -0
  87. package/admin-dist/server/_chunks/_libs/@tanstack/store.mjs +134 -0
  88. package/admin-dist/server/_chunks/_libs/react-dom.mjs +10781 -0
  89. package/admin-dist/server/_chunks/_libs/react.mjs +513 -0
  90. package/admin-dist/server/_libs/aria-hidden.mjs +122 -0
  91. package/admin-dist/server/_libs/class-variance-authority.mjs +44 -0
  92. package/admin-dist/server/_libs/clsx.mjs +16 -0
  93. package/admin-dist/server/_libs/cmdk.mjs +315 -0
  94. package/admin-dist/server/_libs/convex.mjs +4841 -0
  95. package/admin-dist/server/_libs/cookie-es.mjs +58 -0
  96. package/admin-dist/server/_libs/croner.mjs +1 -0
  97. package/admin-dist/server/_libs/crossws.mjs +1 -0
  98. package/admin-dist/server/_libs/date-fns.mjs +1716 -0
  99. package/admin-dist/server/_libs/detect-node-es.mjs +1 -0
  100. package/admin-dist/server/_libs/get-nonce.mjs +9 -0
  101. package/admin-dist/server/_libs/h3-v2.mjs +277 -0
  102. package/admin-dist/server/_libs/h3.mjs +401 -0
  103. package/admin-dist/server/_libs/hookable.mjs +1 -0
  104. package/admin-dist/server/_libs/isbot.mjs +20 -0
  105. package/admin-dist/server/_libs/lucide-react.mjs +850 -0
  106. package/admin-dist/server/_libs/ohash.mjs +1 -0
  107. package/admin-dist/server/_libs/react-day-picker.mjs +2201 -0
  108. package/admin-dist/server/_libs/react-remove-scroll-bar.mjs +82 -0
  109. package/admin-dist/server/_libs/react-remove-scroll.mjs +328 -0
  110. package/admin-dist/server/_libs/react-style-singleton.mjs +69 -0
  111. package/admin-dist/server/_libs/rou3.mjs +8 -0
  112. package/admin-dist/server/_libs/seroval-plugins.mjs +58 -0
  113. package/admin-dist/server/_libs/seroval.mjs +1765 -0
  114. package/admin-dist/server/_libs/srvx.mjs +719 -0
  115. package/admin-dist/server/_libs/tailwind-merge.mjs +3010 -0
  116. package/admin-dist/server/_libs/tiny-invariant.mjs +12 -0
  117. package/admin-dist/server/_libs/tiny-warning.mjs +5 -0
  118. package/admin-dist/server/_libs/tslib.mjs +39 -0
  119. package/admin-dist/server/_libs/ufo.mjs +54 -0
  120. package/admin-dist/server/_libs/unctx.mjs +1 -0
  121. package/admin-dist/server/_libs/unstorage.mjs +1 -0
  122. package/admin-dist/server/_libs/use-callback-ref.mjs +66 -0
  123. package/admin-dist/server/_libs/use-sidecar.mjs +106 -0
  124. package/admin-dist/server/_libs/use-sync-external-store.mjs +139 -0
  125. package/admin-dist/server/_libs/zod.mjs +4223 -0
  126. package/admin-dist/server/_ssr/CmsEmptyState-DU7-7-mV.mjs +290 -0
  127. package/admin-dist/server/_ssr/CmsPageHeader-CseW0AHm.mjs +24 -0
  128. package/admin-dist/server/_ssr/CmsStatusBadge-B_pi4KCp.mjs +127 -0
  129. package/admin-dist/server/_ssr/CmsToolbar-X75ex6ek.mjs +49 -0
  130. package/admin-dist/server/_ssr/ContentEntryEditor-CepusRsA.mjs +3720 -0
  131. package/admin-dist/server/_ssr/ErrorState-cI-bKLez.mjs +89 -0
  132. package/admin-dist/server/_ssr/TaxonomyFilter-Bwrq0-cz.mjs +188 -0
  133. package/admin-dist/server/_ssr/_contentTypeId-BqYKEcLr.mjs +379 -0
  134. package/admin-dist/server/_ssr/_entryId-CRfnqeDf.mjs +161 -0
  135. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BwDlABVk.mjs +4 -0
  136. package/admin-dist/server/_ssr/alert-CVt45UUP.mjs +92 -0
  137. package/admin-dist/server/_ssr/badge-6BsP37vG.mjs +125 -0
  138. package/admin-dist/server/_ssr/command-fy8epIKf.mjs +128 -0
  139. package/admin-dist/server/_ssr/config.server-D7JHDcDv.mjs +117 -0
  140. package/admin-dist/server/_ssr/content-B5RhL7uW.mjs +532 -0
  141. package/admin-dist/server/_ssr/content-types-BIOqCQYN.mjs +1166 -0
  142. package/admin-dist/server/_ssr/index-DHSHDPt1.mjs +193 -0
  143. package/admin-dist/server/_ssr/index.mjs +1275 -0
  144. package/admin-dist/server/_ssr/label-C8Dko1j7.mjs +22 -0
  145. package/admin-dist/server/_ssr/media-CSx3XttC.mjs +1832 -0
  146. package/admin-dist/server/_ssr/new._contentTypeId-DzanEZQM.mjs +144 -0
  147. package/admin-dist/server/_ssr/router-DDWcF-kt.mjs +1556 -0
  148. package/admin-dist/server/_ssr/scroll-area-bjPYwhXN.mjs +59 -0
  149. package/admin-dist/server/_ssr/select-BUhDDf4T.mjs +142 -0
  150. package/admin-dist/server/_ssr/settings-DAsxnw2q.mjs +348 -0
  151. package/admin-dist/server/_ssr/start-HYkvq4Ni.mjs +4 -0
  152. package/admin-dist/server/_ssr/switch-BgyRtQ1Z.mjs +31 -0
  153. package/admin-dist/server/_ssr/tabs-DzMdRB1A.mjs +628 -0
  154. package/admin-dist/server/_ssr/taxonomies-C8j8g5Q5.mjs +915 -0
  155. package/admin-dist/server/_ssr/textarea-9jNeYJSc.mjs +18 -0
  156. package/admin-dist/server/_ssr/trash-DYMxwhZB.mjs +291 -0
  157. package/admin-dist/server/_ssr/useBreadcrumbLabel-FNSAr2Ha.mjs +16 -0
  158. package/admin-dist/server/_ssr/usePermissions-BJGGahrJ.mjs +68 -0
  159. package/admin-dist/server/favicon.ico +0 -0
  160. package/admin-dist/server/index.mjs +627 -0
  161. package/dist/cli/index.js +0 -0
  162. package/dist/client/admin-config.d.ts +0 -1
  163. package/dist/client/admin-config.d.ts.map +1 -1
  164. package/dist/client/admin-config.js +0 -1
  165. package/dist/client/admin-config.js.map +1 -1
  166. package/dist/client/adminApi.d.ts.map +1 -1
  167. package/dist/client/agentTools.d.ts +1237 -135
  168. package/dist/client/agentTools.d.ts.map +1 -1
  169. package/dist/client/agentTools.js +33 -9
  170. package/dist/client/agentTools.js.map +1 -1
  171. package/dist/client/index.d.ts +1 -1
  172. package/dist/client/index.d.ts.map +1 -1
  173. package/dist/client/index.js.map +1 -1
  174. package/dist/component/_generated/component.d.ts +9 -0
  175. package/dist/component/_generated/component.d.ts.map +1 -1
  176. package/dist/component/mediaAssets.d.ts +35 -0
  177. package/dist/component/mediaAssets.d.ts.map +1 -1
  178. package/dist/component/mediaAssets.js +81 -0
  179. package/dist/component/mediaAssets.js.map +1 -1
  180. package/dist/test.d.ts.map +1 -1
  181. package/dist/test.js +2 -1
  182. package/dist/test.js.map +1 -1
  183. package/package.json +9 -5
  184. package/dist/component/auditLog.d.ts +0 -410
  185. package/dist/component/auditLog.d.ts.map +0 -1
  186. package/dist/component/auditLog.js +0 -607
  187. package/dist/component/auditLog.js.map +0 -1
  188. package/dist/component/types.d.ts +0 -4
  189. package/dist/component/types.d.ts.map +0 -1
  190. package/dist/component/types.js +0 -2
  191. package/dist/component/types.js.map +0 -1
  192. package/src/cli/commands/admin.ts +0 -104
  193. package/src/cli/index.ts +0 -21
  194. package/src/cli/utils/detectConvexUrl.ts +0 -54
  195. package/src/cli/utils/openBrowser.ts +0 -16
  196. package/src/client/admin-config.ts +0 -138
  197. package/src/client/adminApi.ts +0 -942
  198. package/src/client/agentTools.ts +0 -1311
  199. package/src/client/argTypes.ts +0 -316
  200. package/src/client/field-types.ts +0 -187
  201. package/src/client/index.ts +0 -1301
  202. package/src/client/queryBuilder.ts +0 -1100
  203. package/src/client/schema/codegen.ts +0 -500
  204. package/src/client/schema/defineContentType.ts +0 -501
  205. package/src/client/schema/index.ts +0 -169
  206. package/src/client/schema/schemaDrift.ts +0 -574
  207. package/src/client/schema/typedClient.ts +0 -688
  208. package/src/client/schema/types.ts +0 -666
  209. package/src/client/types.ts +0 -723
  210. package/src/client/workflows.ts +0 -141
  211. package/src/client/wrapper.ts +0 -4304
  212. package/src/component/_generated/api.ts +0 -140
  213. package/src/component/_generated/component.ts +0 -5029
  214. package/src/component/_generated/dataModel.ts +0 -60
  215. package/src/component/_generated/server.ts +0 -156
  216. package/src/component/authorization.ts +0 -647
  217. package/src/component/authorizationHooks.ts +0 -668
  218. package/src/component/bulkOperations.ts +0 -687
  219. package/src/component/contentEntries.ts +0 -1976
  220. package/src/component/contentEntryMutations.ts +0 -1223
  221. package/src/component/contentEntryValidation.ts +0 -707
  222. package/src/component/contentLock.ts +0 -550
  223. package/src/component/contentTypeMigration.ts +0 -1064
  224. package/src/component/contentTypeMutations.ts +0 -969
  225. package/src/component/contentTypes.ts +0 -346
  226. package/src/component/convex.config.ts +0 -44
  227. package/src/component/documentTypes.ts +0 -240
  228. package/src/component/eventEmitter.ts +0 -485
  229. package/src/component/exportImport.ts +0 -1169
  230. package/src/component/index.ts +0 -491
  231. package/src/component/lib/deepReferenceResolver.ts +0 -999
  232. package/src/component/lib/errors.ts +0 -816
  233. package/src/component/lib/index.ts +0 -145
  234. package/src/component/lib/mediaReferenceResolver.ts +0 -495
  235. package/src/component/lib/metadataExtractor.ts +0 -792
  236. package/src/component/lib/mutationAuth.ts +0 -199
  237. package/src/component/lib/queries.ts +0 -79
  238. package/src/component/lib/ragContentChunker.ts +0 -1371
  239. package/src/component/lib/referenceResolver.ts +0 -430
  240. package/src/component/lib/slugGenerator.ts +0 -262
  241. package/src/component/lib/slugUniqueness.ts +0 -333
  242. package/src/component/lib/softDelete.ts +0 -44
  243. package/src/component/localeFallbackChain.ts +0 -673
  244. package/src/component/localeFields.ts +0 -896
  245. package/src/component/mediaAssetMutations.ts +0 -725
  246. package/src/component/mediaAssets.ts +0 -932
  247. package/src/component/mediaFolderMutations.ts +0 -1046
  248. package/src/component/mediaUploadMutations.ts +0 -224
  249. package/src/component/mediaVariantMutations.ts +0 -900
  250. package/src/component/mediaVariants.ts +0 -793
  251. package/src/component/ragContentIndexer.ts +0 -1067
  252. package/src/component/rateLimitHooks.ts +0 -572
  253. package/src/component/roles.ts +0 -1360
  254. package/src/component/scheduledPublish.ts +0 -358
  255. package/src/component/schema.ts +0 -617
  256. package/src/component/taxonomies.ts +0 -949
  257. package/src/component/taxonomyMutations.ts +0 -1210
  258. package/src/component/trash.ts +0 -724
  259. package/src/component/userContext.ts +0 -898
  260. package/src/component/validation.ts +0 -1388
  261. package/src/component/validators.ts +0 -949
  262. package/src/component/versionMutations.ts +0 -392
  263. package/src/component/webhookTrigger.ts +0 -1922
  264. package/src/react/index.ts +0 -898
  265. package/src/test.ts +0 -1580
@@ -1,501 +0,0 @@
1
- /**
2
- * Content Type Schema Definition
3
- *
4
- * The `defineContentType` function creates type-safe content type definitions
5
- * using Convex validators. Types are automatically inferred via Convex's
6
- * native `Infer<typeof validator>` pattern.
7
- *
8
- * @example
9
- * ```typescript
10
- * import { v } from "convex/values";
11
- * import { defineContentType } from "@convex-cms/core";
12
- *
13
- * export const blogPost = defineContentType({
14
- * name: "blog_post",
15
- * validator: v.object({
16
- * title: v.string(),
17
- * slug: v.string(),
18
- * content: v.string(),
19
- * author: v.id("contentEntries"),
20
- * category: v.optional(v.union(v.literal("tech"), v.literal("news"))),
21
- * publishedAt: v.optional(v.number()),
22
- * }),
23
- * meta: {
24
- * displayName: "Blog Post",
25
- * titleField: "title",
26
- * slugField: "slug",
27
- * fields: {
28
- * title: { label: "Title", maxLength: 200 },
29
- * content: { label: "Content", renderAs: "richText", searchable: true },
30
- * author: { label: "Author", renderAs: "reference" },
31
- * category: { label: "Category", renderAs: "select" },
32
- * },
33
- * },
34
- * });
35
- * ```
36
- */
37
-
38
- import type { Validator } from "convex/values";
39
- import type {
40
- ContentTypeConfig,
41
- ContentTypeDefinition,
42
- ContentTypeMeta,
43
- FieldMeta,
44
- } from "./types.js";
45
-
46
- // =============================================================================
47
- // Content Type Name Validation
48
- // =============================================================================
49
-
50
- /**
51
- * Pattern for valid content type names.
52
- * - Lowercase letters, numbers, and underscores only
53
- * - Must start with a letter
54
- * - 1-50 characters
55
- */
56
- const CONTENT_TYPE_NAME_PATTERN = /^[a-z][a-z0-9_]{0,49}$/;
57
-
58
- /**
59
- * Validates a content type name.
60
- *
61
- * @param name - The name to validate
62
- * @throws Error if the name is invalid
63
- */
64
- function validateContentTypeName(name: string): void {
65
- if (!name) {
66
- throw new Error("Content type name is required");
67
- }
68
-
69
- if (!CONTENT_TYPE_NAME_PATTERN.test(name)) {
70
- throw new Error(
71
- `Invalid content type name "${name}". ` +
72
- "Names must start with a lowercase letter and contain only " +
73
- "lowercase letters, numbers, and underscores (1-50 characters)."
74
- );
75
- }
76
- }
77
-
78
- // =============================================================================
79
- // Define Content Type
80
- // =============================================================================
81
-
82
- /**
83
- * Creates a type-safe content type definition.
84
- *
85
- * This function accepts a Convex validator and CMS metadata, returning a
86
- * definition object that can be used for:
87
- * 1. **Type inference**: `Infer<typeof definition.validator>` gives the data type
88
- * 2. **Runtime validation**: The validator is used to validate content at runtime
89
- * 3. **Admin UI configuration**: Metadata provides display hints and field labels
90
- *
91
- * ## Why Convex Validators?
92
- *
93
- * Using Convex validators directly (instead of custom schema builders) provides:
94
- * - **Native type inference** via `Infer<typeof>` - no custom type machinery
95
- * - **Familiarity** - same validators used in Convex functions
96
- * - **Full power** - supports unions, literals, nested objects, arrays, IDs
97
- * - **Maintenance-free** - types are maintained by Convex
98
- *
99
- * ## Example: Basic Blog Post
100
- *
101
- * ```typescript
102
- * import { v, Infer } from "convex/values";
103
- * import { defineContentType } from "@convex-cms/core";
104
- *
105
- * export const blogPost = defineContentType({
106
- * name: "blog_post",
107
- * validator: v.object({
108
- * title: v.string(),
109
- * content: v.string(),
110
- * publishedAt: v.optional(v.number()),
111
- * }),
112
- * meta: {
113
- * displayName: "Blog Post",
114
- * titleField: "title",
115
- * },
116
- * });
117
- *
118
- * // Type is automatically inferred
119
- * type BlogPostData = Infer<typeof blogPost.validator>;
120
- * // { title: string; content: string; publishedAt?: number }
121
- * ```
122
- *
123
- * ## Example: Product with Variants
124
- *
125
- * ```typescript
126
- * export const product = defineContentType({
127
- * name: "product",
128
- * validator: v.object({
129
- * name: v.string(),
130
- * price: v.number(),
131
- * description: v.optional(v.string()),
132
- * variants: v.array(v.object({
133
- * sku: v.string(),
134
- * name: v.string(),
135
- * price: v.number(),
136
- * attributes: v.record(v.string(), v.string()),
137
- * })),
138
- * seo: v.optional(v.object({
139
- * title: v.string(),
140
- * description: v.string(),
141
- * keywords: v.array(v.string()),
142
- * })),
143
- * }),
144
- * meta: {
145
- * displayName: "Product",
146
- * titleField: "name",
147
- * fields: {
148
- * name: { label: "Product Name", searchable: true },
149
- * price: { label: "Base Price" },
150
- * variants: { label: "Variants", renderAs: "json" },
151
- * seo: { label: "SEO Settings", renderAs: "json" },
152
- * },
153
- * },
154
- * });
155
- * ```
156
- *
157
- * @param config - The content type configuration
158
- * @returns A frozen content type definition object
159
- *
160
- * @typeParam TName - The literal string type of the content type name
161
- * @typeParam TValidator - The Convex validator type
162
- */
163
- export function defineContentType<
164
- const TName extends string,
165
- TValidator extends Validator<Record<string, unknown>, "required", string>
166
- >(
167
- config: ContentTypeConfig<TValidator> & { name: TName }
168
- ): ContentTypeDefinition<TName, TValidator> {
169
- // Validate the content type name at definition time
170
- validateContentTypeName(config.name);
171
-
172
- // Create the definition object
173
- const definition: ContentTypeDefinition<TName, TValidator> = {
174
- name: config.name,
175
- validator: config.validator,
176
- meta: config.meta as ContentTypeMeta,
177
- _type: "content_type_definition",
178
- };
179
-
180
- // Freeze to prevent accidental mutation
181
- return Object.freeze(definition);
182
- }
183
-
184
- // =============================================================================
185
- // Schema Collection Utilities
186
- // =============================================================================
187
-
188
- /**
189
- * Creates a content schema from multiple content type definitions.
190
- *
191
- * This is a convenience function that validates the schema and provides
192
- * runtime utilities for working with multiple content types.
193
- *
194
- * @example
195
- * ```typescript
196
- * import { createContentSchema } from "@convex-cms/core";
197
- *
198
- * export const contentSchema = createContentSchema({
199
- * blogPost,
200
- * author,
201
- * product,
202
- * });
203
- *
204
- * // Get a specific definition
205
- * const blogDef = contentSchema.getDefinition("blog_post");
206
- *
207
- * // List all content type names
208
- * const names = contentSchema.getContentTypeNames();
209
- * // ["blog_post", "author", "product"]
210
- * ```
211
- *
212
- * @param definitions - An object containing content type definitions
213
- * @returns A schema object with utility methods
214
- */
215
- export function createContentSchema<
216
- T extends Record<string, ContentTypeDefinition>
217
- >(definitions: T): ContentSchemaInstance<T> {
218
- // Build a map of name -> definition for quick lookup
219
- const byName = new Map<string, ContentTypeDefinition>();
220
- const names: string[] = [];
221
-
222
- for (const [_key, def] of Object.entries(definitions)) {
223
- if (byName.has(def.name)) {
224
- throw new Error(
225
- `Duplicate content type name "${def.name}" in schema. ` +
226
- `Content type names must be unique.`
227
- );
228
- }
229
- byName.set(def.name, def);
230
- names.push(def.name);
231
- }
232
-
233
- return Object.freeze({
234
- definitions,
235
-
236
- getDefinition(name: string): ContentTypeDefinition | undefined {
237
- return byName.get(name);
238
- },
239
-
240
- getContentTypeNames(): string[] {
241
- return [...names];
242
- },
243
-
244
- hasContentType(name: string): boolean {
245
- return byName.has(name);
246
- },
247
-
248
- getDefinitionByKey<K extends keyof T>(key: K): T[K] {
249
- return definitions[key];
250
- },
251
- });
252
- }
253
-
254
- /**
255
- * A content schema instance with utility methods.
256
- */
257
- export interface ContentSchemaInstance<
258
- T extends Record<string, ContentTypeDefinition>
259
- > {
260
- /**
261
- * The raw definitions object.
262
- */
263
- readonly definitions: T;
264
-
265
- /**
266
- * Get a content type definition by its name.
267
- *
268
- * @param name - The content type name (e.g., "blog_post")
269
- * @returns The definition or undefined if not found
270
- */
271
- getDefinition(name: string): ContentTypeDefinition | undefined;
272
-
273
- /**
274
- * Get all content type names in the schema.
275
- *
276
- * @returns Array of content type names
277
- */
278
- getContentTypeNames(): string[];
279
-
280
- /**
281
- * Check if a content type exists in the schema.
282
- *
283
- * @param name - The content type name to check
284
- * @returns true if the content type exists
285
- */
286
- hasContentType(name: string): boolean;
287
-
288
- /**
289
- * Get a content type definition by its key in the definitions object.
290
- *
291
- * @param key - The key used in the definitions object
292
- * @returns The definition
293
- */
294
- getDefinitionByKey<K extends keyof T>(key: K): T[K];
295
- }
296
-
297
- // =============================================================================
298
- // Schema to Field Definitions Converter
299
- // =============================================================================
300
-
301
- /**
302
- * Field definition format expected by the CMS database.
303
- * This is the format stored in contentTypes.fields.
304
- */
305
- export interface DatabaseFieldDefinition {
306
- name: string;
307
- label: string;
308
- type: string;
309
- required: boolean;
310
- searchable?: boolean;
311
- localized?: boolean;
312
- description?: string;
313
- defaultValue?: unknown;
314
- options?: Record<string, unknown>;
315
- }
316
-
317
- /**
318
- * Converts a content type definition to the database field format.
319
- *
320
- * This bridges the gap between the code-defined schema and the
321
- * database format used by the CMS component.
322
- *
323
- * @param definition - The content type definition
324
- * @returns An array of field definitions for the database
325
- *
326
- * @example
327
- * ```typescript
328
- * const fields = toFieldDefinitions(blogPost);
329
- * // [
330
- * // { name: "title", label: "Title", type: "text", required: true, ... },
331
- * // { name: "content", label: "Content", type: "richText", required: true, ... },
332
- * // ]
333
- * ```
334
- */
335
- export function toFieldDefinitions(
336
- definition: ContentTypeDefinition
337
- ): DatabaseFieldDefinition[] {
338
- // Extract field information from the validator
339
- // This requires introspecting the validator structure
340
- const validatorFields = extractValidatorFields(definition.validator);
341
- const fieldMeta = definition.meta.fields || {};
342
-
343
- return validatorFields.map((field) => {
344
- const meta = fieldMeta[field.name as keyof typeof fieldMeta] || {};
345
-
346
- return {
347
- name: field.name,
348
- label: meta.label || field.name,
349
- type: meta.renderAs || inferFieldType(field.validatorType),
350
- required: field.required,
351
- searchable: meta.searchable,
352
- localized: meta.localized,
353
- description: meta.description,
354
- options: buildFieldOptions(field, meta),
355
- };
356
- });
357
- }
358
-
359
- /**
360
- * Field information extracted from a validator.
361
- */
362
- interface ExtractedField {
363
- name: string;
364
- validatorType: string;
365
- required: boolean;
366
- innerValidator?: unknown;
367
- }
368
-
369
- /**
370
- * Extract field information from a Convex object validator.
371
- *
372
- * @internal
373
- */
374
- function extractValidatorFields(
375
- validator: Validator<Record<string, unknown>, "required", string>
376
- ): ExtractedField[] {
377
- const fields: ExtractedField[] = [];
378
-
379
- // Convex validators have internal structure we can introspect
380
- // The validator has a `fields` property for object validators
381
- const validatorAny = validator as unknown as {
382
- fieldPaths?: Record<string, unknown>;
383
- type?: string;
384
- kind?: string;
385
- fields?: Record<
386
- string,
387
- { fieldPath: string; validator: { isOptional?: string; type?: string; kind?: string } }
388
- >;
389
- };
390
-
391
- // Try to access the validator's internal field definitions
392
- if (validatorAny.fields) {
393
- for (const [name, fieldInfo] of Object.entries(validatorAny.fields)) {
394
- const innerValidator = fieldInfo.validator;
395
- const isOptional = innerValidator?.isOptional === "optional";
396
-
397
- fields.push({
398
- name,
399
- validatorType: innerValidator?.type || innerValidator?.kind || "unknown",
400
- required: !isOptional,
401
- innerValidator,
402
- });
403
- }
404
- }
405
-
406
- return fields;
407
- }
408
-
409
- /**
410
- * Infer a CMS field type from a Convex validator type.
411
- *
412
- * @internal
413
- */
414
- function inferFieldType(validatorType: string): string {
415
- const typeMap: Record<string, string> = {
416
- string: "text",
417
- number: "number",
418
- boolean: "boolean",
419
- id: "reference",
420
- array: "json",
421
- object: "json",
422
- union: "select",
423
- literal: "select",
424
- bytes: "media",
425
- };
426
-
427
- return typeMap[validatorType] || "text";
428
- }
429
-
430
- /**
431
- * Build field options from extracted field info and metadata.
432
- *
433
- * This function maps all FieldMeta options to the database field options format.
434
- * The options object is stored in contentTypes.fields[].options and is used
435
- * for validation and UI rendering.
436
- *
437
- * @internal
438
- */
439
- function buildFieldOptions(
440
- field: ExtractedField,
441
- meta: FieldMeta
442
- ): Record<string, unknown> | undefined {
443
- const options: Record<string, unknown> = {};
444
-
445
- // ==========================================================================
446
- // Text Field Options
447
- // ==========================================================================
448
- if (meta.minLength !== undefined) options.minLength = meta.minLength;
449
- if (meta.maxLength !== undefined) options.maxLength = meta.maxLength;
450
- if (meta.pattern !== undefined) options.pattern = meta.pattern;
451
- // Note: patternMessage and multiline are UI hints, not stored in component schema
452
- // They could be stored in a separate UI hints field if needed
453
-
454
- // ==========================================================================
455
- // Number Field Options
456
- // ==========================================================================
457
- if (meta.min !== undefined) options.min = meta.min;
458
- if (meta.max !== undefined) options.max = meta.max;
459
- if (meta.step !== undefined) options.step = meta.step;
460
- if (meta.precision !== undefined) options.precision = meta.precision;
461
- // Note: prefix/suffix are UI hints, not stored in component schema
462
-
463
- // ==========================================================================
464
- // Reference Field Options
465
- // ==========================================================================
466
- if (meta.allowedContentTypes !== undefined) options.allowedContentTypes = meta.allowedContentTypes;
467
- if (meta.multiple !== undefined) options.multiple = meta.multiple;
468
- if (meta.minItems !== undefined) options.minItems = meta.minItems;
469
- // Note: maxItems maps to minItems in the component (for validation purposes)
470
- // The component schema has minItems but not maxItems - we'll add it anyway
471
- // for forward compatibility
472
-
473
- // ==========================================================================
474
- // Media Field Options
475
- // ==========================================================================
476
- if (meta.allowedMimeTypes !== undefined) options.allowedMimeTypes = meta.allowedMimeTypes;
477
- if (meta.maxFileSize !== undefined) options.maxFileSize = meta.maxFileSize;
478
-
479
- // ==========================================================================
480
- // Select/MultiSelect Field Options
481
- // ==========================================================================
482
- if (meta.options !== undefined) options.options = meta.options;
483
- // Note: minSelections/maxSelections could be mapped to minItems/maxItems
484
-
485
- // ==========================================================================
486
- // Rich Text Field Options
487
- // ==========================================================================
488
- if (meta.allowedBlocks !== undefined) options.allowedBlocks = meta.allowedBlocks;
489
- if (meta.allowedMarks !== undefined) options.allowedMarks = meta.allowedMarks;
490
-
491
- // ==========================================================================
492
- // Taxonomy Field Options (tags/category)
493
- // ==========================================================================
494
- if (meta.taxonomyId !== undefined) options.taxonomyId = meta.taxonomyId;
495
- if (meta.allowCreate !== undefined) options.allowCreate = meta.allowCreate;
496
- if (meta.maxTags !== undefined) options.maxTags = meta.maxTags;
497
- if (meta.minTags !== undefined) options.minTags = meta.minTags;
498
- if (meta.allowMultiple !== undefined) options.allowMultiple = meta.allowMultiple;
499
-
500
- return Object.keys(options).length > 0 ? options : undefined;
501
- }
@@ -1,169 +0,0 @@
1
- /**
2
- * Code-Only Schema System
3
- *
4
- * This module provides type-safe content type definitions using Convex validators.
5
- * Types are automatically inferred via Convex's native `Infer<typeof validator>` pattern.
6
- *
7
- * ## Quick Start
8
- *
9
- * ```typescript
10
- * import { v, Infer } from "convex/values";
11
- * import { defineContentType, InferContentType } from "@convex-cms/core";
12
- *
13
- * // Define a content type with a Convex validator
14
- * export const blogPost = defineContentType({
15
- * name: "blog_post",
16
- * validator: v.object({
17
- * title: v.string(),
18
- * content: v.string(),
19
- * publishedAt: v.optional(v.number()),
20
- * }),
21
- * meta: {
22
- * displayName: "Blog Post",
23
- * titleField: "title",
24
- * },
25
- * });
26
- *
27
- * // Type is automatically inferred
28
- * type BlogPostData = InferContentType<typeof blogPost>;
29
- * // { title: string; content: string; publishedAt?: number }
30
- * ```
31
- *
32
- * ## Creating a Schema
33
- *
34
- * ```typescript
35
- * import { createContentSchema, InferSchema } from "@convex-cms/core";
36
- *
37
- * // Combine multiple content types into a schema
38
- * export const contentSchema = createContentSchema({
39
- * blogPost,
40
- * author,
41
- * product,
42
- * });
43
- *
44
- * // Infer all types at once
45
- * export type ContentTypes = InferSchema<typeof contentSchema.definitions>;
46
- * // {
47
- * // blog_post: { title: string; content: string; ... };
48
- * // author: { name: string; bio?: string; ... };
49
- * // product: { name: string; price: number; ... };
50
- * // }
51
- * ```
52
- *
53
- * ## Using with CMS Client
54
- *
55
- * ```typescript
56
- * import { createCmsClient } from "@convex-cms/core";
57
- * import { components } from "./_generated/api";
58
- * import { contentSchema } from "./schema";
59
- *
60
- * // Create a schema-aware CMS client
61
- * export const cms = createCmsClient(components.convexCms, {
62
- * schema: contentSchema,
63
- * // ... other options
64
- * });
65
- *
66
- * // Now get() returns typed data
67
- * const post = await cms.contentEntries.get<"blog_post">(ctx, id);
68
- * post.data.title // ✅ string - fully typed
69
- * post.data.typo // ❌ Error: Property 'typo' does not exist
70
- * ```
71
- *
72
- * @module
73
- */
74
-
75
- // =============================================================================
76
- // Core Functions
77
- // =============================================================================
78
-
79
- export { defineContentType, createContentSchema, toFieldDefinitions } from "./defineContentType.js";
80
-
81
- // =============================================================================
82
- // Types
83
- // =============================================================================
84
-
85
- // Core definition types
86
- export type {
87
- ContentTypeConfig,
88
- ContentTypeDefinition,
89
- ContentTypeMeta,
90
- FieldMeta,
91
- FieldRenderAs,
92
- } from "./types.js";
93
-
94
- // Type inference utilities
95
- export type {
96
- InferContentType,
97
- InferSchema,
98
- ContentSchema,
99
- SchemaContentTypeNames,
100
- SchemaContentType,
101
- ContentTypeFieldNames,
102
- } from "./types.js";
103
-
104
- // Schema instance type
105
- export type { ContentSchemaInstance, DatabaseFieldDefinition } from "./defineContentType.js";
106
-
107
- // Runtime utilities
108
- export { isContentTypeDefinition } from "./types.js";
109
-
110
- // =============================================================================
111
- // Typed Client Factory
112
- // =============================================================================
113
-
114
- export { createTypedCmsClient, TypedContentEntriesApiImpl } from "./typedClient.js";
115
-
116
- // =============================================================================
117
- // Schema Drift Detection
118
- // =============================================================================
119
-
120
- export {
121
- detectSchemaDrift,
122
- formatDriftReport,
123
- hasErrors,
124
- filterReportByContentTypes,
125
- } from "./schemaDrift.js";
126
-
127
- export type {
128
- DriftSeverity,
129
- DriftType,
130
- DriftIssue,
131
- DriftSummary,
132
- SchemaDriftReport,
133
- DetectDriftOptions,
134
- } from "./schemaDrift.js";
135
-
136
- // =============================================================================
137
- // Type Code Generation
138
- // =============================================================================
139
-
140
- export {
141
- generateTypesFromDatabase,
142
- generateTypesFromDefinitions,
143
- validateGeneratedCode,
144
- } from "./codegen.js";
145
-
146
- export type {
147
- CodegenOptions,
148
- CodegenResult,
149
- } from "./codegen.js";
150
-
151
- // =============================================================================
152
- // Typed Client Types
153
- // =============================================================================
154
-
155
- // Typed content entry types
156
- export type {
157
- TypedContentEntry,
158
- TypedPaginationResult,
159
- TypedContentEntriesApi,
160
- TypedCreateEntryOptions,
161
- TypedUpdateEntryOptions,
162
- TypedListEntriesOptions,
163
- SchemaDataType,
164
- ValidContentTypeName,
165
- HasContentType,
166
- GetContentTypeDefinition,
167
- TypedCmsClientConfig,
168
- TypedCmsClient,
169
- } from "./typedClient.js";