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.
- package/admin-dist/nitro.json +15 -0
- package/admin-dist/public/assets/CmsEmptyState-CRswfTzk.js +5 -0
- package/admin-dist/public/assets/CmsPageHeader-CirpXndm.js +1 -0
- package/admin-dist/public/assets/CmsStatusBadge-CbEUpQu-.js +1 -0
- package/admin-dist/public/assets/CmsToolbar-BI2nZOXp.js +1 -0
- package/admin-dist/public/assets/ContentEntryEditor-CBeCyK_m.js +4 -0
- package/admin-dist/public/assets/ErrorState-BIVaWmom.js +1 -0
- package/admin-dist/public/assets/TaxonomyFilter-ChaY6Y_x.js +1 -0
- package/admin-dist/public/assets/_contentTypeId-DQ8k_Rvw.js +1 -0
- package/admin-dist/public/assets/_entryId-CKU_glsK.js +1 -0
- package/admin-dist/public/assets/alert-BXjTqrwQ.js +1 -0
- package/admin-dist/public/assets/badge-hvUOzpVZ.js +1 -0
- package/admin-dist/public/assets/circle-check-big-CF_pR17r.js +1 -0
- package/admin-dist/public/assets/command-DU82cJlt.js +1 -0
- package/admin-dist/public/assets/content-_LXl3pp7.js +1 -0
- package/admin-dist/public/assets/content-types-KjxaXGxY.js +2 -0
- package/admin-dist/public/assets/globals-CS6BZ0zp.css +1 -0
- package/admin-dist/public/assets/index-DNGIZHL-.js +1 -0
- package/admin-dist/public/assets/label-KNtpL71g.js +1 -0
- package/admin-dist/public/assets/link-2-Bw2aI4V4.js +1 -0
- package/admin-dist/public/assets/list-sYepHjt_.js +1 -0
- package/admin-dist/public/assets/main-CKj5yfEi.js +97 -0
- package/admin-dist/public/assets/media-Bkrkffm7.js +1 -0
- package/admin-dist/public/assets/new._contentTypeId-C3LstjNs.js +1 -0
- package/admin-dist/public/assets/plus-DUn8v_Xf.js +1 -0
- package/admin-dist/public/assets/rotate-ccw-DJEoHcRI.js +1 -0
- package/admin-dist/public/assets/scroll-area-DfIlT0in.js +1 -0
- package/admin-dist/public/assets/search-MuAUDJKR.js +1 -0
- package/admin-dist/public/assets/select-BD29IXCI.js +1 -0
- package/admin-dist/public/assets/settings-DmMyn_6A.js +1 -0
- package/admin-dist/public/assets/switch-h3Rrnl5i.js +1 -0
- package/admin-dist/public/assets/tabs-imc8h-Dp.js +1 -0
- package/admin-dist/public/assets/taxonomies-dAsrT65H.js +1 -0
- package/admin-dist/public/assets/textarea-BTy7nwzR.js +1 -0
- package/admin-dist/public/assets/trash-SAWKZZHv.js +1 -0
- package/admin-dist/public/assets/triangle-alert-E52Vfeuh.js +1 -0
- package/admin-dist/public/assets/useBreadcrumbLabel-BECBMCzM.js +1 -0
- package/admin-dist/public/assets/usePermissions-Basjs9BT.js +1 -0
- package/admin-dist/public/favicon.ico +0 -0
- package/admin-dist/server/_chunks/_libs/@date-fns/tz.mjs +217 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/core.mjs +719 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/dom.mjs +622 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/react-dom.mjs +292 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/utils.mjs +320 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/number.mjs +6 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/primitive.mjs +11 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-arrow.mjs +23 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-avatar.mjs +119 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-checkbox.mjs +270 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-collection.mjs +69 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-compose-refs.mjs +39 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-context.mjs +137 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dialog.mjs +325 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-direction.mjs +9 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dismissable-layer.mjs +210 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dropdown-menu.mjs +253 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-guards.mjs +29 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-scope.mjs +206 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-id.mjs +14 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-label.mjs +23 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-menu.mjs +812 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-popover.mjs +300 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-popper.mjs +286 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-portal.mjs +16 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-presence.mjs +128 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-primitive.mjs +141 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-roving-focus.mjs +224 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-scroll-area.mjs +721 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-select.mjs +1163 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-separator.mjs +28 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-slot.mjs +601 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-switch.mjs +152 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-tabs.mjs +189 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-callback-ref.mjs +11 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-controllable-state.mjs +69 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-effect-event.mjs +1 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-escape-keydown.mjs +17 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-is-hydrated.mjs +15 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-layout-effect.mjs +6 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-previous.mjs +14 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-size.mjs +39 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-visually-hidden.mjs +33 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/history.mjs +409 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +1711 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/react-store.mjs +56 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +4829 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/store.mjs +134 -0
- package/admin-dist/server/_chunks/_libs/react-dom.mjs +10781 -0
- package/admin-dist/server/_chunks/_libs/react.mjs +513 -0
- package/admin-dist/server/_libs/aria-hidden.mjs +122 -0
- package/admin-dist/server/_libs/class-variance-authority.mjs +44 -0
- package/admin-dist/server/_libs/clsx.mjs +16 -0
- package/admin-dist/server/_libs/cmdk.mjs +315 -0
- package/admin-dist/server/_libs/convex.mjs +4841 -0
- package/admin-dist/server/_libs/cookie-es.mjs +58 -0
- package/admin-dist/server/_libs/croner.mjs +1 -0
- package/admin-dist/server/_libs/crossws.mjs +1 -0
- package/admin-dist/server/_libs/date-fns.mjs +1716 -0
- package/admin-dist/server/_libs/detect-node-es.mjs +1 -0
- package/admin-dist/server/_libs/get-nonce.mjs +9 -0
- package/admin-dist/server/_libs/h3-v2.mjs +277 -0
- package/admin-dist/server/_libs/h3.mjs +401 -0
- package/admin-dist/server/_libs/hookable.mjs +1 -0
- package/admin-dist/server/_libs/isbot.mjs +20 -0
- package/admin-dist/server/_libs/lucide-react.mjs +850 -0
- package/admin-dist/server/_libs/ohash.mjs +1 -0
- package/admin-dist/server/_libs/react-day-picker.mjs +2201 -0
- package/admin-dist/server/_libs/react-remove-scroll-bar.mjs +82 -0
- package/admin-dist/server/_libs/react-remove-scroll.mjs +328 -0
- package/admin-dist/server/_libs/react-style-singleton.mjs +69 -0
- package/admin-dist/server/_libs/rou3.mjs +8 -0
- package/admin-dist/server/_libs/seroval-plugins.mjs +58 -0
- package/admin-dist/server/_libs/seroval.mjs +1765 -0
- package/admin-dist/server/_libs/srvx.mjs +719 -0
- package/admin-dist/server/_libs/tailwind-merge.mjs +3010 -0
- package/admin-dist/server/_libs/tiny-invariant.mjs +12 -0
- package/admin-dist/server/_libs/tiny-warning.mjs +5 -0
- package/admin-dist/server/_libs/tslib.mjs +39 -0
- package/admin-dist/server/_libs/ufo.mjs +54 -0
- package/admin-dist/server/_libs/unctx.mjs +1 -0
- package/admin-dist/server/_libs/unstorage.mjs +1 -0
- package/admin-dist/server/_libs/use-callback-ref.mjs +66 -0
- package/admin-dist/server/_libs/use-sidecar.mjs +106 -0
- package/admin-dist/server/_libs/use-sync-external-store.mjs +139 -0
- package/admin-dist/server/_libs/zod.mjs +4223 -0
- package/admin-dist/server/_ssr/CmsEmptyState-DU7-7-mV.mjs +290 -0
- package/admin-dist/server/_ssr/CmsPageHeader-CseW0AHm.mjs +24 -0
- package/admin-dist/server/_ssr/CmsStatusBadge-B_pi4KCp.mjs +127 -0
- package/admin-dist/server/_ssr/CmsToolbar-X75ex6ek.mjs +49 -0
- package/admin-dist/server/_ssr/ContentEntryEditor-CepusRsA.mjs +3720 -0
- package/admin-dist/server/_ssr/ErrorState-cI-bKLez.mjs +89 -0
- package/admin-dist/server/_ssr/TaxonomyFilter-Bwrq0-cz.mjs +188 -0
- package/admin-dist/server/_ssr/_contentTypeId-BqYKEcLr.mjs +379 -0
- package/admin-dist/server/_ssr/_entryId-CRfnqeDf.mjs +161 -0
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BwDlABVk.mjs +4 -0
- package/admin-dist/server/_ssr/alert-CVt45UUP.mjs +92 -0
- package/admin-dist/server/_ssr/badge-6BsP37vG.mjs +125 -0
- package/admin-dist/server/_ssr/command-fy8epIKf.mjs +128 -0
- package/admin-dist/server/_ssr/config.server-D7JHDcDv.mjs +117 -0
- package/admin-dist/server/_ssr/content-B5RhL7uW.mjs +532 -0
- package/admin-dist/server/_ssr/content-types-BIOqCQYN.mjs +1166 -0
- package/admin-dist/server/_ssr/index-DHSHDPt1.mjs +193 -0
- package/admin-dist/server/_ssr/index.mjs +1275 -0
- package/admin-dist/server/_ssr/label-C8Dko1j7.mjs +22 -0
- package/admin-dist/server/_ssr/media-CSx3XttC.mjs +1832 -0
- package/admin-dist/server/_ssr/new._contentTypeId-DzanEZQM.mjs +144 -0
- package/admin-dist/server/_ssr/router-DDWcF-kt.mjs +1556 -0
- package/admin-dist/server/_ssr/scroll-area-bjPYwhXN.mjs +59 -0
- package/admin-dist/server/_ssr/select-BUhDDf4T.mjs +142 -0
- package/admin-dist/server/_ssr/settings-DAsxnw2q.mjs +348 -0
- package/admin-dist/server/_ssr/start-HYkvq4Ni.mjs +4 -0
- package/admin-dist/server/_ssr/switch-BgyRtQ1Z.mjs +31 -0
- package/admin-dist/server/_ssr/tabs-DzMdRB1A.mjs +628 -0
- package/admin-dist/server/_ssr/taxonomies-C8j8g5Q5.mjs +915 -0
- package/admin-dist/server/_ssr/textarea-9jNeYJSc.mjs +18 -0
- package/admin-dist/server/_ssr/trash-DYMxwhZB.mjs +291 -0
- package/admin-dist/server/_ssr/useBreadcrumbLabel-FNSAr2Ha.mjs +16 -0
- package/admin-dist/server/_ssr/usePermissions-BJGGahrJ.mjs +68 -0
- package/admin-dist/server/favicon.ico +0 -0
- package/admin-dist/server/index.mjs +627 -0
- package/dist/cli/index.js +0 -0
- package/dist/client/admin-config.d.ts +0 -1
- package/dist/client/admin-config.d.ts.map +1 -1
- package/dist/client/admin-config.js +0 -1
- package/dist/client/admin-config.js.map +1 -1
- package/dist/client/adminApi.d.ts.map +1 -1
- package/dist/client/agentTools.d.ts +1237 -135
- package/dist/client/agentTools.d.ts.map +1 -1
- package/dist/client/agentTools.js +33 -9
- package/dist/client/agentTools.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +9 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/mediaAssets.d.ts +35 -0
- package/dist/component/mediaAssets.d.ts.map +1 -1
- package/dist/component/mediaAssets.js +81 -0
- package/dist/component/mediaAssets.js.map +1 -1
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +2 -1
- package/dist/test.js.map +1 -1
- package/package.json +9 -5
- package/dist/component/auditLog.d.ts +0 -410
- package/dist/component/auditLog.d.ts.map +0 -1
- package/dist/component/auditLog.js +0 -607
- package/dist/component/auditLog.js.map +0 -1
- package/dist/component/types.d.ts +0 -4
- package/dist/component/types.d.ts.map +0 -1
- package/dist/component/types.js +0 -2
- package/dist/component/types.js.map +0 -1
- package/src/cli/commands/admin.ts +0 -104
- package/src/cli/index.ts +0 -21
- package/src/cli/utils/detectConvexUrl.ts +0 -54
- package/src/cli/utils/openBrowser.ts +0 -16
- package/src/client/admin-config.ts +0 -138
- package/src/client/adminApi.ts +0 -942
- package/src/client/agentTools.ts +0 -1311
- package/src/client/argTypes.ts +0 -316
- package/src/client/field-types.ts +0 -187
- package/src/client/index.ts +0 -1301
- package/src/client/queryBuilder.ts +0 -1100
- package/src/client/schema/codegen.ts +0 -500
- package/src/client/schema/defineContentType.ts +0 -501
- package/src/client/schema/index.ts +0 -169
- package/src/client/schema/schemaDrift.ts +0 -574
- package/src/client/schema/typedClient.ts +0 -688
- package/src/client/schema/types.ts +0 -666
- package/src/client/types.ts +0 -723
- package/src/client/workflows.ts +0 -141
- package/src/client/wrapper.ts +0 -4304
- package/src/component/_generated/api.ts +0 -140
- package/src/component/_generated/component.ts +0 -5029
- package/src/component/_generated/dataModel.ts +0 -60
- package/src/component/_generated/server.ts +0 -156
- package/src/component/authorization.ts +0 -647
- package/src/component/authorizationHooks.ts +0 -668
- package/src/component/bulkOperations.ts +0 -687
- package/src/component/contentEntries.ts +0 -1976
- package/src/component/contentEntryMutations.ts +0 -1223
- package/src/component/contentEntryValidation.ts +0 -707
- package/src/component/contentLock.ts +0 -550
- package/src/component/contentTypeMigration.ts +0 -1064
- package/src/component/contentTypeMutations.ts +0 -969
- package/src/component/contentTypes.ts +0 -346
- package/src/component/convex.config.ts +0 -44
- package/src/component/documentTypes.ts +0 -240
- package/src/component/eventEmitter.ts +0 -485
- package/src/component/exportImport.ts +0 -1169
- package/src/component/index.ts +0 -491
- package/src/component/lib/deepReferenceResolver.ts +0 -999
- package/src/component/lib/errors.ts +0 -816
- package/src/component/lib/index.ts +0 -145
- package/src/component/lib/mediaReferenceResolver.ts +0 -495
- package/src/component/lib/metadataExtractor.ts +0 -792
- package/src/component/lib/mutationAuth.ts +0 -199
- package/src/component/lib/queries.ts +0 -79
- package/src/component/lib/ragContentChunker.ts +0 -1371
- package/src/component/lib/referenceResolver.ts +0 -430
- package/src/component/lib/slugGenerator.ts +0 -262
- package/src/component/lib/slugUniqueness.ts +0 -333
- package/src/component/lib/softDelete.ts +0 -44
- package/src/component/localeFallbackChain.ts +0 -673
- package/src/component/localeFields.ts +0 -896
- package/src/component/mediaAssetMutations.ts +0 -725
- package/src/component/mediaAssets.ts +0 -932
- package/src/component/mediaFolderMutations.ts +0 -1046
- package/src/component/mediaUploadMutations.ts +0 -224
- package/src/component/mediaVariantMutations.ts +0 -900
- package/src/component/mediaVariants.ts +0 -793
- package/src/component/ragContentIndexer.ts +0 -1067
- package/src/component/rateLimitHooks.ts +0 -572
- package/src/component/roles.ts +0 -1360
- package/src/component/scheduledPublish.ts +0 -358
- package/src/component/schema.ts +0 -617
- package/src/component/taxonomies.ts +0 -949
- package/src/component/taxonomyMutations.ts +0 -1210
- package/src/component/trash.ts +0 -724
- package/src/component/userContext.ts +0 -898
- package/src/component/validation.ts +0 -1388
- package/src/component/validators.ts +0 -949
- package/src/component/versionMutations.ts +0 -392
- package/src/component/webhookTrigger.ts +0 -1922
- package/src/react/index.ts +0 -898
- package/src/test.ts +0 -1580
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Version Mutation Functions
|
|
3
|
-
*
|
|
4
|
-
* Provides internal mutation functions for creating and managing version snapshots.
|
|
5
|
-
* These functions are used internally by the CMS to maintain version history
|
|
6
|
-
* for content entries.
|
|
7
|
-
*
|
|
8
|
-
* Version snapshots capture:
|
|
9
|
-
* - Complete content data at a point in time
|
|
10
|
-
* - Slug and status when the snapshot was created
|
|
11
|
-
* - Metadata about who created it and why
|
|
12
|
-
* - Whether the snapshot represents a published version
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { v } from "convex/values";
|
|
16
|
-
import { isDeleted } from "./lib/softDelete.js";
|
|
17
|
-
import { mutation, internalMutation } from "./_generated/server.js";
|
|
18
|
-
import {
|
|
19
|
-
createVersionSnapshotArgs,
|
|
20
|
-
contentVersionDoc,
|
|
21
|
-
contentEntryDoc,
|
|
22
|
-
rollbackVersionArgs,
|
|
23
|
-
} from "./validators.js";
|
|
24
|
-
import {
|
|
25
|
-
versionEntryNotFound,
|
|
26
|
-
versionEntryDeleted,
|
|
27
|
-
versionNotFound,
|
|
28
|
-
versionMismatch,
|
|
29
|
-
versionRollbackFailed,
|
|
30
|
-
internalError,
|
|
31
|
-
} from "./lib/errors.js";
|
|
32
|
-
|
|
33
|
-
// =============================================================================
|
|
34
|
-
// Create Version Snapshot (Internal)
|
|
35
|
-
// =============================================================================
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Internal mutation to create a version snapshot of a content entry.
|
|
39
|
-
*
|
|
40
|
-
* This function captures the complete state of a content entry at a specific
|
|
41
|
-
* point in time, storing it in the contentVersions table. Snapshots are used
|
|
42
|
-
* for:
|
|
43
|
-
*
|
|
44
|
-
* - **Version History**: Track changes over time for audit and review
|
|
45
|
-
* - **Rollback Support**: Allow reverting to previous versions
|
|
46
|
-
* - **Publishing Records**: Mark which versions were published
|
|
47
|
-
* - **Content Comparison**: Enable diff/compare between versions
|
|
48
|
-
*
|
|
49
|
-
* The snapshot includes:
|
|
50
|
-
* - versionNumber: Current version number from the entry
|
|
51
|
-
* - data: Complete content data snapshot
|
|
52
|
-
* - slug: Slug at the time of snapshot
|
|
53
|
-
* - status: Entry status when snapshot was created
|
|
54
|
-
* - changeDescription: Optional description of changes
|
|
55
|
-
* - createdBy: User who triggered the snapshot
|
|
56
|
-
* - wasPublished: Whether this is a published version
|
|
57
|
-
* - publishedAt: Timestamp if this is a published version
|
|
58
|
-
*
|
|
59
|
-
* @param entryId - The ID of the content entry to snapshot
|
|
60
|
-
* @param changeDescription - Optional description of what changed
|
|
61
|
-
* @param createdBy - User ID for audit trail
|
|
62
|
-
* @param wasPublished - Whether this snapshot represents a publish action
|
|
63
|
-
*
|
|
64
|
-
* @returns The created version snapshot document
|
|
65
|
-
*
|
|
66
|
-
* @throws Error if the entry does not exist
|
|
67
|
-
* @throws Error if the entry has been soft-deleted
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```typescript
|
|
71
|
-
* // Called internally before a destructive operation
|
|
72
|
-
* await ctx.runMutation(internal.versionMutations.createVersionSnapshot, {
|
|
73
|
-
* entryId: entryId,
|
|
74
|
-
* changeDescription: "Pre-update snapshot",
|
|
75
|
-
* createdBy: userId,
|
|
76
|
-
* });
|
|
77
|
-
*
|
|
78
|
-
* // Called during publish to mark as published version
|
|
79
|
-
* await ctx.runMutation(internal.versionMutations.createVersionSnapshot, {
|
|
80
|
-
* entryId: entryId,
|
|
81
|
-
* changeDescription: "Published to production",
|
|
82
|
-
* createdBy: userId,
|
|
83
|
-
* wasPublished: true,
|
|
84
|
-
* });
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
export const createVersionSnapshot = internalMutation({
|
|
88
|
-
args: createVersionSnapshotArgs.fields,
|
|
89
|
-
returns: contentVersionDoc,
|
|
90
|
-
handler: async (ctx, args) => {
|
|
91
|
-
const {
|
|
92
|
-
entryId,
|
|
93
|
-
changeDescription,
|
|
94
|
-
createdBy,
|
|
95
|
-
wasPublished = false,
|
|
96
|
-
} = args;
|
|
97
|
-
|
|
98
|
-
const entry = await ctx.db.get(entryId);
|
|
99
|
-
|
|
100
|
-
if (!entry) {
|
|
101
|
-
throw versionEntryNotFound((entryId as unknown) as string);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Do not allow snapshots of deleted entries
|
|
105
|
-
if (isDeleted(entry)) {
|
|
106
|
-
throw versionEntryDeleted((entryId as unknown) as string);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const now = Date.now();
|
|
110
|
-
|
|
111
|
-
// Create the version snapshot with complete entry state
|
|
112
|
-
const versionId = await ctx.db.insert("contentVersions", {
|
|
113
|
-
entryId,
|
|
114
|
-
versionNumber: entry.version,
|
|
115
|
-
data: entry.data,
|
|
116
|
-
slug: entry.slug,
|
|
117
|
-
status: entry.status,
|
|
118
|
-
changeDescription,
|
|
119
|
-
createdBy,
|
|
120
|
-
wasPublished,
|
|
121
|
-
publishedAt: wasPublished ? now : undefined,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// Retrieve and return the created version
|
|
125
|
-
const version = await ctx.db.get(versionId);
|
|
126
|
-
|
|
127
|
-
if (!version) {
|
|
128
|
-
throw internalError("Failed to create version snapshot");
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return version;
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// =============================================================================
|
|
136
|
-
// Check for Duplicate Version (Internal Helper)
|
|
137
|
-
// =============================================================================
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Internal mutation to check if a version snapshot already exists.
|
|
141
|
-
*
|
|
142
|
-
* This can be used before creating a snapshot to avoid duplicates,
|
|
143
|
-
* particularly useful when the same version might be snapshotted
|
|
144
|
-
* multiple times (e.g., multiple publishes without content changes).
|
|
145
|
-
*
|
|
146
|
-
* @param entryId - The content entry ID
|
|
147
|
-
* @param versionNumber - The version number to check for
|
|
148
|
-
*
|
|
149
|
-
* @returns true if a version with this number exists, false otherwise
|
|
150
|
-
*/
|
|
151
|
-
export const versionExists = internalMutation({
|
|
152
|
-
args: {
|
|
153
|
-
entryId: v.id("contentEntries"),
|
|
154
|
-
versionNumber: v.number(),
|
|
155
|
-
},
|
|
156
|
-
returns: v.boolean(),
|
|
157
|
-
handler: async (ctx, args) => {
|
|
158
|
-
const { entryId, versionNumber } = args;
|
|
159
|
-
|
|
160
|
-
const existing = await ctx.db
|
|
161
|
-
.query("contentVersions")
|
|
162
|
-
.withIndex("by_entry_and_version", (q) =>
|
|
163
|
-
q.eq("entryId", entryId).eq("versionNumber", versionNumber),
|
|
164
|
-
)
|
|
165
|
-
.first();
|
|
166
|
-
|
|
167
|
-
return existing !== null;
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// =============================================================================
|
|
172
|
-
// Create Snapshot If Changed (Internal Helper)
|
|
173
|
-
// =============================================================================
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Internal mutation to create a version snapshot only if the version
|
|
177
|
-
* doesn't already exist. This is a convenience function that combines
|
|
178
|
-
* the existence check and creation.
|
|
179
|
-
*
|
|
180
|
-
* Useful for scenarios where you want to snapshot but only if the
|
|
181
|
-
* current version hasn't been captured yet (e.g., auto-save scenarios).
|
|
182
|
-
*
|
|
183
|
-
* @param entryId - The content entry ID
|
|
184
|
-
* @param changeDescription - Optional description of changes
|
|
185
|
-
* @param createdBy - User ID for audit trail
|
|
186
|
-
* @param wasPublished - Whether this is a published version
|
|
187
|
-
*
|
|
188
|
-
* @returns The version snapshot (new or existing), or null if entry not found
|
|
189
|
-
*/
|
|
190
|
-
export const createVersionSnapshotIfNotExists = internalMutation({
|
|
191
|
-
args: createVersionSnapshotArgs.fields,
|
|
192
|
-
returns: v.union(contentVersionDoc, v.null()),
|
|
193
|
-
handler: async (ctx, args) => {
|
|
194
|
-
const {
|
|
195
|
-
entryId,
|
|
196
|
-
changeDescription,
|
|
197
|
-
createdBy,
|
|
198
|
-
wasPublished = false,
|
|
199
|
-
} = args;
|
|
200
|
-
|
|
201
|
-
const entry = await ctx.db.get(entryId);
|
|
202
|
-
|
|
203
|
-
if (!entry) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Do not process deleted entries
|
|
208
|
-
if (isDeleted(entry)) {
|
|
209
|
-
return null;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Check if this version already has a snapshot
|
|
213
|
-
const existing = await ctx.db
|
|
214
|
-
.query("contentVersions")
|
|
215
|
-
.withIndex("by_entry_and_version", (q) =>
|
|
216
|
-
q.eq("entryId", entryId).eq("versionNumber", entry.version),
|
|
217
|
-
)
|
|
218
|
-
.first();
|
|
219
|
-
|
|
220
|
-
// Return existing if found
|
|
221
|
-
if (existing) {
|
|
222
|
-
return existing;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const now = Date.now();
|
|
226
|
-
|
|
227
|
-
// Create new snapshot
|
|
228
|
-
const versionId = await ctx.db.insert("contentVersions", {
|
|
229
|
-
entryId,
|
|
230
|
-
versionNumber: entry.version,
|
|
231
|
-
data: entry.data,
|
|
232
|
-
slug: entry.slug,
|
|
233
|
-
status: entry.status,
|
|
234
|
-
changeDescription,
|
|
235
|
-
createdBy,
|
|
236
|
-
wasPublished,
|
|
237
|
-
publishedAt: wasPublished ? now : undefined,
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
const version = await ctx.db.get(versionId);
|
|
241
|
-
|
|
242
|
-
return version ?? null;
|
|
243
|
-
},
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// =============================================================================
|
|
247
|
-
// Rollback Version (Public)
|
|
248
|
-
// =============================================================================
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Mutation to restore a content entry to a previous version.
|
|
252
|
-
*
|
|
253
|
-
* This is the core rollback functionality that allows users to revert content
|
|
254
|
-
* to any previously captured version state. Importantly, rollback is a
|
|
255
|
-
* **non-destructive operation** - it creates a new version with the restored
|
|
256
|
-
* content rather than actually "going back in time."
|
|
257
|
-
*
|
|
258
|
-
* ## How Rollback Works
|
|
259
|
-
*
|
|
260
|
-
* 1. **Validate**: Ensure the entry and target version exist and are accessible
|
|
261
|
-
* 2. **Snapshot Current State**: Create a version snapshot of the current state
|
|
262
|
-
* before making any changes (preserves ability to "undo" the rollback)
|
|
263
|
-
* 3. **Restore Content**: Update the entry's `data` and `slug` from the target version
|
|
264
|
-
* 4. **Increment Version**: The entry's version number is incremented (normal update behavior)
|
|
265
|
-
* 5. **Create Rollback Snapshot**: Create a new version snapshot documenting the rollback
|
|
266
|
-
*
|
|
267
|
-
* ## What Gets Restored
|
|
268
|
-
*
|
|
269
|
-
* - **data**: The complete content data object from the target version
|
|
270
|
-
* - **slug**: The URL-friendly slug from the target version
|
|
271
|
-
*
|
|
272
|
-
* ## What Does NOT Get Restored
|
|
273
|
-
*
|
|
274
|
-
* - **status**: The current publish status is preserved (a rollback doesn't
|
|
275
|
-
* unpublish or publish content automatically)
|
|
276
|
-
* - **scheduledPublishAt**: Scheduling is not affected
|
|
277
|
-
* - **Publishing timestamps**: firstPublishedAt/lastPublishedAt are preserved
|
|
278
|
-
*
|
|
279
|
-
* ## Use Cases
|
|
280
|
-
*
|
|
281
|
-
* - **Accidental Changes**: Undo unwanted edits by restoring to a known good state
|
|
282
|
-
* - **Content Review**: Compare and restore to previously approved versions
|
|
283
|
-
* - **A/B Testing**: Switch between content variants by rolling back
|
|
284
|
-
* - **Emergency Fixes**: Quickly revert problematic changes in production
|
|
285
|
-
*
|
|
286
|
-
* @param entryId - The ID of the content entry to roll back
|
|
287
|
-
* @param versionNumber - The version number to restore to
|
|
288
|
-
* @param updatedBy - Optional user ID for audit trail
|
|
289
|
-
*
|
|
290
|
-
* @returns The updated content entry with restored content
|
|
291
|
-
*
|
|
292
|
-
* @throws Error if the entry does not exist
|
|
293
|
-
* @throws Error if the entry has been soft-deleted
|
|
294
|
-
* @throws Error if the target version does not exist
|
|
295
|
-
* @throws Error if the target version doesn't belong to this entry
|
|
296
|
-
*
|
|
297
|
-
* @example
|
|
298
|
-
* ```typescript
|
|
299
|
-
* // Restore entry to version 3
|
|
300
|
-
* const restored = await ctx.runMutation(api.versionMutations.rollbackVersion, {
|
|
301
|
-
* entryId: myEntryId,
|
|
302
|
-
* versionNumber: 3,
|
|
303
|
-
* updatedBy: currentUserId,
|
|
304
|
-
* });
|
|
305
|
-
*
|
|
306
|
-
* console.log(`Rolled back to version 3, now at version ${restored.version}`);
|
|
307
|
-
* // Note: The entry is now at a new version number (e.g., 7), not version 3
|
|
308
|
-
* // The content matches what was in version 3
|
|
309
|
-
* ```
|
|
310
|
-
*/
|
|
311
|
-
export const rollbackVersion = mutation({
|
|
312
|
-
args: rollbackVersionArgs.fields,
|
|
313
|
-
returns: contentEntryDoc,
|
|
314
|
-
handler: async (ctx, args) => {
|
|
315
|
-
const { entryId, versionNumber, updatedBy } = args;
|
|
316
|
-
|
|
317
|
-
// Step 1: Validate the entry exists and is not deleted
|
|
318
|
-
const entry = await ctx.db.get(entryId);
|
|
319
|
-
|
|
320
|
-
if (!entry) {
|
|
321
|
-
throw versionEntryNotFound((entryId as unknown) as string);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (isDeleted(entry)) {
|
|
325
|
-
throw versionEntryDeleted((entryId as unknown) as string);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Step 2: Retrieve the target version to restore
|
|
329
|
-
const targetVersion = await ctx.db
|
|
330
|
-
.query("contentVersions")
|
|
331
|
-
.withIndex("by_entry_and_version", (q) =>
|
|
332
|
-
q.eq("entryId", entryId).eq("versionNumber", versionNumber),
|
|
333
|
-
)
|
|
334
|
-
.first();
|
|
335
|
-
|
|
336
|
-
if (!targetVersion) {
|
|
337
|
-
throw versionNotFound((entryId as unknown) as string, versionNumber);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Security: Verify the version belongs to this entry (defensive check)
|
|
341
|
-
if (targetVersion.entryId !== entryId) {
|
|
342
|
-
throw versionMismatch(
|
|
343
|
-
(entryId as unknown) as string,
|
|
344
|
-
(targetVersion._id as unknown) as string,
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// Step 3: Snapshot the current state before rollback (for undo capability)
|
|
349
|
-
// This allows users to "undo" a rollback by rolling back to this snapshot
|
|
350
|
-
await ctx.db.insert("contentVersions", {
|
|
351
|
-
entryId,
|
|
352
|
-
versionNumber: entry.version,
|
|
353
|
-
data: entry.data,
|
|
354
|
-
slug: entry.slug,
|
|
355
|
-
status: entry.status,
|
|
356
|
-
changeDescription: `Pre-rollback snapshot (before restoring to version ${versionNumber})`,
|
|
357
|
-
createdBy: updatedBy,
|
|
358
|
-
wasPublished: false,
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// Step 4: Update the entry with restored content
|
|
362
|
-
// Note: We restore data and slug, but preserve the current status
|
|
363
|
-
const newVersionNumber = entry.version + 1;
|
|
364
|
-
|
|
365
|
-
await ctx.db.patch(entryId, {
|
|
366
|
-
data: targetVersion.data,
|
|
367
|
-
slug: targetVersion.slug,
|
|
368
|
-
version: newVersionNumber,
|
|
369
|
-
updatedBy,
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// Step 5: Create a snapshot documenting the rollback
|
|
373
|
-
await ctx.db.insert("contentVersions", {
|
|
374
|
-
entryId,
|
|
375
|
-
versionNumber: newVersionNumber,
|
|
376
|
-
data: targetVersion.data,
|
|
377
|
-
slug: targetVersion.slug,
|
|
378
|
-
status: entry.status, // Preserve current status
|
|
379
|
-
changeDescription: `Rolled back to version ${versionNumber}`,
|
|
380
|
-
createdBy: updatedBy,
|
|
381
|
-
wasPublished: false,
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
const updatedEntry = await ctx.db.get(entryId);
|
|
385
|
-
|
|
386
|
-
if (!updatedEntry) {
|
|
387
|
-
throw versionRollbackFailed((entryId as unknown) as string);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return updatedEntry;
|
|
391
|
-
},
|
|
392
|
-
});
|