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,141 @@
1
+ import { Edit2, Save, X } from "lucide-react";
2
+ import type React from "react";
3
+ import { useEffect, useState } from "react";
4
+ import { DataDetailView } from "./DataDetailView";
5
+ import { Button } from "./ui/button";
6
+ import { ScrollArea } from "./ui/scroll-area";
7
+ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "./ui/sheet";
8
+ import "../styles/data-detail.scss";
9
+
10
+ interface DataDetailSheetProps {
11
+ open: boolean;
12
+ onOpenChange: (open: boolean) => void;
13
+ title: string;
14
+ description?: string;
15
+ data: any;
16
+ onSave?: (updatedData: any) => void;
17
+ field?: string;
18
+ }
19
+
20
+ import { useStore } from "@nanostores/react";
21
+ import { $config } from "../../stores/config";
22
+
23
+ export const DataDetailSheet: React.FC<DataDetailSheetProps> = ({
24
+ open,
25
+ onOpenChange,
26
+ title,
27
+ description,
28
+ data: initialData,
29
+ onSave,
30
+ field,
31
+ }) => {
32
+ const [isEditing, setIsEditing] = useState(false);
33
+ const [data, setData] = useState(initialData);
34
+
35
+ const config = useStore($config) as any;
36
+ const i18nConfig = config?.i18n;
37
+
38
+ const [activeLocale, setActiveLocale] = useState(i18nConfig?.defaultLocale || "default");
39
+
40
+ useEffect(() => {
41
+ setData(initialData);
42
+ setIsEditing(false);
43
+ if (i18nConfig) {
44
+ setActiveLocale(i18nConfig.defaultLocale);
45
+ }
46
+ }, [initialData, open, i18nConfig]);
47
+
48
+ const handleSave = () => {
49
+ if (onSave) {
50
+ onSave(data);
51
+ }
52
+ setIsEditing(false);
53
+ };
54
+
55
+ return (
56
+ <Sheet open={open} onOpenChange={onOpenChange}>
57
+ <SheetContent onClose={() => onOpenChange(false)} className="opaca-data-detail-sheet">
58
+ <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
59
+ <SheetHeader>
60
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
61
+ <div>
62
+ <SheetTitle>{title}</SheetTitle>
63
+ {description && <SheetDescription>{description}</SheetDescription>}
64
+ </div>
65
+ {onSave && (
66
+ <div style={{ display: "flex", gap: "0.5rem", alignItems: "center" }}>
67
+ {isEditing && i18nConfig && i18nConfig.locales.length > 0 && (
68
+ <div
69
+ style={{
70
+ display: "flex",
71
+ borderRight: "1px solid var(--border)",
72
+ paddingRight: "0.5rem",
73
+ marginRight: "0.5rem",
74
+ gap: "0.25rem",
75
+ }}
76
+ >
77
+ {i18nConfig.locales.map((locale: string) => (
78
+ <Button
79
+ key={locale}
80
+ variant={activeLocale === locale ? "default" : "outline"}
81
+ size="sm"
82
+ onClick={() => setActiveLocale(locale)}
83
+ style={{ height: "32px", fontSize: "12px" }}
84
+ >
85
+ {locale.toUpperCase()}
86
+ </Button>
87
+ ))}
88
+ </div>
89
+ )}
90
+ {!isEditing ? (
91
+ <Button
92
+ variant="outline"
93
+ size="sm"
94
+ onClick={() => setIsEditing(true)}
95
+ style={{ height: "32px", gap: "4px" }}
96
+ >
97
+ <Edit2 size={14} />
98
+ Edit
99
+ </Button>
100
+ ) : (
101
+ <>
102
+ <Button
103
+ variant="ghost"
104
+ size="sm"
105
+ onClick={() => {
106
+ setData(initialData);
107
+ setIsEditing(false);
108
+ }}
109
+ style={{ height: "32px", gap: "4px" }}
110
+ >
111
+ <X size={14} />
112
+ Cancel
113
+ </Button>
114
+ <Button
115
+ variant="default"
116
+ size="sm"
117
+ onClick={handleSave}
118
+ style={{ height: "32px", gap: "4px" }}
119
+ >
120
+ <Save size={14} />
121
+ Save
122
+ </Button>
123
+ </>
124
+ )}
125
+ </div>
126
+ )}
127
+ </div>
128
+ </SheetHeader>
129
+
130
+ <div style={{ flex: 1, minHeight: 0, marginTop: "1.5rem" }}>
131
+ <ScrollArea style={{ height: "100%" }}>
132
+ <div style={{ paddingRight: "1rem", paddingBottom: "2rem" }}>
133
+ <DataDetailView data={data} isEditing={isEditing} onChange={setData} />
134
+ </div>
135
+ </ScrollArea>
136
+ </div>
137
+ </div>
138
+ </SheetContent>
139
+ </Sheet>
140
+ );
141
+ };
@@ -0,0 +1,175 @@
1
+ import { RichTextEditor } from "./fields/richtext-editor";
2
+ import { Input } from "./ui/input";
3
+ import { cn } from "./ui/utils";
4
+
5
+ interface DataDetailViewProps {
6
+ data: any;
7
+ label?: string;
8
+ depth?: number;
9
+ isEditing?: boolean;
10
+ onChange?: (data: any) => void;
11
+ }
12
+
13
+ export const DataDetailView: React.FC<DataDetailViewProps> = ({
14
+ data,
15
+ label,
16
+ depth = 0,
17
+ isEditing,
18
+ onChange,
19
+ }) => {
20
+ if (data === null || data === undefined) {
21
+ return <span className="opaca-text-muted">None</span>;
22
+ }
23
+
24
+ // Handle arrays (Blocks or HasMany Relationships)
25
+ if (Array.isArray(data)) {
26
+ if (data.length === 0) return <span className="opaca-text-muted">Empty</span>;
27
+
28
+ return (
29
+ <div className="opaca-detail-list">
30
+ {data.map((item, index) => (
31
+ <div key={item || index} className="opaca-detail-item-card">
32
+ {item?.blockType && (
33
+ <div className="opaca-detail-item-header">
34
+ <span className="opaca-badge">{item.blockType}</span>
35
+ </div>
36
+ )}
37
+ <div className="opaca-detail-item-content">
38
+ {typeof item === "object" ? (
39
+ <DataDetailView
40
+ data={item}
41
+ depth={depth + 1}
42
+ isEditing={isEditing}
43
+ onChange={(val) => {
44
+ const newData = [...data];
45
+ newData[index] = val;
46
+ onChange?.(newData);
47
+ }}
48
+ />
49
+ ) : isEditing ? (
50
+ <Input
51
+ value={String(item)}
52
+ onChange={(e) => {
53
+ const newData = [...data];
54
+ newData[index] = e.target.value;
55
+ onChange?.(newData);
56
+ }}
57
+ />
58
+ ) : (
59
+ <span className="opaca-detail-value">{String(item)}</span>
60
+ )}
61
+ </div>
62
+ </div>
63
+ ))}
64
+ </div>
65
+ );
66
+ }
67
+
68
+ // Handle objects or strings that might be Lexical JSON
69
+ const isLexicalJSON = (val: unknown): boolean => {
70
+ if (!val) return false;
71
+
72
+ if (typeof val === "object") {
73
+ return val !== null && "root" in val;
74
+ }
75
+
76
+ if (typeof val === "string") {
77
+ const trimmed = val.trim();
78
+
79
+ if (!trimmed.startsWith("{")) return false;
80
+
81
+ try {
82
+ const parsed = JSON.parse(trimmed);
83
+ return parsed && typeof parsed === "object" && "root" in parsed;
84
+ } catch {
85
+ return false;
86
+ }
87
+ }
88
+
89
+ return false;
90
+ };
91
+
92
+ if (isLexicalJSON(data) && depth === 0) {
93
+ let valueToEdit = data;
94
+ if (typeof data === "object") {
95
+ try {
96
+ valueToEdit = JSON.stringify(data);
97
+ } catch (e) {}
98
+ }
99
+
100
+ return (
101
+ <div className="opaca-detail-richtext-preview">
102
+ <RichTextEditor
103
+ value={valueToEdit}
104
+ onChange={(val) => {
105
+ try {
106
+ onChange?.(JSON.parse(val));
107
+ } catch (e) {
108
+ onChange?.(val);
109
+ }
110
+ }}
111
+ readOnly={!isEditing}
112
+ />
113
+ </div>
114
+ );
115
+ }
116
+
117
+ // Handle objects (Groups or Block contents)
118
+ if (typeof data === "object" && data !== null) {
119
+ const keys = Object.keys(data).filter(
120
+ (k) => k !== "blockType" && k !== "id" && k !== "_order" && !k.startsWith("_"),
121
+ );
122
+ if (keys.length === 0) return <span className="opaca-text-muted">Empty Object</span>;
123
+
124
+ return (
125
+ <div className={cn("opaca-detail-grid", depth > 0 && "nested")}>
126
+ {keys.map((key) => (
127
+ <div key={key} className="opaca-detail-row">
128
+ <span className="opaca-detail-label">
129
+ {key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase())}
130
+ </span>
131
+ <div className="opaca-detail-value-container">
132
+ {typeof data[key] === "object" && data[key] !== null ? (
133
+ <DataDetailView
134
+ data={data[key]}
135
+ depth={depth + 1}
136
+ isEditing={isEditing}
137
+ onChange={(val) => {
138
+ onChange?.({ ...data, [key]: val });
139
+ }}
140
+ />
141
+ ) : isEditing ? (
142
+ <Input
143
+ value={
144
+ data[key] === true
145
+ ? "true"
146
+ : data[key] === false
147
+ ? "false"
148
+ : String(data[key] ?? "")
149
+ }
150
+ onChange={(e) => {
151
+ let val: any = e.target.value;
152
+ if (val === "true") val = true;
153
+ if (val === "false") val = false;
154
+ onChange?.({ ...data, [key]: val });
155
+ }}
156
+ />
157
+ ) : (
158
+ <span className="opaca-detail-value">
159
+ {data[key] === true
160
+ ? "Yes"
161
+ : data[key] === false
162
+ ? "No"
163
+ : String(data[key] ?? "-")}
164
+ </span>
165
+ )}
166
+ </div>
167
+ </div>
168
+ ))}
169
+ </div>
170
+ );
171
+ }
172
+
173
+ // Fallback for primitives
174
+ return <span className="opaca-detail-value">{String(data)}</span>;
175
+ };
@@ -0,0 +1,67 @@
1
+ import React from "react";
2
+
3
+ const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
4
+ ({ className, ...props }, ref) => (
5
+ <div className="opaca-table-wrapper">
6
+ <table ref={ref} className={`opaca-new-table ${className || ""}`} {...props} />
7
+ </div>
8
+ ),
9
+ );
10
+ Table.displayName = "Table";
11
+
12
+ const TableHeader = React.forwardRef<
13
+ HTMLTableSectionElement,
14
+ React.HTMLAttributes<HTMLTableSectionElement>
15
+ >(({ className, ...props }, ref) => (
16
+ <thead ref={ref} className={`opaca-table-header ${className || ""}`} {...props} />
17
+ ));
18
+ TableHeader.displayName = "TableHeader";
19
+
20
+ const TableBody = React.forwardRef<
21
+ HTMLTableSectionElement,
22
+ React.HTMLAttributes<HTMLTableSectionElement>
23
+ >(({ className, ...props }, ref) => (
24
+ <tbody ref={ref} className={`opaca-table-body ${className || ""}`} {...props} />
25
+ ));
26
+ TableBody.displayName = "TableBody";
27
+
28
+ const TableFooter = React.forwardRef<
29
+ HTMLTableSectionElement,
30
+ React.HTMLAttributes<HTMLTableSectionElement>
31
+ >(({ className, ...props }, ref) => (
32
+ <tfoot ref={ref} className={`opaca-table-footer ${className || ""}`} {...props} />
33
+ ));
34
+ TableFooter.displayName = "TableFooter";
35
+
36
+ const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
37
+ ({ className, ...props }, ref) => (
38
+ <tr ref={ref} className={`opaca-table-row ${className || ""}`} {...props} />
39
+ ),
40
+ );
41
+ TableRow.displayName = "TableRow";
42
+
43
+ const TableHead = React.forwardRef<
44
+ HTMLTableCellElement,
45
+ React.ThHTMLAttributes<HTMLTableCellElement>
46
+ >(({ className, ...props }, ref) => (
47
+ <th ref={ref} className={`opaca-table-head ${className || ""}`} {...props} />
48
+ ));
49
+ TableHead.displayName = "TableHead";
50
+
51
+ const TableCell = React.forwardRef<
52
+ HTMLTableCellElement,
53
+ React.TdHTMLAttributes<HTMLTableCellElement>
54
+ >(({ className, ...props }, ref) => (
55
+ <td ref={ref} className={`opaca-table-cell ${className || ""}`} {...props} />
56
+ ));
57
+ TableCell.displayName = "TableCell";
58
+
59
+ const TableCaption = React.forwardRef<
60
+ HTMLTableCaptionElement,
61
+ React.HTMLAttributes<HTMLTableCaptionElement>
62
+ >(({ className, ...props }, ref) => (
63
+ <caption ref={ref} className={`opaca-table-caption ${className || ""}`} {...props} />
64
+ ));
65
+ TableCaption.displayName = "TableCaption";
66
+
67
+ export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
@@ -0,0 +1,166 @@
1
+ import { Plus, Trash2 } from "lucide-react";
2
+ import type React from "react";
3
+ import { Button } from "../ui/button";
4
+ import { capitalize } from "./utils";
5
+
6
+ interface ArrayFieldProps {
7
+ name: string;
8
+ label?: string;
9
+ fields: any[];
10
+ value: any[];
11
+ onChange: (val: any[]) => void;
12
+ disabled?: boolean;
13
+ readOnly?: boolean;
14
+ renderField: (field: any, value: any, onChange: (val: any) => void) => React.ReactNode;
15
+ }
16
+
17
+ export const ArrayField: React.FC<ArrayFieldProps> = ({
18
+ name,
19
+ label,
20
+ fields = [],
21
+ value = [],
22
+ onChange,
23
+ disabled,
24
+ readOnly,
25
+ renderField,
26
+ }) => {
27
+ const addItem = () => {
28
+ const currentValue = Array.isArray(value) ? value : [];
29
+ const initialData: Record<string, any> = {};
30
+
31
+ fields.forEach((f) => {
32
+ if (f.name) {
33
+ if (f.defaultValue !== undefined) {
34
+ initialData[f.name] = f.defaultValue;
35
+ } else if (f.type === "boolean") {
36
+ initialData[f.name] = false;
37
+ } else if (f.type === "number") {
38
+ initialData[f.name] = 0;
39
+ } else if (f.type === "relationship" && f.hasMany) {
40
+ initialData[f.name] = [];
41
+ } else if (f.type === "blocks") {
42
+ initialData[f.name] = [];
43
+ } else if (f.type === "array") {
44
+ initialData[f.name] = [];
45
+ } else {
46
+ initialData[f.name] = "";
47
+ }
48
+ }
49
+ });
50
+
51
+ onChange([...currentValue, initialData]);
52
+ };
53
+
54
+ const removeItem = (index: number) => {
55
+ const currentValue = Array.isArray(value) ? value : [];
56
+ const newValue = [...currentValue];
57
+ newValue.splice(index, 1);
58
+ onChange(newValue);
59
+ };
60
+
61
+ const updateItemData = (index: number, fieldName: string, fieldValue: any) => {
62
+ const currentValue = Array.isArray(value) ? value : [];
63
+ const newValue = [...currentValue];
64
+ newValue[index] = {
65
+ ...newValue[index],
66
+ [fieldName]: fieldValue,
67
+ };
68
+ onChange(newValue);
69
+ };
70
+
71
+ const updateRawItemData = (index: number, fieldValue: any) => {
72
+ const currentValue = Array.isArray(value) ? value : [];
73
+ const newValue = [...currentValue];
74
+ newValue[index] = fieldValue;
75
+ onChange(newValue);
76
+ };
77
+
78
+ return (
79
+ <div className="opaca-array-field">
80
+ <div
81
+ style={{
82
+ display: "flex",
83
+ justifyContent: "space-between",
84
+ alignItems: "center",
85
+ marginBottom: "0.75rem",
86
+ }}
87
+ >
88
+ <label htmlFor={name} className="opaca-label" style={{ marginBottom: 0 }}>
89
+ {label || capitalize(name)}
90
+ </label>
91
+ </div>
92
+
93
+ <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
94
+ {(Array.isArray(value) ? value : []).map((item, index) => (
95
+ <div
96
+ key={item || index}
97
+ style={{
98
+ border: "1px solid var(--opaca-border)",
99
+ borderRadius: "var(--opaca-radius-lg)",
100
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
101
+ padding: "1rem",
102
+ position: "relative",
103
+ }}
104
+ >
105
+ <div
106
+ style={{
107
+ display: "flex",
108
+ justifyContent: "flex-end",
109
+ marginBottom: "0.5rem",
110
+ }}
111
+ >
112
+ {!disabled && !readOnly && (
113
+ <Button
114
+ type="button"
115
+ variant="ghost"
116
+ size="icon"
117
+ onClick={() => removeItem(index)}
118
+ style={{
119
+ color: "var(--opaca-text-dim)",
120
+ height: "24px",
121
+ width: "24px",
122
+ }}
123
+ >
124
+ <Trash2 size={14} />
125
+ </Button>
126
+ )}
127
+ </div>
128
+
129
+ <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
130
+ {fields.map((field, fieldIndex) => (
131
+ <div key={field.name || fieldIndex} className="array-field-item">
132
+ {renderField(field, field.name ? item[field.name] : item, (val) => {
133
+ if (field.name) {
134
+ updateItemData(index, field.name, val);
135
+ } else {
136
+ updateRawItemData(index, val);
137
+ }
138
+ })}
139
+ </div>
140
+ ))}
141
+ </div>
142
+ </div>
143
+ ))}
144
+
145
+ {!disabled && !readOnly && (
146
+ <Button
147
+ type="button"
148
+ variant="outline"
149
+ size="sm"
150
+ onClick={addItem}
151
+ style={{
152
+ display: "flex",
153
+ alignItems: "center",
154
+ gap: "6px",
155
+ fontSize: "0.75rem",
156
+ width: "fit-content",
157
+ }}
158
+ >
159
+ <Plus size={12} />
160
+ Add Item
161
+ </Button>
162
+ )}
163
+ </div>
164
+ </div>
165
+ );
166
+ };