@kyro-cms/core 0.8.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,162 @@
1
+ import { timingSafeEqual } from 'crypto';
2
+
3
+ // src/access/types.ts
4
+ async function evaluateAccess(access, args) {
5
+ if (typeof access === "boolean") {
6
+ return access;
7
+ }
8
+ if (typeof access === "function") {
9
+ return await access(args);
10
+ }
11
+ return true;
12
+ }
13
+ function mergeWhereClauses(...whereClauses) {
14
+ const result = {};
15
+ for (const clause of whereClauses) {
16
+ if (clause && typeof clause === "object") {
17
+ Object.assign(result, clause);
18
+ }
19
+ }
20
+ return result;
21
+ }
22
+ function getWhereClause(access, args) {
23
+ return evaluateAccess(access, args).then((result) => {
24
+ if (result === true) return void 0;
25
+ if (result === false) return { _id: { $eq: null } };
26
+ return result;
27
+ });
28
+ }
29
+ var API_KEY_COLLECTION = "_api_keys";
30
+ function generateKeyPrefix(key) {
31
+ return key.substring(0, 8);
32
+ }
33
+ function constantTimeCompare(a, b) {
34
+ if (a.length !== b.length) {
35
+ return false;
36
+ }
37
+ try {
38
+ return timingSafeEqual(Buffer.from(a), Buffer.from(b));
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ async function validateApiKey(rawKey, db, userLookup) {
44
+ if (!rawKey || typeof rawKey !== "string") {
45
+ return { valid: false, error: "No API key provided" };
46
+ }
47
+ if (!rawKey.startsWith("kyro_")) {
48
+ return { valid: false, error: "Invalid API key format" };
49
+ }
50
+ const keyPrefix = generateKeyPrefix(rawKey);
51
+ try {
52
+ const result = await db.find({
53
+ collection: API_KEY_COLLECTION,
54
+ where: { keyPrefix: { equals: keyPrefix } },
55
+ limit: 100,
56
+ page: 1
57
+ });
58
+ if (!result.docs || result.docs.length === 0) {
59
+ return { valid: false, error: "Invalid API key" };
60
+ }
61
+ let matchedKey = null;
62
+ for (const doc of result.docs) {
63
+ const record = doc;
64
+ if (constantTimeCompare(record.key, rawKey)) {
65
+ matchedKey = record;
66
+ break;
67
+ }
68
+ }
69
+ if (!matchedKey) {
70
+ return { valid: false, error: "Invalid API key" };
71
+ }
72
+ if (matchedKey.expiresAt) {
73
+ const expiresAt = new Date(matchedKey.expiresAt);
74
+ if (expiresAt < /* @__PURE__ */ new Date()) {
75
+ return { valid: false, error: "API key has expired" };
76
+ }
77
+ }
78
+ try {
79
+ await db.update({
80
+ collection: API_KEY_COLLECTION,
81
+ id: matchedKey.id,
82
+ data: { lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }
83
+ });
84
+ } catch {
85
+ }
86
+ const user = {
87
+ id: matchedKey.userId,
88
+ role: matchedKey.role || "author",
89
+ tenantId: matchedKey.tenantId
90
+ };
91
+ if (userLookup) {
92
+ const dbUser = await userLookup(matchedKey.userId);
93
+ if (dbUser) {
94
+ Object.assign(user, dbUser);
95
+ }
96
+ }
97
+ return {
98
+ valid: true,
99
+ userId: matchedKey.userId,
100
+ user,
101
+ permissions: matchedKey.permissions || [],
102
+ apiKeyId: matchedKey.id,
103
+ tenantId: user.tenantId,
104
+ role: user.role
105
+ };
106
+ } catch (error) {
107
+ console.error("[ApiKey] Validation error:", error);
108
+ return { valid: false, error: "Failed to validate API key" };
109
+ }
110
+ }
111
+ function extractApiKeyFromRequest(request) {
112
+ const authHeader = request.headers.get("Authorization");
113
+ if (authHeader) {
114
+ if (authHeader.startsWith("ApiKey ")) {
115
+ return authHeader.slice(7).trim();
116
+ }
117
+ if (authHeader.startsWith("Bearer ")) {
118
+ return null;
119
+ }
120
+ }
121
+ const xApiKey = request.headers.get("X-API-Key");
122
+ if (xApiKey) {
123
+ return xApiKey.trim();
124
+ }
125
+ return null;
126
+ }
127
+ function createApiKeyContext(result) {
128
+ if (!result.valid || !result.userId) {
129
+ return null;
130
+ }
131
+ return {
132
+ userId: result.userId,
133
+ user: result.user || {},
134
+ permissions: result.permissions || [],
135
+ apiKeyId: result.apiKeyId || "",
136
+ tenantId: result.tenantId,
137
+ role: result.role
138
+ };
139
+ }
140
+ function hasApiKeyPermission(permissions, required) {
141
+ if (permissions.length === 0) return false;
142
+ if (permissions.includes("*")) return true;
143
+ if (permissions.includes(required)) return true;
144
+ const [resource, action] = required.split(":");
145
+ if (permissions.includes(`${resource}:*`)) return true;
146
+ return false;
147
+ }
148
+ function generateApiKey() {
149
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
150
+ let suffix = "";
151
+ for (let i = 0; i < 32; i++) {
152
+ suffix += chars[Math.floor(Math.random() * chars.length)];
153
+ }
154
+ return `kyro_${suffix}`;
155
+ }
156
+ function generateApiKeyPrefix(key) {
157
+ return key.substring(0, 8);
158
+ }
159
+
160
+ export { API_KEY_COLLECTION, createApiKeyContext, evaluateAccess, extractApiKeyFromRequest, generateApiKey, generateApiKeyPrefix, getWhereClause, hasApiKeyPermission, mergeWhereClauses, validateApiKey };
161
+ //# sourceMappingURL=chunk-CJONKRHJ.js.map
162
+ //# sourceMappingURL=chunk-CJONKRHJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/access/types.ts","../src/auth/api-key.ts"],"names":[],"mappings":"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","file":"chunk-CJONKRHJ.js","sourcesContent":["import type { User, Request } from '../hooks/types.js';\n\n// ============================================================================\n// Access Control Types\n// ============================================================================\n\nexport interface WhereClause {\n [field: string]: any;\n}\n\nexport interface AccessArgs {\n req: Request;\n user?: User;\n data?: any;\n doc?: any;\n id?: string;\n tenantID?: string;\n context?: Record<string, any>;\n}\n\nexport type AccessControl = boolean | ((args: AccessArgs) => Promise<boolean | WhereClause> | boolean | WhereClause);\n\nexport interface CollectionAccess {\n create?: AccessControl;\n read?: AccessControl;\n update?: AccessControl;\n delete?: AccessControl;\n admin?: AccessControl;\n unlock?: AccessControl;\n readVersions?: AccessControl;\n}\n\nexport interface GlobalAccess {\n read?: AccessControl;\n update?: AccessControl;\n}\n\nexport interface FieldAccess {\n create?: AccessControl;\n read?: AccessControl;\n update?: AccessControl;\n}\n\n// ============================================================================\n// Access Control Evaluation\n// ============================================================================\n\nexport async function evaluateAccess(\n access: AccessControl,\n args: AccessArgs\n): Promise<boolean | WhereClause> {\n if (typeof access === 'boolean') {\n return access;\n }\n if (typeof access === 'function') {\n return await access(args);\n }\n return true;\n}\n\nexport function mergeWhereClauses(\n ...whereClauses: (WhereClause | boolean | undefined)[]\n): WhereClause {\n const result: WhereClause = {};\n for (const clause of whereClauses) {\n if (clause && typeof clause === 'object') {\n Object.assign(result, clause);\n }\n }\n return result;\n}\n\nexport function getWhereClause(\n access: AccessControl,\n args: AccessArgs\n): Promise<WhereClause | undefined> {\n return evaluateAccess(access, args).then(result => {\n if (result === true) return undefined;\n if (result === false) return { _id: { $eq: null } };\n return result;\n });\n}\n","import { timingSafeEqual } from \"crypto\";\nimport type { BaseAdapter } from \"../registry/types.js\";\nimport type { AuthUser, UserRole } from \"./types.js\";\n\nexport interface ApiKeyRecord {\n id: string;\n userId: string;\n name: string;\n key: string;\n keyPrefix: string;\n permissions: string[];\n lastUsedAt?: string;\n expiresAt?: string;\n createdAt: string;\n}\n\nexport interface ApiKeyValidationResult {\n valid: boolean;\n userId?: string;\n user?: Partial<AuthUser>;\n permissions?: string[];\n apiKeyId?: string;\n error?: string;\n tenantId?: string;\n role?: UserRole;\n}\n\nexport interface ApiKeyContext {\n userId: string;\n user: Partial<AuthUser>;\n permissions: string[];\n apiKeyId: string;\n tenantId?: string;\n role?: UserRole;\n}\n\nexport const API_KEY_COLLECTION = \"_api_keys\";\n\nfunction generateKeyPrefix(key: string): string {\n return key.substring(0, 8);\n}\n\nfunction constantTimeCompare(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n try {\n return timingSafeEqual(Buffer.from(a), Buffer.from(b));\n } catch {\n return false;\n }\n}\n\nexport async function validateApiKey(\n rawKey: string,\n db: BaseAdapter,\n userLookup?: (userId: string) => Promise<Partial<AuthUser> | null>,\n): Promise<ApiKeyValidationResult> {\n if (!rawKey || typeof rawKey !== \"string\") {\n return { valid: false, error: \"No API key provided\" };\n }\n\n if (!rawKey.startsWith(\"kyro_\")) {\n return { valid: false, error: \"Invalid API key format\" };\n }\n\n const keyPrefix = generateKeyPrefix(rawKey);\n\n try {\n const result = await db.find({\n collection: API_KEY_COLLECTION,\n where: { keyPrefix: { equals: keyPrefix } },\n limit: 100,\n page: 1,\n });\n\n if (!result.docs || result.docs.length === 0) {\n return { valid: false, error: \"Invalid API key\" };\n }\n\n let matchedKey: ApiKeyRecord | null = null;\n for (const doc of result.docs) {\n const record = doc as unknown as ApiKeyRecord;\n if (constantTimeCompare(record.key, rawKey)) {\n matchedKey = record;\n break;\n }\n }\n\n if (!matchedKey) {\n return { valid: false, error: \"Invalid API key\" };\n }\n\n if (matchedKey.expiresAt) {\n const expiresAt = new Date(matchedKey.expiresAt);\n if (expiresAt < new Date()) {\n return { valid: false, error: \"API key has expired\" };\n }\n }\n\n try {\n await db.update({\n collection: API_KEY_COLLECTION,\n id: matchedKey.id,\n data: { lastUsedAt: new Date().toISOString() },\n });\n } catch {\n // Non-critical: don't fail if lastUsedAt update fails\n }\n\n const user: Partial<AuthUser> = {\n id: matchedKey.userId,\n role: (matchedKey as any).role || \"author\",\n tenantId: (matchedKey as any).tenantId,\n };\n\n if (userLookup) {\n const dbUser = await userLookup(matchedKey.userId);\n if (dbUser) {\n Object.assign(user, dbUser);\n }\n }\n\n return {\n valid: true,\n userId: matchedKey.userId,\n user,\n permissions: matchedKey.permissions || [],\n apiKeyId: matchedKey.id,\n tenantId: user.tenantId,\n role: user.role,\n };\n } catch (error) {\n console.error(\"[ApiKey] Validation error:\", error);\n return { valid: false, error: \"Failed to validate API key\" };\n }\n}\n\nexport function extractApiKeyFromRequest(request: Request): string | null {\n const authHeader = request.headers.get(\"Authorization\");\n if (authHeader) {\n if (authHeader.startsWith(\"ApiKey \")) {\n return authHeader.slice(7).trim();\n }\n if (authHeader.startsWith(\"Bearer \")) {\n return null;\n }\n }\n\n const xApiKey = request.headers.get(\"X-API-Key\");\n if (xApiKey) {\n return xApiKey.trim();\n }\n\n return null;\n}\n\nexport function createApiKeyContext(\n result: ApiKeyValidationResult,\n): ApiKeyContext | null {\n if (!result.valid || !result.userId) {\n return null;\n }\n return {\n userId: result.userId,\n user: result.user || {},\n permissions: result.permissions || [],\n apiKeyId: result.apiKeyId || \"\",\n tenantId: result.tenantId,\n role: result.role,\n };\n}\n\nexport function hasApiKeyPermission(\n permissions: string[],\n required: string,\n): boolean {\n if (permissions.length === 0) return false;\n if (permissions.includes(\"*\")) return true;\n if (permissions.includes(required)) return true;\n\n const [resource, action] = required.split(\":\");\n if (permissions.includes(`${resource}:*`)) return true;\n\n return false;\n}\n\nexport function generateApiKey(): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let suffix = \"\";\n for (let i = 0; i < 32; i++) {\n suffix += chars[Math.floor(Math.random() * chars.length)];\n }\n return `kyro_${suffix}`;\n}\n\nexport function generateApiKeyPrefix(key: string): string {\n return key.substring(0, 8);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSA7NSSIQ_cjs = require('./chunk-SA7NSSIQ.cjs');
3
+ var chunkPI73NNOK_cjs = require('./chunk-PI73NNOK.cjs');
4
4
  var drizzleOrm = require('drizzle-orm');
5
5
  var pgCore = require('drizzle-orm/pg-core');
6
6
  var sqliteCore = require('drizzle-orm/sqlite-core');
@@ -22,11 +22,13 @@ function fieldToDrizzleType(field, dialect = "postgres") {
22
22
  case "text":
23
23
  case "email":
24
24
  case "password":
25
- case "textarea":
26
25
  case "color":
26
+ return dialect === "sqlite" ? "text" : "varchar";
27
+ case "textarea":
27
28
  case "code":
28
29
  case "markdown":
29
- return dialect === "sqlite" ? "text" : "varchar";
30
+ case "secret":
31
+ return "text";
30
32
  case "number":
31
33
  return field.integer ? "integer" : "decimal";
32
34
  case "checkbox":
@@ -48,7 +50,7 @@ function fieldToDrizzleType(field, dialect = "postgres") {
48
50
  case "relationship":
49
51
  return dialect === "sqlite" ? "text" : "varchar";
50
52
  case "upload":
51
- return dialect === "sqlite" ? "text" : "varchar";
53
+ return "jsonb";
52
54
  default:
53
55
  return "jsonb";
54
56
  }
@@ -81,25 +83,18 @@ function collectionToDrizzleSchema(collection, dialect = "postgres") {
81
83
  lines.push(` createdAt: pg.timestamp('created_at').defaultNow(),`);
82
84
  lines.push(` updatedAt: pg.timestamp('updated_at').defaultNow(),`);
83
85
  }
84
- lines.push(` _status: ${dialect === "sqlite" ? "sqlite" : "pg"}.varchar('_status').default('published'),`);
85
- lines.push(` _has_draft: ${dialect === "sqlite" ? "sqlite" : "pg"}.boolean('_has_draft').default(false),`);
86
+ lines.push(` publishStatus: ${dialect === "sqlite" ? "sqlite" : "pg"}.varchar('publishStatus').default('draft'),`);
87
+ lines.push(` hasDraft: ${dialect === "sqlite" ? "sqlite" : "pg"}.boolean('hasDraft').default(false),`);
86
88
  lines.push("});");
87
89
  return lines.join("\n");
88
90
  }
89
- var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
91
+ var DrizzleAdapter = class extends chunkPI73NNOK_cjs.AbstractBaseAdapter {
90
92
  client;
91
93
  schema;
92
94
  dialect;
93
95
  connectionString;
94
96
  draftsTableReady = false;
95
97
  versionsTableReady = false;
96
- tenantContext;
97
- setTenantContext(context) {
98
- this.tenantContext = context;
99
- }
100
- getTenantContext() {
101
- return this.tenantContext;
102
- }
103
98
  constructor(options) {
104
99
  super();
105
100
  this.schema = options.schema || {};
@@ -126,6 +121,14 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
126
121
  if (result.updatedAt && typeof result.updatedAt === "string") {
127
122
  result.updatedAt = new Date(result.updatedAt);
128
123
  }
124
+ for (const field of config.fields) {
125
+ if (field.type === "date" && field.name) {
126
+ const value = result[field.name];
127
+ if (value && typeof value === "string") {
128
+ result[field.name] = new Date(value);
129
+ }
130
+ }
131
+ }
129
132
  for (const field of config.fields) {
130
133
  const dbType = fieldToDrizzleType(field, this.dialect);
131
134
  const isJsonb = dbType === "jsonb";
@@ -154,6 +157,14 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
154
157
  }
155
158
  }
156
159
  }
160
+ for (const field of config.fields) {
161
+ if (field.name && result[field.name] === "") {
162
+ const dbType = fieldToDrizzleType(field, this.dialect);
163
+ if (dbType === "timestamp" || dbType === "jsonb" || dbType === "decimal" || dbType === "integer" || dbType === "numeric" || dbType === "boolean") {
164
+ result[field.name] = null;
165
+ }
166
+ }
167
+ }
157
168
  return result;
158
169
  }
159
170
  async connect() {
@@ -270,8 +281,8 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
270
281
  }
271
282
  if (!columns.createdAt) columns.createdAt = this.dialect === "sqlite" ? sqliteCore.text("created_at").default((/* @__PURE__ */ new Date()).toISOString()) : pgCore.timestamp("created_at").defaultNow();
272
283
  if (!columns.updatedAt) columns.updatedAt = this.dialect === "sqlite" ? sqliteCore.text("updated_at").default((/* @__PURE__ */ new Date()).toISOString()) : pgCore.timestamp("updated_at").defaultNow();
273
- columns._status = this.dialect === "sqlite" ? sqliteCore.text("_status").default("published") : pgCore.varchar("_status", { length: 20 }).default("published");
274
- columns._has_draft = this.dialect === "sqlite" ? sqliteCore.integer("_has_draft", { mode: "boolean" }).default(false) : pgCore.boolean("_has_draft").default(false);
284
+ columns.publishStatus = this.dialect === "sqlite" ? sqliteCore.text("publishStatus").default("draft") : pgCore.varchar("publishStatus", { length: 20 }).default("draft");
285
+ columns.hasDraft = this.dialect === "sqlite" ? sqliteCore.integer("hasDraft", { mode: "boolean" }).default(false) : pgCore.boolean("hasDraft").default(false);
275
286
  return this.dialect === "sqlite" ? sqliteCore.sqliteTable(tableName, columns) : pgCore.pgTable(tableName, columns);
276
287
  }
