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,485 +0,0 @@
1
- /**
2
- * Event Emitter Module
3
- *
4
- * Internal system to emit events on content changes (created, updated, published, deleted).
5
- * Events are stored in the cmsEvents table for async processing by external systems,
6
- * webhooks, audit logging, and other integrations.
7
- *
8
- * Design Philosophy:
9
- * - Events are emitted synchronously within the same transaction as mutations
10
- * - This ensures atomicity: if the mutation fails, no event is created
11
- * - Events are stored for later processing (not real-time pub/sub)
12
- * - Consumers can poll events or use Convex reactivity to process them
13
- *
14
- * Usage:
15
- * ```typescript
16
- * // In a mutation handler:
17
- * await emitEvent(ctx, {
18
- * eventType: "contentEntry.created",
19
- * resourceType: "contentEntry",
20
- * resourceId: entry._id.toString(),
21
- * action: "created",
22
- * payload: { slug: entry.slug, contentTypeName: "blog_post" },
23
- * userId: createdBy,
24
- * });
25
- * ```
26
- */
27
-
28
- import { v } from "convex/values";
29
- import { mutation, query, internalMutation, MutationCtx } from "./_generated/server.js";
30
- import {
31
- eventResourceTypeValidator,
32
- eventActionValidator,
33
- cmsEventDoc,
34
- } from "./validators.js";
35
-
36
- // =============================================================================
37
- // Event Types
38
- // =============================================================================
39
-
40
- /**
41
- * Resource types that can emit events.
42
- */
43
- export type EventResourceType =
44
- | "contentEntry"
45
- | "contentType"
46
- | "mediaAsset"
47
- | "mediaFolder";
48
-
49
- /**
50
- * Actions that can be performed on resources.
51
- */
52
- export type EventAction =
53
- | "created"
54
- | "updated"
55
- | "published"
56
- | "unpublished"
57
- | "deleted"
58
- | "restored"
59
- | "duplicated"
60
- | "scheduled";
61
-
62
- /**
63
- * Full event type combining resource and action.
64
- */
65
- export type EventType = `${EventResourceType}.${EventAction}`;
66
-
67
- /**
68
- * Payload structure for content entry events.
69
- */
70
- export interface ContentEntryEventPayload {
71
- slug: string;
72
- contentTypeName: string;
73
- contentTypeId: string;
74
- status: string;
75
- version: number;
76
- locale?: string;
77
- /** For duplicate events, the source entry ID */
78
- sourceEntryId?: string;
79
- /** For scheduled events, the scheduled publish time */
80
- scheduledPublishAt?: number;
81
- /** Change description if provided */
82
- changeDescription?: string;
83
- }
84
-
85
- /**
86
- * Payload structure for content type events.
87
- */
88
- export interface ContentTypeEventPayload {
89
- name: string;
90
- displayName: string;
91
- fieldCount: number;
92
- isActive: boolean;
93
- /** For update events, list of changed field names */
94
- changedFields?: string[];
95
- }
96
-
97
- /**
98
- * Payload structure for media asset events.
99
- */
100
- export interface MediaAssetEventPayload {
101
- name: string;
102
- mimeType: string;
103
- type: string;
104
- size: number;
105
- parentId?: string;
106
- path?: string;
107
- }
108
-
109
- /**
110
- * Payload structure for media folder events.
111
- */
112
- export interface MediaFolderEventPayload {
113
- name: string;
114
- path: string;
115
- parentId?: string;
116
- }
117
-
118
- /**
119
- * Union type for all event payloads.
120
- */
121
- export type EventPayload =
122
- | ContentEntryEventPayload
123
- | ContentTypeEventPayload
124
- | MediaAssetEventPayload
125
- | MediaFolderEventPayload;
126
-
127
- /**
128
- * Parameters for emitting an event.
129
- */
130
- export interface EmitEventParams {
131
- eventType: EventType;
132
- resourceType: EventResourceType;
133
- resourceId: string;
134
- action: EventAction;
135
- payload: EventPayload;
136
- userId?: string;
137
- correlationId?: string;
138
- metadata?: Record<string, unknown>;
139
- }
140
-
141
- /**
142
- * CMS Event document structure (as stored in the database).
143
- */
144
- export interface CMSEvent {
145
- _id: string;
146
- _creationTime: number;
147
- eventType: string;
148
- resourceType: EventResourceType;
149
- resourceId: string;
150
- action: EventAction;
151
- payload: EventPayload;
152
- userId?: string;
153
- processed: boolean;
154
- processedAt?: number;
155
- correlationId?: string;
156
- metadata?: Record<string, unknown>;
157
- }
158
-
159
- // =============================================================================
160
- // Internal Event Emission Helper
161
- // =============================================================================
162
-
163
- /**
164
- * Internal helper function to emit events within mutation handlers.
165
- *
166
- * This function inserts an event record into the cmsEvents table.
167
- * It's designed to be called from within other mutations to ensure
168
- * the event is part of the same atomic transaction.
169
- *
170
- * @param ctx - The mutation context from Convex
171
- * @param params - Event parameters
172
- * @returns The created event ID as a string
173
- */
174
- export async function emitEvent(
175
- ctx: MutationCtx,
176
- params: EmitEventParams
177
- ): Promise<string> {
178
- const {
179
- eventType,
180
- resourceType,
181
- resourceId,
182
- action,
183
- payload,
184
- userId,
185
- correlationId,
186
- metadata,
187
- } = params;
188
-
189
- const eventId = await ctx.db.insert("cmsEvents", {
190
- eventType,
191
- resourceType,
192
- resourceId,
193
- action,
194
- payload,
195
- userId,
196
- processed: false,
197
- correlationId,
198
- metadata,
199
- });
200
-
201
- return eventId;
202
- }
203
-
204
- // =============================================================================
205
- // Event Query Functions
206
- // =============================================================================
207
-
208
- /**
209
- * Query to list recent events with optional filtering.
210
- *
211
- * @param resourceType - Filter by resource type
212
- * @param action - Filter by action
213
- * @param processed - Filter by processed status
214
- * @param limit - Maximum number of events to return
215
- *
216
- * @returns Array of recent events
217
- */
218
- export const listEvents = query({
219
- args: {
220
- resourceType: v.optional(eventResourceTypeValidator),
221
- action: v.optional(eventActionValidator),
222
- processed: v.optional(v.boolean()),
223
- limit: v.optional(v.number()),
224
- cursor: v.optional(v.string()),
225
- },
226
- returns: v.object({
227
- events: v.array(cmsEventDoc),
228
- hasMore: v.boolean(),
229
- }),
230
- handler: async (ctx, args) => {
231
- const { resourceType, action, processed, limit = 50 } = args;
232
-
233
- // Collect and filter in memory for other filters
234
- // (In a production system, you might want more specific indexes)
235
- let events;
236
- if (processed !== undefined) {
237
- events = await ctx.db
238
- .query("cmsEvents")
239
- .withIndex("by_processed", (q) => q.eq("processed", processed))
240
- .order("desc")
241
- .take(limit * 2);
242
- } else {
243
- events = await ctx.db
244
- .query("cmsEvents")
245
- .order("desc")
246
- .take(limit * 2);
247
- }
248
-
249
- // Apply additional filters
250
- if (resourceType !== undefined) {
251
- events = events.filter((e) => e.resourceType === resourceType);
252
- }
253
- if (action !== undefined) {
254
- events = events.filter((e) => e.action === action);
255
- }
256
-
257
- // Limit results
258
- const limitedEvents = events.slice(0, limit);
259
- const hasMore = events.length > limit;
260
-
261
- return {
262
- events: limitedEvents,
263
- hasMore,
264
- };
265
- },
266
- });
267
-
268
- /**
269
- * Query to get events for a specific resource.
270
- *
271
- * @param resourceType - The resource type
272
- * @param resourceId - The resource ID
273
- * @param limit - Maximum number of events to return
274
- *
275
- * @returns Array of events for the resource
276
- */
277
- export const getResourceEvents = query({
278
- args: {
279
- resourceType: eventResourceTypeValidator,
280
- resourceId: v.string(),
281
- limit: v.optional(v.number()),
282
- },
283
- returns: v.array(cmsEventDoc),
284
- handler: async (ctx, args) => {
285
- const { resourceType, resourceId, limit = 50 } = args;
286
-
287
- const events = await ctx.db
288
- .query("cmsEvents")
289
- .withIndex("by_resource", (q) =>
290
- q.eq("resourceType", resourceType).eq("resourceId", resourceId)
291
- )
292
- .order("desc")
293
- .take(limit);
294
-
295
- return events;
296
- },
297
- });
298
-
299
- /**
300
- * Query to get unprocessed events for async processing.
301
- *
302
- * This is useful for building event processors that handle events
303
- * asynchronously (e.g., sending webhooks, updating search indexes).
304
- *
305
- * @param limit - Maximum number of events to return
306
- *
307
- * @returns Array of unprocessed events
308
- */
309
- export const getUnprocessedEvents = query({
310
- args: {
311
- limit: v.optional(v.number()),
312
- },
313
- returns: v.array(cmsEventDoc),
314
- handler: async (ctx, args) => {
315
- const { limit = 100 } = args;
316
-
317
- const events = await ctx.db
318
- .query("cmsEvents")
319
- .withIndex("by_processed", (q) => q.eq("processed", false))
320
- .order("asc") // Process oldest first
321
- .take(limit);
322
-
323
- return events;
324
- },
325
- });
326
-
327
- // =============================================================================
328
- // Event Mutation Functions
329
- // =============================================================================
330
-
331
- /**
332
- * Mutation to mark events as processed.
333
- *
334
- * This should be called by event processors after successfully
335
- * handling an event. This enables at-least-once processing semantics.
336
- *
337
- * @param eventIds - Array of event IDs to mark as processed
338
- *
339
- * @returns Count of events marked as processed
340
- */
341
- export const markEventsProcessed = mutation({
342
- args: {
343
- eventIds: v.array(v.id("cmsEvents")),
344
- },
345
- returns: v.object({
346
- processedCount: v.number(),
347
- }),
348
- handler: async (ctx, args) => {
349
- const { eventIds } = args;
350
- const now = Date.now();
351
- let processedCount = 0;
352
-
353
- for (const eventId of eventIds) {
354
- const event = await ctx.db.get(eventId);
355
- if (event && !event.processed) {
356
- await ctx.db.patch(eventId, {
357
- processed: true,
358
- processedAt: now,
359
- });
360
- processedCount++;
361
- }
362
- }
363
-
364
- return { processedCount };
365
- },
366
- });
367
-
368
- /**
369
- * Internal mutation to emit an event from scheduled functions.
370
- *
371
- * This is used by internal scheduled functions that need to emit events
372
- * but don't have direct access to the emitEvent helper.
373
- */
374
- export const internalEmitEvent = internalMutation({
375
- args: {
376
- eventType: v.string(),
377
- resourceType: v.union(
378
- v.literal("contentEntry"),
379
- v.literal("contentType"),
380
- v.literal("mediaAsset"),
381
- v.literal("mediaFolder")
382
- ),
383
- resourceId: v.string(),
384
- action: v.union(
385
- v.literal("created"),
386
- v.literal("updated"),
387
- v.literal("published"),
388
- v.literal("unpublished"),
389
- v.literal("deleted"),
390
- v.literal("restored"),
391
- v.literal("duplicated"),
392
- v.literal("scheduled")
393
- ),
394
- payload: v.any(),
395
- userId: v.optional(v.string()),
396
- correlationId: v.optional(v.string()),
397
- metadata: v.optional(v.any()),
398
- },
399
- returns: v.id("cmsEvents"),
400
- handler: async (ctx, args) => {
401
- const eventId = await ctx.db.insert("cmsEvents", {
402
- eventType: args.eventType,
403
- resourceType: args.resourceType,
404
- resourceId: args.resourceId,
405
- action: args.action,
406
- payload: args.payload,
407
- userId: args.userId,
408
- processed: false,
409
- correlationId: args.correlationId,
410
- metadata: args.metadata,
411
- });
412
-
413
- return eventId;
414
- },
415
- });
416
-
417
- /**
418
- * Mutation to clean up old processed events.
419
- *
420
- * Events older than the retention period are permanently deleted.
421
- * This helps prevent unbounded growth of the events table.
422
- *
423
- * @param retentionDays - Number of days to retain processed events (default: 30)
424
- *
425
- * @returns Count of events deleted
426
- */
427
- export const cleanupOldEvents = mutation({
428
- args: {
429
- retentionDays: v.optional(v.number()),
430
- },
431
- returns: v.object({
432
- deletedCount: v.number(),
433
- }),
434
- handler: async (ctx, args) => {
435
- const { retentionDays = 30 } = args;
436
- const cutoffTime = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
437
- let deletedCount = 0;
438
-
439
- // Get old processed events
440
- const oldEvents = await ctx.db
441
- .query("cmsEvents")
442
- .withIndex("by_processed", (q) => q.eq("processed", true))
443
- .filter((q) => q.lt(q.field("_creationTime"), cutoffTime))
444
- .take(1000); // Batch limit for safety
445
-
446
- for (const event of oldEvents) {
447
- await ctx.db.delete(event._id);
448
- deletedCount++;
449
- }
450
-
451
- return { deletedCount };
452
- },
453
- });
454
-
455
- // =============================================================================
456
- // Event Type Builders
457
- // =============================================================================
458
-
459
- /**
460
- * Helper function to build a content entry event type string.
461
- */
462
- export function contentEntryEventType(action: EventAction): EventType {
463
- return `contentEntry.${action}`;
464
- }
465
-
466
- /**
467
- * Helper function to build a content type event type string.
468
- */
469
- export function contentTypeEventType(action: EventAction): EventType {
470
- return `contentType.${action}`;
471
- }
472
-
473
- /**
474
- * Helper function to build a media asset event type string.
475
- */
476
- export function mediaAssetEventType(action: EventAction): EventType {
477
- return `mediaAsset.${action}`;
478
- }
479
-
480
- /**
481
- * Helper function to build a media folder event type string.
482
- */
483
- export function mediaFolderEventType(action: EventAction): EventType {
484
- return `mediaFolder.${action}`;
485
- }