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,464 @@
1
+ /**
2
+ * Authorization Module
3
+ *
4
+ * Core permission checking logic that evaluates user roles against requested
5
+ * actions and resources. This module is called internally by all CMS operations
6
+ * to enforce access control.
7
+ *
8
+ * Key concepts:
9
+ * - Users are mapped to roles via the getUserRole hook (configured in ComponentConfig)
10
+ * - Roles have permissions that define what actions can be performed on resources
11
+ * - Permissions can be scoped to "all" (any resource) or "own" (resources created by the user)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { requirePermission, checkPermission, UnauthorizedError } from './authorization';
16
+ *
17
+ * // In a mutation handler:
18
+ * const userRole = await getUserRole(userId);
19
+ * await requirePermission({
20
+ * userId,
21
+ * role: userRole,
22
+ * resource: 'contentEntries',
23
+ * action: 'update',
24
+ * resourceOwnerId: entry.createdBy,
25
+ * });
26
+ *
27
+ * // Throws UnauthorizedError if permission denied
28
+ * ```
29
+ */
30
+ import { hasPermission, getRole, } from "./roles.js";
31
+ /**
32
+ * Error thrown when a user lacks permission to perform an action.
33
+ *
34
+ * Includes detailed context about the failed authorization check,
35
+ * making it easy to understand why access was denied.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * try {
40
+ * await requirePermission({ ... });
41
+ * } catch (error) {
42
+ * if (error instanceof UnauthorizedError) {
43
+ * console.log(error.code); // 'PERMISSION_DENIED'
44
+ * console.log(error.resource); // 'contentEntries'
45
+ * console.log(error.action); // 'delete'
46
+ * console.log(error.message); // Human-readable message
47
+ * }
48
+ * }
49
+ * ```
50
+ */
51
+ export class UnauthorizedError extends Error {
52
+ /** Machine-readable error code for classification */
53
+ code;
54
+ /** The resource being accessed (if applicable) */
55
+ resource;
56
+ /** The action being attempted (if applicable) */
57
+ action;
58
+ /** The user's role (if known) */
59
+ role;
60
+ /** The user ID (if provided) */
61
+ userId;
62
+ /** The scope that was required but not granted */
63
+ requiredScope;
64
+ constructor(message, options) {
65
+ super(message);
66
+ this.name = "UnauthorizedError";
67
+ this.code = options.code;
68
+ this.resource = options.resource;
69
+ this.action = options.action;
70
+ this.role = options.role;
71
+ this.userId = options.userId;
72
+ this.requiredScope = options.requiredScope;
73
+ // Maintains proper stack trace in V8 environments
74
+ if (Error.captureStackTrace) {
75
+ Error.captureStackTrace(this, UnauthorizedError);
76
+ }
77
+ }
78
+ /**
79
+ * Create a JSON-serializable representation of the error.
80
+ * Useful for logging or API responses.
81
+ */
82
+ toJSON() {
83
+ return {
84
+ name: this.name,
85
+ message: this.message,
86
+ code: this.code,
87
+ resource: this.resource,
88
+ action: this.action,
89
+ role: this.role,
90
+ userId: this.userId,
91
+ requiredScope: this.requiredScope,
92
+ };
93
+ }
94
+ }
95
+ /**
96
+ * Get a human-readable label for a resource.
97
+ */
98
+ function getResourceLabel(resource) {
99
+ const labels = {
100
+ contentTypes: "content types",
101
+ contentEntries: "content entries",
102
+ mediaItems: "media items",
103
+ settings: "settings",
104
+ };
105
+ return labels[resource] ?? resource;
106
+ }
107
+ /**
108
+ * Get a human-readable label for an action.
109
+ */
110
+ function getActionLabel(action) {
111
+ const labels = {
112
+ create: "create",
113
+ read: "view",
114
+ update: "update",
115
+ delete: "delete",
116
+ publish: "publish",
117
+ unpublish: "unpublish",
118
+ restore: "restore",
119
+ manage: "manage",
120
+ move: "move",
121
+ };
122
+ return labels[action] ?? action;
123
+ }
124
+ /**
125
+ * Generate a descriptive error message for a permission denial.
126
+ */
127
+ function generateDenialMessage(options) {
128
+ const { code, role, resource, action, requiredScope: _requiredScope } = options;
129
+ const resourceLabel = getResourceLabel(resource);
130
+ const actionLabel = getActionLabel(action);
131
+ switch (code) {
132
+ case "NO_ROLE":
133
+ return `Access denied: No role assigned. You need a valid role to ${actionLabel} ${resourceLabel}.`;
134
+ case "UNKNOWN_ROLE":
135
+ return `Access denied: Unknown role "${role}". Contact an administrator to fix your role assignment.`;
136
+ case "PERMISSION_DENIED":
137
+ return `Access denied: The "${role}" role does not have permission to ${actionLabel} ${resourceLabel}.`;
138
+ case "OWNERSHIP_REQUIRED":
139
+ return `Access denied: The "${role}" role can only ${actionLabel} their own ${resourceLabel}. ` +
140
+ `You can only perform this action on items you created.`;
141
+ case "INVALID_RESOURCE":
142
+ return `Invalid resource type: "${resource}". This is a system error.`;
143
+ case "INVALID_ACTION":
144
+ return `Invalid action type: "${action}". This is a system error.`;
145
+ default:
146
+ return `Access denied: Cannot ${actionLabel} ${resourceLabel}.`;
147
+ }
148
+ }
149
+ /**
150
+ * Check if a user has permission to perform an action on a resource.
151
+ *
152
+ * This is the core permission evaluation function. It returns a result object
153
+ * indicating whether the permission was granted or denied, with details about
154
+ * why.
155
+ *
156
+ * The function checks permissions in the following order:
157
+ * 1. Validates that the user has a role assigned
158
+ * 2. Validates that the role exists (in default or custom roles)
159
+ * 3. Checks if the role has the required permission
160
+ * 4. For "own" scope permissions, validates ownership if resourceOwnerId is provided
161
+ *
162
+ * @param options - The permission check configuration
163
+ * @returns Result indicating whether permission was granted or denied
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Check if an editor can update any content entry
168
+ * const result = checkPermission({
169
+ * role: 'editor',
170
+ * resource: 'contentEntries',
171
+ * action: 'update',
172
+ * });
173
+ * if (result.allowed) {
174
+ * console.log('Permission granted with scope:', result.grantedScope);
175
+ * }
176
+ *
177
+ * // Check if an author can update their own content entry
178
+ * const result = checkPermission({
179
+ * userId: 'user123',
180
+ * role: 'author',
181
+ * resource: 'contentEntries',
182
+ * action: 'update',
183
+ * resourceOwnerId: 'user123', // Same as userId - ownership verified
184
+ * });
185
+ * ```
186
+ */
187
+ export function checkPermission(options) {
188
+ const { userId, role, resource, action, resourceOwnerId, customRoles } = options;
189
+ // Check 1: User must have a role assigned
190
+ if (role === null || role === undefined) {
191
+ return {
192
+ allowed: false,
193
+ reason: "No role assigned to user",
194
+ code: "NO_ROLE",
195
+ };
196
+ }
197
+ // Check 2: Role must exist
198
+ const roleDefinition = getRole(role, customRoles);
199
+ if (!roleDefinition) {
200
+ return {
201
+ allowed: false,
202
+ reason: `Unknown role: ${role}`,
203
+ code: "UNKNOWN_ROLE",
204
+ };
205
+ }
206
+ // Check 3: Check if role has permission with "all" scope
207
+ if (hasPermission(role, { resource, action, scope: "all" }, customRoles)) {
208
+ return {
209
+ allowed: true,
210
+ grantedScope: "all",
211
+ ownershipVerified: false,
212
+ };
213
+ }
214
+ // Check 4: Check if role has permission with "own" scope
215
+ if (hasPermission(role, { resource, action, scope: "own" }, customRoles)) {
216
+ // If no resourceOwnerId provided, we cannot verify ownership - deny access
217
+ // for defense-in-depth (callers must always provide resourceOwnerId for
218
+ // ownership-scoped operations)
219
+ if (resourceOwnerId === undefined) {
220
+ return {
221
+ allowed: false,
222
+ reason: "Ownership cannot be verified: resourceOwnerId not provided",
223
+ code: "OWNERSHIP_REQUIRED",
224
+ };
225
+ }
226
+ // Verify ownership: user must own the resource
227
+ if (userId !== undefined && resourceOwnerId === userId) {
228
+ return {
229
+ allowed: true,
230
+ grantedScope: "own",
231
+ ownershipVerified: true,
232
+ };
233
+ }
234
+ // User has "own" permission but doesn't own this resource
235
+ return {
236
+ allowed: false,
237
+ reason: `Ownership required: user does not own this resource`,
238
+ code: "OWNERSHIP_REQUIRED",
239
+ };
240
+ }
241
+ // No matching permission found
242
+ return {
243
+ allowed: false,
244
+ reason: `Role "${role}" does not have ${action} permission on ${resource}`,
245
+ code: "PERMISSION_DENIED",
246
+ };
247
+ }
248
+ /**
249
+ * Require that a user has permission to perform an action.
250
+ *
251
+ * This is the throwing version of `checkPermission`. It's designed to be used
252
+ * at the start of mutation/query handlers to enforce access control. If the
253
+ * permission check fails, it throws an UnauthorizedError with a descriptive
254
+ * message.
255
+ *
256
+ * @param options - The permission check configuration
257
+ * @returns The granted permission details (if allowed)
258
+ * @throws UnauthorizedError if the permission is denied
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * // In a content entry update mutation:
263
+ * export const updateEntry = mutation({
264
+ * args: { id: v.id("contentEntries"), data: v.any() },
265
+ * handler: async (ctx, { id, data }) => {
266
+ * const entry = await ctx.db.get(id);
267
+ * if (!entry) throw new Error("Entry not found");
268
+ *
269
+ * // Check authorization before proceeding
270
+ * const userRole = await getUserRole(ctx.auth.userId);
271
+ * await requirePermission({
272
+ * userId: ctx.auth.userId,
273
+ * role: userRole,
274
+ * resource: 'contentEntries',
275
+ * action: 'update',
276
+ * resourceOwnerId: entry.createdBy,
277
+ * });
278
+ *
279
+ * // If we get here, the user is authorized
280
+ * await ctx.db.patch(id, data);
281
+ * },
282
+ * });
283
+ * ```
284
+ */
285
+ export function requirePermission(options) {
286
+ const result = checkPermission(options);
287
+ if (!result.allowed) {
288
+ // Type narrowing: result is PermissionDenied when allowed is false
289
+ const denied = result;
290
+ throw new UnauthorizedError(generateDenialMessage({
291
+ code: denied.code,
292
+ role: options.role,
293
+ resource: options.resource,
294
+ action: options.action,
295
+ }), {
296
+ code: denied.code,
297
+ resource: options.resource,
298
+ action: options.action,
299
+ role: options.role ?? undefined,
300
+ userId: options.userId,
301
+ });
302
+ }
303
+ return result;
304
+ }
305
+ /**
306
+ * Check if a user owns a resource.
307
+ *
308
+ * This is a simple helper for ownership checks without full permission validation.
309
+ * Use this when you've already verified the permission and just need to check
310
+ * ownership for scope enforcement.
311
+ *
312
+ * @param userId - The ID of the user performing the action
313
+ * @param resourceOwnerId - The ID of the user who created/owns the resource
314
+ * @returns True if the user owns the resource
315
+ *
316
+ * @example
317
+ * ```typescript
318
+ * // Check ownership before allowing a delete
319
+ * if (!isResourceOwner(currentUserId, entry.createdBy)) {
320
+ * throw new UnauthorizedError(
321
+ * 'You can only delete your own content entries',
322
+ * { code: 'OWNERSHIP_REQUIRED', resource: 'contentEntries', action: 'delete' }
323
+ * );
324
+ * }
325
+ * ```
326
+ */
327
+ export function isResourceOwner(userId, resourceOwnerId) {
328
+ // Both must be defined and equal for ownership to be verified
329
+ if (userId === undefined || resourceOwnerId === undefined) {
330
+ return false;
331
+ }
332
+ return userId === resourceOwnerId;
333
+ }
334
+ /**
335
+ * Require that a user owns a resource.
336
+ *
337
+ * Throws an UnauthorizedError if the user doesn't own the resource.
338
+ * Use this when you need to enforce "own" scope on a resource.
339
+ *
340
+ * @param userId - The ID of the user performing the action
341
+ * @param resourceOwnerId - The ID of the user who created/owns the resource
342
+ * @param options - Additional context for the error message
343
+ * @throws UnauthorizedError if the user doesn't own the resource
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * // Require ownership before allowing update
348
+ * requireResourceOwnership(currentUserId, entry.createdBy, {
349
+ * resource: 'contentEntries',
350
+ * action: 'update',
351
+ * role: userRole,
352
+ * });
353
+ * ```
354
+ */
355
+ export function requireResourceOwnership(userId, resourceOwnerId, options) {
356
+ if (!isResourceOwner(userId, resourceOwnerId)) {
357
+ throw new UnauthorizedError(generateDenialMessage({
358
+ code: "OWNERSHIP_REQUIRED",
359
+ role: options.role ?? null,
360
+ resource: options.resource,
361
+ action: options.action,
362
+ }), {
363
+ code: "OWNERSHIP_REQUIRED",
364
+ resource: options.resource,
365
+ action: options.action,
366
+ role: options.role,
367
+ userId: userId,
368
+ requiredScope: "own",
369
+ });
370
+ }
371
+ }
372
+ /**
373
+ * Create an authorization context for a user.
374
+ *
375
+ * This is a convenience function for building the context object used by
376
+ * authorization functions. It validates that the user has a role assigned.
377
+ *
378
+ * @param userId - The user's ID
379
+ * @param role - The user's role (from getUserRole hook)
380
+ * @param customRoles - Optional custom role definitions
381
+ * @returns Authorization context for permission checks
382
+ * @throws UnauthorizedError if the user has no role assigned
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * // At the start of a mutation handler:
387
+ * const userRole = await getUserRole({ userId });
388
+ * const authCtx = createAuthContext(userId, userRole);
389
+ *
390
+ * // Later, check permissions with the context:
391
+ * requirePermission({
392
+ * ...authCtx,
393
+ * resource: 'contentEntries',
394
+ * action: 'create',
395
+ * });
396
+ * ```
397
+ */
398
+ export function createAuthContext(userId, role, customRoles) {
399
+ if (role === null) {
400
+ throw new UnauthorizedError("No CMS role assigned. Contact an administrator to get access.", {
401
+ code: "NO_ROLE",
402
+ userId,
403
+ });
404
+ }
405
+ const roleDefinition = getRole(role, customRoles);
406
+ if (!roleDefinition) {
407
+ throw new UnauthorizedError(`Unknown role "${role}". Contact an administrator to fix your role assignment.`, {
408
+ code: "UNKNOWN_ROLE",
409
+ role,
410
+ userId,
411
+ });
412
+ }
413
+ return {
414
+ userId,
415
+ role,
416
+ customRoles,
417
+ };
418
+ }
419
+ /**
420
+ * Check if a user can perform an action using an authorization context.
421
+ *
422
+ * This is a convenience wrapper around checkPermission that uses a pre-built
423
+ * authorization context.
424
+ *
425
+ * @param authCtx - The authorization context
426
+ * @param resource - The resource type being accessed
427
+ * @param action - The action being performed
428
+ * @param resourceOwnerId - Optional owner ID for ownership validation
429
+ * @returns Permission check result
430
+ */
431
+ export function canPerform(authCtx, resource, action, resourceOwnerId) {
432
+ return checkPermission({
433
+ userId: authCtx.userId,
434
+ role: authCtx.role,
435
+ resource,
436
+ action,
437
+ resourceOwnerId,
438
+ customRoles: authCtx.customRoles,
439
+ });
440
+ }
441
+ /**
442
+ * Require that a user can perform an action using an authorization context.
443
+ *
444
+ * This is a convenience wrapper around requirePermission that uses a pre-built
445
+ * authorization context.
446
+ *
447
+ * @param authCtx - The authorization context
448
+ * @param resource - The resource type being accessed
449
+ * @param action - The action being performed
450
+ * @param resourceOwnerId - Optional owner ID for ownership validation
451
+ * @returns The granted permission details
452
+ * @throws UnauthorizedError if permission is denied
453
+ */
454
+ export function mustPerform(authCtx, resource, action, resourceOwnerId) {
455
+ return requirePermission({
456
+ userId: authCtx.userId,
457
+ role: authCtx.role,
458
+ resource,
459
+ action,
460
+ resourceOwnerId,
461
+ customRoles: authCtx.customRoles,
462
+ });
463
+ }
464
+ //# sourceMappingURL=authorization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../src/component/authorization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Authorization Hooks Execution Module
3
+ *
4
+ * This module provides the infrastructure for executing authorization hooks
5
+ * that enable custom permission logic beyond the built-in RBAC system.
6
+ *
7
+ * Authorization hooks allow parent applications to:
8
+ * - Implement custom authorization logic (team-based, subscription-based, etc.)
9
+ * - Add additional restrictions beyond RBAC
10
+ * - Override RBAC decisions in special cases
11
+ * - Log and audit authorization decisions
12
+ *
13
+ * Hook execution order:
14
+ * 1. beforeRbac hook (can reject early or skip RBAC)
15
+ * 2. Built-in RBAC permission check (if not skipped)
16
+ * 3. afterRbac hook (additional restrictions)
17
+ * 4. Operation-specific hook (fine-grained control)
18
+ * 5. onDeny hook (if denied, can override)
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { executeAuthorizationHooks } from './authorizationHooks';
23
+ *
24
+ * // In a mutation handler
25
+ * const authResult = await executeAuthorizationHooks({
26
+ * hooks: config.authorizationHooks,
27
+ * context: {
28
+ * operation: 'contentEntries.create',
29
+ * userId: args.createdBy,
30
+ * role: userRole,
31
+ * contentTypeId: args.contentTypeId,
32
+ * operationData: args,
33
+ * },
34
+ * rbacCheck: () => checkPermission({ role: userRole, ... }),
35
+ * skipRbac: config.skipRbac,
36
+ * });
37
+ *
38
+ * if (!authResult.allowed) {
39
+ * throw new UnauthorizedError(authResult.reason ?? 'Access denied', { ... });
40
+ * }
41
+ * ```
42
+ */
43
+ import type { AuthorizationHooks, AuthorizationHookContext, CmsOperation } from "../client/types.js";
44
+ import { type PermissionCheckOptions, type PermissionCheckResult } from "./authorization.js";
45
+ import type { Resource, Action, RoleDefinition } from "./roles.js";
46
+ /**
47
+ * Options for executing the authorization hook chain.
48
+ */
49
+ export interface ExecuteAuthorizationOptions {
50
+ /**
51
+ * The authorization hooks configuration from ComponentConfig.
52
+ */
53
+ hooks?: AuthorizationHooks;
54
+ /**
55
+ * The context for this authorization check.
56
+ */
57
+ context: AuthorizationHookContext;
58
+ /**
59
+ * Options for the built-in RBAC permission check.
60
+ * If not provided, RBAC is skipped.
61
+ */
62
+ rbacOptions?: PermissionCheckOptions;
63
+ /**
64
+ * Whether to skip built-in RBAC checks entirely.
65
+ * From ComponentConfig.skipRbac
66
+ */
67
+ skipRbac?: boolean;
68
+ /**
69
+ * Custom role definitions to use for RBAC checks.
70
+ */
71
+ customRoles?: Record<string, RoleDefinition>;
72
+ }
73
+ /**
74
+ * Result from executing the authorization hook chain.
75
+ */
76
+ export interface AuthorizationResult {
77
+ /**
78
+ * Whether the operation is allowed.
79
+ */
80
+ allowed: boolean;
81
+ /**
82
+ * The reason for denial (if denied).
83
+ */
84
+ reason?: string;
85
+ /**
86
+ * Modified operation data from hooks (if any).
87
+ */
88
+ modifiedData?: Record<string, unknown>;
89
+ /**
90
+ * Which check denied the operation.
91
+ */
92
+ deniedBy?: "beforeRbac" | "rbac" | "authorize" | "afterRbac" | "operationHook";
93
+ /**
94
+ * The RBAC check result (if RBAC was run).
95
+ */
96
+ rbacResult?: PermissionCheckResult;
97
+ }
98
+ /**
99
+ * Maps a CMS operation to an RBAC resource and action.
100
+ */
101
+ export declare function operationToRbac(operation: CmsOperation): {
102
+ resource: Resource;
103
+ action: Action;
104
+ } | null;
105
+ /**
106
+ * Execute the full authorization hook chain for an operation.
107
+ *
108
+ * This function orchestrates the execution of all authorization hooks and the
109
+ * built-in RBAC check in the correct order:
110
+ *
111
+ * 1. **beforeRbac hook**: Can reject early or skip RBAC
112
+ * 2. **Built-in RBAC**: Standard role-based permission check
113
+ * 3. **authorize hook**: Receives RBAC decision, can override allow/deny
114
+ * 4. **afterRbac hook**: Additional restrictions after authorize passes
115
+ * 5. **Operation hook**: Operation-specific restrictions
116
+ * 6. **onDeny hook**: Can override denials
117
+ *
118
+ * @param options - Configuration for the authorization execution
119
+ * @returns AuthorizationResult indicating if the operation is allowed
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const result = await executeAuthorizationHooks({
124
+ * hooks: config.authorizationHooks,
125
+ * context: {
126
+ * operation: 'contentEntries.publish',
127
+ * userId: currentUser,
128
+ * role: 'editor',
129
+ * resourceId: entryId,
130
+ * resourceOwnerId: entry.createdBy,
131
+ * },
132
+ * rbacOptions: {
133
+ * role: 'editor',
134
+ * resource: 'contentEntries',
135
+ * action: 'publish',
136
+ * userId: currentUser,
137
+ * resourceOwnerId: entry.createdBy,
138
+ * },
139
+ * });
140
+ *
141
+ * if (!result.allowed) {
142
+ * throw new Error(result.reason ?? 'Operation not allowed');
143
+ * }
144
+ * ```
145
+ */
146
+ export declare function executeAuthorizationHooks(options: ExecuteAuthorizationOptions): Promise<AuthorizationResult>;
147
+ /**
148
+ * Create an authorization context for a content entry operation.
149
+ *
150
+ * @param operation - The CMS operation being performed
151
+ * @param userId - The user performing the operation
152
+ * @param role - The user's CMS role
153
+ * @param entry - The content entry (if available)
154
+ * @param contentType - The content type (if available)
155
+ * @param operationData - Additional operation data (args)
156
+ * @returns AuthorizationHookContext
157
+ */
158
+ export declare function createContentEntryAuthContext(operation: CmsOperation, userId: string | undefined, role: string | null | undefined, entry?: {
159
+ _id: unknown;
160
+ createdBy?: string;
161
+ contentTypeId: unknown;
162
+ }, contentType?: {
163
+ _id: unknown;
164
+ name: string;
165
+ }, operationData?: Record<string, unknown>): Omit<AuthorizationHookContext, "ctx">;
166
+ /**
167
+ * Create RBAC options from an authorization context.
168
+ *
169
+ * @param context - The authorization context
170
+ * @returns PermissionCheckOptions for the RBAC check
171
+ */
172
+ export declare function contextToRbacOptions(context: AuthorizationHookContext): PermissionCheckOptions | null;
173
+ /**
174
+ * Execute authorization for an operation and throw if denied.
175
+ *
176
+ * This is a convenience wrapper that executes hooks and throws
177
+ * UnauthorizedError if the operation is not allowed.
178
+ *
179
+ * @param options - Authorization execution options
180
+ * @throws UnauthorizedError if the operation is denied
181
+ * @returns The authorization result (if allowed)
182
+ */
183
+ export declare function requireAuthorization(options: ExecuteAuthorizationOptions): Promise<AuthorizationResult>;
184
+ //# sourceMappingURL=authorizationHooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorizationHooks.d.ts","sourceRoot":"","sources":["../../src/component/authorizationHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,wBAAwB,EAGxB,YAAY,EACb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE3B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkBnE;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAE3B;;OAEG;IACH,OAAO,EAAE,wBAAwB,CAAC;IAElC;;;OAGG;IACH,WAAW,CAAC,EAAE,sBAAsB,CAAC;IAErC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEvC;;OAEG;IACH,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,eAAe,CAAC;IAE/E;;OAEG;IACH,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+BtG;AAkED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,CA2R9B;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,YAAY,EACvB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,KAAK,CAAC,EAAE;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,EACpE,WAAW,CAAC,EAAE;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC,IAAI,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAWvC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,wBAAwB,GAChC,sBAAsB,GAAG,IAAI,CAa/B;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,CA2B9B"}