@kyro-cms/core 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/README.md +57 -589
  2. package/dist/{WebhookService-118ZTFis.d.ts → WebhookService-CUTb9XOy.d.ts} +1 -1
  3. package/dist/{WebhookService-AefJfqX0.d.cts → WebhookService-Yg2UEOB4.d.cts} +1 -1
  4. package/dist/api-handler-graphql.cjs +44 -0
  5. package/dist/api-handler-graphql.cjs.map +1 -0
  6. package/dist/api-handler-graphql.d.cts +6 -0
  7. package/dist/api-handler-graphql.d.ts +6 -0
  8. package/dist/api-handler-graphql.js +41 -0
  9. package/dist/api-handler-graphql.js.map +1 -0
  10. package/dist/api-handler-trpc.cjs +38 -0
  11. package/dist/api-handler-trpc.cjs.map +1 -0
  12. package/dist/api-handler-trpc.d.cts +5 -0
  13. package/dist/api-handler-trpc.d.ts +5 -0
  14. package/dist/api-handler-trpc.js +36 -0
  15. package/dist/api-handler-trpc.js.map +1 -0
  16. package/dist/api-handler.cjs +31 -97
  17. package/dist/api-handler.cjs.map +1 -1
  18. package/dist/api-handler.d.cts +2 -1
  19. package/dist/api-handler.d.ts +2 -1
  20. package/dist/api-handler.js +19 -95
  21. package/dist/api-handler.js.map +1 -1
  22. package/dist/{tenant-B1YB0Jy8.d.ts → base-B71y_EAF.d.cts} +6 -12
  23. package/dist/{tenant-Cpeveji6.d.cts → base-DaqY2GhA.d.ts} +6 -12
  24. package/dist/bootstrap-5NLASFOG.cjs +32 -0
  25. package/dist/{bootstrap-AKAUP6F6.cjs.map → bootstrap-5NLASFOG.cjs.map} +1 -1
  26. package/dist/bootstrap-T5BK77LD.js +7 -0
  27. package/dist/{bootstrap-JCML6NFO.js.map → bootstrap-T5BK77LD.js.map} +1 -1
  28. package/dist/{chunk-35U3FROB.js → chunk-22M4O4ZJ.js} +607 -63
  29. package/dist/chunk-22M4O4ZJ.js.map +1 -0
  30. package/dist/chunk-2HZRBATX.cjs +253 -0
  31. package/dist/chunk-2HZRBATX.cjs.map +1 -0
  32. package/dist/{chunk-VJT6P4N6.cjs → chunk-3HR772HI.cjs} +199 -32
  33. package/dist/chunk-3HR772HI.cjs.map +1 -0
  34. package/dist/chunk-3KTWGODI.cjs +178 -0
  35. package/dist/chunk-3KTWGODI.cjs.map +1 -0
  36. package/dist/{chunk-QXIQWPAP.js → chunk-3UK5XBVJ.js} +4 -134
  37. package/dist/chunk-3UK5XBVJ.js.map +1 -0
  38. package/dist/{chunk-FXYP2HA6.js → chunk-4AO3A3JM.js} +48 -4
  39. package/dist/chunk-4AO3A3JM.js.map +1 -0
  40. package/dist/chunk-4M7X5HAB.cjs +173 -0
  41. package/dist/chunk-4M7X5HAB.cjs.map +1 -0
  42. package/dist/chunk-5EPFQUQD.js +3243 -0
  43. package/dist/chunk-5EPFQUQD.js.map +1 -0
  44. package/dist/{chunk-Y3N7UUDO.js → chunk-7OGPN7MP.js} +5 -2
  45. package/dist/chunk-7OGPN7MP.js.map +1 -0
  46. package/dist/{chunk-WOWUL7ZY.js → chunk-AL5KX63J.js} +4 -3
  47. package/dist/chunk-AL5KX63J.js.map +1 -0
  48. package/dist/{chunk-2OL4O2TH.cjs → chunk-C36TMDTY.cjs} +66 -61
  49. package/dist/chunk-C36TMDTY.cjs.map +1 -0
  50. package/dist/{chunk-ES5HNFFT.js → chunk-CF7OL6HR.js} +4 -2
  51. package/dist/chunk-CF7OL6HR.js.map +1 -0
  52. package/dist/chunk-CJONKRHJ.js +162 -0
  53. package/dist/chunk-CJONKRHJ.js.map +1 -0
  54. package/dist/{chunk-2KVHZE6O.cjs → chunk-COIASRDK.cjs} +202 -46
  55. package/dist/chunk-COIASRDK.cjs.map +1 -0
  56. package/dist/chunk-DEVFAKCQ.cjs +3291 -0
  57. package/dist/chunk-DEVFAKCQ.cjs.map +1 -0
  58. package/dist/{chunk-3ZFYL34R.js → chunk-DYTZ6FQ7.js} +12 -185
  59. package/dist/chunk-DYTZ6FQ7.js.map +1 -0
  60. package/dist/{chunk-QPPDLRNR.js → chunk-EJN2PAOE.js} +197 -41
  61. package/dist/chunk-EJN2PAOE.js.map +1 -0
  62. package/dist/chunk-FAXU7BMP.js +220 -0
  63. package/dist/chunk-FAXU7BMP.js.map +1 -0
  64. package/dist/{chunk-OHVB4AJ7.js → chunk-FOPGUM27.js} +22 -17
  65. package/dist/chunk-FOPGUM27.js.map +1 -0
  66. package/dist/chunk-GAOXD3XT.js +175 -0
  67. package/dist/chunk-GAOXD3XT.js.map +1 -0
  68. package/dist/{chunk-4DA7QPLA.cjs → chunk-GXFOGU7N.cjs} +5 -2
  69. package/dist/chunk-GXFOGU7N.cjs.map +1 -0
  70. package/dist/{chunk-I7HHI6QV.cjs → chunk-IDVRRRAK.cjs} +17 -9
  71. package/dist/chunk-IDVRRRAK.cjs.map +1 -0
  72. package/dist/{chunk-WQBRWOQT.cjs → chunk-JOPVMWTM.cjs} +3 -2
  73. package/dist/chunk-JOPVMWTM.cjs.map +1 -0
  74. package/dist/chunk-KC2GDBLS.cjs +84 -0
  75. package/dist/chunk-KC2GDBLS.cjs.map +1 -0
  76. package/dist/{chunk-K7JPTH3G.cjs → chunk-KNRSROWB.cjs} +132 -74
  77. package/dist/chunk-KNRSROWB.cjs.map +1 -0
  78. package/dist/{chunk-3AJE4SEG.js → chunk-KPA4AN4R.js} +125 -67
  79. package/dist/chunk-KPA4AN4R.js.map +1 -0
  80. package/dist/{chunk-QUW2RZTM.cjs → chunk-L46ROHUS.cjs} +51 -7
  81. package/dist/chunk-L46ROHUS.cjs.map +1 -0
  82. package/dist/chunk-L4EZKIEX.js +185 -0
  83. package/dist/chunk-L4EZKIEX.js.map +1 -0
  84. package/dist/{chunk-REK7AYOC.js → chunk-L5UKKZQN.js} +199 -32
  85. package/dist/chunk-L5UKKZQN.js.map +1 -0
  86. package/dist/chunk-NKPKR5BW.cjs +188 -0
  87. package/dist/chunk-NKPKR5BW.cjs.map +1 -0
  88. package/dist/{chunk-Y3QQN7PN.js → chunk-P2HKJ7P5.js} +13 -4
  89. package/dist/chunk-P2HKJ7P5.js.map +1 -0
  90. package/dist/{chunk-SA7NSSIQ.cjs → chunk-PI73NNOK.cjs} +13 -187
  91. package/dist/chunk-PI73NNOK.cjs.map +1 -0
  92. package/dist/{chunk-HXRD4B37.js → chunk-PU2Z5VWF.js} +1279 -556
  93. package/dist/chunk-PU2Z5VWF.js.map +1 -0
  94. package/dist/{chunk-H727JIG7.js → chunk-Q72BOAPK.js} +16 -8
  95. package/dist/chunk-Q72BOAPK.js.map +1 -0
  96. package/dist/{chunk-IBG6V56E.cjs → chunk-QFLB4EIJ.cjs} +2 -139
  97. package/dist/chunk-QFLB4EIJ.cjs.map +1 -0
  98. package/dist/{chunk-YVUJBEXE.cjs → chunk-RAMGUDJN.cjs} +16 -7
  99. package/dist/chunk-RAMGUDJN.cjs.map +1 -0
  100. package/dist/{chunk-LINKCEG4.cjs → chunk-ROJHKAQ4.cjs} +617 -73
  101. package/dist/chunk-ROJHKAQ4.cjs.map +1 -0
  102. package/dist/{chunk-5KVM3WEY.cjs → chunk-RSF3UU7H.cjs} +1330 -602
  103. package/dist/chunk-RSF3UU7H.cjs.map +1 -0
  104. package/dist/{chunk-V3LKPM3O.cjs → chunk-SHTTJMLT.cjs} +4 -2
  105. package/dist/chunk-SHTTJMLT.cjs.map +1 -0
  106. package/dist/chunk-SPBTLUN6.js +92 -0
  107. package/dist/chunk-SPBTLUN6.js.map +1 -0
  108. package/dist/{chunk-57P6MJKC.js → chunk-TXSZFA4G.js} +3 -3
  109. package/dist/chunk-TXSZFA4G.js.map +1 -0
  110. package/dist/chunk-UERVXYVK.cjs +99 -0
  111. package/dist/chunk-UERVXYVK.cjs.map +1 -0
  112. package/dist/{chunk-PDYFVNUX.cjs → chunk-V2TVSCV5.cjs} +16 -23
  113. package/dist/chunk-V2TVSCV5.cjs.map +1 -0
  114. package/dist/{chunk-DXHRBMGB.js → chunk-VO35MNPH.js} +12 -19
  115. package/dist/chunk-VO35MNPH.js.map +1 -0
  116. package/dist/{chunk-IA6AU5PI.cjs → chunk-WNCYAKF3.cjs} +3 -3
  117. package/dist/chunk-WNCYAKF3.cjs.map +1 -0
  118. package/dist/chunk-XEB7PH2E.js +81 -0
  119. package/dist/chunk-XEB7PH2E.js.map +1 -0
  120. package/dist/cli/index.cjs +5 -5
  121. package/dist/cli/index.cjs.map +1 -1
  122. package/dist/cli/index.js +5 -5
  123. package/dist/cli/index.js.map +1 -1
  124. package/dist/client.cjs +3 -3
  125. package/dist/client.d.cts +3 -3
  126. package/dist/client.d.ts +3 -3
  127. package/dist/client.js +1 -1
  128. package/dist/drizzle/index.cjs +14 -13
  129. package/dist/drizzle/index.d.cts +9 -7
  130. package/dist/drizzle/index.d.ts +9 -7
  131. package/dist/drizzle/index.js +5 -4
  132. package/dist/fields/index.cjs +21 -37
  133. package/dist/fields/index.d.cts +2 -22
  134. package/dist/fields/index.d.ts +2 -22
  135. package/dist/fields/index.js +1 -1
  136. package/dist/graphql/index.cjs +5 -4
  137. package/dist/graphql/index.d.cts +5 -3
  138. package/dist/graphql/index.d.ts +5 -3
  139. package/dist/graphql/index.js +3 -2
  140. package/dist/index-CJXPB_ot.d.ts +276 -0
  141. package/dist/index-CaTNnLGd.d.cts +276 -0
  142. package/dist/index.cjs +304 -162
  143. package/dist/index.cjs.map +1 -1
  144. package/dist/index.d.cts +129 -205
  145. package/dist/index.d.ts +129 -205
  146. package/dist/index.js +172 -33
  147. package/dist/index.js.map +1 -1
  148. package/dist/integration.cjs +2 -2
  149. package/dist/integration.js +1 -1
  150. package/dist/mongo-auth-adapter-ISOM7FSS.cjs +17 -0
  151. package/dist/{mongo-auth-adapter-NHHUJHVH.cjs.map → mongo-auth-adapter-ISOM7FSS.cjs.map} +1 -1
  152. package/dist/mongo-auth-adapter-MO6STCV3.js +4 -0
  153. package/dist/{mongo-auth-adapter-NJQUUCTP.js.map → mongo-auth-adapter-MO6STCV3.js.map} +1 -1
  154. package/dist/mongodb/index.cjs +8 -7
  155. package/dist/mongodb/index.d.cts +5 -7
  156. package/dist/mongodb/index.d.ts +5 -7
  157. package/dist/mongodb/index.js +4 -3
  158. package/dist/postgres-auth-adapter-DWDR7P5G.js +5 -0
  159. package/dist/{postgres-auth-adapter-3T2NKTSE.js.map → postgres-auth-adapter-DWDR7P5G.js.map} +1 -1
  160. package/dist/postgres-auth-adapter-WRWSJD4E.cjs +14 -0
  161. package/dist/{postgres-auth-adapter-7IEENCKQ.cjs.map → postgres-auth-adapter-WRWSJD4E.cjs.map} +1 -1
  162. package/dist/redis-adapter-HGTPWIGV.js +4 -0
  163. package/dist/{redis-adapter-VQXD7ESY.js.map → redis-adapter-HGTPWIGV.js.map} +1 -1
  164. package/dist/redis-adapter-KJ3YOOT6.cjs +13 -0
  165. package/dist/{redis-adapter-D2E2S3GB.cjs.map → redis-adapter-KJ3YOOT6.cjs.map} +1 -1
  166. package/dist/rest/index.cjs +15 -14
  167. package/dist/rest/index.d.cts +4 -4
  168. package/dist/rest/index.d.ts +4 -4
  169. package/dist/rest/index.js +13 -12
  170. package/dist/{schema-5PHL5IVB.js → schema-6I5OFR4Z.js} +3 -3
  171. package/dist/{schema-5PHL5IVB.js.map → schema-6I5OFR4Z.js.map} +1 -1
  172. package/dist/{schema-37SE2F4B.cjs → schema-TTFE4467.cjs} +14 -14
  173. package/dist/{schema-37SE2F4B.cjs.map → schema-TTFE4467.cjs.map} +1 -1
  174. package/dist/sqlite-adapter-6GEUSVXQ.js +4 -0
  175. package/dist/{sqlite-adapter-TR3U3W6Q.js.map → sqlite-adapter-6GEUSVXQ.js.map} +1 -1
  176. package/dist/sqlite-adapter-CSIZE5SX.cjs +13 -0
  177. package/dist/{sqlite-adapter-LVK5PS4T.cjs.map → sqlite-adapter-CSIZE5SX.cjs.map} +1 -1
  178. package/dist/templates/index.cjs +133 -31
  179. package/dist/templates/index.d.cts +52 -9
  180. package/dist/templates/index.d.ts +52 -9
  181. package/dist/templates/index.js +3 -1
  182. package/dist/trpc/index.cjs +13 -12
  183. package/dist/trpc/index.d.cts +55 -49
  184. package/dist/trpc/index.d.ts +55 -49
  185. package/dist/trpc/index.js +4 -3
  186. package/dist/{types-D6ZLRGbH.d.cts → types-CpjuXbe7.d.cts} +2 -0
  187. package/dist/{types-D6ZLRGbH.d.ts → types-CpjuXbe7.d.ts} +2 -0
  188. package/dist/{types-Bs1up4yP.d.ts → types-CyCQ6SAI.d.ts} +28 -2
  189. package/dist/{types-J3R9nVsZ.d.cts → types-DJxD9394.d.cts} +28 -2
  190. package/dist/{types-VtjUxIMp.d.cts → types-Z6FBiqa2.d.cts} +35 -14
  191. package/dist/{types-VtjUxIMp.d.ts → types-Z6FBiqa2.d.ts} +35 -14
  192. package/package.json +22 -4
  193. package/dist/bootstrap-AKAUP6F6.cjs +0 -32
  194. package/dist/bootstrap-JCML6NFO.js +0 -7
  195. package/dist/chunk-2KVHZE6O.cjs.map +0 -1
  196. package/dist/chunk-2OL4O2TH.cjs.map +0 -1
  197. package/dist/chunk-35U3FROB.js.map +0 -1
  198. package/dist/chunk-3AJE4SEG.js.map +0 -1
  199. package/dist/chunk-3J4MFTI3.js +0 -3872
  200. package/dist/chunk-3J4MFTI3.js.map +0 -1
  201. package/dist/chunk-3ZFYL34R.js.map +0 -1
  202. package/dist/chunk-4DA7QPLA.cjs.map +0 -1
  203. package/dist/chunk-57P6MJKC.js.map +0 -1
  204. package/dist/chunk-5KVM3WEY.cjs.map +0 -1
  205. package/dist/chunk-6IMPH6WV.cjs +0 -3897
  206. package/dist/chunk-6IMPH6WV.cjs.map +0 -1
  207. package/dist/chunk-ATBOUGQP.cjs +0 -513
  208. package/dist/chunk-ATBOUGQP.cjs.map +0 -1
  209. package/dist/chunk-DXHRBMGB.js.map +0 -1
  210. package/dist/chunk-ES5HNFFT.js.map +0 -1
  211. package/dist/chunk-FXYP2HA6.js.map +0 -1
  212. package/dist/chunk-H727JIG7.js.map +0 -1
  213. package/dist/chunk-HXRD4B37.js.map +0 -1
  214. package/dist/chunk-I7HHI6QV.cjs.map +0 -1
  215. package/dist/chunk-IA6AU5PI.cjs.map +0 -1
  216. package/dist/chunk-IBG6V56E.cjs.map +0 -1
  217. package/dist/chunk-K7JPTH3G.cjs.map +0 -1
  218. package/dist/chunk-LINKCEG4.cjs.map +0 -1
  219. package/dist/chunk-OHVB4AJ7.js.map +0 -1
  220. package/dist/chunk-PDYFVNUX.cjs.map +0 -1
  221. package/dist/chunk-Q23JB3KL.js +0 -488
  222. package/dist/chunk-Q23JB3KL.js.map +0 -1
  223. package/dist/chunk-QPPDLRNR.js.map +0 -1
  224. package/dist/chunk-QUW2RZTM.cjs.map +0 -1
  225. package/dist/chunk-QXIQWPAP.js.map +0 -1
  226. package/dist/chunk-R3XIBBAW.cjs +0 -34
  227. package/dist/chunk-R3XIBBAW.cjs.map +0 -1
  228. package/dist/chunk-REK7AYOC.js.map +0 -1
  229. package/dist/chunk-SA7NSSIQ.cjs.map +0 -1
  230. package/dist/chunk-SDMNUYVU.js +0 -30
  231. package/dist/chunk-SDMNUYVU.js.map +0 -1
  232. package/dist/chunk-V3LKPM3O.cjs.map +0 -1
  233. package/dist/chunk-VJT6P4N6.cjs.map +0 -1
  234. package/dist/chunk-WOWUL7ZY.js.map +0 -1
  235. package/dist/chunk-WQBRWOQT.cjs.map +0 -1
  236. package/dist/chunk-Y3N7UUDO.js.map +0 -1
  237. package/dist/chunk-Y3QQN7PN.js.map +0 -1
  238. package/dist/chunk-YVUJBEXE.cjs.map +0 -1
  239. package/dist/index-CLp-DRKA.d.ts +0 -64
  240. package/dist/index-DfO7G4kN.d.cts +0 -64
  241. package/dist/mongo-auth-adapter-NHHUJHVH.cjs +0 -17
  242. package/dist/mongo-auth-adapter-NJQUUCTP.js +0 -4
  243. package/dist/postgres-auth-adapter-3T2NKTSE.js +0 -5
  244. package/dist/postgres-auth-adapter-7IEENCKQ.cjs +0 -14
  245. package/dist/redis-adapter-D2E2S3GB.cjs +0 -13
  246. package/dist/redis-adapter-VQXD7ESY.js +0 -4
  247. package/dist/sqlite-adapter-LVK5PS4T.cjs +0 -13
  248. package/dist/sqlite-adapter-TR3U3W6Q.js +0 -4