277
288
  async ensureCollectionTables(collections) {
@@ -290,8 +301,8 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
290
301
  ${colDefs}
291
302
  ${hasCreated ? "" : '"created_at" TIMESTAMP NOT NULL DEFAULT NOW(),'}
292
303
  ${hasUpdated ? "" : '"updated_at" TIMESTAMP NOT NULL DEFAULT NOW(),'}
293
- "_status" VARCHAR(20) DEFAULT 'published',
294
- "_has_draft" BOOLEAN DEFAULT false
304
+ "publishStatus" VARCHAR(20) DEFAULT 'draft',
305
+ "hasDraft" BOOLEAN DEFAULT false
295
306
  )
296
307
  `);
297
308
  } else {
@@ -302,8 +313,8 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
302
313
  ${colDefs}
303
314
  ${hasCreated ? "" : `"created_at" TEXT NOT NULL DEFAULT (datetime('now')),`}
304
315
  ${hasUpdated ? "" : `"updated_at" TEXT NOT NULL DEFAULT (datetime('now')),`}
305
- "_status" TEXT DEFAULT 'published',
306
- "_has_draft" INTEGER DEFAULT 0
316
+ "publishStatus" TEXT DEFAULT 'draft',
317
+ "hasDraft" INTEGER DEFAULT 0
307
318
  )
308
319
  `);
