opacacms 0.1.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 (399) hide show
  1. package/bun.lock +34 -0
  2. package/dist/admin/api-client.d.ts +8 -0
  3. package/dist/admin/auth-client.d.ts +940 -0
  4. package/dist/admin/custom-field.d.ts +71 -0
  5. package/dist/admin/index.d.ts +11 -0
  6. package/dist/admin/react.d.ts +3 -0
  7. package/dist/admin/router.d.ts +7 -0
  8. package/dist/admin/stores/admin-queries.d.ts +32 -0
  9. package/dist/admin/stores/auth.d.ts +33 -0
  10. package/dist/admin/stores/column-visibility.d.ts +21 -0
  11. package/dist/admin/stores/config.d.ts +7 -0
  12. package/dist/admin/stores/media.d.ts +44 -0
  13. package/dist/admin/stores/query.d.ts +4 -0
  14. package/dist/admin/stores/ui.d.ts +11 -0
  15. package/dist/admin/ui/admin-client.d.ts +7 -0
  16. package/dist/admin/ui/admin-layout.d.ts +14 -0
  17. package/dist/admin/ui/components/ColumnVisibilityToggle.d.ts +10 -0
  18. package/dist/admin/ui/components/DataDetailSheet.d.ts +13 -0
  19. package/dist/admin/ui/components/DataDetailView.d.ts +9 -0
  20. package/dist/admin/ui/components/Table.d.ts +10 -0
  21. package/dist/admin/ui/components/fields/ArrayField.d.ts +13 -0
  22. package/dist/admin/ui/components/fields/BlocksField.d.ts +17 -0
  23. package/dist/admin/ui/components/fields/BooleanField.d.ts +13 -0
  24. package/dist/admin/ui/components/fields/CollapsibleField.d.ts +16 -0
  25. package/dist/admin/ui/components/fields/DateField.d.ts +13 -0
  26. package/dist/admin/ui/components/fields/FileField.d.ts +23 -0
  27. package/dist/admin/ui/components/fields/GroupField.d.ts +13 -0
  28. package/dist/admin/ui/components/fields/JoinField.d.ts +15 -0
  29. package/dist/admin/ui/components/fields/NumberField.d.ts +14 -0
  30. package/dist/admin/ui/components/fields/RadioField.d.ts +17 -0
  31. package/dist/admin/ui/components/fields/RelationshipField.d.ts +16 -0
  32. package/dist/admin/ui/components/fields/RowField.d.ts +12 -0
  33. package/dist/admin/ui/components/fields/SelectField.d.ts +18 -0
  34. package/dist/admin/ui/components/fields/TabsField.d.ts +15 -0
  35. package/dist/admin/ui/components/fields/TextAreaField.d.ts +14 -0
  36. package/dist/admin/ui/components/fields/TextField.d.ts +14 -0
  37. package/dist/admin/ui/components/fields/VirtualField.d.ts +8 -0
  38. package/dist/admin/ui/components/fields/index.d.ts +28 -0
  39. package/dist/admin/ui/components/fields/richtext-editor/index.d.ts +10 -0
  40. package/dist/admin/ui/components/fields/richtext-editor/nodes/ImageComponent.d.ts +7 -0
  41. package/dist/admin/ui/components/fields/richtext-editor/nodes/ImageNode.d.ts +27 -0
  42. package/dist/admin/ui/components/fields/richtext-editor/plugins/ComponentPickerPlugin.d.ts +1 -0
  43. package/dist/admin/ui/components/fields/richtext-editor/plugins/EditableSyncPlugin.d.ts +5 -0
  44. package/dist/admin/ui/components/fields/richtext-editor/plugins/NotionToolbarPlugin.d.ts +1 -0
  45. package/dist/admin/ui/components/fields/richtext-editor/plugins/SimpleToolbarPlugin.d.ts +1 -0
  46. package/dist/admin/ui/components/fields/richtext-editor/plugins/ValueSyncPlugin.d.ts +5 -0
  47. package/dist/admin/ui/components/fields/utils.d.ts +1 -0
  48. package/dist/admin/ui/components/link.d.ts +8 -0
  49. package/dist/admin/ui/components/media/AssetManagerModal.d.ts +17 -0
  50. package/dist/admin/ui/components/toast.d.ts +10 -0
  51. package/dist/admin/ui/components/ui/accordion.d.ts +11 -0
  52. package/dist/admin/ui/components/ui/alert-dialog.d.ts +12 -0
  53. package/dist/admin/ui/components/ui/blocks.d.ts +5 -0
  54. package/dist/admin/ui/components/ui/breadcrumbs.d.ts +7 -0
  55. package/dist/admin/ui/components/ui/button.d.ts +7 -0
  56. package/dist/admin/ui/components/ui/collapsible.d.ts +16 -0
  57. package/dist/admin/ui/components/ui/dialog.d.ts +27 -0
  58. package/dist/admin/ui/components/ui/group.d.ts +6 -0
  59. package/dist/admin/ui/components/ui/index.d.ts +17 -0
  60. package/dist/admin/ui/components/ui/input.d.ts +5 -0
  61. package/dist/admin/ui/components/ui/join.d.ts +7 -0
  62. package/dist/admin/ui/components/ui/label.d.ts +3 -0
  63. package/dist/admin/ui/components/ui/radio-group.d.ts +13 -0
  64. package/dist/admin/ui/components/ui/relationship-detail-sheet.d.ts +9 -0
  65. package/dist/admin/ui/components/ui/relationship.d.ts +8 -0
  66. package/dist/admin/ui/components/ui/scroll-area.d.ts +7 -0
  67. package/dist/admin/ui/components/ui/select.d.ts +37 -0
  68. package/dist/admin/ui/components/ui/separator.d.ts +8 -0
  69. package/dist/admin/ui/components/ui/sheet.d.ts +28 -0
  70. package/dist/admin/ui/components/ui/tabs.d.ts +17 -0
  71. package/dist/admin/ui/components/ui/utils.d.ts +1 -0
  72. package/dist/admin/ui/hooks/use-debounce.d.ts +1 -0
  73. package/dist/admin/ui/views/collection-list-view.d.ts +5 -0
  74. package/dist/admin/ui/views/dashboard-view.d.ts +10 -0
  75. package/dist/admin/ui/views/document-edit-view.d.ts +7 -0
  76. package/dist/admin/ui/views/global-edit-view.d.ts +19 -0
  77. package/dist/admin/ui/views/init-view.d.ts +4 -0
  78. package/dist/admin/ui/views/login-view.d.ts +4 -0
  79. package/dist/admin/ui/views/media-registry-view.d.ts +7 -0
  80. package/dist/admin/ui/views/settings-view.d.ts +7 -0
  81. package/dist/admin/webcomponent.d.ts +1 -0
  82. package/dist/api.d.ts +6 -0
  83. package/dist/auth/index.d.ts +2107 -0
  84. package/dist/auth/migrations.d.ts +5 -0
  85. package/dist/auth/premissions.d.ts +6 -0
  86. package/dist/chunk-16vgcf3k.js +88 -0
  87. package/dist/chunk-2zm8cy1w.js +9482 -0
  88. package/dist/chunk-5gvbp2qa.js +167 -0
  89. package/dist/chunk-62ev8gnc.js +41 -0
  90. package/dist/chunk-6dhs73zq.js +126 -0
  91. package/dist/chunk-6ew02s0c.js +472 -0
  92. package/dist/chunk-7a9kn0np.js +116 -0
  93. package/dist/chunk-8gkhn1d4.js +309 -0
  94. package/dist/chunk-8sqjbsgt.js +42 -0
  95. package/dist/chunk-9kxpbcb1.js +85 -0
  96. package/dist/chunk-cvdd4eqh.js +110 -0
  97. package/dist/chunk-d3ffeqp9.js +87 -0
  98. package/dist/chunk-dy5t83hr.js +261 -0
  99. package/dist/chunk-f3nvxn63.js +17 -0
  100. package/dist/chunk-hmhcense.js +1352 -0
  101. package/dist/chunk-j4d50hrx.js +20 -0
  102. package/dist/chunk-jwjk85ze.js +15 -0
  103. package/dist/chunk-kwp83w8b.js +250 -0
  104. package/dist/chunk-s8mqwnm1.js +14 -0
  105. package/dist/chunk-srsac177.js +85 -0
  106. package/dist/chunk-v521d72w.js +10 -0
  107. package/dist/chunk-xa7rjsn2.js +20 -0
  108. package/dist/chunk-xg35h5a3.js +15 -0
  109. package/dist/chunk-ybbbqj63.js +130 -0
  110. package/dist/chunk-zvwb67nd.js +332 -0
  111. package/dist/cli/commands/generate-types.d.ts +1 -0
  112. package/dist/cli/commands/init.d.ts +1 -0
  113. package/dist/cli/commands/migrate-commands.d.ts +5 -0
  114. package/dist/cli/commands/seed-command.d.ts +2 -0
  115. package/dist/cli/d1-mock.d.ts +30 -0
  116. package/dist/cli/index.d.ts +5 -0
  117. package/dist/cli/index.test.d.ts +1 -0
  118. package/dist/cli/r2-mock.d.ts +46 -0
  119. package/dist/cli/seeding.d.ts +17 -0
  120. package/dist/client.d.ts +51 -0
  121. package/dist/config-utils.d.ts +6 -0
  122. package/dist/config.d.ts +10 -0
  123. package/dist/db/adapter.d.ts +34 -0
  124. package/dist/db/better-sqlite.d.ts +40 -0
  125. package/dist/db/bun-sqlite.d.ts +40 -0
  126. package/dist/db/d1.d.ts +42 -0
  127. package/dist/db/kysely/data-mapper.d.ts +6 -0
  128. package/dist/db/kysely/field-mapper.d.ts +22 -0
  129. package/dist/db/kysely/migration-generator.d.ts +9 -0
  130. package/dist/db/kysely/query-builder.d.ts +9 -0
  131. package/dist/db/kysely/schema-builder.d.ts +15 -0
  132. package/dist/db/kysely/sql-utils.d.ts +1 -0
  133. package/dist/db/postgres.d.ts +51 -0
  134. package/dist/db/sqlite.d.ts +41 -0
  135. package/dist/db/system-schema.d.ts +2 -0
  136. package/dist/index.d.ts +6 -0
  137. package/dist/runtimes/bun.d.ts +17 -0
  138. package/dist/runtimes/cloudflare-workers.d.ts +10 -0
  139. package/dist/runtimes/next.d.ts +16 -0
  140. package/dist/runtimes/node.d.ts +18 -0
  141. package/dist/schema/collection.d.ts +100 -0
  142. package/dist/schema/fields/base.d.ts +83 -0
  143. package/dist/schema/fields/index.d.ts +135 -0
  144. package/dist/schema/global.d.ts +82 -0
  145. package/dist/schema/index.d.ts +4 -0
  146. package/dist/schema/infer.d.ts +55 -0
  147. package/dist/server/admin-router.d.ts +9 -0
  148. package/dist/server/admin.d.ts +18 -0
  149. package/dist/server/assets.d.ts +47 -0
  150. package/dist/server/collection-router.d.ts +14 -0
  151. package/dist/server/handlers.d.ts +76 -0
  152. package/dist/server/middlewares/admin.d.ts +6 -0
  153. package/dist/server/middlewares/auth.d.ts +16 -0
  154. package/dist/server/middlewares/context.d.ts +9 -0
  155. package/dist/server/middlewares/cors.d.ts +3 -0
  156. package/dist/server/middlewares/database-init.d.ts +11 -0
  157. package/dist/server/middlewares/rate-limit.d.ts +3 -0
  158. package/dist/server/router.d.ts +7 -0
  159. package/dist/server/setup-middlewares.d.ts +17 -0
  160. package/dist/server/system-router.d.ts +9 -0
  161. package/dist/server.d.ts +6 -0
  162. package/dist/src/admin/index.css +47 -0
  163. package/dist/src/admin/index.js +176 -0
  164. package/dist/src/admin/webcomponent.js +19 -0
  165. package/dist/src/api.js +27 -0
  166. package/dist/src/cli/index.js +157 -0
  167. package/dist/src/client.js +9 -0
  168. package/dist/src/db/bun-sqlite.js +523 -0
  169. package/dist/src/db/d1.js +568 -0
  170. package/dist/src/db/postgres.js +520 -0
  171. package/dist/src/db/sqlite.js +534 -0
  172. package/dist/src/index.js +20 -0
  173. package/dist/src/runtimes/bun.js +36 -0
  174. package/dist/src/runtimes/cloudflare-workers.js +29 -0
  175. package/dist/src/runtimes/next.js +26 -0
  176. package/dist/src/runtimes/node.js +38 -0
  177. package/dist/src/server.js +27 -0
  178. package/dist/src/storage/index.js +355 -0
  179. package/dist/storage/adapters/cloudflare-r2.d.ts +6 -0
  180. package/dist/storage/adapters/local.d.ts +6 -0
  181. package/dist/storage/adapters/s3.d.ts +13 -0
  182. package/dist/storage/errors.d.ts +12 -0
  183. package/dist/storage/index.d.ts +5 -0
  184. package/dist/storage/types.d.ts +31 -0
  185. package/dist/types.d.ts +484 -0
  186. package/dist/utils/lexical.d.ts +5 -0
  187. package/dist/utils/logger.d.ts +35 -0
  188. package/dist/validation.d.ts +300 -0
  189. package/dist/validator.d.ts +9 -0
  190. package/global.d.ts +11 -0
  191. package/package.json +151 -0
  192. package/src/admin/api-client.ts +63 -0
  193. package/src/admin/auth-client.ts +40 -0
  194. package/src/admin/custom-field.ts +179 -0
  195. package/src/admin/index.ts +15 -0
  196. package/src/admin/react.tsx +72 -0
  197. package/src/admin/router.ts +9 -0
  198. package/src/admin/stores/admin-queries.ts +121 -0
  199. package/src/admin/stores/auth.ts +61 -0
  200. package/src/admin/stores/column-visibility.ts +67 -0
  201. package/src/admin/stores/config.ts +15 -0
  202. package/src/admin/stores/media.ts +95 -0
  203. package/src/admin/stores/query.ts +13 -0
  204. package/src/admin/stores/ui.ts +29 -0
  205. package/src/admin/ui/admin-client.tsx +283 -0
  206. package/src/admin/ui/admin-layout.tsx +276 -0
  207. package/src/admin/ui/components/ColumnVisibilityToggle.tsx +141 -0
  208. package/src/admin/ui/components/DataDetailSheet.tsx +141 -0
  209. package/src/admin/ui/components/DataDetailView.tsx +175 -0
  210. package/src/admin/ui/components/Table.tsx +67 -0
  211. package/src/admin/ui/components/fields/ArrayField.tsx +166 -0
  212. package/src/admin/ui/components/fields/BlocksField.tsx +202 -0
  213. package/src/admin/ui/components/fields/BooleanField.tsx +50 -0
  214. package/src/admin/ui/components/fields/CollapsibleField.tsx +75 -0
  215. package/src/admin/ui/components/fields/DateField.tsx +45 -0
  216. package/src/admin/ui/components/fields/FileField.tsx +322 -0
  217. package/src/admin/ui/components/fields/GroupField.tsx +50 -0
  218. package/src/admin/ui/components/fields/JoinField.tsx +23 -0
  219. package/src/admin/ui/components/fields/NumberField.tsx +46 -0
  220. package/src/admin/ui/components/fields/RadioField.tsx +62 -0
  221. package/src/admin/ui/components/fields/RelationshipField.tsx +278 -0
  222. package/src/admin/ui/components/fields/RowField.tsx +40 -0
  223. package/src/admin/ui/components/fields/SelectField.tsx +59 -0
  224. package/src/admin/ui/components/fields/TabsField.tsx +101 -0
  225. package/src/admin/ui/components/fields/TextAreaField.tsx +54 -0
  226. package/src/admin/ui/components/fields/TextField.tsx +49 -0
  227. package/src/admin/ui/components/fields/VirtualField.tsx +53 -0
  228. package/src/admin/ui/components/fields/index.tsx +371 -0
  229. package/src/admin/ui/components/fields/richtext-editor/index.tsx +211 -0
  230. package/src/admin/ui/components/fields/richtext-editor/nodes/ImageComponent.tsx +142 -0
  231. package/src/admin/ui/components/fields/richtext-editor/nodes/ImageNode.tsx +95 -0
  232. package/src/admin/ui/components/fields/richtext-editor/plugins/ComponentPickerPlugin.tsx +226 -0
  233. package/src/admin/ui/components/fields/richtext-editor/plugins/EditableSyncPlugin.tsx +16 -0
  234. package/src/admin/ui/components/fields/richtext-editor/plugins/NotionToolbarPlugin.tsx +184 -0
  235. package/src/admin/ui/components/fields/richtext-editor/plugins/SimpleToolbarPlugin.tsx +240 -0
  236. package/src/admin/ui/components/fields/richtext-editor/plugins/ValueSyncPlugin.tsx +40 -0
  237. package/src/admin/ui/components/fields/utils.ts +1 -0
  238. package/src/admin/ui/components/link.tsx +41 -0
  239. package/src/admin/ui/components/media/AssetManagerModal.tsx +334 -0
  240. package/src/admin/ui/components/toast.tsx +72 -0
  241. package/src/admin/ui/components/ui/accordion.tsx +51 -0
  242. package/src/admin/ui/components/ui/alert-dialog.tsx +98 -0
  243. package/src/admin/ui/components/ui/blocks.tsx +32 -0
  244. package/src/admin/ui/components/ui/breadcrumbs.tsx +59 -0
  245. package/src/admin/ui/components/ui/button.tsx +26 -0
  246. package/src/admin/ui/components/ui/collapsible.tsx +124 -0
  247. package/src/admin/ui/components/ui/dialog.tsx +79 -0
  248. package/src/admin/ui/components/ui/group.tsx +20 -0
  249. package/src/admin/ui/components/ui/index.ts +17 -0
  250. package/src/admin/ui/components/ui/input.tsx +12 -0
  251. package/src/admin/ui/components/ui/join.tsx +53 -0
  252. package/src/admin/ui/components/ui/label.tsx +11 -0
  253. package/src/admin/ui/components/ui/radio-group.tsx +75 -0
  254. package/src/admin/ui/components/ui/relationship-detail-sheet.tsx +122 -0
  255. package/src/admin/ui/components/ui/relationship.tsx +58 -0
  256. package/src/admin/ui/components/ui/scroll-area.tsx +19 -0
  257. package/src/admin/ui/components/ui/select.tsx +187 -0
  258. package/src/admin/ui/components/ui/separator.tsx +21 -0
  259. package/src/admin/ui/components/ui/sheet.tsx +106 -0
  260. package/src/admin/ui/components/ui/tabs.tsx +116 -0
  261. package/src/admin/ui/components/ui/utils.ts +3 -0
  262. package/src/admin/ui/hooks/use-debounce.ts +15 -0
  263. package/src/admin/ui/styles/_locale-switcher.scss +33 -0
  264. package/src/admin/ui/styles/accordion.scss +60 -0
  265. package/src/admin/ui/styles/animations.scss +41 -0
  266. package/src/admin/ui/styles/asset-manager.scss +547 -0
  267. package/src/admin/ui/styles/badge.scss +13 -0
  268. package/src/admin/ui/styles/base.scss +22 -0
  269. package/src/admin/ui/styles/button.scss +161 -0
  270. package/src/admin/ui/styles/card.scss +13 -0
  271. package/src/admin/ui/styles/collapsible.scss +75 -0
  272. package/src/admin/ui/styles/data-detail.scss +92 -0
  273. package/src/admin/ui/styles/dialog.scss +102 -0
  274. package/src/admin/ui/styles/empty-state.scss +22 -0
  275. package/src/admin/ui/styles/group.scss +19 -0
  276. package/src/admin/ui/styles/index.scss +33 -0
  277. package/src/admin/ui/styles/input.scss +80 -0
  278. package/src/admin/ui/styles/label.scss +12 -0
  279. package/src/admin/ui/styles/layout.scss +56 -0
  280. package/src/admin/ui/styles/lexical.scss +469 -0
  281. package/src/admin/ui/styles/loading.scss +102 -0
  282. package/src/admin/ui/styles/media-registry.scss +597 -0
  283. package/src/admin/ui/styles/pagination.scss +20 -0
  284. package/src/admin/ui/styles/radio-group.scss +66 -0
  285. package/src/admin/ui/styles/row.scss +17 -0
  286. package/src/admin/ui/styles/scrollbar.scss +36 -0
  287. package/src/admin/ui/styles/select.scss +121 -0
  288. package/src/admin/ui/styles/separator.scss +14 -0
  289. package/src/admin/ui/styles/sheet.scss +152 -0
  290. package/src/admin/ui/styles/sidebar.scss +148 -0
  291. package/src/admin/ui/styles/switch.scss +59 -0
  292. package/src/admin/ui/styles/table.scss +207 -0
  293. package/src/admin/ui/styles/tabs.scss +62 -0
  294. package/src/admin/ui/styles/toast.scss +45 -0
  295. package/src/admin/ui/styles/variables.scss +24 -0
  296. package/src/admin/ui/views/collection-list-view.tsx +720 -0
  297. package/src/admin/ui/views/dashboard-view.tsx +263 -0
  298. package/src/admin/ui/views/document-edit-view.tsx +384 -0
  299. package/src/admin/ui/views/global-edit-view.tsx +226 -0
  300. package/src/admin/ui/views/init-view.tsx +182 -0
  301. package/src/admin/ui/views/login-view.tsx +123 -0
  302. package/src/admin/ui/views/media-registry-view.tsx +1104 -0
  303. package/src/admin/ui/views/settings-view.tsx +729 -0
  304. package/src/admin/webcomponent.tsx +15 -0
  305. package/src/api.ts +9 -0
  306. package/src/auth/index.ts +194 -0
  307. package/src/auth/migrations.ts +87 -0
  308. package/src/auth/premissions.ts +46 -0
  309. package/src/cli/commands/generate-types.ts +116 -0
  310. package/src/cli/commands/init.ts +95 -0
  311. package/src/cli/commands/migrate-commands.ts +160 -0
  312. package/src/cli/commands/seed-command.ts +11 -0
  313. package/src/cli/d1-mock.ts +101 -0
  314. package/src/cli/index.test.ts +84 -0
  315. package/src/cli/index.ts +183 -0
  316. package/src/cli/r2-mock.ts +217 -0
  317. package/src/cli/seeding.ts +405 -0
  318. package/src/client.ts +181 -0
  319. package/src/config-utils.ts +102 -0
  320. package/src/config.ts +49 -0
  321. package/src/db/adapter.ts +53 -0
  322. package/src/db/better-sqlite.ts +630 -0
  323. package/src/db/bun-sqlite.ts +646 -0
  324. package/src/db/d1.ts +711 -0
  325. package/src/db/kysely/data-mapper.ts +142 -0
  326. package/src/db/kysely/field-mapper.ts +148 -0
  327. package/src/db/kysely/migration-generator.ts +223 -0
  328. package/src/db/kysely/query-builder.ts +92 -0
  329. package/src/db/kysely/schema-builder.ts +439 -0
  330. package/src/db/kysely/sql-utils.ts +13 -0
  331. package/src/db/postgres.ts +621 -0
  332. package/src/db/sqlite.ts +658 -0
  333. package/src/db/system-schema.ts +121 -0
  334. package/src/index.ts +13 -0
  335. package/src/runtimes/README.md +59 -0
  336. package/src/runtimes/bun.ts +49 -0
  337. package/src/runtimes/cloudflare-workers.ts +38 -0
  338. package/src/runtimes/next.ts +26 -0
  339. package/src/runtimes/node.ts +52 -0
  340. package/src/schema/collection.ts +184 -0
  341. package/src/schema/fields/base.ts +164 -0
  342. package/src/schema/fields/index.ts +427 -0
  343. package/src/schema/global.ts +145 -0
  344. package/src/schema/index.ts +4 -0
  345. package/src/schema/infer.ts +72 -0
  346. package/src/server/admin-router.ts +20 -0
  347. package/src/server/admin.ts +142 -0
  348. package/src/server/assets.ts +306 -0
  349. package/src/server/collection-router.ts +55 -0
  350. package/src/server/handlers.ts +722 -0
  351. package/src/server/middlewares/admin.ts +27 -0
  352. package/src/server/middlewares/auth.ts +89 -0
  353. package/src/server/middlewares/context.ts +17 -0
  354. package/src/server/middlewares/cors.ts +24 -0
  355. package/src/server/middlewares/database-init.ts +74 -0
  356. package/src/server/middlewares/rate-limit.ts +71 -0
  357. package/src/server/router.ts +47 -0
  358. package/src/server/setup-middlewares.ts +58 -0
  359. package/src/server/system-router.ts +35 -0
  360. package/src/server.ts +9 -0
  361. package/src/storage/adapters/cloudflare-r2.ts +136 -0
  362. package/src/storage/adapters/local.ts +146 -0
  363. package/src/storage/adapters/s3.ts +186 -0
  364. package/src/storage/errors.ts +46 -0
  365. package/src/storage/index.ts +5 -0
  366. package/src/storage/types.ts +39 -0
  367. package/src/types.ts +577 -0
  368. package/src/utils/lexical.ts +37 -0
  369. package/src/utils/logger.ts +73 -0
  370. package/src/validation.ts +429 -0
  371. package/src/validator.ts +179 -0
  372. package/test/admin-custom-field.test.ts +162 -0
  373. package/test/admin-react-field.test.tsx +134 -0
  374. package/test/api-features.test.ts +78 -0
  375. package/test/api.test.ts +178 -0
  376. package/test/auth.test.ts +62 -0
  377. package/test/cli-integration.test.ts +146 -0
  378. package/test/cli.test.ts +25 -0
  379. package/test/db/postgres.test.ts +95 -0
  380. package/test/db/sqlite-filter.test.ts +53 -0
  381. package/test/db/sqlite.test.ts +82 -0
  382. package/test/engine-features.test.ts +79 -0
  383. package/test/globals.test.ts +74 -0
  384. package/test/integration-tmp/db-app/opacacms.config.ts +15 -0
  385. package/test/integration-tmp/my-sqlite-app/opacacms.config.ts +25 -0
  386. package/test/integration-tmp/my-test-app/index.ts +8 -0
  387. package/test/integration-tmp/my-test-app/opacacms.config.ts +16 -0
  388. package/test/integration-tmp/my-test-app/package.json +12 -0
  389. package/test/populate.test.ts +79 -0
  390. package/test/runtimes.test.ts +43 -0
  391. package/test/schema-builder.test.ts +107 -0
  392. package/test/schema-features.test.ts +63 -0
  393. package/test/seeding.test.ts +68 -0
  394. package/test/storage/local.test.ts +72 -0
  395. package/test/storage/s3.test.ts +60 -0
  396. package/test/structural-data.test.ts +100 -0
  397. package/test/test-setup.ts +11 -0
  398. package/test/validation.test.ts +162 -0
  399. package/tsconfig.json +42 -0
