@revealui/core 0.2.1 → 0.3.0

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 (325) hide show
  1. package/dist/api/compression.d.ts.map +1 -1
  2. package/dist/api/payload-optimization.d.ts.map +1 -1
  3. package/dist/api/rate-limit.d.ts +29 -28
  4. package/dist/api/rate-limit.d.ts.map +1 -1
  5. package/dist/api/rate-limit.js +63 -3
  6. package/dist/api/response-cache.d.ts.map +1 -1
  7. package/dist/api/response-cache.js +1 -1
  8. package/dist/api/rest.d.ts.map +1 -1
  9. package/dist/api/rest.js +3 -2
  10. package/dist/auth/access.d.ts.map +1 -1
  11. package/dist/auth/index.d.ts.map +1 -1
  12. package/dist/cache/query-cache.d.ts +12 -10
  13. package/dist/cache/query-cache.d.ts.map +1 -1
  14. package/dist/cache/query-cache.js +38 -42
  15. package/dist/caching/app-cache.d.ts +5 -0
  16. package/dist/caching/app-cache.d.ts.map +1 -1
  17. package/dist/caching/app-cache.js +9 -1
  18. package/dist/caching/cdn-config.d.ts.map +1 -1
  19. package/dist/caching/cdn-config.js +4 -0
  20. package/dist/caching/edge-cache.d.ts +1 -1
  21. package/dist/caching/edge-cache.d.ts.map +1 -1
  22. package/dist/caching/edge-cache.js +36 -7
  23. package/dist/caching/index.d.ts +6 -0
  24. package/dist/caching/index.d.ts.map +1 -0
  25. package/dist/caching/index.js +5 -0
  26. package/dist/caching/service-worker.d.ts +6 -3
  27. package/dist/caching/service-worker.d.ts.map +1 -1
  28. package/dist/caching/service-worker.js +3 -2
  29. package/dist/client/admin/RichText.d.ts +1 -1
  30. package/dist/client/admin/RichText.d.ts.map +1 -1
  31. package/dist/client/admin/components/AdminDashboard.d.ts.map +1 -1
  32. package/dist/client/admin/components/AdminDashboard.js +178 -205
  33. package/dist/client/admin/components/CollectionList.d.ts.map +1 -1
  34. package/dist/client/admin/components/DocumentForm.d.ts.map +1 -1
  35. package/dist/client/admin/components/DocumentForm.js +130 -6
  36. package/dist/client/admin/components/GlobalForm.d.ts.map +1 -1
  37. package/dist/client/admin/context/ServerFunctionContext.d.ts +8 -0
  38. package/dist/client/admin/context/ServerFunctionContext.d.ts.map +1 -0
  39. package/dist/client/admin/context/ServerFunctionContext.js +15 -0
  40. package/dist/client/admin/i18n/en.d.ts.map +1 -1
  41. package/dist/client/admin/index.d.ts +1 -0
  42. package/dist/client/admin/index.d.ts.map +1 -1
  43. package/dist/client/admin/index.js +1 -0
  44. package/dist/client/admin/layout.d.ts +1 -1
  45. package/dist/client/admin/layout.d.ts.map +1 -1
  46. package/dist/client/admin/layout.js +3 -2
  47. package/dist/client/admin/page.d.ts.map +1 -1
  48. package/dist/client/admin/utils/apiClient.d.ts.map +1 -1
  49. package/dist/client/admin/utils/apiClient.js +0 -4
  50. package/dist/client/admin/utils/index.d.ts +0 -1
  51. package/dist/client/admin/utils/index.d.ts.map +1 -1
  52. package/dist/client/admin/utils/index.js +0 -1
  53. package/dist/client/admin/utils/serializeConfig.d.ts.map +1 -1
  54. package/dist/client/hooks.d.ts.map +1 -1
  55. package/dist/client/index.d.ts.map +1 -1
  56. package/dist/client/richtext/RichTextEditor.d.ts.map +1 -1
  57. package/dist/client/richtext/components/ImageNodeComponent.d.ts.map +1 -1
  58. package/dist/client/richtext/components/ImageNodeComponent.js +0 -1
  59. package/dist/client/richtext/components/ImageUploadButton.d.ts +2 -0
  60. package/dist/client/richtext/components/ImageUploadButton.d.ts.map +1 -1
  61. package/dist/client/richtext/components/ImageUploadButton.js +30 -15
  62. package/dist/client/richtext/index.d.ts.map +1 -1
  63. package/dist/client/richtext/nodes/DecoratorBlockNode.d.ts.map +1 -1
  64. package/dist/client/richtext/nodes/ImageNode.d.ts.map +1 -1
  65. package/dist/client/richtext/plugins/CollaborationPlugin.d.ts.map +1 -1
  66. package/dist/client/richtext/plugins/CursorsOverlayPlugin.d.ts.map +1 -1
  67. package/dist/client/richtext/plugins/FloatingToolbarPlugin.d.ts.map +1 -1
  68. package/dist/client/richtext/plugins/ImagePlugin.d.ts.map +1 -1
  69. package/dist/client/richtext/plugins/ToolbarPlugin.d.ts.map +1 -1
  70. package/dist/client/ui/index.d.ts.map +1 -1
  71. package/dist/client/ui/index.js +1 -1
  72. package/dist/collections/CollectionOperations.d.ts +7 -7
  73. package/dist/collections/CollectionOperations.d.ts.map +1 -1
  74. package/dist/collections/CollectionOperations.js +15 -1
  75. package/dist/collections/hooks.d.ts.map +1 -1
  76. package/dist/collections/index.d.ts.map +1 -1
  77. package/dist/collections/operations/create.d.ts +2 -4
  78. package/dist/collections/operations/create.d.ts.map +1 -1
  79. package/dist/collections/operations/create.js +7 -5
  80. package/dist/collections/operations/createMany.d.ts +12 -0
  81. package/dist/collections/operations/createMany.d.ts.map +1 -0
  82. package/dist/collections/operations/createMany.js +43 -0
  83. package/dist/collections/operations/delete.d.ts +1 -1
  84. package/dist/collections/operations/delete.d.ts.map +1 -1
  85. package/dist/collections/operations/delete.js +31 -2
  86. package/dist/collections/operations/deleteMany.d.ts +11 -0
  87. package/dist/collections/operations/deleteMany.d.ts.map +1 -0
  88. package/dist/collections/operations/deleteMany.js +50 -0
  89. package/dist/collections/operations/fieldHooks.d.ts +2 -2
  90. package/dist/collections/operations/fieldHooks.d.ts.map +1 -1
  91. package/dist/collections/operations/fieldHooks.js +4 -4
  92. package/dist/collections/operations/find.d.ts +2 -4
  93. package/dist/collections/operations/find.d.ts.map +1 -1
  94. package/dist/collections/operations/find.js +115 -8
  95. package/dist/collections/operations/findById.d.ts +3 -4
  96. package/dist/collections/operations/findById.d.ts.map +1 -1
  97. package/dist/collections/operations/findById.js +53 -1
  98. package/dist/collections/operations/sqlAdapter.d.ts +23 -0
  99. package/dist/collections/operations/sqlAdapter.d.ts.map +1 -0
  100. package/dist/collections/operations/sqlAdapter.js +76 -0
  101. package/dist/collections/operations/update.d.ts +3 -5
  102. package/dist/collections/operations/update.d.ts.map +1 -1
  103. package/dist/collections/operations/update.js +103 -11
  104. package/dist/collections/operations/updateMany.d.ts +11 -0
  105. package/dist/collections/operations/updateMany.d.ts.map +1 -0
  106. package/dist/collections/operations/updateMany.js +52 -0
  107. package/dist/collections/registry.d.ts +12 -0
  108. package/dist/collections/registry.d.ts.map +1 -0
  109. package/dist/collections/registry.js +38 -0
  110. package/dist/config/index.d.ts.map +1 -1
  111. package/dist/config/runtime.d.ts.map +1 -1
  112. package/dist/config/utils.d.ts +0 -10
  113. package/dist/config/utils.d.ts.map +1 -1
  114. package/dist/config/utils.js +0 -13
  115. package/dist/database/index.d.ts +3 -0
  116. package/dist/database/index.d.ts.map +1 -1
  117. package/dist/database/index.js +1 -5
  118. package/dist/database/safe-parse.d.ts.map +1 -1
  119. package/dist/database/ssl-config.d.ts.map +1 -1
  120. package/dist/database/type-adapter.d.ts.map +1 -1
  121. package/dist/database/universal-postgres.d.ts.map +1 -1
  122. package/dist/database/universal-postgres.js +6 -1
  123. package/dist/dataloader.d.ts.map +1 -1
  124. package/dist/error-handling/circuit-breaker.d.ts +1 -1
  125. package/dist/error-handling/circuit-breaker.d.ts.map +1 -1
  126. package/dist/error-handling/circuit-breaker.js +11 -3
  127. package/dist/error-handling/error-boundary.d.ts.map +1 -1
  128. package/dist/error-handling/error-reporter.d.ts +1 -1
  129. package/dist/error-handling/error-reporter.d.ts.map +1 -1
  130. package/dist/error-handling/error-reporter.js +19 -5
  131. package/dist/error-handling/fallback-components.d.ts.map +1 -1
  132. package/dist/error-handling/fallback-components.js +1 -1
  133. package/dist/error-handling/index.d.ts +2 -4
  134. package/dist/error-handling/index.d.ts.map +1 -1
  135. package/dist/error-handling/index.js +1 -4
  136. package/dist/error-handling/retry.d.ts.map +1 -1
  137. package/dist/error-handling/retry.js +13 -8
  138. package/dist/factories/builders.d.ts.map +1 -1
  139. package/dist/factories/index.d.ts.map +1 -1
  140. package/dist/features.d.ts +0 -4
  141. package/dist/features.d.ts.map +1 -1
  142. package/dist/features.js +0 -2
  143. package/dist/fieldTraversal.d.ts.map +1 -1
  144. package/dist/fields/config/types.d.ts.map +1 -1
  145. package/dist/fields/getDefaultValue.d.ts.map +1 -1
  146. package/dist/fields/getFieldPaths.d.ts.map +1 -1
  147. package/dist/fields/hooks/afterRead/index.d.ts.map +1 -1
  148. package/dist/fields/hooks/afterRead/promise.d.ts.map +1 -1
  149. package/dist/fields/hooks/afterRead/traverseFields.d.ts.map +1 -1
  150. package/dist/generated/types/cms.d.ts.map +1 -1
  151. package/dist/generated/types/cms.js +0 -1
  152. package/dist/generated/types/neon.d.ts.map +1 -1
  153. package/dist/generated/types/neon.js +4 -2
  154. package/dist/globals/GlobalOperations.d.ts.map +1 -1
  155. package/dist/globals/GlobalOperations.js +4 -2
  156. package/dist/globals/index.d.ts.map +1 -1
  157. package/dist/index.d.ts +4 -4
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +4 -4
  160. package/dist/instance/RevealUIInstance.d.ts.map +1 -1
  161. package/dist/instance/RevealUIInstance.js +6 -19
  162. package/dist/instance/index.d.ts.map +1 -1
  163. package/dist/instance/logger.d.ts.map +1 -1
  164. package/dist/instance/methods/create.d.ts.map +1 -1
  165. package/dist/instance/methods/create.js +0 -3
  166. package/dist/instance/methods/delete.d.ts.map +1 -1
  167. package/dist/instance/methods/delete.js +1 -4
  168. package/dist/instance/methods/find.d.ts.map +1 -1
  169. package/dist/instance/methods/find.js +0 -3
  170. package/dist/instance/methods/findById.d.ts.map +1 -1
  171. package/dist/instance/methods/findById.js +0 -3
  172. package/dist/instance/methods/hooks.d.ts.map +1 -1
  173. package/dist/instance/methods/update.d.ts.map +1 -1
  174. package/dist/instance/methods/update.js +0 -3
  175. package/dist/jobs/index.d.ts +16 -0
  176. package/dist/jobs/index.d.ts.map +1 -0
  177. package/dist/jobs/index.js +14 -0
  178. package/dist/jobs/queue.d.ts +57 -0
  179. package/dist/jobs/queue.d.ts.map +1 -0
  180. package/dist/jobs/queue.js +134 -0
  181. package/dist/license-encryption.d.ts +21 -0
  182. package/dist/license-encryption.d.ts.map +1 -0
  183. package/dist/license-encryption.js +74 -0
  184. package/dist/license.d.ts +20 -3
  185. package/dist/license.d.ts.map +1 -1
  186. package/dist/license.js +73 -6
  187. package/dist/monitoring/alerts.d.ts.map +1 -1
  188. package/dist/monitoring/cleanup-manager.d.ts.map +1 -1
  189. package/dist/monitoring/health-monitor.d.ts.map +1 -1
  190. package/dist/monitoring/index.d.ts.map +1 -1
  191. package/dist/monitoring/process-registry.d.ts.map +1 -1
  192. package/dist/monitoring/query-monitor.d.ts.map +1 -1
  193. package/dist/monitoring/types.d.ts.map +1 -1
  194. package/dist/monitoring/zombie-detector.d.ts.map +1 -1
  195. package/dist/monitoring/zombie-detector.js +5 -0
  196. package/dist/nextjs/index.d.ts.map +1 -1
  197. package/dist/nextjs/utilities.d.ts.map +1 -1
  198. package/dist/nextjs/withRevealUI.d.ts.map +1 -1
  199. package/dist/observability/alerts.d.ts.map +1 -1
  200. package/dist/observability/alerts.js +1 -2
  201. package/dist/observability/health-check.d.ts +0 -4
  202. package/dist/observability/health-check.d.ts.map +1 -1
  203. package/dist/observability/health-check.js +0 -36
  204. package/dist/observability/index.d.ts.map +1 -1
  205. package/dist/observability/logger.d.ts.map +1 -1
  206. package/dist/observability/logger.js +1 -1
  207. package/dist/observability/metrics.d.ts.map +1 -1
  208. package/dist/observability/tracing.d.ts.map +1 -1
  209. package/dist/observability/tracing.js +0 -1
  210. package/dist/optimization/asset-optimizer.d.ts +6 -2
  211. package/dist/optimization/asset-optimizer.d.ts.map +1 -1
  212. package/dist/optimization/asset-optimizer.js +31 -7
  213. package/dist/optimization/bundle-analyzer.d.ts +1 -1
  214. package/dist/optimization/bundle-analyzer.d.ts.map +1 -1
  215. package/dist/optimization/bundle-analyzer.js +29 -5
  216. package/dist/optimization/code-splitting.d.ts +0 -10
  217. package/dist/optimization/code-splitting.d.ts.map +1 -1
  218. package/dist/optimization/code-splitting.js +0 -16
  219. package/dist/plugins/form-builder.d.ts.map +1 -1
  220. package/dist/plugins/index.d.ts.map +1 -1
  221. package/dist/plugins/nested-docs.d.ts +4 -0
  222. package/dist/plugins/nested-docs.d.ts.map +1 -1
  223. package/dist/plugins/nested-docs.js +50 -5
  224. package/dist/plugins/redirects.d.ts.map +1 -1
  225. package/dist/queries/index.d.ts.map +1 -1
  226. package/dist/queries/queryBuilder.d.ts.map +1 -1
  227. package/dist/queries/queryBuilder.js +9 -2
  228. package/dist/relationships/analyzer.d.ts.map +1 -1
  229. package/dist/relationships/analyzer.js +8 -0
  230. package/dist/relationships/index.d.ts.map +1 -1
  231. package/dist/relationships/populate-core.d.ts +57 -0
  232. package/dist/relationships/populate-core.d.ts.map +1 -0
  233. package/dist/relationships/populate-core.js +116 -0
  234. package/dist/relationships/populate-helpers.d.ts +5 -51
  235. package/dist/relationships/populate-helpers.d.ts.map +1 -1
  236. package/dist/relationships/populate-helpers.js +4 -109
  237. package/dist/relationships/population.d.ts +1 -9
  238. package/dist/relationships/population.d.ts.map +1 -1
  239. package/dist/relationships/population.js +8 -3
  240. package/dist/revealui.d.ts.map +1 -1
  241. package/dist/richtext/exports/client/rcc.d.ts.map +1 -1
  242. package/dist/richtext/exports/client/rcc.js +1 -1
  243. package/dist/richtext/exports/server/rsc.d.ts +17 -0
  244. package/dist/richtext/exports/server/rsc.d.ts.map +1 -1
  245. package/dist/richtext/exports/server/rsc.js +61 -5
  246. package/dist/richtext/index.d.ts.map +1 -1
  247. package/dist/richtext/lexical.d.ts.map +1 -1
  248. package/dist/security/audit.d.ts +1 -1
  249. package/dist/security/audit.d.ts.map +1 -1
  250. package/dist/security/audit.js +4 -2
  251. package/dist/security/auth.d.ts +29 -160
  252. package/dist/security/auth.d.ts.map +1 -1
  253. package/dist/security/auth.js +148 -367
  254. package/dist/security/authorization.d.ts +7 -31
  255. package/dist/security/authorization.d.ts.map +1 -1
  256. package/dist/security/authorization.js +72 -14
  257. package/dist/security/encryption.d.ts +56 -44
  258. package/dist/security/encryption.d.ts.map +1 -1
  259. package/dist/security/encryption.js +113 -96
  260. package/dist/security/gdpr-storage.d.ts +102 -0
  261. package/dist/security/gdpr-storage.d.ts.map +1 -0
  262. package/dist/security/gdpr-storage.js +65 -0
  263. package/dist/security/gdpr.d.ts +57 -37
  264. package/dist/security/gdpr.d.ts.map +1 -1
  265. package/dist/security/gdpr.js +155 -89
  266. package/dist/security/headers.d.ts +4 -2
  267. package/dist/security/headers.d.ts.map +1 -1
  268. package/dist/security/headers.js +35 -17
  269. package/dist/security/index.d.ts +3 -16
  270. package/dist/security/index.d.ts.map +1 -1
  271. package/dist/security/index.js +3 -16
  272. package/dist/server/index.d.ts.map +1 -1
  273. package/dist/server/renderPage.d.ts.map +1 -1
  274. package/dist/storage/index.d.ts +1 -0
  275. package/dist/storage/index.d.ts.map +1 -1
  276. package/dist/storage/index.js +2 -4
  277. package/dist/storage/vercel-blob.d.ts.map +1 -1
  278. package/dist/translations/index.d.ts.map +1 -1
  279. package/dist/types/access.d.ts.map +1 -1
  280. package/dist/types/api.d.ts.map +1 -1
  281. package/dist/types/cms.d.ts.map +1 -1
  282. package/dist/types/config.d.ts.map +1 -1
  283. package/dist/types/core.d.ts.map +1 -1
  284. package/dist/types/extensions.d.ts.map +1 -1
  285. package/dist/types/frontend.d.ts.map +1 -1
  286. package/dist/types/generated.d.ts.map +1 -1
  287. package/dist/types/hooks.d.ts.map +1 -1
  288. package/dist/types/index.d.ts +1 -1
  289. package/dist/types/index.d.ts.map +1 -1
  290. package/dist/types/interfaces/app.d.ts.map +1 -1
  291. package/dist/types/jobs.d.ts.map +1 -1
  292. package/dist/types/legacy.d.ts.map +1 -1
  293. package/dist/types/plugins.d.ts.map +1 -1
  294. package/dist/types/query.d.ts.map +1 -1
  295. package/dist/types/request.d.ts.map +1 -1
  296. package/dist/types/richtext.d.ts.map +1 -1
  297. package/dist/types/runtime.d.ts +59 -1
  298. package/dist/types/runtime.d.ts.map +1 -1
  299. package/dist/types/schema.d.ts.map +1 -1
  300. package/dist/types/user.d.ts.map +1 -1
  301. package/dist/utils/access-conversion.d.ts.map +1 -1
  302. package/dist/utils/api-wrapper.d.ts.map +1 -1
  303. package/dist/utils/api-wrapper.js +1 -1
  304. package/dist/utils/block-conversion.d.ts.map +1 -1
  305. package/dist/utils/cache.d.ts.map +1 -1
  306. package/dist/utils/deep-clone.js +0 -1
  307. package/dist/utils/error-responses.d.ts.map +1 -1
  308. package/dist/utils/errors.d.ts +36 -0
  309. package/dist/utils/errors.d.ts.map +1 -1
  310. package/dist/utils/errors.js +103 -0
  311. package/dist/utils/field-conversion.d.ts +1 -1
  312. package/dist/utils/field-conversion.d.ts.map +1 -1
  313. package/dist/utils/flattenResult.d.ts.map +1 -1
  314. package/dist/utils/flattenResult.js +0 -1
  315. package/dist/utils/getBlockSelect.d.ts.map +1 -1
  316. package/dist/utils/getSelectMode.d.ts.map +1 -1
  317. package/dist/utils/isValidID.d.ts.map +1 -1
  318. package/dist/utils/json-parsing.d.ts.map +1 -1
  319. package/dist/utils/logger-client.d.ts.map +1 -1
  320. package/dist/utils/logger-server.d.ts.map +1 -1
  321. package/dist/utils/logger.d.ts.map +1 -1
  322. package/dist/utils/request-context.d.ts.map +1 -1
  323. package/dist/utils/stripUnselectedFields.d.ts.map +1 -1
  324. package/dist/utils/type-guards.d.ts.map +1 -1
  325. package/package.json +39 -7
