convex-cms 0.0.1

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 (379) hide show
  1. package/dist/cli/commands/admin.d.ts +16 -0
  2. package/dist/cli/commands/admin.d.ts.map +1 -0
  3. package/dist/cli/commands/admin.js +88 -0
  4. package/dist/cli/commands/admin.js.map +1 -0
  5. package/dist/cli/index.d.ts +3 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +18 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/utils/detectConvexUrl.d.ts +13 -0
  10. package/dist/cli/utils/detectConvexUrl.d.ts.map +1 -0
  11. package/dist/cli/utils/detectConvexUrl.js +48 -0
  12. package/dist/cli/utils/detectConvexUrl.js.map +1 -0
  13. package/dist/cli/utils/openBrowser.d.ts +7 -0
  14. package/dist/cli/utils/openBrowser.d.ts.map +1 -0
  15. package/dist/cli/utils/openBrowser.js +17 -0
  16. package/dist/cli/utils/openBrowser.js.map +1 -0
  17. package/dist/client/admin-config.d.ts +126 -0
  18. package/dist/client/admin-config.d.ts.map +1 -0
  19. package/dist/client/admin-config.js +117 -0
  20. package/dist/client/admin-config.js.map +1 -0
  21. package/dist/client/adminApi.d.ts +2273 -0
  22. package/dist/client/adminApi.d.ts.map +1 -0
  23. package/dist/client/adminApi.js +716 -0
  24. package/dist/client/adminApi.js.map +1 -0
  25. package/dist/client/agentTools.d.ts +933 -0
  26. package/dist/client/agentTools.d.ts.map +1 -0
  27. package/dist/client/agentTools.js +1004 -0
  28. package/dist/client/agentTools.js.map +1 -0
  29. package/dist/client/argTypes.d.ts +212 -0
  30. package/dist/client/argTypes.d.ts.map +1 -0
  31. package/dist/client/argTypes.js +5 -0
  32. package/dist/client/argTypes.js.map +1 -0
  33. package/dist/client/field-types.d.ts +55 -0
  34. package/dist/client/field-types.d.ts.map +1 -0
  35. package/dist/client/field-types.js +152 -0
  36. package/dist/client/field-types.js.map +1 -0
  37. package/dist/client/index.d.ts +189 -0
  38. package/dist/client/index.d.ts.map +1 -0
  39. package/dist/client/index.js +668 -0
  40. package/dist/client/index.js.map +1 -0
  41. package/dist/client/queryBuilder.d.ts +765 -0
  42. package/dist/client/queryBuilder.d.ts.map +1 -0
  43. package/dist/client/queryBuilder.js +970 -0
  44. package/dist/client/queryBuilder.js.map +1 -0
  45. package/dist/client/schema/codegen.d.ts +128 -0
  46. package/dist/client/schema/codegen.d.ts.map +1 -0
  47. package/dist/client/schema/codegen.js +318 -0
  48. package/dist/client/schema/codegen.js.map +1 -0
  49. package/dist/client/schema/defineContentType.d.ts +221 -0
  50. package/dist/client/schema/defineContentType.d.ts.map +1 -0
  51. package/dist/client/schema/defineContentType.js +380 -0
  52. package/dist/client/schema/defineContentType.js.map +1 -0
  53. package/dist/client/schema/index.d.ts +85 -0
  54. package/dist/client/schema/index.d.ts.map +1 -0
  55. package/dist/client/schema/index.js +92 -0
  56. package/dist/client/schema/index.js.map +1 -0
  57. package/dist/client/schema/schemaDrift.d.ts +199 -0
  58. package/dist/client/schema/schemaDrift.d.ts.map +1 -0
  59. package/dist/client/schema/schemaDrift.js +340 -0
  60. package/dist/client/schema/schemaDrift.js.map +1 -0
  61. package/dist/client/schema/typedClient.d.ts +401 -0
  62. package/dist/client/schema/typedClient.d.ts.map +1 -0
  63. package/dist/client/schema/typedClient.js +269 -0
  64. package/dist/client/schema/typedClient.js.map +1 -0
  65. package/dist/client/schema/types.d.ts +477 -0
  66. package/dist/client/schema/types.d.ts.map +1 -0
  67. package/dist/client/schema/types.js +39 -0
  68. package/dist/client/schema/types.js.map +1 -0
  69. package/dist/client/types.d.ts +449 -0
  70. package/dist/client/types.d.ts.map +1 -0
  71. package/dist/client/types.js +149 -0
  72. package/dist/client/types.js.map +1 -0
  73. package/dist/client/workflows.d.ts +51 -0
  74. package/dist/client/workflows.d.ts.map +1 -0
  75. package/dist/client/workflows.js +103 -0
  76. package/dist/client/workflows.js.map +1 -0
  77. package/dist/client/wrapper.d.ts +2198 -0
  78. package/dist/client/wrapper.d.ts.map +1 -0
  79. package/dist/client/wrapper.js +2651 -0
  80. package/dist/client/wrapper.js.map +1 -0
  81. package/dist/component/_generated/api.d.ts +124 -0
  82. package/dist/component/_generated/api.d.ts.map +1 -0
  83. package/dist/component/_generated/api.js +31 -0
  84. package/dist/component/_generated/api.js.map +1 -0
  85. package/dist/component/_generated/component.d.ts +4321 -0
  86. package/dist/component/_generated/component.d.ts.map +1 -0
  87. package/dist/component/_generated/component.js +11 -0
  88. package/dist/component/_generated/component.js.map +1 -0
  89. package/dist/component/_generated/dataModel.d.ts +46 -0
  90. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  91. package/dist/component/_generated/dataModel.js +11 -0
  92. package/dist/component/_generated/dataModel.js.map +1 -0
  93. package/dist/component/_generated/server.d.ts +121 -0
  94. package/dist/component/_generated/server.d.ts.map +1 -0
  95. package/dist/component/_generated/server.js +78 -0
  96. package/dist/component/_generated/server.js.map +1 -0
  97. package/dist/component/auditLog.d.ts +410 -0
  98. package/dist/component/auditLog.d.ts.map +1 -0
  99. package/dist/component/auditLog.js +607 -0
  100. package/dist/component/auditLog.js.map +1 -0
  101. package/dist/component/authorization.d.ts +323 -0
  102. package/dist/component/authorization.d.ts.map +1 -0
  103. package/dist/component/authorization.js +464 -0
  104. package/dist/component/authorization.js.map +1 -0
  105. package/dist/component/authorizationHooks.d.ts +184 -0
  106. package/dist/component/authorizationHooks.d.ts.map +1 -0
  107. package/dist/component/authorizationHooks.js +521 -0
  108. package/dist/component/authorizationHooks.js.map +1 -0
  109. package/dist/component/bulkOperations.d.ts +200 -0
  110. package/dist/component/bulkOperations.d.ts.map +1 -0
  111. package/dist/component/bulkOperations.js +568 -0
  112. package/dist/component/bulkOperations.js.map +1 -0
  113. package/dist/component/contentEntries.d.ts +719 -0
  114. package/dist/component/contentEntries.d.ts.map +1 -0
  115. package/dist/component/contentEntries.js +1617 -0
  116. package/dist/component/contentEntries.js.map +1 -0
  117. package/dist/component/contentEntryMutations.d.ts +505 -0
  118. package/dist/component/contentEntryMutations.d.ts.map +1 -0
  119. package/dist/component/contentEntryMutations.js +1009 -0
  120. package/dist/component/contentEntryMutations.js.map +1 -0
  121. package/dist/component/contentEntryValidation.d.ts +115 -0
  122. package/dist/component/contentEntryValidation.d.ts.map +1 -0
  123. package/dist/component/contentEntryValidation.js +546 -0
  124. package/dist/component/contentEntryValidation.js.map +1 -0
  125. package/dist/component/contentLock.d.ts +328 -0
  126. package/dist/component/contentLock.d.ts.map +1 -0
  127. package/dist/component/contentLock.js +471 -0
  128. package/dist/component/contentLock.js.map +1 -0
  129. package/dist/component/contentTypeMigration.d.ts +411 -0
  130. package/dist/component/contentTypeMigration.d.ts.map +1 -0
  131. package/dist/component/contentTypeMigration.js +805 -0
  132. package/dist/component/contentTypeMigration.js.map +1 -0
  133. package/dist/component/contentTypeMutations.d.ts +975 -0
  134. package/dist/component/contentTypeMutations.d.ts.map +1 -0
  135. package/dist/component/contentTypeMutations.js +768 -0
  136. package/dist/component/contentTypeMutations.js.map +1 -0
  137. package/dist/component/contentTypes.d.ts +538 -0
  138. package/dist/component/contentTypes.d.ts.map +1 -0
  139. package/dist/component/contentTypes.js +304 -0
  140. package/dist/component/contentTypes.js.map +1 -0
  141. package/dist/component/convex.config.d.ts +42 -0
  142. package/dist/component/convex.config.d.ts.map +1 -0
  143. package/dist/component/convex.config.js +43 -0
  144. package/dist/component/convex.config.js.map +1 -0
  145. package/dist/component/documentTypes.d.ts +186 -0
  146. package/dist/component/documentTypes.d.ts.map +1 -0
  147. package/dist/component/documentTypes.js +23 -0
  148. package/dist/component/documentTypes.js.map +1 -0
  149. package/dist/component/eventEmitter.d.ts +281 -0
  150. package/dist/component/eventEmitter.d.ts.map +1 -0
  151. package/dist/component/eventEmitter.js +300 -0
  152. package/dist/component/eventEmitter.js.map +1 -0
  153. package/dist/component/exportImport.d.ts +1120 -0
  154. package/dist/component/exportImport.d.ts.map +1 -0
  155. package/dist/component/exportImport.js +931 -0
  156. package/dist/component/exportImport.js.map +1 -0
  157. package/dist/component/index.d.ts +28 -0
  158. package/dist/component/index.d.ts.map +1 -0
  159. package/dist/component/index.js +142 -0
  160. package/dist/component/index.js.map +1 -0
  161. package/dist/component/lib/deepReferenceResolver.d.ts +252 -0
  162. package/dist/component/lib/deepReferenceResolver.d.ts.map +1 -0
  163. package/dist/component/lib/deepReferenceResolver.js +601 -0
  164. package/dist/component/lib/deepReferenceResolver.js.map +1 -0
  165. package/dist/component/lib/errors.d.ts +306 -0
  166. package/dist/component/lib/errors.d.ts.map +1 -0
  167. package/dist/component/lib/errors.js +407 -0
  168. package/dist/component/lib/errors.js.map +1 -0
  169. package/dist/component/lib/index.d.ts +10 -0
  170. package/dist/component/lib/index.d.ts.map +1 -0
  171. package/dist/component/lib/index.js +33 -0
  172. package/dist/component/lib/index.js.map +1 -0
  173. package/dist/component/lib/mediaReferenceResolver.d.ts +217 -0
  174. package/dist/component/lib/mediaReferenceResolver.d.ts.map +1 -0
  175. package/dist/component/lib/mediaReferenceResolver.js +326 -0
  176. package/dist/component/lib/mediaReferenceResolver.js.map +1 -0
  177. package/dist/component/lib/metadataExtractor.d.ts +245 -0
  178. package/dist/component/lib/metadataExtractor.d.ts.map +1 -0
  179. package/dist/component/lib/metadataExtractor.js +548 -0
  180. package/dist/component/lib/metadataExtractor.js.map +1 -0
  181. package/dist/component/lib/mutationAuth.d.ts +95 -0
  182. package/dist/component/lib/mutationAuth.d.ts.map +1 -0
  183. package/dist/component/lib/mutationAuth.js +146 -0
  184. package/dist/component/lib/mutationAuth.js.map +1 -0
  185. package/dist/component/lib/queries.d.ts +17 -0
  186. package/dist/component/lib/queries.d.ts.map +1 -0
  187. package/dist/component/lib/queries.js +49 -0
  188. package/dist/component/lib/queries.js.map +1 -0
  189. package/dist/component/lib/ragContentChunker.d.ts +423 -0
  190. package/dist/component/lib/ragContentChunker.d.ts.map +1 -0
  191. package/dist/component/lib/ragContentChunker.js +897 -0
  192. package/dist/component/lib/ragContentChunker.js.map +1 -0
  193. package/dist/component/lib/referenceResolver.d.ts +175 -0
  194. package/dist/component/lib/referenceResolver.d.ts.map +1 -0
  195. package/dist/component/lib/referenceResolver.js +293 -0
  196. package/dist/component/lib/referenceResolver.js.map +1 -0
  197. package/dist/component/lib/slugGenerator.d.ts +71 -0
  198. package/dist/component/lib/slugGenerator.d.ts.map +1 -0
  199. package/dist/component/lib/slugGenerator.js +207 -0
  200. package/dist/component/lib/slugGenerator.js.map +1 -0
  201. package/dist/component/lib/slugUniqueness.d.ts +131 -0
  202. package/dist/component/lib/slugUniqueness.d.ts.map +1 -0
  203. package/dist/component/lib/slugUniqueness.js +229 -0
  204. package/dist/component/lib/slugUniqueness.js.map +1 -0
  205. package/dist/component/lib/softDelete.d.ts +18 -0
  206. package/dist/component/lib/softDelete.d.ts.map +1 -0
  207. package/dist/component/lib/softDelete.js +29 -0
  208. package/dist/component/lib/softDelete.js.map +1 -0
  209. package/dist/component/localeFallbackChain.d.ts +410 -0
  210. package/dist/component/localeFallbackChain.d.ts.map +1 -0
  211. package/dist/component/localeFallbackChain.js +467 -0
  212. package/dist/component/localeFallbackChain.js.map +1 -0
  213. package/dist/component/localeFields.d.ts +508 -0
  214. package/dist/component/localeFields.d.ts.map +1 -0
  215. package/dist/component/localeFields.js +592 -0
  216. package/dist/component/localeFields.js.map +1 -0
  217. package/dist/component/mediaAssetMutations.d.ts +235 -0
  218. package/dist/component/mediaAssetMutations.d.ts.map +1 -0
  219. package/dist/component/mediaAssetMutations.js +558 -0
  220. package/dist/component/mediaAssetMutations.js.map +1 -0
  221. package/dist/component/mediaAssets.d.ts +168 -0
  222. package/dist/component/mediaAssets.d.ts.map +1 -0
  223. package/dist/component/mediaAssets.js +618 -0
  224. package/dist/component/mediaAssets.js.map +1 -0
  225. package/dist/component/mediaFolderMutations.d.ts +642 -0
  226. package/dist/component/mediaFolderMutations.d.ts.map +1 -0
  227. package/dist/component/mediaFolderMutations.js +849 -0
  228. package/dist/component/mediaFolderMutations.js.map +1 -0
  229. package/dist/component/mediaUploadMutations.d.ts +136 -0
  230. package/dist/component/mediaUploadMutations.d.ts.map +1 -0
  231. package/dist/component/mediaUploadMutations.js +205 -0
  232. package/dist/component/mediaUploadMutations.js.map +1 -0
  233. package/dist/component/mediaVariantMutations.d.ts +468 -0
  234. package/dist/component/mediaVariantMutations.d.ts.map +1 -0
  235. package/dist/component/mediaVariantMutations.js +737 -0
  236. package/dist/component/mediaVariantMutations.js.map +1 -0
  237. package/dist/component/mediaVariants.d.ts +525 -0
  238. package/dist/component/mediaVariants.d.ts.map +1 -0
  239. package/dist/component/mediaVariants.js +661 -0
  240. package/dist/component/mediaVariants.js.map +1 -0
  241. package/dist/component/ragContentIndexer.d.ts +595 -0
  242. package/dist/component/ragContentIndexer.d.ts.map +1 -0
  243. package/dist/component/ragContentIndexer.js +794 -0
  244. package/dist/component/ragContentIndexer.js.map +1 -0
  245. package/dist/component/rateLimitHooks.d.ts +266 -0
  246. package/dist/component/rateLimitHooks.d.ts.map +1 -0
  247. package/dist/component/rateLimitHooks.js +412 -0
  248. package/dist/component/rateLimitHooks.js.map +1 -0
  249. package/dist/component/roles.d.ts +649 -0
  250. package/dist/component/roles.d.ts.map +1 -0
  251. package/dist/component/roles.js +884 -0
  252. package/dist/component/roles.js.map +1 -0
  253. package/dist/component/scheduledPublish.d.ts +182 -0
  254. package/dist/component/scheduledPublish.d.ts.map +1 -0
  255. package/dist/component/scheduledPublish.js +304 -0
  256. package/dist/component/scheduledPublish.js.map +1 -0
  257. package/dist/component/schema.d.ts +4114 -0
  258. package/dist/component/schema.d.ts.map +1 -0
  259. package/dist/component/schema.js +469 -0
  260. package/dist/component/schema.js.map +1 -0
  261. package/dist/component/taxonomies.d.ts +476 -0
  262. package/dist/component/taxonomies.d.ts.map +1 -0
  263. package/dist/component/taxonomies.js +785 -0
  264. package/dist/component/taxonomies.js.map +1 -0
  265. package/dist/component/taxonomyMutations.d.ts +206 -0
  266. package/dist/component/taxonomyMutations.d.ts.map +1 -0
  267. package/dist/component/taxonomyMutations.js +1001 -0
  268. package/dist/component/taxonomyMutations.js.map +1 -0
  269. package/dist/component/trash.d.ts +265 -0
  270. package/dist/component/trash.d.ts.map +1 -0
  271. package/dist/component/trash.js +621 -0
  272. package/dist/component/trash.js.map +1 -0
  273. package/dist/component/types.d.ts +4 -0
  274. package/dist/component/types.d.ts.map +1 -0
  275. package/dist/component/types.js +2 -0
  276. package/dist/component/types.js.map +1 -0
  277. package/dist/component/userContext.d.ts +508 -0
  278. package/dist/component/userContext.d.ts.map +1 -0
  279. package/dist/component/userContext.js +615 -0
  280. package/dist/component/userContext.js.map +1 -0
  281. package/dist/component/validation.d.ts +387 -0
  282. package/dist/component/validation.d.ts.map +1 -0
  283. package/dist/component/validation.js +1052 -0
  284. package/dist/component/validation.js.map +1 -0
  285. package/dist/component/validators.d.ts +4645 -0
  286. package/dist/component/validators.d.ts.map +1 -0
  287. package/dist/component/validators.js +641 -0
  288. package/dist/component/validators.js.map +1 -0
  289. package/dist/component/versionMutations.d.ts +216 -0
  290. package/dist/component/versionMutations.d.ts.map +1 -0
  291. package/dist/component/versionMutations.js +321 -0
  292. package/dist/component/versionMutations.js.map +1 -0
  293. package/dist/component/webhookTrigger.d.ts +770 -0
  294. package/dist/component/webhookTrigger.d.ts.map +1 -0
  295. package/dist/component/webhookTrigger.js +1413 -0
  296. package/dist/component/webhookTrigger.js.map +1 -0
  297. package/dist/react/index.d.ts +316 -0
  298. package/dist/react/index.d.ts.map +1 -0
  299. package/dist/react/index.js +558 -0
  300. package/dist/react/index.js.map +1 -0
  301. package/dist/test.d.ts +2230 -0
  302. package/dist/test.d.ts.map +1 -0
  303. package/dist/test.js +1107 -0
  304. package/dist/test.js.map +1 -0
  305. package/package.json +95 -0
  306. package/src/cli/commands/admin.ts +104 -0
  307. package/src/cli/index.ts +21 -0
  308. package/src/cli/utils/detectConvexUrl.ts +54 -0
  309. package/src/cli/utils/openBrowser.ts +16 -0
  310. package/src/client/admin-config.ts +138 -0
  311. package/src/client/adminApi.ts +942 -0
  312. package/src/client/agentTools.ts +1311 -0
  313. package/src/client/argTypes.ts +316 -0
  314. package/src/client/field-types.ts +187 -0
  315. package/src/client/index.ts +1301 -0
  316. package/src/client/queryBuilder.ts +1100 -0
  317. package/src/client/schema/codegen.ts +500 -0
  318. package/src/client/schema/defineContentType.ts +501 -0
  319. package/src/client/schema/index.ts +169 -0
  320. package/src/client/schema/schemaDrift.ts +574 -0
  321. package/src/client/schema/typedClient.ts +688 -0
  322. package/src/client/schema/types.ts +666 -0
  323. package/src/client/types.ts +723 -0
  324. package/src/client/workflows.ts +141 -0
  325. package/src/client/wrapper.ts +4304 -0
  326. package/src/component/_generated/api.ts +140 -0
  327. package/src/component/_generated/component.ts +5029 -0
  328. package/src/component/_generated/dataModel.ts +60 -0
  329. package/src/component/_generated/server.ts +156 -0
  330. package/src/component/authorization.ts +647 -0
  331. package/src/component/authorizationHooks.ts +668 -0
  332. package/src/component/bulkOperations.ts +687 -0
  333. package/src/component/contentEntries.ts +1976 -0
  334. package/src/component/contentEntryMutations.ts +1223 -0
  335. package/src/component/contentEntryValidation.ts +707 -0
  336. package/src/component/contentLock.ts +550 -0
  337. package/src/component/contentTypeMigration.ts +1064 -0
  338. package/src/component/contentTypeMutations.ts +969 -0
  339. package/src/component/contentTypes.ts +346 -0
  340. package/src/component/convex.config.ts +44 -0
  341. package/src/component/documentTypes.ts +240 -0
  342. package/src/component/eventEmitter.ts +485 -0
  343. package/src/component/exportImport.ts +1169 -0
  344. package/src/component/index.ts +491 -0
  345. package/src/component/lib/deepReferenceResolver.ts +999 -0
  346. package/src/component/lib/errors.ts +816 -0
  347. package/src/component/lib/index.ts +145 -0
  348. package/src/component/lib/mediaReferenceResolver.ts +495 -0
  349. package/src/component/lib/metadataExtractor.ts +792 -0
  350. package/src/component/lib/mutationAuth.ts +199 -0
  351. package/src/component/lib/queries.ts +79 -0
  352. package/src/component/lib/ragContentChunker.ts +1371 -0
  353. package/src/component/lib/referenceResolver.ts +430 -0
  354. package/src/component/lib/slugGenerator.ts +262 -0
  355. package/src/component/lib/slugUniqueness.ts +333 -0
  356. package/src/component/lib/softDelete.ts +44 -0
  357. package/src/component/localeFallbackChain.ts +673 -0
  358. package/src/component/localeFields.ts +896 -0
  359. package/src/component/mediaAssetMutations.ts +725 -0
  360. package/src/component/mediaAssets.ts +932 -0
  361. package/src/component/mediaFolderMutations.ts +1046 -0
  362. package/src/component/mediaUploadMutations.ts +224 -0
  363. package/src/component/mediaVariantMutations.ts +900 -0
  364. package/src/component/mediaVariants.ts +793 -0
  365. package/src/component/ragContentIndexer.ts +1067 -0
  366. package/src/component/rateLimitHooks.ts +572 -0
  367. package/src/component/roles.ts +1360 -0
  368. package/src/component/scheduledPublish.ts +358 -0
  369. package/src/component/schema.ts +617 -0
  370. package/src/component/taxonomies.ts +949 -0
  371. package/src/component/taxonomyMutations.ts +1210 -0
  372. package/src/component/trash.ts +724 -0
  373. package/src/component/userContext.ts +898 -0
  374. package/src/component/validation.ts +1388 -0
  375. package/src/component/validators.ts +949 -0
  376. package/src/component/versionMutations.ts +392 -0
  377. package/src/component/webhookTrigger.ts +1922 -0
  378. package/src/react/index.ts +898 -0
  379. package/src/test.ts +1580 -0
