create-vexcms 0.0.19 → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +93 -83
  3. package/dist/index.js +246 -81
  4. package/dist/index.mjs +30976 -0
  5. package/package.json +35 -15
  6. package/templates/base-nextjs/README.md +53 -205
  7. package/templates/base-nextjs/_env.example +7 -9
  8. package/templates/base-nextjs/_gitignore +41 -1
  9. package/templates/base-nextjs/convex/_generated/api.d.ts +6 -62
  10. package/templates/base-nextjs/convex/_generated/server.d.ts +19 -0
  11. package/templates/base-nextjs/convex/_generated/server.js +8 -0
  12. package/templates/base-nextjs/convex/auth/api.ts +49 -3
  13. package/templates/base-nextjs/convex/auth/db.ts +42 -300
  14. package/templates/base-nextjs/convex/auth/index.ts +11 -7
  15. package/templates/base-nextjs/convex/auth/options.ts +5 -29
  16. package/templates/base-nextjs/convex/auth/plugins/index.ts +15 -5
  17. package/templates/base-nextjs/convex/auth/sessions.ts +9 -15
  18. package/templates/base-nextjs/convex/http.ts +18 -3
  19. package/templates/base-nextjs/convex/schema.ts +104 -2
  20. package/templates/base-nextjs/convex/vex/firstUser.ts +10 -84
  21. package/templates/base-nextjs/convex/vex/globals.ts +19 -82
  22. package/templates/base-nextjs/convex/vex/media.ts +19 -246
  23. package/templates/base-nextjs/convex/vex.schema.ts +138 -0
  24. package/templates/base-nextjs/convex/vex.ts +19 -0
  25. package/templates/base-nextjs/convex.json +6 -0
  26. package/templates/base-nextjs/eslint.config.mjs +1 -21
  27. package/templates/base-nextjs/next.config.ts +10 -0
  28. package/templates/base-nextjs/package.json +47 -48
  29. package/templates/base-nextjs/src/app/(frontend)/@auth/(...)auth/[pathname]/view.tsx +17 -5
  30. package/templates/base-nextjs/src/app/(frontend)/auth/[pathname]/view.tsx +2 -4
  31. package/templates/base-nextjs/src/app/(frontend)/layout.tsx +12 -2
  32. package/templates/base-nextjs/src/app/(frontend)/page.tsx +2 -113
  33. package/templates/base-nextjs/src/app/(vexcms)/admin/[[...path]]/page.tsx +40 -0
  34. package/templates/base-nextjs/src/app/(vexcms)/admin/clientProviders.tsx +22 -0
  35. package/templates/base-nextjs/src/app/(vexcms)/admin/layout.tsx +19 -0
  36. package/templates/base-nextjs/src/app/globals.css +240 -104
  37. package/templates/base-nextjs/src/app/layout.tsx +23 -13
  38. package/templates/base-nextjs/src/app/unauthorized/page.tsx +24 -0
  39. package/templates/base-nextjs/src/auth/access.ts +46 -0
  40. package/templates/base-nextjs/src/auth/client.tsx +17 -5
  41. package/templates/base-nextjs/src/auth/hasPermission.ts +39 -0
  42. package/templates/base-nextjs/src/auth/serverUtils.ts +15 -22
  43. package/templates/base-nextjs/src/components/WelcomePage.tsx +116 -0
  44. package/templates/base-nextjs/src/components/component-example.tsx +56 -464
  45. package/templates/base-nextjs/src/components/providers/auth.tsx +13 -0
  46. package/templates/base-nextjs/src/components/providers/client.tsx +6 -1
  47. package/templates/base-nextjs/src/components/providers/convex.tsx +53 -21
  48. package/templates/base-nextjs/src/components/providers/server.tsx +10 -7
  49. package/templates/{marketing-site → base-nextjs}/src/components/ui/accordion.tsx +30 -32
  50. package/templates/base-nextjs/src/components/ui/badge.tsx +10 -13
  51. package/templates/base-nextjs/src/components/ui/input.tsx +35 -5
  52. package/templates/base-nextjs/src/context/AuthContext.tsx +29 -0
  53. package/templates/base-nextjs/src/db/constants/auth.ts +0 -1
  54. package/templates/base-nextjs/src/db/constants/index.ts +22 -35
  55. package/templates/base-nextjs/src/lib/utils.ts +0 -12
  56. package/templates/base-nextjs/src/proxy.ts +98 -11
  57. package/templates/base-nextjs/src/vex.config.ts +35 -0
  58. package/templates/base-nextjs/src/vex.types.ts +293 -0
  59. package/templates/base-nextjs/src/vexcms/collections/images.ts +15 -0
  60. package/templates/base-nextjs/src/vexcms/collections/index.ts +2 -1
  61. package/templates/base-nextjs/src/vexcms/collections/users.ts +7 -35
  62. package/templates/base-nextjs/tsconfig.json +3 -0
  63. package/templates/marketing-site/convex/_generated/api.d.ts +81 -0
  64. package/templates/marketing-site/convex/_generated/api.js +23 -0
  65. package/templates/marketing-site/convex/_generated/dataModel.d.ts +60 -0
  66. package/templates/marketing-site/convex/_generated/server.d.ts +162 -0
  67. package/templates/marketing-site/convex/_generated/server.js +101 -0
  68. package/templates/marketing-site/convex/footers.ts +11 -7
  69. package/templates/marketing-site/convex/headers.ts +15 -5
  70. package/templates/marketing-site/convex/pages.ts +20 -35
  71. package/templates/marketing-site/convex/schema.ts +119 -0
  72. package/templates/marketing-site/convex/seed.ts +582 -35
  73. package/templates/marketing-site/convex/siteSettings.ts +19 -5
  74. package/templates/marketing-site/convex/theme.ts +55 -61
  75. package/templates/marketing-site/convex/vex.schema.ts +355 -0
  76. package/templates/marketing-site/src/app/(frontend)/PageContent.tsx +27 -160
  77. package/templates/marketing-site/src/app/(frontend)/[slug]/page.tsx +6 -9
  78. package/templates/marketing-site/src/app/(frontend)/layout.tsx +4 -2
  79. package/templates/marketing-site/src/app/(frontend)/page.tsx +2 -5
  80. package/templates/marketing-site/src/components/SiteFooter.tsx +6 -3
  81. package/templates/marketing-site/src/components/SiteHeader.tsx +6 -3
  82. package/templates/marketing-site/src/components/ThemeLive.tsx +59 -0
  83. package/templates/marketing-site/src/components/ThemeStyle.tsx +45 -89
  84. package/templates/marketing-site/src/components/motion-primitives/animated-group.tsx +2 -2
  85. package/templates/marketing-site/src/lib/metadata.ts +51 -72
  86. package/templates/marketing-site/src/vex.config.ts +35 -0
  87. package/templates/marketing-site/src/vex.types.ts +634 -0
  88. package/templates/marketing-site/src/vexcms/api.ts +23 -0
  89. package/templates/marketing-site/src/vexcms/blocks/CTA/config.ts +3 -3
  90. package/templates/marketing-site/src/vexcms/blocks/CTA/index.tsx +2 -2
  91. package/templates/marketing-site/src/vexcms/blocks/FAQ/config.ts +4 -4
  92. package/templates/marketing-site/src/vexcms/blocks/FAQ/index.tsx +2 -2
  93. package/templates/marketing-site/src/vexcms/blocks/Features/config.ts +4 -8
  94. package/templates/marketing-site/src/vexcms/blocks/Features/index.tsx +2 -2
  95. package/templates/marketing-site/src/vexcms/blocks/Footer/config.ts +7 -11
  96. package/templates/marketing-site/src/vexcms/blocks/Footer/index.tsx +1 -1
  97. package/templates/marketing-site/src/vexcms/blocks/Header/config.ts +9 -9
  98. package/templates/marketing-site/src/vexcms/blocks/Header/index.tsx +4 -5
  99. package/templates/marketing-site/src/vexcms/blocks/Hero/config.ts +3 -4
  100. package/templates/marketing-site/src/vexcms/blocks/Hero/index.tsx +10 -19
  101. package/templates/marketing-site/src/vexcms/blocks/HowItWorks/config.ts +4 -9
  102. package/templates/marketing-site/src/vexcms/blocks/HowItWorks/index.tsx +3 -6
  103. package/templates/marketing-site/src/vexcms/blocks/Roadmap/config.ts +28 -68
  104. package/templates/marketing-site/src/vexcms/blocks/Roadmap/index.tsx +13 -43
  105. package/templates/marketing-site/src/vexcms/blocks/config.ts +7 -22
  106. package/templates/marketing-site/src/vexcms/blocks/constants.ts +2 -3
  107. package/templates/marketing-site/src/vexcms/blocks/index.ts +9 -8
  108. package/templates/marketing-site/src/vexcms/collections/footers.ts +1 -1
  109. package/templates/marketing-site/src/vexcms/collections/headers.ts +1 -1
  110. package/templates/marketing-site/src/vexcms/collections/index.ts +2 -1
  111. package/templates/marketing-site/src/vexcms/collections/pages.ts +12 -21
  112. package/templates/marketing-site/src/vexcms/collections/themeColors.ts +118 -0
  113. package/templates/marketing-site/src/vexcms/collections/themes.ts +29 -111
  114. package/templates/marketing-site/src/vexcms/globals/index.ts +1 -1
  115. package/templates/marketing-site/src/vexcms/globals/siteSettings.ts +43 -27
  116. package/templates/base-nextjs/convex/auth/adapter/index.ts +0 -230
  117. package/templates/base-nextjs/convex/auth/adapter/utils.ts +0 -547
  118. package/templates/base-nextjs/convex/auth/config.ts +0 -10
  119. package/templates/base-nextjs/convex/vex/auth.ts +0 -38
  120. package/templates/base-nextjs/convex/vex/collections.ts +0 -321
  121. package/templates/base-nextjs/convex/vex/helpers.ts +0 -33
  122. package/templates/base-nextjs/convex/vex/impersonation.ts +0 -51
  123. package/templates/base-nextjs/convex/vex/migrate.ts +0 -74
  124. package/templates/base-nextjs/convex/vex/model/collections.ts +0 -196
  125. package/templates/base-nextjs/convex/vex/model/media.ts +0 -87
  126. package/templates/base-nextjs/convex/vex/model/versions.ts +0 -254
  127. package/templates/base-nextjs/convex/vex/previewSnapshot.ts +0 -53
  128. package/templates/base-nextjs/convex/vex/versions.ts +0 -648
  129. package/templates/base-nextjs/src/app/admin/AdminLayoutWrapper.tsx +0 -33
  130. package/templates/base-nextjs/src/app/admin/AdminPageWrapper.tsx +0 -38
  131. package/templates/base-nextjs/src/app/admin/RichTextFieldWithMedia.tsx +0 -101
  132. package/templates/base-nextjs/src/app/admin/[[...path]]/page.tsx +0 -15
  133. package/templates/base-nextjs/src/app/admin/layout.tsx +0 -51
  134. package/templates/base-nextjs/src/app/favicon.ico +0 -0
  135. package/templates/base-nextjs/src/components/providers/theme.tsx +0 -11
  136. package/templates/base-nextjs/src/components/ui/theme-toggle.tsx +0 -67
  137. package/templates/base-nextjs/src/db/types.ts +0 -6
  138. package/templates/base-nextjs/src/vexcms/access.ts +0 -44
  139. package/templates/base-nextjs/src/vexcms/auth.ts +0 -4
  140. package/templates/base-nextjs/src/vexcms/collections/media.ts +0 -15
  141. package/templates/base-nextjs/vex.config.ts +0 -25
  142. package/templates/marketing-site/public/favicons/favicon.ico +0 -0
  143. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/PreviewPageContent.tsx +0 -55
  144. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/page.tsx +0 -27
  145. package/templates/marketing-site/src/app/(frontend)/preview/layout.tsx +0 -18
  146. package/templates/marketing-site/src/app/admin/AdminLayoutWrapper.tsx +0 -71
  147. package/templates/marketing-site/src/components/ThemeInjector.tsx +0 -128
  148. package/templates/marketing-site/src/components/admin/IconPickerField.tsx +0 -134
  149. package/templates/marketing-site/src/components/admin/ThemeImport.tsx +0 -174
  150. package/templates/marketing-site/src/components/admin/ThemeImportField.tsx +0 -33
  151. package/templates/marketing-site/src/db/constants/index.ts +0 -52
  152. package/templates/marketing-site/src/lib/colorConvert.ts +0 -171
  153. package/templates/marketing-site/src/vexcms/access.ts +0 -36
  154. package/templates/marketing-site/vex.config.ts +0 -32