@@ -1 +1 @@
1
- {"version":3,"file":"findById.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/findById.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,aAAa,EAEd,MAAM,sBAAsB,CAAA;AAG7B,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE;IACF,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;CACtE,GAAG,IAAI,EACR,OAAO,EAAE;IACP,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,aAAa,CAAA;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB,GACA,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA2DhC"}
1
+ {"version":3,"file":"findById.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/findById.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACd,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAI9B,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE;IACP,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GACA,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAwHhC"}
@@ -5,17 +5,69 @@
5
5
  */
6
6
  import { afterRead } from '../../fields/hooks/afterRead/index.js';
7
7
  import { deserializeJsonFields } from '../../utils/json-parsing.js';
8
+ import { selectByIdQuery } from './sqlAdapter.js';
8
9
  export async function findByID(config, db, options) {
9
10
  const { id, depth = 0, req, populate: populateOption } = options;
10
11
  // Validate depth
11
12
  if (depth < 0 || depth > 3) {
12
13
  throw new Error(`Depth must be between 0 and 3, got ${depth}`);
13
14
  }
15
+ // --- Access control enforcement ---
16
+ if (!options.overrideAccess) {
17
+ const accessConfig = config.access;
18
+ const readAccess = accessConfig?.read;
19
+ if (readAccess) {
20
+ if (!req)
21
+ return null; // No request context = deny
22
+ const result = await readAccess({ req, id });
23
+ if (result === false)
24
+ return null;
25
+ // If result is a WhereClause (row-level filter), we fetch the doc first then verify.
26
+ // For findByID, we check after fetch whether the doc matches the access filter.
27
+ // Boolean true = allow, WhereClause = post-fetch filter (handled below after query).
28
+ }
29
+ }
30
+ if (db?.collectionStorage?.findByID) {
31
+ const doc = await db.collectionStorage.findByID(config, { id });
32
+ if (doc !== undefined) {
33
+ if (!doc)
34
+ return null;
35
+ if (req && depth > 0) {
36
+ const sanitizedConfig = {
37
+ ...config,
38
+ fields: config.fields,
39
+ flattenedFields: config.fields,
40
+ endpoints: config.endpoints === false ? undefined : config.endpoints,
41
+ };
42
+ return await afterRead({
43
+ collection: sanitizedConfig,
44
+ context: req.context || {},
45
+ currentDepth: 1,
46
+ depth,
47
+ doc,
48
+ draft: false,
49
+ fallbackLocale: req.fallbackLocale || 'en',
50
+ findMany: false,
51
+ flattenLocales: true,
52
+ global: null,
53
+ locale: req.locale || 'en',
54
+ overrideAccess: false,
55
+ populate: populateOption,
56
+ req,
57
+ select: undefined,
58
+ showHiddenFields: false,
59
+ });
60
+ }
61
+ return doc;
62
+ }
63
+ }
14
64
  if (db?.query) {
65
+ // Dynamic collection storage is quarantined in sqlAdapter.ts until this
66
+ // layer is redesigned around typed tables that Drizzle can model directly.
15
67
  const tableName = config.slug;
16
68
  // Ensure id is a string for consistent comparison
17
69
  const idString = String(id);
18
- const query = `SELECT * FROM "${tableName}" WHERE id = $1 LIMIT 1`;
70
+ const query = selectByIdQuery(tableName);
19
71
  const result = await db.query(query, [idString]);
20
72
  const rawDoc = result.rows[0];
21
73
  if (!rawDoc) {
@@ -0,0 +1,23 @@
1
+ import type { DatabaseResult } from '../../types/index.js';
2
+ export type QueryableCollectionDb = {
3
+ query: (query: string, values?: unknown[]) => Promise<DatabaseResult>;
4
+ };
5
+ export declare function validateSlug(slug: string): void;
6
+ export declare function validateColumnName(column: string): void;
7
+ export declare function escapeIdentifier(identifier: string): string;
8
+ export declare function collectionTable(configSlug: string): string;
9
+ export declare function selectByIdQuery(configSlug: string): string;
10
+ export declare function deleteByIdQuery(configSlug: string): string;
11
+ export declare function countDocumentsQuery(configSlug: string, whereClause?: string): string;
12
+ export declare function listDocumentsQuery(configSlug: string, whereClause: string, orderByClause: string, limitParam: number, offsetParam: number): string;
13
+ export declare function insertDocumentQuery(configSlug: string, columns: string[]): string;
14
+ export declare function selectJsonByIdQuery(configSlug: string): string;
15
+ export declare function checkExistsByIdQuery(configSlug: string): string;
16
+ export declare function updateByIdQuery(configSlug: string, keys: string[]): string;
17
+ /**
18
+ * Version-aware UPDATE: includes `version = version + 1` in SET
19
+ * and `AND version = $N` in WHERE for optimistic locking.
20
+ * Returns the number of affected rows (0 = conflict).
21
+ */
22
+ export declare function updateByIdWithVersionQuery(configSlug: string, keys: string[]): string;
23
+ //# sourceMappingURL=sqlAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlAdapter.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/sqlAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CACvE,CAAC;AAgBF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM/C;AAKD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpF;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,MAAM,CAER;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAKjF;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAI1E;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAKrF"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Dynamic collections resolve table and column names at runtime from config.
3
+ * Drizzle is the default elsewhere in the codebase. This adapter exists only
4
+ * because these collection operations target runtime-selected tables/columns
5
+ * that do not map cleanly to Drizzle's compile-time table model yet.
6
+ *
7
+ * Treat this as a temporary quarantine boundary for dynamic SQL. Do not add
8
+ * inline SQL back into the collection operations; extend this adapter or
9
+ * redesign the collection storage layer toward typed tables instead.
10
+ */
11
+ /** Only lowercase alphanumeric, hyphens, and underscores (1-63 chars, PostgreSQL identifier limit). */
12
+ const VALID_SLUG = /^[a-z][a-z0-9_-]{0,62}$/;
13
+ export function validateSlug(slug) {
14
+ if (!VALID_SLUG.test(slug)) {
15
+ throw new Error(`Invalid collection slug: "${slug}". Slugs must start with a lowercase letter and contain only lowercase alphanumeric characters, hyphens, and underscores (max 63 chars).`);
16
+ }
17
+ }
18
+ /** Only lowercase alphanumeric and underscores (PostgreSQL column name safe). */
19
+ const VALID_COLUMN = /^[a-z_][a-z0-9_]{0,62}$/;
20
+ export function validateColumnName(column) {
21
+ if (!VALID_COLUMN.test(column)) {
22
+ throw new Error(`Invalid column name: "${column}". Column names must start with a lowercase letter or underscore and contain only lowercase alphanumeric characters and underscores.`);
23
+ }
24
+ }
25
+ export function escapeIdentifier(identifier) {
26
+ return identifier.replace(/"/g, '""');
27
+ }
28
+ export function collectionTable(configSlug) {
29
+ validateSlug(configSlug);
30
+ return `"${escapeIdentifier(configSlug)}"`;
31
+ }
32
+ export function selectByIdQuery(configSlug) {
33
+ return `SELECT * FROM ${collectionTable(configSlug)} WHERE id = $1 LIMIT 1`;
34
+ }
35
+ export function deleteByIdQuery(configSlug) {
36
+ return `DELETE FROM ${collectionTable(configSlug)} WHERE id = $1`;
37
+ }
38
+ export function countDocumentsQuery(configSlug, whereClause) {
39
+ return whereClause
40
+ ? `SELECT COUNT(*) as total FROM ${collectionTable(configSlug)} WHERE ${whereClause}`
41
+ : `SELECT COUNT(*) as total FROM ${collectionTable(configSlug)}`;
42
+ }
43
+ export function listDocumentsQuery(configSlug, whereClause, orderByClause, limitParam, offsetParam) {
44
+ return `SELECT * FROM ${collectionTable(configSlug)} ${whereClause ? `WHERE ${whereClause}` : ''} ${orderByClause} LIMIT $${limitParam} OFFSET $${offsetParam}`;
45
+ }
46
+ export function insertDocumentQuery(configSlug, columns) {
47
+ for (const col of columns)
48
+ validateColumnName(col);
49
+ const escapedColumns = columns.map((column) => `"${escapeIdentifier(column)}"`).join(', ');
50
+ const placeholders = columns.map((_, i) => `$${i + 2}`).join(', ');
51
+ return `INSERT INTO ${collectionTable(configSlug)} (id, ${escapedColumns}) VALUES ($1, ${placeholders})`;
52
+ }
53
+ export function selectJsonByIdQuery(configSlug) {
54
+ return `SELECT _json FROM ${collectionTable(configSlug)} WHERE id = $1 LIMIT 1`;
55
+ }
56
+ export function checkExistsByIdQuery(configSlug) {
57
+ return `SELECT id FROM ${collectionTable(configSlug)} WHERE id = $1 LIMIT 1`;
58
+ }
59
+ export function updateByIdQuery(configSlug, keys) {
60
+ for (const key of keys)
61
+ validateColumnName(key);
62
+ const setClause = keys.map((key, i) => `"${escapeIdentifier(key)}" = $${i + 1}`).join(', ');
63
+ return `UPDATE ${collectionTable(configSlug)} SET ${setClause} WHERE id = $${keys.length + 1}`;
64
+ }
65
+ /**
66
+ * Version-aware UPDATE: includes `version = version + 1` in SET
67
+ * and `AND version = $N` in WHERE for optimistic locking.
68
+ * Returns the number of affected rows (0 = conflict).
69
+ */
70
+ export function updateByIdWithVersionQuery(configSlug, keys) {
71
+ for (const key of keys)
72
+ validateColumnName(key);
73
+ const setClause = keys.map((key, i) => `"${escapeIdentifier(key)}" = $${i + 1}`).join(', ');
74
+ // version param is at keys.length + 1, id param is at keys.length + 2
75
+ return `UPDATE ${collectionTable(configSlug)} SET ${setClause}, "version" = "version" + 1 WHERE id = $${keys.length + 2} AND "version" = $${keys.length + 1}`;
76
+ }
@@ -1,10 +1,8 @@
1
1
  /**
2
2
  * Update Operation
3
3
  *
4
- * Updates an existing document with validation, password hashing, and JSON field handling.
4
+ * Updates an existing document with access control, validation, password hashing, and JSON field handling.
5
5
  */
6
- import type { DatabaseResult, RevealCollectionConfig, RevealDocument, RevealUpdateOptions } from '../../types/index.js';
7
- export declare function update(config: RevealCollectionConfig, db: {
8
- query: (query: string, values?: unknown[]) => Promise<DatabaseResult>;
9
- } | null, options: RevealUpdateOptions): Promise<RevealDocument>;
6
+ import type { QueryableDatabaseAdapter, RevealCollectionConfig, RevealDocument, RevealUpdateOptions } from '../../types/index.js';
7
+ export declare function update(config: RevealCollectionConfig, db: QueryableDatabaseAdapter | null, options: RevealUpdateOptions): Promise<RevealDocument>;
10
8
  //# sourceMappingURL=update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/update.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,cAAc,EAEd,mBAAmB,EACpB,MAAM,sBAAsB,CAAA;AAM7B,wBAAsB,MAAM,CAC1B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE;IACF,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;CACtE,GAAG,IAAI,EACR,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAgJzB"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/update.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EAGd,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAiF9B,wBAAsB,MAAM,CAC1B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAkMzB"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Update Operation
3
3
  *
4
- * Updates an existing document with validation, password hashing, and JSON field handling.
4
+ * Updates an existing document with access control, validation, password hashing, and JSON field handling.
5
5
  */
6
6
  import bcrypt from 'bcryptjs';
7
7
  import { defaultLogger } from '../../instance/logger.js';
@@ -9,10 +9,61 @@ import { collectJsonFields, serializeValueForDatabase } from '../../utils/json-p
9
9
  import { flattenFields, isJsonFieldType } from '../../utils/type-guards.js';
10
10
  import { runBeforeFieldHooks } from './fieldHooks.js';
11
11
  import { findByID } from './findById.js';
12
+ import { checkExistsByIdQuery, selectJsonByIdQuery, updateByIdQuery, updateByIdWithVersionQuery, } from './sqlAdapter.js';
13
+ /**
14
+ * Recursively deep-merge two plain objects. Arrays, nulls, Dates, and
15
+ * primitives in `source` replace the corresponding key in `target`.
16
+ * Only plain-object vs plain-object pairs are merged recursively.
17
+ */
18
+ function deepMergeJson(target, source) {
19
+ const result = structuredClone(target);
20
+ for (const key of Object.keys(source)) {
21
+ const sourceVal = source[key];
22
+ const targetVal = result[key];
23
+ if (sourceVal !== null &&
24
+ typeof sourceVal === 'object' &&
25
+ !Array.isArray(sourceVal) &&
26
+ targetVal !== null &&
27
+ typeof targetVal === 'object' &&
28
+ !Array.isArray(targetVal)) {
29
+ result[key] = deepMergeJson(targetVal, sourceVal);
30
+ }
31
+ else {
32
+ result[key] = structuredClone(sourceVal);
33
+ }
34
+ }
35
+ return result;
36
+ }
37
+ /**
38
+ * Evaluate a collection's access.update function.
39
+ * Returns true (allow) or false (deny).
40
+ */
41
+ async function evaluateUpdateAccess(config, options) {
42
+ if (options.overrideAccess)
43
+ return true;
44
+ const accessConfig = config.access;
45
+ const updateAccess = accessConfig?.update;
46
+ // No access rule defined = allow all (backward compatible)
47
+ if (!updateAccess)
48
+ return true;
49
+ const req = options.req;
50
+ if (!req)
51
+ return false; // No request context = deny (safe default)
52
+ const result = await updateAccess({ req, id: options.id, data: options.data });
53
+ if (result === false)
54
+ return false;
55
+ // Any truthy result (true, WhereClause) = allowed for single-document operations
56
+ return !!result;
57
+ }
12
58
  export async function update(config, db, options) {
13
59
  const { id, data } = options;
60
+ // --- Access control enforcement ---
61
+ const allowed = await evaluateUpdateAccess(config, options);
62
+ if (!allowed) {
63
+ throw new Error('Access denied: insufficient permissions to update this document');
64
+ }
14
65
  // Run beforeValidate field hooks before validation so they can transform values.
15
- await runBeforeFieldHooks(config, data, 'update', 'beforeValidate');
66
+ await runBeforeFieldHooks(config, data, 'update', 'beforeValidate', undefined, options.req);
16
67
  // Validate email format if email field is being updated
17
68
  if (config.fields) {
18
69
  for (const field of config.fields) {
@@ -42,13 +93,15 @@ export async function update(config, db, options) {
42
93
  }
43
94
  }
44
95
  // Run beforeChange field hooks after validation but before the DB write.
45
- await runBeforeFieldHooks(config, data, 'update', 'beforeChange');
96
+ await runBeforeFieldHooks(config, data, 'update', 'beforeChange', undefined, options.req);
46
97
  // Hash password if present and not already hashed (doesn't start with $2a$ or $2b$)
47
98
  if (data.password && typeof data.password === 'string' && !data.password.startsWith('$2')) {
48
- const saltRounds = 10;
99
+ const saltRounds = 12;
49
100
  data.password = await bcrypt.hash(data.password, saltRounds);
50
101
  }
51
102
  if (db?.query) {
103
+ // Dynamic collection storage is quarantined in sqlAdapter.ts until this
104
+ // layer is redesigned around typed tables that Drizzle can model directly.
52
105
  const tableName = config.slug;
53
106
  // Build UPDATE query (PostgreSQL uses $1, $2 style)
54
107
  // Serialize complex values (objects, arrays) to JSON strings for SQLite
@@ -57,7 +110,23 @@ export async function update(config, db, options) {
57
110
  .filter((field) => isJsonFieldType(field) && field.name)
58
111
  .map((field) => field.name)
59
112
  .filter((name) => typeof name === 'string'));
60
- const keys = Object.keys(data).filter((k) => k !== 'id' && !jsonFieldNames.has(k));
113
+ // Build allowlist from collection fields + system columns to prevent SQL injection via crafted keys
114
+ const allowedColumns = new Set([
115
+ 'id',
116
+ 'createdAt',
117
+ 'updatedAt',
118
+ 'created_at',
119
+ 'updated_at',
120
+ '_json',
121
+ 'password',
122
+ ]);
123
+ if (config.fields) {
124
+ for (const field of config.fields) {
125
+ if (field.name)
126
+ allowedColumns.add(field.name);
127
+ }
128
+ }
129
+ const keys = Object.keys(data).filter((k) => k !== 'id' && !jsonFieldNames.has(k) && allowedColumns.has(k));
61
130
  const jsonKeys = Object.keys(data).filter((k) => k !== 'id' && jsonFieldNames.has(k));
62
131
  // Collect JSON fields to update using collectJsonFields utility
63
132
  const jsonUpdates = collectJsonFields(data, jsonFieldNames);
@@ -67,7 +136,7 @@ export async function update(config, db, options) {
67
136
  let existingJson = {};
68
137
  if (jsonFieldNames.size > 0) {
69
138
  // Fetch _json to preserve existing JSON fields (even when only updating non-JSON fields)
70
- const rawQuery = `SELECT _json FROM "${tableName}" WHERE id = $1 LIMIT 1`;
139
+ const rawQuery = selectJsonByIdQuery(tableName);
71
140
  const rawResult = await db.query(rawQuery, [String(id)]);
72
141
  if (!rawResult.rows[0]) {
73
142
  throw new Error(`Document with id ${id} not found`);
@@ -95,7 +164,7 @@ export async function update(config, db, options) {
95
164
  }
96
165
  else if (keys.length > 0) {
97
166
  // No JSON fields in collection - just verify document exists
98
- const checkQuery = `SELECT id FROM "${tableName}" WHERE id = $1 LIMIT 1`;
167
+ const checkQuery = checkExistsByIdQuery(tableName);
99
168
  const checkResult = await db.query(checkQuery, [String(id)]);
100
169
  if (!checkResult.rows[0]) {
101
170
  throw new Error(`Document with id ${id} not found`);
@@ -104,13 +173,12 @@ export async function update(config, db, options) {
104
173
  // Merge existing JSON with updates (only if we have JSON fields)
105
174
  let mergedJson = {};
106
175
  if (jsonFieldNames.size > 0) {
107
- mergedJson = { ...existingJson, ...jsonUpdates };
176
+ mergedJson = deepMergeJson(existingJson, jsonUpdates);
108
177
  // Only include _json in UPDATE if there are actual changes or existing JSON to preserve
109
178
  if (jsonKeys.length > 0 || Object.keys(existingJson).length > 0) {
110
179
  keys.push('_json');
111
180
  }
112
181
  }
113
- const setClause = keys.map((key, i) => `"${key}" = $${i + 1}`).join(', ');
114
182
  const values = keys.map((key) => {
115
183
  if (key === '_json') {
116
184
  // Serialize merged JSON fields object to JSON string
@@ -121,8 +189,32 @@ export async function update(config, db, options) {
121
189
  });
122
190
  // Ensure id is a string for consistent comparison
123
191
  const idString = String(id);
124
- const query = `UPDATE "${tableName}" SET ${setClause} WHERE id = $${keys.length + 1}`;
125
- await db.query(query, [...values, idString]);
192
+ // Optimistic locking: if the caller provides a `version` field, use version-aware update
193
+ // to detect concurrent modifications. The version is stripped from the SET clause and
194
+ // moved to the WHERE clause; the DB auto-increments version on success.
195
+ const clientVersion = typeof data.version === 'number' ? data.version : undefined;
196
+ const updateKeys = clientVersion !== undefined ? keys.filter((k) => k !== 'version') : keys;
197
+ const updateValues = clientVersion !== undefined
198
+ ? updateKeys.map((key) => {
199
+ if (key === '_json')
200
+ return serializeValueForDatabase(mergedJson);
201
+ return serializeValueForDatabase(data[key]);
202
+ })
203
+ : values;
204
+ if (clientVersion !== undefined) {
205
+ const query = updateByIdWithVersionQuery(tableName, updateKeys);
206
+ const result = await db.query(query, [...updateValues, clientVersion, idString]);
207
+ if (result.rowCount === 0) {
208
+ // Document exists but version mismatch — concurrent edit detected
209
+ const err = new Error('Document was modified by another user. Refresh and try again.');
210
+ err.statusCode = 409;
211
+ throw err;
212
+ }
213
+ }
214
+ else {
215
+ const query = updateByIdQuery(tableName, updateKeys);
216
+ await db.query(query, [...updateValues, idString]);
217
+ }
126
218
  // Return updated document (use idString for consistency)
127
219
  const updatedDoc = await findByID(config, db, { id: idString });
128
220
  if (!updatedDoc) {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * updateMany Operation
3
+ *
4
+ * Updates multiple documents in a single transaction. All-or-nothing: if any
5
+ * update fails, the entire batch is rolled back.
6
+ *
7
+ * Documents without a db adapter fall back to in-memory objects (no transaction).
8
+ */
9
+ import type { BatchResult, BatchUpdateOptions, QueryableDatabaseAdapter, RevealCollectionConfig, RevealDocument } from '../../types/index.js';
10
+ export declare function updateMany(config: RevealCollectionConfig, db: QueryableDatabaseAdapter | null, options: BatchUpdateOptions): Promise<BatchResult<RevealDocument>>;
11
+ //# sourceMappingURL=updateMany.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateMany.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/updateMany.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACf,MAAM,sBAAsB,CAAC;AAG9B,wBAAsB,UAAU,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CA2CtC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * updateMany Operation
3
+ *
4
+ * Updates multiple documents in a single transaction. All-or-nothing: if any
5
+ * update fails, the entire batch is rolled back.
6
+ *
7
+ * Documents without a db adapter fall back to in-memory objects (no transaction).
8
+ */
9
+ import { update } from './update.js';
10
+ export async function updateMany(config, db, options) {
11
+ const results = [];
12
+ const errors = [];
13
+ if (!db?.query || options.updates.length === 0) {
14
+ // No DB or empty batch: run each update independently (no transaction available).
15
+ for (const [i, item] of options.updates.entries()) {
16
+ try {
17
+ const doc = await update(config, db, {
18
+ id: item.id,
19
+ data: item.data,
20
+ req: options.req,
21
+ overrideAccess: options.overrideAccess,
22
+ });
23
+ results.push(doc);
24
+ }
25
+ catch (error) {
26
+ errors.push({ index: i, error: error instanceof Error ? error.message : String(error) });
27
+ }
28
+ }
29
+ return { results, errors };
30
+ }
31
+ // Wrap all updates in a transaction: stop on first error, rollback on failure.
32
+ await db.query('BEGIN');
33
+ try {
34
+ for (const item of options.updates) {
35
+ const doc = await update(config, db, {
36
+ id: item.id,
37
+ data: item.data,
38
+ req: options.req,
39
+ overrideAccess: options.overrideAccess,
40
+ });
41
+ results.push(doc);
42
+ }
43
+ await db.query('COMMIT');
44
+ }
45
+ catch (error) {
46
+ await db.query('ROLLBACK');
47
+ const index = results.length; // Index of the failing item
48
+ errors.push({ index, error: error instanceof Error ? error.message : String(error) });
49
+ return { results: [], errors };
50
+ }
51
+ return { results, errors };
52
+ }
@@ -0,0 +1,12 @@
1
+ import type { RevealCollectionConfig } from '../types/index.js';
2
+ export type CollectionStorageMode = 'dynamic' | 'typed-candidate';
3
+ export interface CollectionStorageDescriptor {
4
+ slug: string;
5
+ tableName: string;
6
+ storageMode: CollectionStorageMode;
7
+ allowedColumns: string[];
8
+ jsonFieldNames: string[];
9
+ }
10
+ export declare function buildCollectionStorageDescriptor(collection: RevealCollectionConfig): CollectionStorageDescriptor;
11
+ export declare function buildCollectionStorageRegistry(collections: RevealCollectionConfig[] | undefined): Record<string, CollectionStorageDescriptor>;
12
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/collections/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAiB,MAAM,mBAAmB,CAAC;AAG/E,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,iBAAiB,CAAC;AAElE,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,qBAAqB,CAAC;IACnC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAID,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,sBAAsB,GACjC,2BAA2B,CA6B7B;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,sBAAsB,EAAE,GAAG,SAAS,GAChD,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAM7C"}
@@ -0,0 +1,38 @@
1
+ import { flattenFields, isJsonFieldType } from '../utils/type-guards.js';
2
+ const TYPED_CANDIDATE_SLUGS = new Set(['sites', 'pages', 'posts', 'media', 'users']);
3
+ export function buildCollectionStorageDescriptor(collection) {
4
+ const flattenedFields = flattenFields(collection.fields || []);
5
+ const allowedColumns = new Set([
6
+ 'id',
7
+ 'createdAt',
8
+ 'updatedAt',
9
+ 'created_at',
10
+ 'updated_at',
11
+ '_json',
12
+ 'password',
13
+ ]);
14
+ const jsonFieldNames = new Set();
15
+ for (const field of flattenedFields) {
16
+ if (!field.name)
17
+ continue;
18
+ if (isJsonFieldType(field)) {
19
+ jsonFieldNames.add(field.name);
20
+ continue;
21
+ }
22
+ allowedColumns.add(field.name);
23
+ }
24
+ return {
25
+ slug: collection.slug,
26
+ tableName: collection.slug,
27
+ storageMode: TYPED_CANDIDATE_SLUGS.has(collection.slug) ? 'typed-candidate' : 'dynamic',
28
+ allowedColumns: [...allowedColumns],
29
+ jsonFieldNames: [...jsonFieldNames],
30
+ };
31
+ }
32
+ export function buildCollectionStorageRegistry(collections) {
33
+ const registry = {};
34
+ for (const collection of collections || []) {
35
+ registry[collection.slug] = buildCollectionStorageDescriptor(collection);
36
+ }
37
+ return registry;
38
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAG/C;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAyD1D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAyD1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/config/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEvE,4CAA4C;AAC5C,KAAK,cAAc,GAAG,YAAY,GAAG,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAK9E;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoBhG"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/config/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAExE,4CAA4C;AAC5C,KAAK,cAAc,GAAG,YAAY,GAAG,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAK/E;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoBhG"}
@@ -1,12 +1,2 @@
1
1
  export declare function deepMerge<T extends object>(target: Partial<T>, source: T): T;
2
- /**
3
- * @deprecated This function is deprecated. Use ConfigContract validation instead.
4
- * Validation is now handled by the contract system in @revealui/contracts/cms.
5
- * This function is kept for backward compatibility but should not be used in new code.
6
- */
7
- export declare function validateConfig(config: {
8
- secret?: string;
9
- collections?: unknown[];
10
- globals?: unknown[];
11
- }): void;
12
2
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/config/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAuB5E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,EAAE,CAAA;IACvB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;CACpB,GAAG,IAAI,CAQP"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/config/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAuB5E"}
@@ -19,16 +19,3 @@ export function deepMerge(target, source) {
19
19
  }
20
20
  return result;
21
21
  }
22
- /**
23
- * @deprecated This function is deprecated. Use ConfigContract validation instead.
24
- * Validation is now handled by the contract system in @revealui/contracts/cms.
25
- * This function is kept for backward compatibility but should not be used in new code.
26
- */
27
- export function validateConfig(config) {
28
- if (!config.secret) {
29
- throw new Error('RevealUI config requires a secret');
30
- }
31
- if (!(config.collections || config.globals)) {
32
- throw new Error('RevealUI config must have at least one collection or global');
33
- }
34
- }
@@ -1 +1,4 @@
1
+ export type { DatabaseResult } from '../types/index.js';
2
+ export type { UniversalPostgresAdapterConfig } from './universal-postgres.js';
3
+ export { universalPostgresAdapter } from './universal-postgres.js';
1
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/database/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/database/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -1,6 +1,2 @@
1
- "use strict";
2
1
  // Re-export database adapters and types (PostgreSQL/PGlite only)
3
- // Temporarily commented out to get CMS running
4
- // export type { DatabaseResult } from '../types/index.js'
5
- // export type { UniversalPostgresAdapterConfig } from './universal-postgres.js'
6
- // export { universalPostgresAdapter } from './universal-postgres.js'
2
+ export { universalPostgresAdapter } from './universal-postgres.js';
@@ -1 +1 @@
1
- {"version":3,"file":"safe-parse.d.ts","sourceRoot":"","sources":["../../src/database/safe-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAI1E"}
1
+ {"version":3,"file":"safe-parse.d.ts","sourceRoot":"","sources":["../../src/database/safe-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAI1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"ssl-config.d.ts","sourceRoot":"","sources":["../../src/database/ssl-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA"}
1
+ {"version":3,"file":"ssl-config.d.ts","sourceRoot":"","sources":["../../src/database/ssl-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"type-adapter.d.ts","sourceRoot":"","sources":["../../src/database/type-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAA;AAE9D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAEvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAC/C,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC7B,KAAK,EAAE,MAAM,GACZ,SAAS,CAEX;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,GAAG,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KAC3E,CAAA;CACF,CAAA;AAED,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,YAAY,IAAI;KACxD,CAAC,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QAEpE,GAAG,EAAE,MAAM,CAAC,CAAA;KACb,GACG,QAAQ,CAAC,CAAC,CAAC,GACX,KAAK;CACV,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAC9F,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;IAE1C,GAAG,EAAE,MAAM,CAAC,CAAA;CACb,GACG,QAAQ,CAAC,CAAC,CAAC,GACX,KAAK;IAuBP;;;;;;;;OAQG;;aA1BE,MAAM,CAAC;;aAAP,MAAM,CAAC;;IAqCZ;;OAEG;;aAvCE,MAAM,CAAC;;gBAMJ,MAAM,CAAC;;IAsCf;;OAEG;mBACY,OAAO;aA/CjB,MAAM,CAAC;kBA+CmB;gBAnCvB,MAAM,CAAC;;EAuClB"}
1
+ {"version":3,"file":"type-adapter.d.ts","sourceRoot":"","sources":["../../src/database/type-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE/D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAEvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAC/C,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC7B,KAAK,EAAE,MAAM,GACZ,SAAS,CAEX;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE;QAEN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,GAAG,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC5E,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,YAAY,IAAI;KACxD,CAAC,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QAEpE,GAAG,EAAE,MAAM,CAAC,CAAC;KACd,GACG,QAAQ,CAAC,CAAC,CAAC,GACX,KAAK;CACV,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAC9F,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;IAE1C,GAAG,EAAE,MAAM,CAAC,CAAC;CACd,GACG,QAAQ,CAAC,CAAC,CAAC,GACX,KAAK;IAuBP;;;;;;;;OAQG;;aA1BE,MAAM,CAAC;;aAAP,MAAM,CAAC;;IAqCZ;;OAEG;;aAvCE,MAAM,CAAC;;gBAMJ,MAAM,CAAC;;IAsCf;;OAEG;mBACY,OAAO;aA/CjB,MAAM,CAAC;kBA+CmB;gBAnCvB,MAAM,CAAC;;EAuClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"universal-postgres.d.ts","sourceRoot":"","sources":["../../src/database/universal-postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAkC,MAAM,mBAAmB,CAAA;AAIxF,MAAM,WAAW,8BAA8B;IAC7C;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAA;CAC5C;AAiGD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,8BAAmC,GAC1C,eAAe,CAqcjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,UAAQ,GAAG,IAAI,CAa/D;AAGD,eAAe,wBAAwB,CAAA"}
1
+ {"version":3,"file":"universal-postgres.d.ts","sourceRoot":"","sources":["../../src/database/universal-postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,mBAAmB,CAAC;AAIzE,MAAM,WAAW,8BAA8B;IAC7C;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;CAC7C;AAmGD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,8BAAmC,GAC1C,eAAe,CAwcjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,UAAQ,GAAG,IAAI,CAa/D;AAGD,eAAe,wBAAwB,CAAC"}