@@ -0,0 +1,737 @@
1
+ /**
2
+ * Media Variant Mutation Functions
3
+ *
4
+ * Provides mutation functions for creating, updating, and deleting media variants.
5
+ * Variants are optimized versions of media assets (thumbnails, responsive sizes,
6
+ * format conversions).
7
+ *
8
+ * Key operations:
9
+ * - Create variant: Register a completed variant after external processing
10
+ * - Request generation: Queue a variant for async processing
11
+ * - Update status: Update processing status (for job queue integration)
12
+ * - Delete variant: Soft or hard delete variants
13
+ * - Bulk operations: Generate multiple variants from presets
14
+ */
15
+ import { v } from "convex/values";
16
+ import { isDeleted } from "./lib/softDelete.js";
17
+ import { mutation, internalMutation } from "./_generated/server.js";
18
+ import { createMediaVariantArgs, requestVariantGenerationArgs, updateVariantStatusArgs, deleteMediaVariantArgs, deleteAssetVariantsArgs, mediaVariantDoc, mediaVariantWithUrlDoc,
19
+ // variantTypeValidator,
20
+ // variantStatusValidator,
21
+ generateVariantsResult, } from "./validators.js";
22
+ import { classifyMimeType } from "./lib/metadataExtractor.js";
23
+ import { emitEvent } from "./eventEmitter.js";
24
+ import { DEFAULT_VARIANT_PRESETS } from "./mediaVariants.js";
25
+ // =============================================================================
26
+ // Create Variant (completed)
27
+ // =============================================================================
28
+ /**
29
+ * Mutation to create a media variant that has already been processed.
30
+ *
31
+ * Use this when variant processing happens externally (e.g., in a serverless
32
+ * function or image processing service) and you need to register the
33
+ * completed variant in the CMS.
34
+ *
35
+ * @param assetId - Parent media asset ID
36
+ * @param storageId - Storage ID of the variant file
37
+ * @param variantType - Type of variant (thumbnail, responsive, format)
38
+ * @param width - Width in pixels
39
+ * @param height - Height in pixels
40
+ * @param format - Output format (webp, avif, jpeg, etc.)
41
+ * @param mimeType - MIME type of the variant
42
+ * @param size - File size in bytes
43
+ * @param quality - Quality setting used (0-100)
44
+ * @param preset - Named preset if applicable
45
+ * @param autoGenerated - Whether this was auto-generated
46
+ * @param createdBy - User ID who created this variant
47
+ * @returns The created variant document with URL
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // After processing an image externally and uploading the result
52
+ * const variant = await ctx.runMutation(api.mediaVariantMutations.createMediaVariant, {
53
+ * assetId: assetId,
54
+ * storageId: uploadedStorageId,
55
+ * variantType: "responsive",
56
+ * width: 480,
57
+ * height: 320,
58
+ * format: "webp",
59
+ * mimeType: "image/webp",
60
+ * size: 25600,
61
+ * quality: 80,
62
+ * preset: "small",
63
+ * autoGenerated: true,
64
+ * });
65
+ * ```
66
+ */
67
+ export const createMediaVariant = mutation({
68
+ args: createMediaVariantArgs.fields,
69
+ returns: mediaVariantWithUrlDoc,
70
+ handler: async (ctx, args) => {
71
+ const { assetId, storageId, variantType, width, height, format, mimeType, size, quality, preset, autoGenerated = false, createdBy, } = args;
72
+ // Validate parent asset exists and is not deleted
73
+ const item = await ctx.db.get(assetId);
74
+ if (!item || item.kind !== "asset") {
75
+ throw new Error(`Media asset not found: ${assetId}`);
76
+ }
77
+ if (isDeleted(item)) {
78
+ throw new Error(`Cannot create variant for deleted asset: ${assetId}`);
79
+ }
80
+ const asset = item;
81
+ // Check for duplicate variant (same dimensions, format, and preset)
82
+ const existingVariants = await ctx.db
83
+ .query("mediaVariants")
84
+ .withIndex("by_asset", (q) => q.eq("assetId", assetId))
85
+ .filter((q) => q.and(q.eq(q.field("variantType"), variantType), q.eq(q.field("width"), width), q.eq(q.field("height"), height), q.eq(q.field("format"), format), q.eq(q.field("deletedAt"), undefined)))
86
+ .first();
87
+ if (existingVariants) {
88
+ throw new Error(`Variant already exists for asset ${assetId} with type=${variantType}, ` +
89
+ `dimensions=${width}x${height}, format=${format}`);
90
+ }
91
+ // Create the variant record
92
+ const variantId = await ctx.db.insert("mediaVariants", {
93
+ assetId,
94
+ storageId,
95
+ variantType,
96
+ width,
97
+ height,
98
+ format,
99
+ mimeType,
100
+ size,
101
+ quality,
102
+ preset,
103
+ autoGenerated,
104
+ status: "completed",
105
+ processingCompletedAt: Date.now(),
106
+ createdBy,
107
+ });
108
+ // Get the created variant
109
+ const variant = await ctx.db.get(variantId);
110
+ if (!variant) {
111
+ throw new Error("Failed to create variant");
112
+ }
113
+ // Resolve URL
114
+ const url = await ctx.storage.getUrl(storageId);
115
+ // Emit event
116
+ await emitEvent(ctx, {
117
+ eventType: "mediaAsset.updated",
118
+ resourceType: "mediaAsset",
119
+ resourceId: assetId.toString(),
120
+ action: "updated",
121
+ payload: {
122
+ name: asset.name,
123
+ mimeType: asset.mimeType,
124
+ type: classifyMimeType(asset.mimeType),
125
+ size: asset.size ?? 0,
126
+ },
127
+ userId: createdBy,
128
+ metadata: {
129
+ variantCreated: true,
130
+ variantId: variantId.toString(),
131
+ variantType,
132
+ variantFormat: format,
133
+ variantPreset: preset,
134
+ },
135
+ });
136
+ return {
137
+ ...variant,
138
+ url,
139
+ };
140
+ },
141
+ });
142
+ // =============================================================================
143
+ // Request Variant Generation
144
+ // =============================================================================
145
+ /**
146
+ * Mutation to request async generation of a variant.
147
+ *
148
+ * Creates a variant record with "pending" status. An external processing
149
+ * system should pick up pending variants, process them, upload the result,
150
+ * and update the status to "completed".
151
+ *
152
+ * @param assetId - Parent media asset ID
153
+ * @param variantType - Type of variant to generate
154
+ * @param width - Target width (optional)
155
+ * @param height - Target height (optional)
156
+ * @param format - Output format
157
+ * @param quality - Quality setting (0-100)
158
+ * @param preset - Named preset to use
159
+ * @param requestedBy - User ID requesting the variant
160
+ * @returns The created variant document (pending status)
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * // Request a thumbnail variant be generated
165
+ * const pendingVariant = await ctx.runMutation(api.mediaVariantMutations.requestVariantGeneration, {
166
+ * assetId: assetId,
167
+ * variantType: "thumbnail",
168
+ * width: 150,
169
+ * height: 150,
170
+ * format: "webp",
171
+ * quality: 80,
172
+ * preset: "thumbnail",
173
+ * });
174
+ *
175
+ * // The variant now has status: "pending"
176
+ * // An external processor should pick it up and generate the image
177
+ * ```
178
+ */
179
+ export const requestVariantGeneration = mutation({
180
+ args: requestVariantGenerationArgs.fields,
181
+ returns: mediaVariantDoc,
182
+ handler: async (ctx, args) => {
183
+ const { assetId, variantType, width, height, format, quality, preset, requestedBy, } = args;
184
+ // Validate parent asset exists and is not deleted
185
+ const item = await ctx.db.get(assetId);
186
+ if (!item || item.kind !== "asset") {
187
+ throw new Error(`Media asset not found: ${assetId}`);
188
+ }
189
+ if (isDeleted(item)) {
190
+ throw new Error(`Cannot create variant for deleted asset: ${assetId}`);
191
+ }
192
+ const asset = item;
193
+ // Validate asset is an image (variants only make sense for images)
194
+ const assetType = classifyMimeType(asset.mimeType);
195
+ if (assetType !== "image") {
196
+ throw new Error(`Variants can only be generated for images. Asset type: ${assetType}`);
197
+ }
198
+ // Check for existing pending/processing variant with same parameters
199
+ const existingPending = await ctx.db
200
+ .query("mediaVariants")
201
+ .withIndex("by_asset", (q) => q.eq("assetId", assetId))
202
+ .filter((q) => q.and(q.eq(q.field("variantType"), variantType), q.eq(q.field("width"), width), q.eq(q.field("height"), height), q.eq(q.field("format"), format), q.or(q.eq(q.field("status"), "pending"), q.eq(q.field("status"), "processing"))))
203
+ .first();
204
+ if (existingPending) {
205
+ // Return existing pending variant instead of creating duplicate
206
+ return existingPending;
207
+ }
208
+ // Check for existing completed variant
209
+ const existingCompleted = await ctx.db
210
+ .query("mediaVariants")
211
+ .withIndex("by_asset", (q) => q.eq("assetId", assetId))
212
+ .filter((q) => q.and(q.eq(q.field("variantType"), variantType), q.eq(q.field("width"), width), q.eq(q.field("height"), height), q.eq(q.field("format"), format), q.eq(q.field("status"), "completed"), q.eq(q.field("deletedAt"), undefined)))
213
+ .first();
214
+ if (existingCompleted) {
215
+ // Variant already exists, return it
216
+ return existingCompleted;
217
+ }
218
+ // Create placeholder storage ID (will be updated when processing completes)
219
+ // For pending variants, we use a placeholder that will be replaced
220
+ const variantId = await ctx.db.insert("mediaVariants", {
221
+ assetId,
222
+ storageId: asset.storageId, // Placeholder - will be replaced
223
+ variantType,
224
+ width,
225
+ height,
226
+ format,
227
+ mimeType: getMimeTypeFromFormat(format),
228
+ size: 0, // Unknown until processed
229
+ quality,
230
+ preset,
231
+ autoGenerated: true,
232
+ status: "pending",
233
+ createdBy: requestedBy,
234
+ });
235
+ const variant = await ctx.db.get(variantId);
236
+ if (!variant) {
237
+ throw new Error("Failed to create pending variant");
238
+ }
239
+ return variant;
240
+ },
241
+ });
242
+ // =============================================================================
243
+ // Update Variant Status
244
+ // =============================================================================
245
+ /**
246
+ * Mutation to update the status of a variant during processing.
247
+ *
248
+ * Used by the processing system to:
249
+ * - Mark a variant as "processing" when it starts
250
+ * - Mark as "completed" with final storage ID and dimensions
251
+ * - Mark as "failed" with error message
252
+ *
253
+ * @param id - Variant ID to update
254
+ * @param status - New status
255
+ * @param storageId - Storage ID of completed variant
256
+ * @param size - Final file size
257
+ * @param mimeType - Final MIME type
258
+ * @param width - Final width
259
+ * @param height - Final height
260
+ * @param errorMessage - Error message if failed
261
+ * @returns Updated variant document
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * // Mark as processing
266
+ * await ctx.runMutation(api.mediaVariantMutations.updateVariantStatus, {
267
+ * id: variantId,
268
+ * status: "processing",
269
+ * });
270
+ *
271
+ * // ... process the image ...
272
+ *
273
+ * // Mark as completed
274
+ * await ctx.runMutation(api.mediaVariantMutations.updateVariantStatus, {
275
+ * id: variantId,
276
+ * status: "completed",
277
+ * storageId: processedStorageId,
278
+ * size: 25600,
279
+ * width: 480,
280
+ * height: 320,
281
+ * });
282
+ * ```
283
+ */
284
+ export const updateVariantStatus = mutation({
285
+ args: updateVariantStatusArgs.fields,
286
+ returns: mediaVariantDoc,
287
+ handler: async (ctx, args) => {
288
+ const { id, status, storageId, size, mimeType, width, height, errorMessage, } = args;
289
+ const variant = await ctx.db.get(id);
290
+ if (!variant) {
291
+ throw new Error(`Variant not found: ${id}`);
292
+ }
293
+ const updates = { status };
294
+ if (status === "processing") {
295
+ updates.processingStartedAt = Date.now();
296
+ }
297
+ else if (status === "completed") {
298
+ updates.processingCompletedAt = Date.now();
299
+ if (storageId)
300
+ updates.storageId = storageId;
301
+ if (size !== undefined)
302
+ updates.size = size;
303
+ if (mimeType)
304
+ updates.mimeType = mimeType;
305
+ if (width !== undefined)
306
+ updates.width = width;
307
+ if (height !== undefined)
308
+ updates.height = height;
309
+ }
310
+ else if (status === "failed") {
311
+ updates.processingCompletedAt = Date.now();
312
+ if (errorMessage)
313
+ updates.errorMessage = errorMessage;
314
+ }
315
+ await ctx.db.patch(id, updates);
316
+ const updatedVariant = await ctx.db.get(id);
317
+ if (!updatedVariant) {
318
+ throw new Error("Failed to update variant");
319
+ }
320
+ return updatedVariant;
321
+ },
322
+ });
323
+ // =============================================================================
324
+ // Delete Variant
325
+ // =============================================================================
326
+ /**
327
+ * Mutation to delete a media variant.
328
+ *
329
+ * Supports soft delete (default) and hard delete.
330
+ * Hard delete also removes the storage file.
331
+ *
332
+ * @param id - Variant ID to delete
333
+ * @param hardDelete - If true, permanently delete and remove storage file
334
+ * @param deletedBy - User ID performing the deletion
335
+ * @returns Deleted variant document
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * // Soft delete (can be recovered)
340
+ * await ctx.runMutation(api.mediaVariantMutations.deleteMediaVariant, {
341
+ * id: variantId,
342
+ * });
343
+ *
344
+ * // Hard delete (permanent)
345
+ * await ctx.runMutation(api.mediaVariantMutations.deleteMediaVariant, {
346
+ * id: variantId,
347
+ * hardDelete: true,
348
+ * });
349
+ * ```
350
+ */
351
+ export const deleteMediaVariant = mutation({
352
+ args: deleteMediaVariantArgs.fields,
353
+ returns: mediaVariantDoc,
354
+ handler: async (ctx, args) => {
355
+ const { id, hardDelete = false } = args;
356
+ const variant = await ctx.db.get(id);
357
+ if (!variant) {
358
+ throw new Error(`Variant not found: ${id}`);
359
+ }
360
+ if (hardDelete) {
361
+ // Delete storage file if it's not a placeholder
362
+ if (variant.status === "completed") {
363
+ try {
364
+ await ctx.storage.delete(variant.storageId);
365
+ }
366
+ catch {
367
+ // Storage file might already be deleted
368
+ }
369
+ }
370
+ // Hard delete the variant record
371
+ await ctx.db.delete(id);
372
+ }
373
+ else {
374
+ // Soft delete
375
+ await ctx.db.patch(id, { deletedAt: Date.now() });
376
+ }
377
+ return variant;
378
+ },
379
+ });
380
+ // =============================================================================
381
+ // Delete All Variants for Asset
382
+ // =============================================================================
383
+ /**
384
+ * Mutation to delete all variants for a media asset.
385
+ *
386
+ * Useful when deleting the parent asset or when regenerating
387
+ * all variants from scratch.
388
+ *
389
+ * @param assetId - Parent asset ID
390
+ * @param hardDelete - If true, permanently delete and remove storage files
391
+ * @param deletedBy - User ID performing the deletion
392
+ * @returns Summary of deleted variants
393
+ *
394
+ * @example
395
+ * ```typescript
396
+ * // Soft delete all variants
397
+ * const result = await ctx.runMutation(api.mediaVariantMutations.deleteAssetVariants, {
398
+ * assetId: assetId,
399
+ * });
400
+ * console.log(`Deleted ${result.deleted} variants`);
401
+ *
402
+ * // Hard delete all variants
403
+ * await ctx.runMutation(api.mediaVariantMutations.deleteAssetVariants, {
404
+ * assetId: assetId,
405
+ * hardDelete: true,
406
+ * });
407
+ * ```
408
+ */
409
+ export const deleteAssetVariants = mutation({
410
+ args: deleteAssetVariantsArgs.fields,
411
+ returns: v.object({
412
+ deleted: v.number(),
413
+ assetId: v.id("mediaItems"),
414
+ }),
415
+ handler: async (ctx, args) => {
416
+ const { assetId, hardDelete = false } = args;
417
+ const variants = await ctx.db
418
+ .query("mediaVariants")
419
+ .withIndex("by_asset", (q) => q.eq("assetId", assetId))
420
+ .filter((q) => q.eq(q.field("deletedAt"), undefined))
421
+ .collect();
422
+ let deletedCount = 0;
423
+ for (const variant of variants) {
424
+ if (hardDelete) {
425
+ // Delete storage file
426
+ if (variant.status === "completed") {
427
+ try {
428
+ await ctx.storage.delete(variant.storageId);
429
+ }
430
+ catch {
431
+ // Storage file might already be deleted
432
+ }
433
+ }
434
+ await ctx.db.delete(variant._id);
435
+ }
436
+ else {
437
+ await ctx.db.patch(variant._id, { deletedAt: Date.now() });
438
+ }
439
+ deletedCount++;
440
+ }
441
+ return {
442
+ deleted: deletedCount,
443
+ assetId,
444
+ };
445
+ },
446
+ });
447
+ // =============================================================================
448
+ // Generate Variants from Presets
449
+ // =============================================================================
450
+ /**
451
+ * Mutation to request generation of multiple variants from presets.
452
+ *
453
+ * Creates pending variant records for each preset. An external processor
454
+ * should pick up and process these variants.
455
+ *
456
+ * @param assetId - Parent asset ID
457
+ * @param presets - Array of preset names to generate
458
+ * @param requestedBy - User ID requesting the variants
459
+ * @returns Summary of created variant requests
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * // Generate thumbnail and responsive sizes
464
+ * const result = await ctx.runMutation(api.mediaVariantMutations.generateFromPresets, {
465
+ * assetId: assetId,
466
+ * presets: ["thumbnail", "small", "medium", "large"],
467
+ * });
468
+ *
469
+ * console.log(`Queued ${result.succeeded} variants for processing`);
470
+ * ```
471
+ */
472
+ export const generateFromPresets = mutation({
473
+ args: {
474
+ assetId: v.id("mediaItems"),
475
+ presets: v.array(v.string()),
476
+ requestedBy: v.optional(v.string()),
477
+ },
478
+ returns: generateVariantsResult,
479
+ handler: async (ctx, args) => {
480
+ const { assetId, presets, requestedBy } = args;
481
+ // Validate asset exists and is an image
482
+ const item = await ctx.db.get(assetId);
483
+ if (!item || item.kind !== "asset") {
484
+ throw new Error(`Media asset not found: ${assetId}`);
485
+ }
486
+ if (isDeleted(item)) {
487
+ throw new Error(`Cannot generate variants for deleted asset: ${assetId}`);
488
+ }
489
+ const asset = item;
490
+ const assetMediaType = classifyMimeType(asset.mimeType);
491
+ if (assetMediaType !== "image") {
492
+ throw new Error(`Variants can only be generated for images. Asset type: ${assetMediaType}`);
493
+ }
494
+ const results = [];
495
+ for (const presetName of presets) {
496
+ const preset = DEFAULT_VARIANT_PRESETS[presetName];
497
+ if (!preset) {
498
+ results.push({
499
+ preset: presetName,
500
+ success: false,
501
+ error: `Unknown preset: ${presetName}`,
502
+ });
503
+ continue;
504
+ }
505
+ try {
506
+ // Check for existing variant
507
+ const existing = await ctx.db
508
+ .query("mediaVariants")
509
+ .withIndex("by_asset_and_preset", (q) => q.eq("assetId", assetId).eq("preset", presetName))
510
+ .filter((q) => q.and(q.eq(q.field("deletedAt"), undefined), q.or(q.eq(q.field("status"), "pending"), q.eq(q.field("status"), "processing"), q.eq(q.field("status"), "completed"))))
511
+ .first();
512
+ if (existing) {
513
+ results.push({
514
+ preset: presetName,
515
+ success: true,
516
+ variantId: existing._id,
517
+ });
518
+ continue;
519
+ }
520
+ // Create pending variant
521
+ const variantId = await ctx.db.insert("mediaVariants", {
522
+ assetId,
523
+ storageId: asset.storageId, // Placeholder
524
+ variantType: preset.variantType,
525
+ width: "width" in preset ? preset.width : undefined,
526
+ height: "height" in preset ? preset.height : undefined,
527
+ format: preset.format,
528
+ mimeType: getMimeTypeFromFormat(preset.format),
529
+ size: 0,
530
+ quality: preset.quality,
531
+ preset: presetName,
532
+ autoGenerated: true,
533
+ status: "pending",
534
+ createdBy: requestedBy,
535
+ });
536
+ results.push({
537
+ preset: presetName,
538
+ success: true,
539
+ variantId,
540
+ });
541
+ }
542
+ catch (error) {
543
+ results.push({
544
+ preset: presetName,
545
+ success: false,
546
+ error: error instanceof Error ? error.message : String(error),
547
+ });
548
+ }
549
+ }
550
+ const succeeded = results.filter((r) => r.success).length;
551
+ const failed = results.filter((r) => !r.success).length;
552
+ // Emit event for bulk variant generation request
553
+ await emitEvent(ctx, {
554
+ eventType: "mediaAsset.updated",
555
+ resourceType: "mediaAsset",
556
+ resourceId: assetId.toString(),
557
+ action: "updated",
558
+ payload: {
559
+ name: asset.name,
560
+ mimeType: asset.mimeType,
561
+ type: classifyMimeType(asset.mimeType),
562
+ size: asset.size ?? 0,
563
+ },
564
+ userId: requestedBy,
565
+ metadata: {
566
+ variantsRequested: true,
567
+ presetsRequested: presets,
568
+ succeeded,
569
+ failed,
570
+ },
571
+ });
572
+ return {
573
+ total: presets.length,
574
+ succeeded,
575
+ failed,
576
+ results: results.map((r) => ({
577
+ ...r,
578
+ variantId: r.variantId ? r.variantId : undefined,
579
+ })),
580
+ };
581
+ },
582
+ });
583
+ // =============================================================================
584
+ // Restore Variant (undo soft delete)
585
+ // =============================================================================
586
+ /**
587
+ * Mutation to restore a soft-deleted variant.
588
+ *
589
+ * @param id - Variant ID to restore
590
+ * @param restoredBy - User ID performing the restoration
591
+ * @returns Restored variant document
592
+ *
593
+ * @example
594
+ * ```typescript
595
+ * await ctx.runMutation(api.mediaVariantMutations.restoreMediaVariant, {
596
+ * id: variantId,
597
+ * restoredBy: userId,
598
+ * });
599
+ * ```
600
+ */
601
+ export const restoreMediaVariant = mutation({
602
+ args: {
603
+ id: v.id("mediaVariants"),
604
+ restoredBy: v.optional(v.string()),
605
+ },
606
+ returns: mediaVariantDoc,
607
+ handler: async (ctx, args) => {
608
+ const { id } = args;
609
+ const variant = await ctx.db.get(id);
610
+ if (!variant) {
611
+ throw new Error(`Variant not found: ${id}`);
612
+ }
613
+ if (!isDeleted(variant)) {
614
+ // Already restored, return as-is
615
+ return variant;
616
+ }
617
+ // Verify parent asset is not deleted
618
+ const asset = await ctx.db.get(variant.assetId);
619
+ if (!asset) {
620
+ throw new Error(`Cannot restore variant: parent asset not found: ${variant.assetId}`);
621
+ }
622
+ if (isDeleted(asset)) {
623
+ throw new Error(`Cannot restore variant: parent asset is deleted: ${variant.assetId}`);
624
+ }
625
+ await ctx.db.patch(id, { deletedAt: undefined });
626
+ const restoredVariant = await ctx.db.get(id);
627
+ if (!restoredVariant) {
628
+ throw new Error("Failed to restore variant");
629
+ }
630
+ return restoredVariant;
631
+ },
632
+ });
633
+ // =============================================================================
634
+ // Internal: Process Pending Variant
635
+ // =============================================================================
636
+ /**
637
+ * Internal mutation for the processing system to mark a variant as processing.
638
+ *
639
+ * This is called when a processor picks up a pending variant from the queue.
640
+ */
641
+ export const markVariantProcessing = internalMutation({
642
+ args: {
643
+ id: v.id("mediaVariants"),
644
+ },
645
+ returns: v.union(mediaVariantDoc, v.null()),
646
+ handler: async (ctx, args) => {
647
+ const { id } = args;
648
+ const variant = await ctx.db.get(id);
649
+ if (!variant || variant.status !== "pending") {
650
+ return null;
651
+ }
652
+ await ctx.db.patch(id, {
653
+ status: "processing",
654
+ processingStartedAt: Date.now(),
655
+ });
656
+ return await ctx.db.get(id);
657
+ },
658
+ });
659
+ /**
660
+ * Internal mutation to complete a variant after processing.
661
+ */
662
+ export const completeVariant = internalMutation({
663
+ args: {
664
+ id: v.id("mediaVariants"),
665
+ storageId: v.id("_storage"),
666
+ size: v.number(),
667
+ width: v.optional(v.number()),
668
+ height: v.optional(v.number()),
669
+ },
670
+ returns: mediaVariantDoc,
671
+ handler: async (ctx, args) => {
672
+ const { id, storageId, size, width, height } = args;
673
+ const variant = await ctx.db.get(id);
674
+ if (!variant) {
675
+ throw new Error(`Variant not found: ${id}`);
676
+ }
677
+ await ctx.db.patch(id, {
678
+ status: "completed",
679
+ storageId,
680
+ size,
681
+ width: width ?? variant.width,
682
+ height: height ?? variant.height,
683
+ processingCompletedAt: Date.now(),
684
+ });
685
+ const completed = await ctx.db.get(id);
686
+ if (!completed) {
687
+ throw new Error("Failed to complete variant");
688
+ }
689
+ return completed;
690
+ },
691
+ });
692
+ /**
693
+ * Internal mutation to mark a variant as failed.
694
+ */
695
+ export const failVariant = internalMutation({
696
+ args: {
697
+ id: v.id("mediaVariants"),
698
+ errorMessage: v.string(),
699
+ },
700
+ returns: mediaVariantDoc,
701
+ handler: async (ctx, args) => {
702
+ const { id, errorMessage } = args;
703
+ const variant = await ctx.db.get(id);
704
+ if (!variant) {
705
+ throw new Error(`Variant not found: ${id}`);
706
+ }
707
+ await ctx.db.patch(id, {
708
+ status: "failed",
709
+ errorMessage,
710
+ processingCompletedAt: Date.now(),
711
+ });
712
+ const failed = await ctx.db.get(id);
713
+ if (!failed) {
714
+ throw new Error("Failed to update variant");
715
+ }
716
+ return failed;
717
+ },
718
+ });
719
+ // =============================================================================
720
+ // Helper Functions
721
+ // =============================================================================
722
+ /**
723
+ * Get MIME type from format string.
724
+ */
725
+ function getMimeTypeFromFormat(format) {
726
+ const mimeTypes = {
727
+ jpeg: "image/jpeg",
728
+ jpg: "image/jpeg",
729
+ png: "image/png",
730
+ webp: "image/webp",
731
+ avif: "image/avif",
732
+ gif: "image/gif",
733
+ svg: "image/svg+xml",
734
+ };
735
+ return mimeTypes[format.toLowerCase()] || `image/${format}`;
736
+ }
737
+ //# sourceMappingURL=mediaVariantMutations.js.map