@@ -1,87 +0,0 @@
1
- import type {
2
- GenericDataModel,
3
- GenericMutationCtx,
4
- GenericQueryCtx,
5
- PaginationOptions,
6
- TableNamesInDataModel,
7
- } from "convex/server"
8
-
9
- import { ConvexError } from "convex/values"
10
- import { generateFormSchema } from "@vexcms/core"
11
- import type { VexField } from "@vexcms/core"
12
-
13
- export async function createMediaDocument<DataModel extends GenericDataModel>(props: {
14
- ctx: GenericMutationCtx<DataModel>
15
- args: {
16
- collectionSlug: TableNamesInDataModel<DataModel>
17
- fields: Record<string, unknown>
18
- collectionFields: Record<string, VexField>
19
- }
20
- }): Promise<string> {
21
- const f = { ...props.args.fields }
22
-
23
- // Extract system fields that bypass form schema validation
24
- const storageId = f.storageId
25
- delete f.storageId
26
-
27
- // Resolve the file URL from storageId before inserting
28
- if (storageId && (!f.url || f.url === "")) {
29
- const url = await props.ctx.storage.getUrl(storageId as any)
30
- if (url) f.url = url
31
- }
32
-
33
- const schema = generateFormSchema({
34
- fields: props.args.collectionFields,
35
- })
36
-
37
- const result = schema.safeParse(f)
38
- if (!result.success) {
39
- throw new ConvexError({
40
- message: "Validation failed",
41
- errors: result.error.flatten(),
42
- })
43
- }
44
-
45
- // Re-attach storageId for the DB insert
46
- const data = { ...result.data, ...(storageId ? { storageId } : {}) } as any
47
- const id = await props.ctx.db.insert(props.args.collectionSlug as any, data)
48
- return id as string
49
- }
50
-
51
- async function resolveStorageUrl(
52
- ctx: { storage: { getUrl: (id: any) => Promise<string | null> } },
53
- doc: any,
54
- ) {
55
- if (doc?.storageId) {
56
- const url = await ctx.storage.getUrl(doc.storageId)
57
- if (url) return { ...doc, url }
58
- }
59
- return doc
60
- }
61
-
62
- export async function paginatedSearchDocuments<DataModel extends GenericDataModel>(props: {
63
- args: {
64
- collectionSlug: TableNamesInDataModel<DataModel>
65
- searchIndexName: string
66
- searchField: string
67
- query: string
68
- paginationOpts: PaginationOptions
69
- }
70
- ctx: GenericQueryCtx<DataModel>
71
- }) {
72
- const { args, ctx } = props
73
-
74
- let result
75
- if (args.query === "") {
76
- result = await ctx.db.query(args.collectionSlug).paginate(args.paginationOpts)
77
- } else {
78
- result = await (ctx.db.query(args.collectionSlug))
79
- .withSearchIndex(args.searchIndexName, (q) => q.search(args.searchField, args.query))
80
- .paginate(args.paginationOpts)
81
- }
82
-
83
- const resolvedPage = await Promise.all(
84
- result.page.map((doc: any) => resolveStorageUrl(ctx, doc)),
85
- )
86
- return { ...result, page: resolvedPage }
87
- }
@@ -1,254 +0,0 @@
1
- import type {
2
- GenericDataModel,
3
- GenericMutationCtx,
4
- GenericQueryCtx,
5
- } from "convex/server"
6
-
7
- /**
8
- * Status values for version records.
9
- * - "draft": a saved draft
10
- * - "published": this snapshot was published to the main document
11
- * - "autosave": an autosave version (coalesced in-place)
12
- */
13
- export type VersionStatus = "draft" | "published" | "autosave"
14
-
15
- /**
16
- * Gets the next version number for a document.
17
- */
18
- export async function getNextVersionNumber<DataModel extends GenericDataModel>(props: {
19
- ctx: GenericQueryCtx<DataModel>
20
- collection: string
21
- documentId: string
22
- }): Promise<number> {
23
- // Query all versions and find the highest version number.
24
- // We can't just take the latest by createdAt because previewSnapshot
25
- // entries have version: 0 and may have a later createdAt.
26
- const allVersions = await (props.ctx.db as any)
27
- .query("vex_versions")
28
- .withIndex("by_document", (q: any) =>
29
- q.eq("collection", props.collection).eq("documentId", props.documentId),
30
- )
31
- .collect()
32
-
33
- let maxVersion = 0
34
- for (const v of allVersions) {
35
- const ver = v.version as number
36
- if (ver > maxVersion) maxVersion = ver
37
- }
38
-
39
- return maxVersion + 1
40
- }
41
-
42
- /**
43
- * Creates a new version record in the vex_versions table.
44
- */
45
- export async function createVersion<DataModel extends GenericDataModel>(props: {
46
- ctx: GenericMutationCtx<DataModel>
47
- collection: string
48
- documentId: string
49
- snapshot: Record<string, unknown>
50
- status: VersionStatus
51
- createdBy: string | null
52
- restoredFrom?: number
53
- }): Promise<{ versionId: string; version: number }> {
54
- const version = await getNextVersionNumber({
55
- ctx: props.ctx,
56
- collection: props.collection,
57
- documentId: props.documentId,
58
- })
59
-
60
- const versionId = await (props.ctx.db as any).insert("vex_versions", {
61
- collection: props.collection,
62
- documentId: props.documentId,
63
- version,
64
- status: props.status,
65
- snapshot: props.snapshot,
66
- createdAt: Date.now(),
67
- createdBy: props.createdBy ?? undefined,
68
- isAutosave: props.status === "autosave",
69
- restoredFrom: props.restoredFrom ?? undefined,
70
- })
71
-
72
- return { versionId: versionId as string, version }
73
- }
74
-
75
- /**
76
- * Gets the latest version for a document (any status).
77
- * Used by the admin edit view to load the most recent content.
78
- */
79
- export async function getLatestVersion<DataModel extends GenericDataModel>(props: {
80
- ctx: GenericQueryCtx<DataModel>
81
- collection: string
82
- documentId: string
83
- }): Promise<Record<string, unknown> | null> {
84
- // Get all versions and find the one with the highest version number,
85
- // excluding previewSnapshot and autosave entries.
86
- const allVersions = await (props.ctx.db as any)
87
- .query("vex_versions")
88
- .withIndex("by_document", (q: any) =>
89
- q.eq("collection", props.collection).eq("documentId", props.documentId),
90
- )
91
- .collect()
92
-
93
- let latest: Record<string, unknown> | null = null
94
- let maxVersion = -1
95
- for (const v of allVersions) {
96
- if (v.status === "previewSnapshot" || v.status === "autosave") continue
97
- const ver = v.version as number
98
- if (ver > maxVersion) {
99
- maxVersion = ver
100
- latest = v as Record<string, unknown>
101
- }
102
- }
103
-
104
- return latest
105
- }
106
-
107
- /**
108
- * Gets the latest version with status "published" for a document.
109
- */
110
- export async function getLatestPublishedVersion<DataModel extends GenericDataModel>(props: {
111
- ctx: GenericQueryCtx<DataModel>
112
- collection: string
113
- documentId: string
114
- }): Promise<Record<string, unknown> | null> {
115
- const latest = await (props.ctx.db as any)
116
- .query("vex_versions")
117
- .withIndex("by_document_status", (q: any) =>
118
- q
119
- .eq("collection", props.collection)
120
- .eq("documentId", props.documentId)
121
- .eq("status", "published"),
122
- )
123
- .order("desc")
124
- .first()
125
-
126
- return latest as Record<string, unknown> | null
127
- }
128
-
129
- /**
130
- * Lists all versions for a document, ordered newest first.
131
- * Excludes autosave versions from the list.
132
- */
133
- export async function listVersions<DataModel extends GenericDataModel>(props: {
134
- ctx: GenericQueryCtx<DataModel>
135
- collection: string
136
- documentId: string
137
- limit?: number
138
- }): Promise<Record<string, unknown>[]> {
139
- const versions = await (props.ctx.db as any)
140
- .query("vex_versions")
141
- .withIndex("by_document_latest", (q: any) =>
142
- q.eq("collection", props.collection).eq("documentId", props.documentId),
143
- )
144
- .order("desc")
145
- .take(props.limit ?? 50)
146
-
147
- return (versions as Record<string, unknown>[])
148
- .filter((v) => !v.isAutosave && v.status !== "previewSnapshot")
149
- .map((v) => ({
150
- _id: v._id,
151
- version: v.version,
152
- status: v.status,
153
- createdAt: v.createdAt,
154
- createdBy: v.createdBy,
155
- isAutosave: v.isAutosave,
156
- restoredFrom: v.restoredFrom ?? null,
157
- }))
158
- }
159
-
160
- /**
161
- * Gets a specific version by version number.
162
- * Includes the full snapshot for restore preview.
163
- */
164
- export async function getVersion<DataModel extends GenericDataModel>(props: {
165
- ctx: GenericQueryCtx<DataModel>
166
- collection: string
167
- documentId: string
168
- version: number
169
- }): Promise<Record<string, unknown> | null> {
170
- const version = await (props.ctx.db as any)
171
- .query("vex_versions")
172
- .withIndex("by_document_version", (q: any) =>
173
- q
174
- .eq("collection", props.collection)
175
- .eq("documentId", props.documentId)
176
- .eq("version", props.version),
177
- )
178
- .first()
179
-
180
- return version as Record<string, unknown> | null
181
- }
182
-
183
- /**
184
- * Finds the latest autosave version for a document and updates it in-place.
185
- * If no autosave exists, creates a new one.
186
- */
187
- export async function coalesceAutosave<DataModel extends GenericDataModel>(props: {
188
- ctx: GenericMutationCtx<DataModel>
189
- collection: string
190
- documentId: string
191
- snapshot: Record<string, unknown>
192
- createdBy: string | null
193
- }): Promise<{ versionId: string; version: number }> {
194
- const existing = await (props.ctx.db as any)
195
- .query("vex_versions")
196
- .withIndex("by_autosave", (q: any) =>
197
- q
198
- .eq("collection", props.collection)
199
- .eq("documentId", props.documentId)
200
- .eq("isAutosave", true),
201
- )
202
- .order("desc")
203
- .first()
204
-
205
- if (existing) {
206
- await (props.ctx.db as any).patch(existing._id, {
207
- snapshot: props.snapshot,
208
- createdAt: Date.now(),
209
- })
210
- return { versionId: existing._id as string, version: existing.version as number }
211
- }
212
-
213
- return createVersion({
214
- ctx: props.ctx,
215
- collection: props.collection,
216
- documentId: props.documentId,
217
- snapshot: props.snapshot,
218
- status: "autosave",
219
- createdBy: props.createdBy,
220
- })
221
- }
222
-
223
- /**
224
- * Cleans up old versions exceeding the maxPerDoc limit.
225
- * Preserves all published versions regardless of limit.
226
- * Never deletes the most recent version.
227
- */
228
- export async function cleanupOldVersions<DataModel extends GenericDataModel>(props: {
229
- ctx: GenericMutationCtx<DataModel>
230
- collection: string
231
- documentId: string
232
- maxPerDoc: number
233
- }): Promise<void> {
234
- if (props.maxPerDoc === 0) return
235
-
236
- const allVersions = await (props.ctx.db as any)
237
- .query("vex_versions")
238
- .withIndex("by_document_latest", (q: any) =>
239
- q.eq("collection", props.collection).eq("documentId", props.documentId),
240
- )
241
- .order("desc")
242
- .collect()
243
-
244
- if (allVersions.length <= props.maxPerDoc) return
245
-
246
- const toKeep = allVersions.slice(0, props.maxPerDoc)
247
- const candidates = allVersions.slice(props.maxPerDoc)
248
-
249
- for (const candidate of candidates) {
250
- // Always preserve published versions
251
- if (candidate.status === "published") continue
252
- await (props.ctx.db as any).delete(candidate._id)
253
- }
254
- }
@@ -1,53 +0,0 @@
1
- import type { DataModel } from "@convex/_generated/dataModel"
2
-
3
- import { mutation, query } from "@convex/_generated/server"
4
- import {
5
- upsertPreviewSnapshot,
6
- deletePreviewSnapshot,
7
- getPreviewSnapshot,
8
- } from "@vexcms/core"
9
- import { v } from "convex/values"
10
-
11
- export const upsert = mutation({
12
- args: {
13
- collectionSlug: v.string(),
14
- documentId: v.string(),
15
- snapshot: v.any(),
16
- },
17
- handler: async (ctx, { collectionSlug, documentId, snapshot }) => {
18
- await upsertPreviewSnapshot<DataModel>({
19
- ctx,
20
- collection: collectionSlug,
21
- documentId,
22
- snapshot: snapshot as Record<string, unknown>,
23
- })
24
- },
25
- })
26
-
27
- export const remove = mutation({
28
- args: {
29
- collectionSlug: v.string(),
30
- documentId: v.string(),
31
- },
32
- handler: async (ctx, { collectionSlug, documentId }) => {
33
- await deletePreviewSnapshot<DataModel>({
34
- ctx,
35
- collection: collectionSlug,
36
- documentId,
37
- })
38
- },
39
- })
40
-
41
- export const get = query({
42
- args: {
43
- collectionSlug: v.string(),
44
- documentId: v.string(),
45
- },
46
- handler: async (ctx, { collectionSlug, documentId }) => {
47
- return await getPreviewSnapshot<DataModel>({
48
- ctx,
49
- collection: collectionSlug,
50
- documentId,
51
- })
52
- },
53
- })