@@ -0,0 +1,185 @@
1
+ // src/auth/rbac/roles.ts
2
+ var DEFAULT_ROLES = [
3
+ {
4
+ name: "super_admin",
5
+ level: 100,
6
+ inherits: [],
7
+ description: "Full system access across all tenants"
8
+ },
9
+ {
10
+ name: "admin",
11
+ level: 90,
12
+ inherits: ["editor"],
13
+ description: "Full tenant access with all content permissions"
14
+ },
15
+ {
16
+ name: "editor",
17
+ level: 70,
18
+ inherits: ["author"],
19
+ description: "Edit and publish all content"
20
+ },
21
+ {
22
+ name: "author",
23
+ level: 50,
24
+ inherits: ["customer"],
25
+ description: "Create and edit own content"
26
+ },
27
+ {
28
+ name: "customer",
29
+ level: 30,
30
+ inherits: [],
31
+ description: "Access own data and make purchases"
32
+ },
33
+ {
34
+ name: "guest",
35
+ level: 10,
36
+ inherits: [],
37
+ description: "Public read-only access"
38
+ }
39
+ ];
40
+ var ROLE_PERMISSIONS = {
41
+ super_admin: ["*"],
42
+ admin: [
43
+ "users:admin",
44
+ "users:read",
45
+ "users:update",
46
+ "audit_logs:read",
47
+ "posts:admin",
48
+ "posts:read",
49
+ "posts:create",
50
+ "posts:update",
51
+ "posts:delete",
52
+ "pages:admin",
53
+ "pages:read",
54
+ "pages:create",
55
+ "pages:update",
56
+ "pages:delete",
57
+ "media:admin",
58
+ "media:read",
59
+ "media:create",
60
+ "media:update",
61
+ "media:delete",
62
+ "categories:admin",
63
+ "categories:read",
64
+ "categories:create",
65
+ "categories:update",
66
+ "categories:delete",
67
+ "products:admin",
68
+ "products:read",
69
+ "products:create",
70
+ "products:update",
71
+ "products:delete",
72
+ "orders:admin",
73
+ "orders:read",
74
+ "orders:update",
75
+ "customers:admin",
76
+ "customers:read",
77
+ "customers:update",
78
+ "coupons:admin",
79
+ "coupons:read",
80
+ "coupons:create",
81
+ "coupons:update",
82
+ "coupons:delete",
83
+ "navigation:admin",
84
+ "navigation:read",
85
+ "navigation:create",
86
+ "navigation:update",
87
+ "navigation:delete",
88
+ "settings:admin",
89
+ "settings:read",
90
+ "settings:update",
91
+ "profile:admin",
92
+ "profile:read",
93
+ "profile:update"
94
+ ],
95
+ editor: [
96
+ "posts:admin",
97
+ "posts:read",
98
+ "posts:create",
99
+ "posts:update",
100
+ "posts:delete",
101
+ "pages:admin",
102
+ "pages:read",
103
+ "pages:create",
104
+ "pages:update",
105
+ "pages:delete",
106
+ "media:read",
107
+ "media:create",
108
+ "media:update",
109
+ "categories:read",
110
+ "categories:create",
111
+ "categories:update",
112
+ "products:read",
113
+ "orders:read",
114
+ "orders:update",
115
+ "navigation:read",
116
+ "navigation:create",
117
+ "navigation:update",
118
+ "profile:read",
119
+ "profile:update"
120
+ ],
121
+ author: [
122
+ "posts:read",
123
+ "posts:create",
124
+ "posts:update",
125
+ "media:read",
126
+ "media:create",
127
+ "categories:read",
128
+ "profile:read",
129
+ "profile:update"
130
+ ],
131
+ customer: ["profile:read", "profile:update", "orders:read", "orders:create"],
132
+ guest: ["posts:read", "pages:read", "products:read"]
133
+ };
134
+ function getRoleHierarchy(role, roles = DEFAULT_ROLES) {
135
+ const hierarchy = [role];
136
+ const roleMap = new Map(roles.map((r) => [r.name, r]));
137
+ const addInherited = (r) => {
138
+ const roleData = roleMap.get(r);
139
+ if (roleData && roleData.inherits) {
140
+ for (const inherited of roleData.inherits) {
141
+ if (!hierarchy.includes(inherited)) {
142
+ hierarchy.push(inherited);
143
+ addInherited(inherited);
144
+ }
145
+ }
146
+ }
147
+ };
148
+ addInherited(role);
149
+ return hierarchy;
150
+ }
151
+
152
+ // src/auth/rbac/checker.ts
153
+ function hasPermission(user, permission, rolePermissions = ROLE_PERMISSIONS) {
154
+ if (!user || !user.role) return false;
155
+ const userPermissions = getUserPermissions(user, rolePermissions);
156
+ if (userPermissions.includes("*")) return true;
157
+ if (userPermissions.includes(permission)) return true;
158
+ const [resource, action] = permission.split(":");
159
+ if (userPermissions.includes(`${resource}:*`)) return true;
160
+ if (userPermissions.includes(`${resource}:admin`)) return true;
161
+ return false;
162
+ }
163
+ function hasAnyRole(user, checkRoles) {
164
+ if (!user || !user.role) return false;
165
+ const hierarchy = getRoleHierarchy(user.role);
166
+ return checkRoles.some((role) => hierarchy.includes(role));
167
+ }
168
+ function getUserPermissions(user, rolePermissions = ROLE_PERMISSIONS) {
169
+ if (!user || !user.role) return [];
170
+ const hierarchy = getRoleHierarchy(user.role);
171
+ const permissions = /* @__PURE__ */ new Set();
172
+ for (const role of hierarchy) {
173
+ const rolePerms = rolePermissions[role];
174
+ if (rolePerms) {
175
+ for (const perm of rolePerms) {
176
+ permissions.add(perm);
177
+ }
178
+ }
179
+ }
180
+ return Array.from(permissions);
181
+ }
182
+
183
+ export { hasAnyRole, hasPermission };
184
+ //# sourceMappingURL=chunk-L4EZKIEX.js.map
185
+ //# sourceMappingURL=chunk-L4EZKIEX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/rbac/roles.ts","../src/auth/rbac/checker.ts"],"names":[],"mappings":"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","file":"chunk-L4EZKIEX.js","sourcesContent":["export interface Role {\n name: string;\n level: number;\n inherits: string[];\n description: string;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface Permission {\n resource: string;\n action: \"create\" | \"read\" | \"update\" | \"delete\" | \"admin\";\n conditions?: Condition[];\n}\n\nexport interface Condition {\n field: string;\n operator:\n | \"eq\"\n | \"neq\"\n | \"in\"\n | \"nin\"\n | \"gt\"\n | \"lt\"\n | \"gte\"\n | \"lte\"\n | \"contains\";\n value: any;\n}\n\nexport interface RolePermission {\n role: string;\n permissions: Permission[];\n}\n\nexport const DEFAULT_ROLES: Role[] = [\n {\n name: \"super_admin\",\n level: 100,\n inherits: [],\n description: \"Full system access across all tenants\",\n },\n {\n name: \"admin\",\n level: 90,\n inherits: [\"editor\"],\n description: \"Full tenant access with all content permissions\",\n },\n {\n name: \"editor\",\n level: 70,\n inherits: [\"author\"],\n description: \"Edit and publish all content\",\n },\n {\n name: \"author\",\n level: 50,\n inherits: [\"customer\"],\n description: \"Create and edit own content\",\n },\n {\n name: \"customer\",\n level: 30,\n inherits: [],\n description: \"Access own data and make purchases\",\n },\n {\n name: \"guest\",\n level: 10,\n inherits: [],\n description: \"Public read-only access\",\n },\n];\n\nexport const DEFAULT_PERMISSIONS: Permission[] = [\n { resource: \"users\", action: \"admin\" },\n { resource: \"users\", action: \"read\" },\n { resource: \"users\", action: \"create\" },\n { resource: \"users\", action: \"update\" },\n { resource: \"users\", action: \"delete\" },\n\n { resource: \"audit_logs\", action: \"admin\" },\n { resource: \"audit_logs\", action: \"read\" },\n\n { resource: \"posts\", action: \"admin\" },\n { resource: \"posts\", action: \"read\" },\n { resource: \"posts\", action: \"create\" },\n { resource: \"posts\", action: \"update\" },\n { resource: \"posts\", action: \"delete\" },\n\n { resource: \"pages\", action: \"admin\" },\n { resource: \"pages\", action: \"read\" },\n { resource: \"pages\", action: \"create\" },\n { resource: \"pages\", action: \"update\" },\n { resource: \"pages\", action: \"delete\" },\n\n { resource: \"media\", action: \"admin\" },\n { resource: \"media\", action: \"read\" },\n { resource: \"media\", action: \"create\" },\n { resource: \"media\", action: \"update\" },\n { resource: \"media\", action: \"delete\" },\n\n { resource: \"categories\", action: \"admin\" },\n { resource: \"categories\", action: \"read\" },\n { resource: \"categories\", action: \"create\" },\n { resource: \"categories\", action: \"update\" },\n { resource: \"categories\", action: \"delete\" },\n\n { resource: \"products\", action: \"admin\" },\n { resource: \"products\", action: \"read\" },\n { resource: \"products\", action: \"create\" },\n { resource: \"products\", action: \"update\" },\n { resource: \"products\", action: \"delete\" },\n\n { resource: \"orders\", action: \"admin\" },\n { resource: \"orders\", action: \"read\" },\n { resource: \"orders\", action: \"create\" },\n { resource: \"orders\", action: \"update\" },\n { resource: \"orders\", action: \"delete\" },\n\n { resource: \"customers\", action: \"admin\" },\n { resource: \"customers\", action: \"read\" },\n { resource: \"customers\", action: \"create\" },\n { resource: \"customers\", action: \"update\" },\n { resource: \"customers\", action: \"delete\" },\n\n { resource: \"coupons\", action: \"admin\" },\n { resource: \"coupons\", action: \"read\" },\n { resource: \"coupons\", action: \"create\" },\n { resource: \"coupons\", action: \"update\" },\n { resource: \"coupons\", action: \"delete\" },\n\n { resource: \"menu\", action: \"admin\" },\n { resource: \"menu\", action: \"read\" },\n { resource: \"menu\", action: \"create\" },\n { resource: \"menu\", action: \"update\" },\n { resource: \"menu\", action: \"delete\" },\n\n { resource: \"settings\", action: \"admin\" },\n { resource: \"settings\", action: \"read\" },\n { resource: \"settings\", action: \"update\" },\n\n { resource: \"profile\", action: \"admin\" },\n { resource: \"profile\", action: \"read\" },\n { resource: \"profile\", action: \"update\" },\n];\n\nexport const ROLE_PERMISSIONS: Record<string, string[]> = {\n super_admin: [\"*\"],\n\n admin: [\n \"users:admin\",\n \"users:read\",\n \"users:update\",\n \"audit_logs:read\",\n \"posts:admin\",\n \"posts:read\",\n \"posts:create\",\n \"posts:update\",\n \"posts:delete\",\n \"pages:admin\",\n \"pages:read\",\n \"pages:create\",\n \"pages:update\",\n \"pages:delete\",\n \"media:admin\",\n \"media:read\",\n \"media:create\",\n \"media:update\",\n \"media:delete\",\n \"categories:admin\",\n \"categories:read\",\n \"categories:create\",\n \"categories:update\",\n \"categories:delete\",\n \"products:admin\",\n \"products:read\",\n \"products:create\",\n \"products:update\",\n \"products:delete\",\n \"orders:admin\",\n \"orders:read\",\n \"orders:update\",\n \"customers:admin\",\n \"customers:read\",\n \"customers:update\",\n \"coupons:admin\",\n \"coupons:read\",\n \"coupons:create\",\n \"coupons:update\",\n \"coupons:delete\",\n \"navigation:admin\",\n \"navigation:read\",\n \"navigation:create\",\n \"navigation:update\",\n \"navigation:delete\",\n \"settings:admin\",\n \"settings:read\",\n \"settings:update\",\n \"profile:admin\",\n \"profile:read\",\n \"profile:update\",\n ],\n\n editor: [\n \"posts:admin\",\n \"posts:read\",\n \"posts:create\",\n \"posts:update\",\n \"posts:delete\",\n \"pages:admin\",\n \"pages:read\",\n \"pages:create\",\n \"pages:update\",\n \"pages:delete\",\n \"media:read\",\n \"media:create\",\n \"media:update\",\n \"categories:read\",\n \"categories:create\",\n \"categories:update\",\n \"products:read\",\n \"orders:read\",\n \"orders:update\",\n \"navigation:read\",\n \"navigation:create\",\n \"navigation:update\",\n \"profile:read\",\n \"profile:update\",\n ],\n\n author: [\n \"posts:read\",\n \"posts:create\",\n \"posts:update\",\n \"media:read\",\n \"media:create\",\n \"categories:read\",\n \"profile:read\",\n \"profile:update\",\n ],\n\n customer: [\"profile:read\", \"profile:update\", \"orders:read\", \"orders:create\"],\n\n guest: [\"posts:read\", \"pages:read\", \"products:read\"],\n};\n\nexport function getRoleHierarchy(\n role: string,\n roles: Role[] = DEFAULT_ROLES,\n): string[] {\n const hierarchy: string[] = [role];\n const roleMap = new Map(roles.map((r) => [r.name, r]));\n\n const addInherited = (r: string) => {\n const roleData = roleMap.get(r);\n if (roleData && roleData.inherits) {\n for (const inherited of roleData.inherits) {\n if (!hierarchy.includes(inherited)) {\n hierarchy.push(inherited);\n addInherited(inherited);\n }\n }\n }\n };\n\n addInherited(role);\n return hierarchy;\n}\n\nexport function getRoleLevel(\n role: string,\n roles: Role[] = DEFAULT_ROLES,\n): number {\n const roleMap = new Map(roles.map((r) => [r.name, r]));\n const roleData = roleMap.get(role);\n return roleData?.level ?? 0;\n}\n\nexport function isRoleHigherOrEqual(\n role1: string,\n role2: string,\n roles: Role[] = DEFAULT_ROLES,\n): boolean {\n return getRoleLevel(role1, roles) >= getRoleLevel(role2, roles);\n}\n\nexport function canInheritRole(\n role: string,\n targetRole: string,\n roles: Role[] = DEFAULT_ROLES,\n): boolean {\n const hierarchy = getRoleHierarchy(role, roles);\n return hierarchy.includes(targetRole);\n}\n","import type { AuthUser } from \"../types.js\";\nimport {\n ROLE_PERMISSIONS,\n getRoleHierarchy,\n type Permission,\n type Condition,\n} from \"./roles.js\";\n\nexport interface PermissionContext {\n user: AuthUser;\n resource?: string;\n action?: string;\n doc?: Record<string, any>;\n data?: Record<string, any>;\n tenantId?: string;\n}\n\nexport function hasPermission(\n user: AuthUser,\n permission: string,\n rolePermissions: Record<string, string[]> = ROLE_PERMISSIONS,\n): boolean {\n if (!user || !user.role) return false;\n\n const userPermissions = getUserPermissions(user, rolePermissions);\n\n if (userPermissions.includes(\"*\")) return true;\n if (userPermissions.includes(permission)) return true;\n\n const [resource, action] = permission.split(\":\");\n if (userPermissions.includes(`${resource}:*`)) return true;\n if (userPermissions.includes(`${resource}:admin`)) return true;\n\n return false;\n}\n\nexport function hasRole(\n user: AuthUser,\n role: string,\n roles: string[] = [],\n): boolean {\n if (!user || !user.role) return false;\n\n const hierarchy = getRoleHierarchy(user.role);\n return hierarchy.includes(role);\n}\n\nexport function hasAnyRole(user: AuthUser, checkRoles: string[]): boolean {\n if (!user || !user.role) return false;\n\n const hierarchy = getRoleHierarchy(user.role);\n return checkRoles.some((role) => hierarchy.includes(role));\n}\n\nexport function hasAllRoles(user: AuthUser, checkRoles: string[]): boolean {\n if (!user || !user.role) return false;\n\n const hierarchy = getRoleHierarchy(user.role);\n return checkRoles.every((role) => hierarchy.includes(role));\n}\n\nexport function getUserPermissions(\n user: AuthUser,\n rolePermissions: Record<string, string[]> = ROLE_PERMISSIONS,\n): string[] {\n if (!user || !user.role) return [];\n\n const hierarchy = getRoleHierarchy(user.role);\n const permissions = new Set<string>();\n\n for (const role of hierarchy) {\n const rolePerms = rolePermissions[role];\n if (rolePerms) {\n for (const perm of rolePerms) {\n permissions.add(perm);\n }\n }\n }\n\n return Array.from(permissions);\n}\n\nexport function getEffectivePermissions(\n user: AuthUser,\n rolePermissions: Record<string, string[]> = ROLE_PERMISSIONS,\n): string[] {\n return getUserPermissions(user, rolePermissions);\n}\n\nexport function canAccessResource(\n user: AuthUser,\n resource: string,\n action: string,\n rolePermissions: Record<string, string[]> = ROLE_PERMISSIONS,\n): boolean {\n return hasPermission(user, `${resource}:${action}`, rolePermissions);\n}\n\nexport function filterPermissions(\n permissions: string[],\n resource?: string,\n): string[] {\n if (!resource) return permissions;\n\n return permissions.filter((perm) => {\n const [permResource] = perm.split(\":\");\n return permResource === resource || permResource === \"*\";\n });\n}\n\nexport function parsePermission(permission: string): {\n resource: string;\n action: string;\n condition?: Condition;\n} {\n const [resource, action, ...rest] = permission.split(\":\");\n return {\n resource,\n action,\n condition: rest.length > 0 ? JSON.parse(rest.join(\":\")) : undefined,\n };\n}\n\nexport function buildPermission(\n resource: string,\n action: string,\n condition?: Condition,\n): string {\n if (condition) {\n return `${resource}:${action}:${JSON.stringify(condition)}`;\n }\n return `${resource}:${action}`;\n}\n\nexport function evaluateCondition(\n condition: Condition,\n context: Record<string, any>,\n): boolean {\n const { field, operator, value } = condition;\n const fieldValue = context[field];\n\n if (fieldValue === undefined) return false;\n\n switch (operator) {\n case \"eq\":\n return fieldValue === value;\n case \"neq\":\n return fieldValue !== value;\n case \"in\":\n return Array.isArray(value) && value.includes(fieldValue);\n case \"nin\":\n return Array.isArray(value) && !value.includes(fieldValue);\n case \"gt\":\n return fieldValue > value;\n case \"lt\":\n return fieldValue < value;\n case \"gte\":\n return fieldValue >= value;\n case \"lte\":\n return fieldValue <= value;\n case \"contains\":\n if (typeof fieldValue === \"string\") {\n return fieldValue.includes(value);\n }\n if (Array.isArray(fieldValue)) {\n return fieldValue.includes(value);\n }\n return false;\n default:\n return false;\n }\n}\n\nexport function evaluateConditions(\n conditions: Condition[],\n context: Record<string, any>,\n): boolean {\n if (!conditions || conditions.length === 0) return true;\n\n return conditions.every((condition) => evaluateCondition(condition, context));\n}\n\nexport function resolveConditionValue(\n value: any,\n context: Record<string, any>,\n): any {\n if (typeof value !== \"string\") return value;\n\n if (value.startsWith(\"${\") && value.endsWith(\"}\")) {\n const path = value.slice(2, -1);\n const keys = path.split(\".\");\n let resolved = context;\n\n for (const key of keys) {\n if (resolved === undefined || resolved === null) return undefined;\n resolved = resolved[key];\n }\n\n return resolved;\n }\n\n return value;\n}\n\nexport function evaluateConditionWithContext(\n condition: Condition,\n context: Record<string, any>,\n): boolean {\n const resolvedCondition = {\n ...condition,\n value: resolveConditionValue(condition.value, context),\n };\n\n return evaluateCondition(resolvedCondition, context);\n}\n\nexport class PermissionChecker {\n private rolePermissions: Record<string, string[]>;\n\n constructor(rolePermissions: Record<string, string[]> = ROLE_PERMISSIONS) {\n this.rolePermissions = rolePermissions;\n }\n\n check(user: AuthUser, permission: string): boolean {\n return hasPermission(user, permission, this.rolePermissions);\n }\n\n checkRole(user: AuthUser, role: string): boolean {\n return hasRole(user, role);\n }\n\n checkAnyRole(user: AuthUser, roles: string[]): boolean {\n return hasAnyRole(user, roles);\n }\n\n checkAllRoles(user: AuthUser, roles: string[]): boolean {\n return hasAllRoles(user, roles);\n }\n\n getPermissions(user: AuthUser): string[] {\n return getUserPermissions(user, this.rolePermissions);\n }\n\n canAccess(user: AuthUser, resource: string, action: string): boolean {\n return canAccessResource(user, resource, action, this.rolePermissions);\n }\n\n filterByResource(permissions: string[], resource: string): string[] {\n return filterPermissions(permissions, resource);\n }\n}\n"]}
@@ -1,8 +1,52 @@
1
- import { evaluateAccess } from './chunk-SDMNUYVU.js';
2
- import { GraphQLObjectType, GraphQLString, GraphQLInputObjectType, GraphQLInt, GraphQLBoolean, GraphQLList, GraphQLNonNull, GraphQLSchema, GraphQLFloat } from 'graphql';
1
+ import { hasApiKeyPermission, evaluateAccess } from './chunk-CJONKRHJ.js';
2
+ import { hasPermission } from './chunk-L4EZKIEX.js';
3
+ import { GraphQLObjectType, GraphQLString, GraphQLInputObjectType, GraphQLBoolean, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLSchema, GraphQLFloat } from 'graphql';
3
4
 