309
320
  }
@@ -317,6 +328,126 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
317
328
  }
318
329
  }
319
330
  }
331
+ for (const config of collections) {
332
+ const tableName = this.getTableName(config.slug);
333
+ if (tableName === "users" || tableName === "audit_logs") continue;
334
+ await this.syncTableColumns(config, tableName);
335
+ }
336
+ }
337
+ getColumnSqlDefinition(field, dialect) {
338
+ const dbType = fieldToDrizzleType(field, dialect);
339
+ const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
340
+ const sqlType = this.columnSqlType(dbType, dialect);
341
+ return `"${sqlName}" ${sqlType} DEFAULT NULL`;
342
+ }
343
+ columnSqlType(dbType, dialect) {
344
+ if (dialect === "sqlite") {
345
+ switch (dbType) {
346
+ case "varchar":
347
+ return "TEXT";
348
+ case "text":
349
+ return "TEXT";
350
+ case "integer":
351
+ return "INTEGER";
352
+ case "decimal":
353
+ case "numeric":
354
+ return "NUMERIC";
355
+ case "boolean":
356
+ return "INTEGER";
357
+ case "timestamp":
358
+ return "TEXT";
359
+ case "jsonb":
360
+ return "TEXT";
361
+ default:
362
+ return "TEXT";
363
+ }
364
+ }
365
+ switch (dbType) {
366
+ case "varchar":
367
+ return "VARCHAR(255)";
368
+ case "text":
369
+ return "TEXT";
370
+ case "integer":
371
+ return "INTEGER";
372
+ case "decimal":
373
+ case "numeric":
374
+ return "DECIMAL";
375
+ case "boolean":
376
+ return "BOOLEAN";
377
+ case "timestamp":
378
+ return "TIMESTAMP";
379
+ case "jsonb":
380
+ return "JSONB";
381
+ default:
382
+ return "TEXT";
383
+ }
384
+ }
385
+ getExpectedColumnDefs(config, tableName) {
386
+ const defs = {};
387
+ const isGlobal = config.slug.startsWith("_globals_");
388
+ const hasCreated = config.fields.some((f) => f.name === "createdAt");
389
+ const hasUpdated = config.fields.some((f) => f.name === "updatedAt");
390
+ if (this.dialect === "postgres") {
391
+ defs["id"] = isGlobal ? '"id" TEXT PRIMARY KEY' : '"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()';
392
+ if (!hasCreated) defs["created_at"] = '"created_at" TIMESTAMP DEFAULT NULL';
393
+ if (!hasUpdated) defs["updated_at"] = '"updated_at" TIMESTAMP DEFAULT NULL';
394
+ defs["publishStatus"] = '"publishStatus" VARCHAR(20) DEFAULT NULL';
395
+ defs["hasDraft"] = '"hasDraft" BOOLEAN DEFAULT NULL';
396
+ } else {
397
+ defs["id"] = '"id" TEXT PRIMARY KEY';
398
+ if (!hasCreated) defs["created_at"] = '"created_at" TEXT DEFAULT NULL';
399
+ if (!hasUpdated) defs["updated_at"] = '"updated_at" TEXT DEFAULT NULL';
400
+ defs["publishStatus"] = '"publishStatus" TEXT DEFAULT NULL';
401
+ defs["hasDraft"] = '"hasDraft" INTEGER DEFAULT NULL';
402
+ }
403
+ for (const field of config.fields) {
404
+ if (!field.name || field.name === "id") continue;
405
+ const def = this.getColumnSqlDefinition(field, this.dialect);
406
+ const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
407
+ defs[sqlName] = def;
408
+ }
409
+ return defs;
410
+ }
411
+ async syncTableColumns(config, tableName) {
412
+ let existingCols;
413
+ try {
414
+ if (this.dialect === "postgres") {
415
+ const result = await this.client.execute(
416
+ drizzleOrm.sql`SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = ${tableName}`
417
+ );
418
+ existingCols = new Map(result.map((r) => [r.column_name, { type: r.data_type, maxLen: r.character_maximum_length }]));
419
+ } else {
420
+ const result = await this.client.execute(
421
+ drizzleOrm.sql`PRAGMA table_info("${drizzleOrm.sql.raw(tableName)}")`
422
+ );
423
+ existingCols = new Map(result.map((r) => [r.name, { type: r.type, maxLen: null }]));
424
+ }
425
+ } catch {
426
+ return;
427
+ }
428
+ const expected = this.getExpectedColumnDefs(config, tableName);
429
+ const missing = Object.keys(expected).filter((k) => !existingCols.has(k));
430
+ if (missing.length > 0) {
431
+ const alterStmts = missing.map((k) => `ALTER TABLE "${tableName}" ADD COLUMN ${expected[k]}`);
432
+ await this.executeRaw(drizzleOrm.sql.raw(alterStmts.join(";\n")));
433
+ }
434
+ if (this.dialect === "postgres") {
435
+ for (const field of config.fields) {
436
+ if (!field.name || field.name === "id") continue;
437
+ const expectedDbType = fieldToDrizzleType(field, this.dialect);
438
+ const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
439
+ const info = existingCols.get(sqlName);
440
+ if (!info || info.type !== "character varying") continue;
441
+ if (expectedDbType === "text") {
442
+ await this.executeRaw(drizzleOrm.sql.raw(`ALTER TABLE "${tableName}" ALTER COLUMN "${sqlName}" TYPE TEXT`));
443
+ console.log(`[DrizzleAdapter] Fixed column type: "${tableName}"."${sqlName}" VARCHAR \u2192 TEXT`);
444
+ } else if (expectedDbType === "jsonb") {
445
+ await this.executeRaw(drizzleOrm.sql.raw(`ALTER TABLE "${tableName}" ALTER COLUMN "${sqlName}" DROP DEFAULT`));
446
+ await this.executeRaw(drizzleOrm.sql.raw(`ALTER TABLE "${tableName}" ALTER COLUMN "${sqlName}" TYPE JSONB USING (CASE WHEN "${sqlName}" IS NULL THEN NULL WHEN "${sqlName}"::text ~ '^\\s*\\{' THEN "${sqlName}"::jsonb ELSE jsonb_build_object('id', "${sqlName}"::text) END)`));
447
+ console.log(`[DrizzleAdapter] Fixed column type: "${tableName}"."${sqlName}" VARCHAR \u2192 JSONB`);
448
+ }
449
+ }
450
+ }
320
451
  }