@@ -0,0 +1,429 @@
1
+ import { z } from "zod";
2
+
3
+ export const FieldTypeSchema = z.enum([
4
+ "text",
5
+ "slug",
6
+ "textarea",
7
+ "number",
8
+ "richtext",
9
+ "relationship",
10
+ "select",
11
+ "radio",
12
+ "date",
13
+ "boolean",
14
+ "json",
15
+ "file",
16
+ "blocks",
17
+ "group",
18
+ "row",
19
+ "collapsible",
20
+ "tabs",
21
+ "join",
22
+ "array",
23
+ "virtual",
24
+ ]);
25
+
26
+ export type FieldType = z.infer<typeof FieldTypeSchema>;
27
+
28
+ const BaseFieldSchema = z.object({
29
+ name: z.string(),
30
+ label: z.string().optional(),
31
+ required: z.boolean().optional().default(false),
32
+ unique: z.boolean().optional().default(false),
33
+ localized: z.boolean().optional(),
34
+ defaultValue: z.any().optional(),
35
+ validate: z.function().optional(),
36
+ admin: z
37
+ .object({
38
+ description: z.string().optional(),
39
+ condition: z.function().optional(),
40
+ hidden: z.boolean().optional(),
41
+ readOnly: z.boolean().optional(),
42
+ width: z.string().optional(),
43
+ style: z.any().optional(),
44
+ className: z.string().optional(),
45
+ components: z
46
+ .object({
47
+ Field: z.string().optional(),
48
+ Cell: z.string().optional(),
49
+ })
50
+ .optional(),
51
+ })
52
+ .optional(),
53
+ });
54
+
55
+ export const FieldSchema: z.ZodType<unknown> = z.lazy(() =>
56
+ z.discriminatedUnion("type", [
57
+ // Simple types
58
+ BaseFieldSchema.extend({ type: z.literal("text") }),
59
+ BaseFieldSchema.extend({
60
+ type: z.literal("slug"),
61
+ from: z.string(),
62
+ format: z.function().optional(),
63
+ }),
64
+ BaseFieldSchema.extend({ type: z.literal("textarea") }),
65
+ BaseFieldSchema.extend({ type: z.literal("number") }),
66
+ BaseFieldSchema.extend({ type: z.literal("date") }),
67
+ BaseFieldSchema.extend({
68
+ type: z.literal("boolean"),
69
+ options: z
70
+ .object({
71
+ display: z.enum(["switch", "toggle", "checkbox", "select"]).optional().default("switch"),
72
+ })
73
+ .loose()
74
+ .optional(),
75
+ }),
76
+
77
+ // Complex types
78
+ BaseFieldSchema.extend({
79
+ type: z.literal("richtext"),
80
+ options: z
81
+ .object({
82
+ defaultMode: z.enum(["simple", "notion"]).optional(),
83
+ })
84
+ .loose()
85
+ .optional(),
86
+ }),
87
+
88
+ BaseFieldSchema.extend({
89
+ type: z.literal("relationship"),
90
+ relationTo: z.string(),
91
+ hasMany: z.boolean().optional(),
92
+ displayField: z.string().optional(),
93
+ references: z
94
+ .object({
95
+ table: z.string(),
96
+ column: z.string(),
97
+ onDelete: z.enum(["cascade", "set null", "restrict", "no action"]).optional(),
98
+ })
99
+ .optional(),
100
+ }),
101
+
102
+ BaseFieldSchema.extend({
103
+ type: z.literal("select"),
104
+ options: z
105
+ .object({
106
+ choices: z.array(
107
+ z.union([z.string(), z.object({ label: z.string(), value: z.string() })]),
108
+ ),
109
+ })
110
+ .loose()
111
+ .optional(),
112
+ }),
113
+
114
+ BaseFieldSchema.extend({
115
+ type: z.literal("radio"),
116
+ options: z
117
+ .object({
118
+ choices: z.array(
119
+ z.union([z.string(), z.object({ label: z.string(), value: z.string() })]),
120
+ ),
121
+ })
122
+ .loose(),
123
+ }),
124
+
125
+ BaseFieldSchema.extend({
126
+ type: z.literal("file"),
127
+ bucket: z.string().optional(),
128
+ options: z
129
+ .object({
130
+ allowedmime_types: z.array(z.string()).optional(),
131
+ maxFileSize: z.number().optional(),
132
+ metaFields: z.array(z.lazy(() => FieldSchema)).optional(),
133
+ })
134
+ .loose()
135
+ .optional(),
136
+ }),
137
+
138
+ BaseFieldSchema.extend({
139
+ type: z.literal("json"),
140
+ fields: z.array(z.lazy(() => FieldSchema)).optional(),
141
+ }),
142
+
143
+ BaseFieldSchema.extend({
144
+ type: z.literal("blocks"),
145
+ blocks: z.array(
146
+ z.object({
147
+ slug: z.string(),
148
+ fields: z.array(z.lazy(() => FieldSchema)),
149
+ label: z.string().optional(),
150
+ }),
151
+ ),
152
+ }),
153
+
154
+ BaseFieldSchema.extend({
155
+ type: z.literal("group"),
156
+ fields: z.array(z.lazy(() => FieldSchema)),
157
+ }),
158
+
159
+ // Layout Types
160
+ z.object({
161
+ name: z.string().optional(),
162
+ type: z.literal("row"),
163
+ fields: z.array(z.lazy(() => FieldSchema)),
164
+ label: z.string().optional(),
165
+ }),
166
+
167
+ z.object({
168
+ name: z.string().optional(),
169
+ type: z.literal("collapsible"),
170
+ fields: z.array(z.lazy(() => FieldSchema)),
171
+ label: z.string().optional(),
172
+ options: z
173
+ .object({
174
+ initiallyCollapsed: z.boolean().optional(),
175
+ })
176
+ .loose()
177
+ .optional(),
178
+ }),
179
+
180
+ z.object({
181
+ name: z.string().optional(),
182
+ type: z.literal("tabs"),
183
+ tabs: z.array(
184
+ z.object({
185
+ label: z.string(),
186
+ fields: z.array(z.lazy(() => FieldSchema)),
187
+ }),
188
+ ),
189
+ }),
190
+
191
+ // Virtual Types
192
+ z.object({
193
+ name: z
194
+ .string()
195
+ .optional()
196
+ .refine((val) => val === undefined, {
197
+ message:
198
+ "Join fields are virtual and should not have a 'name' property. They are mapped dynamically via the API.",
199
+ })
200
+ .or(z.string()),
201
+ type: z.literal("join"),
202
+ collection: z.string(),
203
+ on: z.string(),
204
+ label: z.string().optional(),
205
+ }),
206
+
207
+ BaseFieldSchema.extend({
208
+ type: z.literal("array"),
209
+ fields: z.array(z.lazy(() => FieldSchema)).optional(),
210
+ }),
211
+ BaseFieldSchema.extend({
212
+ type: z.literal("virtual"),
213
+ resolve: z.function(),
214
+ returnType: z.string().optional(),
215
+ }),
216
+ ]),
217
+ );
218
+
219
+ export type Field = z.infer<typeof FieldSchema>;
220
+
221
+ export const AccessConfigSchema = z.object({
222
+ read: z.union([z.boolean(), z.function()]).optional(),
223
+ create: z.union([z.boolean(), z.function()]).optional(),
224
+ update: z.union([z.boolean(), z.function()]).optional(),
225
+ delete: z.union([z.boolean(), z.function()]).optional(),
226
+ requireApiKey: z.boolean().optional(),
227
+ });
228
+
229
+ export type AccessConfig = z.infer<typeof AccessConfigSchema>;
230
+
231
+ export const CollectionHooksSchema = z.object({
232
+ beforeCreate: z.function().optional(),
233
+ afterCreate: z.function().optional(),
234
+ beforeUpdate: z.function().optional(),
235
+ afterUpdate: z.function().optional(),
236
+ beforeDelete: z.function().optional(),
237
+ afterDelete: z.function().optional(),
238
+ });
239
+
240
+ export type CollectionHooks = z.infer<typeof CollectionHooksSchema>;
241
+
242
+ export const CollectionSchema = z.object({
243
+ slug: z.string(),
244
+ label: z.string().optional(),
245
+ icon: z.string().optional(),
246
+ apiPath: z.string().optional(),
247
+ fields: z.array(FieldSchema),
248
+ timestamps: z
249
+ .union([
250
+ z.boolean(),
251
+ z.object({
252
+ createdAt: z.string().optional(),
253
+ updatedAt: z.string().optional(),
254
+ }),
255
+ ])
256
+ .optional(),
257
+ auth: z.boolean().optional(),
258
+ hooks: CollectionHooksSchema.optional(),
259
+ access: AccessConfigSchema.optional(),
260
+ versions: z
261
+ .object({
262
+ drafts: z.boolean().optional(),
263
+ maxRevisions: z.number().optional(),
264
+ autosave: z.boolean().optional(),
265
+ })
266
+ .optional(),
267
+ webhooks: z
268
+ .array(
269
+ z.object({
270
+ events: z.array(z.string()),
271
+ url: z.string(),
272
+ headers: z.record(z.string(), z.string()).optional(),
273
+ }),
274
+ )
275
+ .optional(),
276
+ admin: z
277
+ .union([
278
+ z.boolean(),
279
+ z.object({
280
+ defaultColumns: z.array(z.string()).optional(),
281
+ useAsTitle: z.string().optional(),
282
+ hidden: z.boolean().optional(),
283
+ disableAdmin: z.boolean().optional(),
284
+ views: z
285
+ .array(
286
+ z.object({
287
+ name: z.string(),
288
+ filter: z.record(z.string(), z.any()),
289
+ defaultColumns: z.array(z.string()).optional(),
290
+ }),
291
+ )
292
+ .optional(),
293
+ bulkActions: z
294
+ .array(
295
+ z.object({
296
+ label: z.string(),
297
+ action: z.function(),
298
+ }),
299
+ )
300
+ .optional(),
301
+ }),
302
+ ])
303
+ .optional(),
304
+ hidden: z.boolean().optional(),
305
+ });
306
+
307
+ export type Collection = z.infer<typeof CollectionSchema>;
308
+
309
+ export const GlobalSchema = z.object({
310
+ slug: z.string(),
311
+ label: z.string().optional(),
312
+ icon: z.string().optional(),
313
+ fields: z.array(FieldSchema),
314
+ timestamps: z
315
+ .union([
316
+ z.boolean(),
317
+ z.object({
318
+ createdAt: z.string().optional(),
319
+ updatedAt: z.string().optional(),
320
+ }),
321
+ ])
322
+ .optional(),
323
+ access: AccessConfigSchema.optional(),
324
+ });
325
+
326
+ export type Global = z.infer<typeof GlobalSchema>;
327
+
328
+ export const AdminConfigSchema = z.object({
329
+ userCollection: z.string().optional(),
330
+ disableAdmin: z.boolean().optional(),
331
+ route: z.string().optional(),
332
+ });
333
+
334
+ export type AdminConfig = z.infer<typeof AdminConfigSchema>;
335
+
336
+ export const OpacaAuthConfigSchema = z.object({
337
+ strategies: z
338
+ .object({
339
+ emailPassword: z.boolean().optional(),
340
+ magicLink: z
341
+ .object({
342
+ enabled: z.boolean(),
343
+ sendEmail: z.function(),
344
+ })
345
+ .optional(),
346
+ })
347
+ .optional(),
348
+ socialProviders: z
349
+ .object({
350
+ github: z
351
+ .object({
352
+ clientId: z.string(),
353
+ clientSecret: z.string(),
354
+ })
355
+ .optional(),
356
+ google: z
357
+ .object({
358
+ clientId: z.string(),
359
+ clientSecret: z.string(),
360
+ })
361
+ .optional(),
362
+ })
363
+ .optional(),
364
+ session: z
365
+ .object({
366
+ expiresInDays: z.number().optional(),
367
+ updateAgeSeconds: z.number().optional(),
368
+ })
369
+ .optional(),
370
+ features: z
371
+ .object({
372
+ apiKeys: z
373
+ .object({
374
+ enabled: z.boolean(),
375
+ })
376
+ .optional(),
377
+ mfa: z
378
+ .object({
379
+ enabled: z.boolean(),
380
+ issuer: z.string(),
381
+ })
382
+ .optional(),
383
+ })
384
+ .optional(),
385
+ });
386
+
387
+ export const ApiConfigSchema = z.object({
388
+ maxLimit: z.number().optional(),
389
+ rateLimit: z
390
+ .object({
391
+ windowMs: z.number().optional(),
392
+ limit: z.number().optional(),
393
+ enabled: z.boolean().optional(),
394
+ store: z.any().optional(),
395
+ provider: z.function().optional(),
396
+ keyGenerator: z.function().optional(),
397
+ })
398
+ .optional(),
399
+ });
400
+
401
+ export type ApiConfig = z.infer<typeof ApiConfigSchema>;
402
+
403
+ export const OpacaConfigSchema = z.object({
404
+ collections: z.array(CollectionSchema),
405
+ globals: z.array(GlobalSchema).optional(),
406
+ db: z.any(),
407
+ storages: z.record(z.string(), z.any()).optional(),
408
+ runMigrationsOnStartup: z.boolean().optional(),
409
+ admin: AdminConfigSchema.optional(),
410
+ serverURL: z.string().optional(),
411
+ appName: z.string().optional(),
412
+ secret: z.string().optional(),
413
+ trustedOrigins: z.union([z.array(z.string()), z.function()]).optional(),
414
+ auth: OpacaAuthConfigSchema.optional(),
415
+ api: ApiConfigSchema.optional(),
416
+ access: z
417
+ .object({
418
+ roles: z.record(z.string(), z.record(z.string(), z.array(z.string()))).optional(),
419
+ })
420
+ .optional(),
421
+ i18n: z
422
+ .object({
423
+ locales: z.array(z.string()),
424
+ defaultLocale: z.string(),
425
+ })
426
+ .optional(),
427
+ });
428
+
429
+ export type OpacaConfig = z.infer<typeof OpacaConfigSchema>;
@@ -0,0 +1,179 @@
1
+ import { z } from "zod";
2
+ import type { Collection, Field } from "./types";
3
+
4
+ export function generateSchemaForCollection(
5
+ collection: { fields: Field[]; versions?: any; timestamps?: any },
6
+ isUpdate: boolean = false,
7
+ ) {
8
+ const shape = mapFieldsToShape(collection.fields, isUpdate);
9
+
10
+ if (collection.versions) {
11
+ shape._status = z.enum(["draft", "published"]).optional().nullable();
12
+ }
13
+
14
+ const ts = collection.timestamps;
15
+ if (ts !== false && ts !== undefined) {
16
+ const config = typeof ts === "object" ? ts : {};
17
+ const createdField = config.createdAt || "createdAt";
18
+ const updatedField = config.updatedAt || "updatedAt";
19
+ shape[createdField] = z.union([z.string(), z.date()]).optional().nullable();
20
+ shape[updatedField] = z.union([z.string(), z.date()]).optional().nullable();
21
+ }
22
+
23
+ return z.object(shape);
24
+ }
25
+
26
+ function mapFieldsToShape(
27
+ fields: Field[],
28
+ isUpdate: boolean = false,
29
+ ): Record<string, z.ZodTypeAny> {
30
+ const shape: Record<string, z.ZodTypeAny> = {};
31
+
32
+ for (const field of fields) {
33
+ // Layout fields without name merge their fields into the current level
34
+ if (!field.name) {
35
+ if (field.type === "tabs" && field.tabs) {
36
+ for (const tab of field.tabs) {
37
+ Object.assign(shape, mapFieldsToShape(tab.fields, isUpdate));
38
+ }
39
+ } else if (field.type === "group" && field.fields) {
40
+ Object.assign(shape, mapFieldsToShape(field.fields, isUpdate));
41
+ } else if (field.type === "row" && field.fields) {
42
+ Object.assign(shape, mapFieldsToShape(field.fields, isUpdate));
43
+ } else if (field.type === "collapsible" && field.fields) {
44
+ Object.assign(shape, mapFieldsToShape(field.fields, isUpdate));
45
+ }
46
+ continue;
47
+ }
48
+
49
+ const fieldName = field.name;
50
+ let schema: z.ZodTypeAny;
51
+
52
+ if (field.type === "group" && field.fields) {
53
+ schema = z.object(mapFieldsToShape(field.fields, isUpdate));
54
+ } else if (field.type === "blocks" && field.blocks) {
55
+ const blockSchemas = field.blocks.map((block) =>
56
+ z.object({
57
+ blockType: z.literal(block.slug),
58
+ ...mapFieldsToShape(block.fields, isUpdate),
59
+ }),
60
+ );
61
+ schema = z.array(z.union(blockSchemas));
62
+ } else if (field.type === "row" || field.type === "collapsible") {
63
+ // If a row/collapsible HAS a name (unusual but possible), treat it as a group
64
+ if (field.fields) {
65
+ schema = z.object(mapFieldsToShape(field.fields, isUpdate));
66
+ } else {
67
+ schema = z.any();
68
+ }
69
+ } else {
70
+ schema = mapFieldToZod(field);
71
+ }
72
+
73
+ if (field.localized) {
74
+ schema = z.union([z.record(z.string(), schema), schema]);
75
+ }
76
+
77
+ if (field.required && !isUpdate) {
78
+ // Slugs with a 'from' source are not required during input as they are auto-generated
79
+ if (field.type === "slug" && (field as any).from) {
80
+ schema = schema.optional().nullable();
81
+ }
82
+ } else {
83
+ schema = schema.optional().nullable();
84
+ }
85
+
86
+ if (field.defaultValue !== undefined && !isUpdate) {
87
+ schema = schema.default(field.defaultValue);
88
+ }
89
+
90
+ if (field.validate) {
91
+ schema = schema.superRefine((val, ctx) => {
92
+ if (val === undefined || val === null) return;
93
+ const result = field.validate!(val);
94
+ if (result !== true) {
95
+ ctx.addIssue({
96
+ code: z.ZodIssueCode.custom,
97
+ message: typeof result === "string" ? result : "Invalid field",
98
+ });
99
+ }
100
+ });
101
+ }
102
+
103
+ shape[fieldName] = schema;
104
+ }
105
+
106
+ return shape;
107
+ }
108
+
109
+ function mapFieldToZod(field: Field): z.ZodTypeAny {
110
+ switch (field.type) {
111
+ case "text":
112
+ case "slug":
113
+ case "richtext":
114
+ case "textarea":
115
+ return z.string();
116
+
117
+ case "relationship": {
118
+ const isHasMany = "hasMany" in field && field.hasMany;
119
+ const base = z.union([z.string(), z.number(), z.undefined(), z.null()]);
120
+
121
+ const schema = isHasMany ? z.array(base.optional().nullable()) : base;
122
+
123
+ if (isHasMany) {
124
+ return z.preprocess((val) => {
125
+ if (val === undefined || val === null || val === "") return [];
126
+ if (Array.isArray(val)) return val;
127
+ return [val];
128
+ }, schema);
129
+ }
130
+ return schema;
131
+ }
132
+
133
+ case "number":
134
+ return z.preprocess(
135
+ (val) => {
136
+ if (val === "" || val === undefined || val === null) return undefined;
137
+ if (typeof val === "string") {
138
+ const num = Number(val);
139
+ return Number.isNaN(num) ? undefined : num;
140
+ }
141
+ return val;
142
+ },
143
+ z.union([z.number(), z.undefined(), z.null()]),
144
+ );
145
+
146
+ case "boolean":
147
+ return z.preprocess((val) => {
148
+ if (typeof val === "string") return val === "true";
149
+ return val;
150
+ }, z.boolean());
151
+
152
+ case "date":
153
+ return z.preprocess(
154
+ (val) => {
155
+ if (val === "" || val === undefined || val === null) return undefined;
156
+ return val;
157
+ },
158
+ z.union([
159
+ z.string().regex(/^\d{4}-\d{2}-\d{2}/, "Invalid date format"),
160
+ z.date(),
161
+ z.undefined(),
162
+ z.null(),
163
+ ]),
164
+ );
165
+
166
+ case "select":
167
+ return z.string();
168
+
169
+ case "array":
170
+ return z.preprocess((val) => {
171
+ if (val === undefined || val === null || val === "") return [];
172
+ if (Array.isArray(val)) return val;
173
+ return [val];
174
+ }, z.array(z.any()));
175
+
176
+ default:
177
+ return z.any();
178
+ }
179
+ }