4
5
  async function checkGraphQLAccess(collection, operation, context) {
5
6
  const accessRule = collection.access?.[operation];
7
+ if (context.apiKey?.permissions?.length > 0) {
8
+ const resource = collection.slug;
9
+ const action = operation === "read" ? "read" : operation === "create" ? "create" : "update";
10
+ const permission = `${resource}:${action}`;
11
+ if (!hasApiKeyPermission(context.apiKey.permissions, permission) && !hasApiKeyPermission(context.apiKey.permissions, `${resource}:admin`)) {
12
+ return { allowed: false };
13
+ }
14
+ }
15
+ if (context.user) {
16
+ const resource = collection.slug;
17
+ const action = operation === "read" ? "read" : operation === "create" ? "create" : operation === "update" ? "update" : "delete";
18
+ const permission = `${resource}:${action}`;
19
+ const userHasPermission = hasPermission(
20
+ { id: context.user.id, email: context.user.email, role: context.user.role },
21
+ permission
22
+ );
23
+ if (!userHasPermission && !hasPermission(
24
+ { id: context.user.id, email: context.user.email, role: context.user.role },
25
+ `${resource}:admin`
26
+ )) {
27
+ if (!accessRule) {
28
+ return { allowed: false };
29
+ }
30
+ }
31
+ }
32
+ if (!accessRule) {
33
+ if (!context.user && !context.apiKey) {
34
+ return { allowed: false };
35
+ }
36
+ return { allowed: true };
37
+ }
38
+ const result = await evaluateAccess(accessRule, {
39
+ req: context.req,
40
+ user: context.user,
41
+ tenantID: context.tenantID
42
+ });
43
+ if (typeof result === "boolean") {
44
+ return { allowed: result };
45
+ }
46
+ return { allowed: true, extraWhere: result };
47
+ }
48
+ async function checkGlobalAccess(global, operation, context) {
49
+ const accessRule = global.access?.[operation];
6
50
  if (!accessRule) {
7
51
  if (!context.user) {
8
52
  return { allowed: false };
@@ -21,9 +65,9 @@ async function checkGraphQLAccess(collection, operation, context) {
21
65
  if (typeof result === "boolean") {
22
66
  return { allowed: result };
23
67
  }
24
- return { allowed: true, extraWhere: result };
68
+ return { allowed: true };
25
69
  }
26
- function fieldToGraphQLType(field, registry) {
70
+ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = false) {
27
71
  switch (field.type) {
28
72
  case "text":
29
73
  case "email":
@@ -47,13 +91,19 @@ function fieldToGraphQLType(field, registry) {
47
91
  // JSON as string
48
92
  case "relationship":
49
93
  if (typeof field.relationTo === "string") {
94
+ if (isInputType) {
95
+ return GraphQLString;
96
+ }
97
+ if (collectionTypes?.[field.relationTo]) {
98
+ return collectionTypes[field.relationTo];
99
+ }
50
100
  const relatedCollection = registry.getCollection(field.relationTo);
51
101
  if (relatedCollection) {
52
102
  return new GraphQLObjectType({
53
103
  name: `${field.relationTo}_ref`,
54
104
  fields: () => ({
55
105
  id: { type: GraphQLString },
56
- ...buildFieldsFromCollection(relatedCollection, registry)
106
+ ...buildFieldsFromCollection(relatedCollection, registry, collectionTypes)
57
107
  })
58
108
  });
59
109
  }
@@ -76,12 +126,12 @@ function fieldToGraphQLType(field, registry) {
76
126
  return GraphQLString;
77
127
  }
78
128
  }
79
- function buildFieldsFromCollection(config, registry) {
129
+ function buildFieldsFromCollection(config, registry, collectionTypes) {
80
130
  const fields = {};
81
131
  for (const field of config.fields) {
82
132
  if (field.name && field.admin?.hidden !== true) {
83
133
  fields[field.name] = {
84
- type: field.required ? new GraphQLNonNull(fieldToGraphQLType(field, registry)) : fieldToGraphQLType(field, registry),
134
+ type: field.required ? new GraphQLNonNull(fieldToGraphQLType(field, registry, collectionTypes)) : fieldToGraphQLType(field, registry, collectionTypes),
85
135
  description: field.admin?.description || field.label
86
136
  };
87
137
  }
@@ -89,7 +139,7 @@ function buildFieldsFromCollection(config, registry) {
89
139
  return fields;
90
140
  }
91
141
  function buildGraphQLSchema(options) {
92
- const { registry, db, user, req, tenantID, settings } = options;
142
+ const { registry, db, user, req, tenantID, apiKey, settings } = options;
93
143
  const apiAccess = settings?.access?.apiAccess;
94
144
  if (apiAccess?.graphqlEnabled === false) {
95
145
  throw new Error("GraphQL API is disabled");
@@ -103,7 +153,7 @@ function buildGraphQLSchema(options) {
103
153
  name: `${collection.slug.replace(/-/g, "_")}_type`,
104
154
  fields: () => ({
105
155
  id: { type: GraphQLString },
106
- ...buildFieldsFromCollection(collection, registry),
156
+ ...buildFieldsFromCollection(collection, registry, collectionTypes),
107
157
  ...collection.timestamps ? {
108
158
  createdAt: { type: GraphQLString },
109
159
  updatedAt: { type: GraphQLString }
@@ -117,7 +167,7 @@ function buildGraphQLSchema(options) {
117
167
  for (const field of collection.fields) {
118
168
  if (field.name && field.name !== "id") {
119
169
  inputFields[field.name] = {
120
- type: fieldToGraphQLType(field, registry)
170
+ type: fieldToGraphQLType(field, registry, collectionTypes, true)
121
171
  };
122
172
  }
123
173
  }
@@ -127,6 +177,7 @@ function buildGraphQLSchema(options) {
127
177
  });
128
178
  }
129
179
  const globalTypes = {};
180
+ const globalInputTypes = {};
130
181
  for (const global of globals) {
131
182
  globalTypes[global.slug] = new GraphQLObjectType({
132
183
  name: `${global.slug.replace(/-/g, "_")}_global_type`,
@@ -134,16 +185,31 @@ function buildGraphQLSchema(options) {
134
185
  id: { type: GraphQLString },
135
186
  ...buildFieldsFromCollection(
136
187
  { slug: global.slug, fields: global.fields },
137
- registry
188
+ registry,
189
+ collectionTypes
138
190
  )
139
191
  })
140
192
  });
193
+ globalInputTypes[global.slug] = new GraphQLInputObjectType({
194
+ name: `${global.slug.replace(/-/g, "_")}_global_input`,
195
+ fields: () => {
196
+ const inputFields = {};
197
+ for (const field of global.fields) {
198
+ if (field.name && field.name !== "id") {
199
+ inputFields[field.name] = {
200
+ type: fieldToGraphQLType(field, registry, collectionTypes, true)
201
+ };
202
+ }
203
+ }
204
+ return inputFields;
205
+ }
206
+ });
141
207
  }
142
208
  const queryFields = {};
143
209
  for (const collection of collections) {
144
210
  const type = collectionTypes[collection.slug];
145
211
  if (!type) continue;
146
- queryFields[`${collection.slug}Find`] = {
212
+ queryFields[`${collection.slug.replace(/-/g, "_")}Find`] = {
147
213
  type: new GraphQLObjectType({
148
214
  name: `${collection.slug.replace(/-/g, "_")}_find_result`,
149
215
  fields: {
@@ -159,17 +225,22 @@ function buildGraphQLSchema(options) {
159
225
  where: { type: GraphQLString },
160
226
  sort: { type: GraphQLString },
161
227
  limit: { type: GraphQLInt },
162
- page: { type: GraphQLInt }
228
+ page: { type: GraphQLInt },
229
+ draft: { type: GraphQLBoolean }
163
230
  },
164
231
  resolve: async (_, args, context) => {
165
232
  const access = await checkGraphQLAccess(collection, "read", {
166
233
  user,
167
234
  req,
168
- tenantID
235
+ tenantID,
236
+ apiKey
169
237
  });
170
238
  if (!access.allowed) {
171
239
  throw new Error("Access denied");
172
240
  }
241
+ if (tenantID) {
242
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
243
+ }
173
244
  let where = {};
174
245
  if (args.where) {
175
246
  try {
@@ -180,39 +251,48 @@ function buildGraphQLSchema(options) {
180
251
  if (access.extraWhere) {
181
252
  where = { ...where, ...access.extraWhere };
182
253
  }
254
+ const isDraft = args.draft ?? !!user;
183
255
  return db.find({
184
256
  collection: collection.slug,
185
257
  where,
186
258
  sort: args.sort,
187
259
  limit: args.limit || 10,
188
260
  page: args.page || 1,
189
- tenantID
261
+ tenantID,
262
+ draft: isDraft
190
263
  });
191
264
  }
192
265
  };
193
- queryFields[`${collection.slug}FindByID`] = {
266
+ queryFields[`${collection.slug.replace(/-/g, "_")}FindByID`] = {
194
267
  type,
195
268
  args: {
196
- id: { type: new GraphQLNonNull(GraphQLString) }
269
+ id: { type: new GraphQLNonNull(GraphQLString) },
270
+ draft: { type: GraphQLBoolean }
197
271
  },
198
272
  resolve: async (_, args, context) => {
199
273
  const access = await checkGraphQLAccess(collection, "read", {
200
274
  user,
201
275
  req,
202
- tenantID
276
+ tenantID,
277
+ apiKey
203
278
  });
204
279
  if (!access.allowed) {
205
280
  throw new Error("Access denied");
206
281
  }
282
+ if (tenantID) {
283
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
284
+ }
285
+ const isDraft = args.draft ?? !!user;
207
286
  const doc = await db.findByID({
208
287
  collection: collection.slug,
209
288
  id: args.id,
210
- tenantID
289
+ tenantID,
290
+ draft: isDraft
211
291
  });
212
292
  return doc;
213
293
  }
214
294
  };
215
- queryFields[`${collection.slug}Count`] = {
295
+ queryFields[`${collection.slug.replace(/-/g, "_")}Count`] = {
216
296
  type: new GraphQLObjectType({
217
297
  name: `${collection.slug.replace(/-/g, "_")}_count`,
218
298
  fields: {
@@ -226,7 +306,8 @@ function buildGraphQLSchema(options) {
226
306
  const access = await checkGraphQLAccess(collection, "read", {
227
307
  user,
228
308
  req,
229
- tenantID
309
+ tenantID,
310
+ apiKey
230
311
  });
231
312
  if (!access.allowed) {
232
313
  return { totalDocs: 0 };
@@ -250,9 +331,20 @@ function buildGraphQLSchema(options) {
250
331
  for (const global of globals) {
251
332
  const type = globalTypes[global.slug];
252
333
  if (!type) continue;
253
- queryFields[`${global.slug}Get`] = {
334
+ queryFields[`${global.slug.replace(/-/g, "_")}Get`] = {
254
335
  type,
255
336
  resolve: async () => {
337
+ const access = await checkGlobalAccess(global, "read", {
338
+ user,
339
+ req,
340
+ tenantID
341
+ });
342
+ if (!access.allowed) {
343
+ throw new Error("Access denied: cannot read global");
344
+ }
345
+ if (tenantID) {
346
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
347
+ }
256
348
  return db.findOne({
257
349
  collection: `_globals_${global.slug}`,
258
350
  where: {},
@@ -270,7 +362,7 @@ function buildGraphQLSchema(options) {
270
362
  const type = collectionTypes[collection.slug];
271
363
  const inputType = collectionInputTypes[collection.slug];
272
364
  if (!type || !inputType) continue;
273
- mutationFields[`${collection.slug}Create`] = {
365
+ mutationFields[`${collection.slug.replace(/-/g, "_")}Create`] = {
274
366
  type: new GraphQLObjectType({
275
367
  name: `${collection.slug.replace(/-/g, "_")}_create_result`,
276
368
  fields: {
@@ -285,11 +377,15 @@ function buildGraphQLSchema(options) {
285
377
  const access = await checkGraphQLAccess(collection, "create", {
286
378
  user,
287
379
  req,
288
- tenantID
380
+ tenantID,
381
+ apiKey
289
382
  });
290
383
  if (!access.allowed) {
291
384
  throw new Error("Access denied: cannot create");
292
385
  }
386
+ if (tenantID) {
387
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
388
+ }
293
389
  const schema = registry.getCreateZodSchema(collection.slug);
294
390
  const validated = schema.parse(args.data);
295
391
  const doc = await db.create({
@@ -300,7 +396,7 @@ function buildGraphQLSchema(options) {
300
396
  return { doc, message: "Created successfully" };
301
397
  }
302
398
  };
303
- mutationFields[`${collection.slug}Update`] = {
399
+ mutationFields[`${collection.slug.replace(/-/g, "_")}Update`] = {
304
400
  type: new GraphQLObjectType({
305
401
  name: `${collection.slug.replace(/-/g, "_")}_update_result`,
306
402
  fields: {
@@ -310,17 +406,33 @@ function buildGraphQLSchema(options) {
310
406
  }),
311
407
  args: {
312
408
  id: { type: new GraphQLNonNull(GraphQLString) },
313
- data: { type: new GraphQLNonNull(inputType) }
409
+ data: { type: new GraphQLNonNull(inputType) },
410
+ baseUpdatedAt: { type: GraphQLString }
314
411
  },
315
412
  resolve: async (_, args, context) => {
316
413
  const access = await checkGraphQLAccess(collection, "update", {
317
414
  user,
318
415
  req,
319
- tenantID
416
+ tenantID,
417
+ apiKey
320
418
  });
321
419
  if (!access.allowed) {
322
420
  throw new Error("Access denied: cannot update");
323
421
  }
422
+ if (tenantID) {
423
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
424
+ }
425
+ if (args.baseUpdatedAt) {
426
+ const originalDoc = await db.findByID({
427
+ collection: collection.slug,
428
+ id: args.id,
429
+ tenantID,
430
+ draft: true
431
+ });
432
+ if (originalDoc && originalDoc.updatedAt && args.baseUpdatedAt !== originalDoc.updatedAt) {
433
+ throw new Error(`Revision conflict: document has changed since ${args.baseUpdatedAt}. Current updatedAt: ${originalDoc.updatedAt}`);
434
+ }
435
+ }
324
436
  const schema = registry.getUpdateZodSchema(collection.slug);
325
437
  const validated = schema.parse(args.data);
326
438
  const doc = await db.update({
@@ -332,7 +444,7 @@ function buildGraphQLSchema(options) {
332
444
  return { doc, message: "Updated successfully" };
333
445
  }
334
446
  };
335
- mutationFields[`${collection.slug}Delete`] = {
447
+ mutationFields[`${collection.slug.replace(/-/g, "_")}Delete`] = {
336
448
  type: new GraphQLObjectType({
337
449
  name: `${collection.slug.replace(/-/g, "_")}_delete_result`,
338
450
  fields: {
@@ -347,11 +459,15 @@ function buildGraphQLSchema(options) {
347
459
  const access = await checkGraphQLAccess(collection, "delete", {
348
460
  user,
349
461
  req,
350
- tenantID
462
+ tenantID,
463
+ apiKey
351
464
  });
352
465
  if (!access.allowed) {
353
466
  throw new Error("Access denied: cannot delete");
354
467
  }
468
+ if (tenantID) {
469
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
470
+ }
355
471
  const doc = await db.delete({
356
472
  collection: collection.slug,
357
473
  id: args.id,
@@ -361,6 +477,56 @@ function buildGraphQLSchema(options) {
361
477
  }
362
478
  };
363
479
  }
480
+ for (const global of globals) {
481
+ const inputType = globalInputTypes[global.slug];
482
+ if (!inputType) continue;
483
+ mutationFields[`${global.slug.replace(/-/g, "_")}Update`] = {
484
+ type: new GraphQLObjectType({
485
+ name: `${global.slug.replace(/-/g, "_")}_update_result`,
486
+ fields: {
487
+ doc: { type: globalTypes[global.slug] || GraphQLString },
488
+ message: { type: GraphQLString }
489
+ }
490
+ }),
491
+ args: {
492
+ data: { type: new GraphQLNonNull(inputType) }
493
+ },
494
+ resolve: async (_, args, context) => {
495
+ const access = await checkGlobalAccess(global, "update", {
496
+ user,
497
+ req,
498
+ tenantID
499
+ });
500
+ if (!access.allowed) {
501
+ throw new Error("Access denied: cannot update global");
502
+ }
503
+ if (tenantID) {
504
+ db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
505
+ }
506
+ const doc = await db.findOne({
507
+ collection: `_globals_${global.slug}`,
508
+ where: {},
509
+ tenantID
510
+ });
511
+ let result;
512
+ if (doc) {
513
+ result = await db.update({
514
+ collection: `_globals_${global.slug}`,
515
+ id: doc.id,
516
+ data: args.data,
517
+ tenantID
518
+ });
519
+ } else {
520
+ result = await db.create({
521
+ collection: `_globals_${global.slug}`,
522
+ data: args.data,
523
+ tenantID
524
+ });
525
+ }
526
+ return { doc: result, message: "Updated successfully" };
527
+ }
528
+ };
529
+ }
364
530
  const Mutation = new GraphQLObjectType({
365
531
  name: "Mutation",
366
532
  fields: mutationFields
@@ -376,10 +542,11 @@ function createGraphQLSchema(registry, db, options) {
376
542
  db,
377
543
  user: options?.user,
378
544
  req: options?.req,
379
- tenantID: options?.tenantID
545
+ tenantID: options?.tenantID,
546
+ apiKey: options?.apiKey
380
547
  });
381
548
  }
382
549
 
383
550
  export { buildGraphQLSchema, createGraphQLSchema };
384
- //# sourceMappingURL=chunk-REK7AYOC.js.map
385
- //# sourceMappingURL=chunk-REK7AYOC.js.map
551
+ //# sourceMappingURL=chunk-L5UKKZQN.js.map
552
+ //# sourceMappingURL=chunk-L5UKKZQN.js.map