321
452
  generateCreateColumns(config) {
322
453
  const cols = [];
@@ -389,12 +520,12 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
389
520
  const table = this.getTable(slug);
390
521
  let effectiveWhere = { ...where };
391
522
  if (this.tenantContext && config.tenantScoped) {
392
- const rlsQuery = chunkSA7NSSIQ_cjs.applyRLS({ where: effectiveWhere }, slug, this.tenantContext, chunkSA7NSSIQ_cjs.DEFAULT_RLS_CONFIG);
523
+ const rlsQuery = chunkPI73NNOK_cjs.applyRLS({ where: effectiveWhere }, slug, this.tenantContext, chunkPI73NNOK_cjs.DEFAULT_RLS_CONFIG);
393
524
  effectiveWhere = rlsQuery.where || {};
394
525
  }
395
526
  const filters = this.buildWhereClause(effectiveWhere, config, table, tenantID);
396
- if (!draft && table._status) {
397
- filters.push(drizzleOrm.eq(table._status, "published"));
527
+ if (!draft && table.publishStatus) {
528
+ filters.push(drizzleOrm.eq(table.publishStatus, "published"));
398
529
  }
399
530
  const sortOption = this.parseSort(sort);
400
531
  const totalDocs = await this.count({ collection: slug, where: effectiveWhere, tenantID });
@@ -413,11 +544,11 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
413
544
  }
414
545
  let docs = results.map((doc) => this.processResult(doc, config));
415
546
  if (this.tenantContext && !this.tenantContext.isSuperAdmin) {
416
- docs = docs.filter((doc) => chunkSA7NSSIQ_cjs.canAccessDocument(doc, slug, this.tenantContext, chunkSA7NSSIQ_cjs.DEFAULT_RLS_CONFIG));
547
+ docs = docs.filter((doc) => chunkPI73NNOK_cjs.canAccessDocument(doc, slug, this.tenantContext, chunkPI73NNOK_cjs.DEFAULT_RLS_CONFIG));
417
548
  }
418
549
  if (draft) {
419
550
  docs = await Promise.all(docs.map(async (doc) => {
420
- if (doc._has_draft) {
551
+ if (doc.hasDraft) {
421
552
  const versions = await this.findVersions({
422
553
  collection: slug,
423
554
  documentId: doc.id,
@@ -425,7 +556,7 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
425
556
  sort: "-createdAt"
426
557
  });
427
558
  if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
428
- return { ...doc, ...versions.docs[0].data, _has_draft: true, _status: doc._status };
559
+ return { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
429
560
  }
430
561
  }
431
562
  return doc;
@@ -442,18 +573,18 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
442
573
  const table = this.getTable(slug);
443
574
  if (this.tenantContext && config.tenantScoped) {
444
575
  const tempDoc = { id, tenantId: this.tenantContext.tenantId };
445
- if (!chunkSA7NSSIQ_cjs.canAccessDocument(tempDoc, slug, this.tenantContext, chunkSA7NSSIQ_cjs.DEFAULT_RLS_CONFIG)) {
576
+ if (!chunkPI73NNOK_cjs.canAccessDocument(tempDoc, slug, this.tenantContext, chunkPI73NNOK_cjs.DEFAULT_RLS_CONFIG)) {
446
577
  return null;
447
578
  }
448
579
  }
449
580
  const conditions = [drizzleOrm.eq(table.id, id)];
450
581
  if (tenantID && table.tenantId) conditions.push(drizzleOrm.eq(table.tenantId, tenantID));
451
- if (!draft && table._status) conditions.push(drizzleOrm.eq(table._status, "published"));
582
+ if (!draft && table.publishStatus) conditions.push(drizzleOrm.eq(table.publishStatus, "published"));
452
583
  const whereClause = conditions.length > 1 ? drizzleOrm.and(...conditions) : conditions[0];
453
584
  let allRows = await this.client.select().from(table).where(whereClause);
454
585
  if (allRows.length === 0) return null;
455
586
  let doc = this.processResult(allRows[0], config);
456
- if (draft && doc._has_draft) {
587
+ if (draft && doc.hasDraft) {
457
588
  const versions = await this.findVersions({
458
589
  collection: slug,
459
590
  documentId: doc.id,
@@ -461,7 +592,7 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
461
592
  sort: "-createdAt"
462
593
  });
463
594
  if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
464
- doc = { ...doc, ...versions.docs[0].data, _has_draft: true, _status: doc._status };
595
+ doc = { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
465
596
  }
466
597
  }
467
598
  return doc;
@@ -482,21 +613,27 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
482
613
  const config = this.getCollection(slug);
483
614
  const table = this.getTable(slug);
484
615
  const updateData = this.prepareData(data, config);
485
- if (tenantID) {
486
- updateData.tenantId = tenantID;
616
+ delete updateData.id;
617
+ console.log(`[DrizzleAdapter.update] CALLED for ${slug}/${id}`);
618
+ const conditions = [drizzleOrm.eq(table.id, id)];
619
+ if (tenantID && table.tenantId) {
620
+ conditions.push(drizzleOrm.eq(table.tenantId, tenantID));
621
+ }
622
+ const result = await this.client.update(table).set(updateData).where(drizzleOrm.and(...conditions)).returning();
623
+ if (result.length === 0) {
624
+ throw new Error(`Document not found: ${slug}/${id}`);
487
625
  }
488
- const result = await this.client.update(table).set(updateData).where(drizzleOrm.eq(table.id, id)).returning();
489
626
  return this.processResult(result[0], config);
490
627
  }
491
628
  async delete(args) {
492
629
  const { collection: slug, id, tenantID } = args;
493
630
  const config = this.getCollection(slug);
494
631
  const table = this.getTable(slug);
495
- let query = this.client.delete(table).where(drizzleOrm.eq(table.id, id)).returning();
632
+ const conditions = [drizzleOrm.eq(table.id, id)];
496
633
  if (tenantID && table.tenantId) {
497
- query = query.where(drizzleOrm.eq(table.tenantId, tenantID));
634
+ conditions.push(drizzleOrm.eq(table.tenantId, tenantID));
498
635
  }
499
- const result = await query;
636
+ const result = await this.client.delete(table).where(drizzleOrm.and(...conditions)).returning();
500
637
  if (result.length === 0) {
501
638
  throw new Error(`Document not found: ${slug}/${id}`);
502
639
  }
@@ -526,13 +663,13 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
526
663
  if (!globalConfig) throw new Error(`Global "${globalSlug}" not found`);
527
664
  const table = this.getTable(slug);
528
665
  let query = this.client.select().from(table);
529
- if (!draft && table._status) {
530
- query = query.where(drizzleOrm.eq(table._status, "published"));
666
+ if (!draft && table.publishStatus) {
667
+ query = query.where(drizzleOrm.eq(table.publishStatus, "published"));
531
668
  }
532
669
  const results = await query.limit(1);
533
670
  if (results.length === 0) return null;
534
671
  let doc = this.processResult(results[0], globalConfig);
535
- if (draft && doc._has_draft) {
672
+ if (draft && doc.hasDraft) {
536
673
  const versions = await this.findVersions({
537
674
  collection: slug,
538
675
  documentId: globalSlug,
@@ -540,7 +677,7 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
540
677
  sort: "-createdAt"
541
678
  });
542
679
  if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
543
- doc = { ...doc, ...versions.docs[0].data, _has_draft: true, _status: doc._status };
680
+ doc = { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
544
681
  }
545
682
  }
546
683
  return doc;
@@ -779,6 +916,22 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
779
916
  }
780
917
  if (field.type === "tabs" && "tabs" in field && field.name) {
781
918
  if (typeof result[field.name] === "object" && result[field.name] !== null && !Array.isArray(result[field.name])) {
919
+ for (const tab of field.tabs) {
920
+ for (const tabField of tab.fields) {
921
+ if ((tabField.type === "upload" || tabField.type === "image") && tabField.name) {
922
+ const val = result[field.name][tabField.name];
923
+ if (typeof val === "string") {
924
+ try {
925
+ const parsed = JSON.parse(val);
926
+ result[field.name][tabField.name] = Array.isArray(parsed) ? parsed.map((item) => item && typeof item === "object" && typeof item.id === "string" ? item.id : String(item || "")) : typeof parsed.id === "string" ? parsed.id : String(parsed.id || "");
927
+ } catch {
928
+ }
929
+ } else if (val && typeof val === "object") {
930
+ result[field.name][tabField.name] = Array.isArray(val) ? val.map((item) => item && typeof item === "object" && typeof item.id === "string" ? item.id : String(item || "")) : typeof val.id === "string" ? val.id : String(val.id || "");
931
+ }
932
+ }
933
+ }
934
+ }
782
935
  continue;
783
936
  }
784
937
  if (typeof result[field.name] === "string") {
@@ -803,6 +956,9 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
803
956
  } catch {
804
957
  }
805
958
  }
959
+ if ((tabField.type === "upload" || tabField.type === "image") && value && typeof value === "object") {
960
+ value = Array.isArray(value) ? value.map((item) => item && typeof item === "object" && typeof item.id === "string" ? item.id : String(item || "")) : typeof value.id === "string" ? value.id : String(value.id || "");
961
+ }
806
962
  }
807
963
  tabData[tabField.name] = value;
808
964
  delete result[tabField.name];
@@ -821,7 +977,7 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
821
977
  return result;
822
978
  }
823
979
  async ensureDraftsTable() {
824
- if (_schemaEnsured || this.draftsTableReady) return;
980
+ if (this.draftsTableReady) return;
825
981
  let createTableSQL;
826
982
  if (this.dialect === "sqlite") {
827
983
  createTableSQL = `
@@ -856,7 +1012,7 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
856
1012
  this.draftsTableReady = true;
857
1013
  }
858
1014
  async ensureVersionsTable() {
859
- if (_schemaEnsured || this.versionsTableReady) return;
1015
+ if (this.versionsTableReady) return;
860
1016
  let createTableSQL;
861
1017
  if (this.dialect === "sqlite") {
862
1018
  createTableSQL = `
@@ -925,7 +1081,7 @@ var DrizzleAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
925
1081
  function createDrizzleAdapter(options) {
926
1082
  return new DrizzleAdapter(options);
927
1083
  }
928
- var _require = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-2KVHZE6O.cjs', document.baseURI).href)));
1084
+ var _require = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-COIASRDK.cjs', document.baseURI).href)));
929
1085
  var modPath = "node:sqlite";
930
1086
  var { DatabaseSync } = _require(modPath);
931
1087
  function getDialect() {
@@ -963,7 +1119,7 @@ async function runMigrations(_db, _dialect) {
963
1119
  );
964
1120
  }
965
1121
  async function seedDefaultRoles(db) {
966
- const { roles } = await import('./schema-37SE2F4B.cjs');
1122
+ const { roles } = await import('./schema-TTFE4467.cjs');
967
1123
  await db.insert(roles).values({
968
1124
  name: "super_admin",
969
1125
  level: 100,
@@ -981,5 +1137,5 @@ exports.fieldToDrizzleType = fieldToDrizzleType;
981
1137
  exports.genId = genId;
982
1138
  exports.runMigrations = runMigrations;
983
1139
  exports.seedDefaultRoles = seedDefaultRoles;
984
- //# sourceMappingURL=chunk-2KVHZE6O.cjs.map
985
- //# sourceMappingURL=chunk-2KVHZE6O.cjs.map
1140
+ //# sourceMappingURL=chunk-COIASRDK.cjs.map
1141
+ //# sourceMappingURL=chunk-COIASRDK.cjs.map