@kyro-cms/core 0.10.4 → 0.10.6

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 (301) hide show
  1. package/dist/api-handler-graphql.cjs +1 -49
  2. package/dist/api-handler-graphql.js +1 -46
  3. package/dist/api-handler-trpc.cjs +1 -38
  4. package/dist/api-handler-trpc.js +1 -36
  5. package/dist/api-handler.cjs +1 -44
  6. package/dist/api-handler.js +1 -27
  7. package/dist/bootstrap-HIAV5ZFT.cjs +1 -0
  8. package/dist/bootstrap-P7QPQYQP.js +1 -0
  9. package/dist/chunk-2BTRHVT3.cjs +20 -0
  10. package/dist/chunk-2W4FK6CJ.js +122 -0
  11. package/dist/chunk-4ORJMSJU.cjs +1 -0
  12. package/dist/chunk-65G73T7Z.cjs +2 -0
  13. package/dist/chunk-7N6NKCRT.js +1 -0
  14. package/dist/chunk-7WOX27LK.js +259 -0
  15. package/dist/chunk-AE6GXUT7.js +1 -0
  16. package/dist/chunk-AJAZ7D3W.cjs +259 -0
  17. package/dist/chunk-ATLSIYRH.cjs +1 -0
  18. package/dist/chunk-AU6IWTBO.js +2 -0
  19. package/dist/chunk-CDL7ARXT.js +133 -0
  20. package/dist/chunk-CUTFS6N2.cjs +1 -0
  21. package/dist/chunk-CVVW4LXZ.cjs +1 -0
  22. package/dist/chunk-DGJUBN33.js +1 -0
  23. package/dist/chunk-DV4LFLPL.cjs +1 -0
  24. package/dist/chunk-EEWCANFX.js +1 -0
  25. package/dist/chunk-ELICKLFM.cjs +3 -0
  26. package/dist/chunk-EQUQJBPP.cjs +2 -0
  27. package/dist/chunk-ET6NN2V2.cjs +122 -0
  28. package/dist/chunk-F7P36SLX.cjs +74 -0
  29. package/dist/chunk-F7SR5IDT.cjs +1 -0
  30. package/dist/chunk-FO3HLBC7.js +1 -0
  31. package/dist/chunk-FS7GL2BR.js +73 -0
  32. package/dist/chunk-G6A7OSIG.js +2 -0
  33. package/dist/chunk-GFU7AOI3.cjs +1 -0
  34. package/dist/chunk-GYQMNXXW.cjs +114 -0
  35. package/dist/chunk-HLSB2MCK.js +1 -0
  36. package/dist/chunk-HVXO3OFB.cjs +1 -0
  37. package/dist/chunk-IFJJ44OQ.cjs +133 -0
  38. package/dist/chunk-ISWMETHJ.cjs +1 -0
  39. package/dist/chunk-K6WUOU6P.js +1 -0
  40. package/dist/chunk-KDNYHLD2.js +1 -0
  41. package/dist/chunk-KIW36TG7.cjs +86 -0
  42. package/dist/chunk-L6CZYN3L.cjs +20 -0
  43. package/dist/chunk-LRGAPGG3.js +74 -0
  44. package/dist/chunk-LZ6YFYQM.js +20 -0
  45. package/dist/chunk-MIOMMB23.cjs +1 -0
  46. package/dist/chunk-NGBJKZMT.js +90 -0
  47. package/dist/chunk-NRLIGDYF.js +1 -0
  48. package/dist/chunk-NY47CFVP.cjs +1 -0
  49. package/dist/chunk-NZ35PV5R.js +2 -0
  50. package/dist/chunk-OG7CNQGU.js +1 -0
  51. package/dist/chunk-OQD3WG6Z.cjs +1 -0
  52. package/dist/chunk-P7CESLDJ.js +1 -0
  53. package/dist/chunk-PP5S2UBV.js +0 -0
  54. package/dist/chunk-Q3Q7BJVQ.cjs +1 -0
  55. package/dist/chunk-Q4CSLXCO.cjs +90 -0
  56. package/dist/chunk-QRXDCV6K.js +0 -0
  57. package/dist/chunk-R7DVVXXI.cjs +73 -0
  58. package/dist/chunk-RHCWCG3O.js +114 -0
  59. package/dist/chunk-SL3LZQCF.js +1 -0
  60. package/dist/chunk-UBHFUFD4.cjs +1 -0
  61. package/dist/chunk-UBRYJP2G.js +1 -0
  62. package/dist/chunk-UDSJGML2.cjs +2 -0
  63. package/dist/chunk-UHFDH3PG.js +20 -0
  64. package/dist/chunk-UJNSOOYZ.cjs +1 -0
  65. package/dist/chunk-URCLFIME.js +86 -0
  66. package/dist/chunk-UVTS2IWM.js +1 -0
  67. package/dist/chunk-V65NPSR5.cjs +1 -0
  68. package/dist/chunk-WIZ6C5QZ.cjs +1 -0
  69. package/dist/chunk-ZAQOSRP6.js +1 -0
  70. package/dist/chunk-ZELCS7IC.js +3 -0
  71. package/dist/cli/index.cjs +35 -405
  72. package/dist/cli/index.js +35 -402
  73. package/dist/client.cjs +1 -55
  74. package/dist/client.js +1 -6
  75. package/dist/drizzle/index.cjs +1 -50
  76. package/dist/drizzle/index.d.cts +1 -2
  77. package/dist/drizzle/index.d.ts +1 -2
  78. package/dist/drizzle/index.js +1 -9
  79. package/dist/fields/index.cjs +1 -89
  80. package/dist/fields/index.js +1 -4
  81. package/dist/graphql/index.cjs +1 -31
  82. package/dist/graphql/index.d.cts +1 -1
  83. package/dist/graphql/index.d.ts +1 -1
  84. package/dist/graphql/index.js +1 -6
  85. package/dist/{index-jLs0zlft.d.ts → index-DXr33e0x.d.ts} +1 -1
  86. package/dist/{index-DHbywDs-.d.cts → index-DuuUzWBq.d.cts} +1 -1
  87. package/dist/index.cjs +29 -2464
  88. package/dist/index.d.cts +2 -2
  89. package/dist/index.d.ts +2 -2
  90. package/dist/index.js +29 -1929
  91. package/dist/integration.cjs +1 -10
  92. package/dist/integration.js +1 -4
  93. package/dist/media-NSSMOB7N.cjs +1 -0
  94. package/dist/media-RNMCZYPZ.js +1 -0
  95. package/dist/mongo-auth-adapter-JYJ4GBZE.cjs +1 -0
  96. package/dist/mongo-auth-adapter-XI7EPURZ.js +1 -0
  97. package/dist/mongodb/index.cjs +1 -29
  98. package/dist/mongodb/index.d.cts +1 -2
  99. package/dist/mongodb/index.d.ts +1 -2
  100. package/dist/mongodb/index.js +1 -8
  101. package/dist/postgres-auth-adapter-E7OGMDD4.cjs +1 -0
  102. package/dist/postgres-auth-adapter-F4KLOGAG.js +1 -0
  103. package/dist/redis-adapter-AQJVABYT.cjs +1 -0
  104. package/dist/redis-adapter-AUKOV74G.js +1 -0
  105. package/dist/rest/index.cjs +1 -31
  106. package/dist/rest/index.d.cts +1 -1
  107. package/dist/rest/index.d.ts +1 -1
  108. package/dist/rest/index.js +1 -18
  109. package/dist/schema-5XNROI7I.js +1 -0
  110. package/dist/schema-6O4JTJRU.cjs +1 -0
  111. package/dist/sqlite-adapter-5XFLNJDH.js +1 -0
  112. package/dist/sqlite-adapter-W53Q32N5.cjs +1 -0
  113. package/dist/templates/index.cjs +1 -207
  114. package/dist/templates/index.js +1 -6
  115. package/dist/trpc/index.cjs +1 -48
  116. package/dist/trpc/index.js +1 -7
  117. package/dist/ws/index.cjs +1 -25
  118. package/dist/ws/index.js +1 -4
  119. package/package.json +44 -13
  120. package/dist/api-handler-graphql.cjs.map +0 -1
  121. package/dist/api-handler-graphql.js.map +0 -1
  122. package/dist/api-handler-trpc.cjs.map +0 -1
  123. package/dist/api-handler-trpc.js.map +0 -1
  124. package/dist/api-handler.cjs.map +0 -1
  125. package/dist/api-handler.js.map +0 -1
  126. package/dist/bootstrap-FUAPY2OF.cjs +0 -32
  127. package/dist/bootstrap-FUAPY2OF.cjs.map +0 -1
  128. package/dist/bootstrap-OXNVM7FP.js +0 -7
  129. package/dist/bootstrap-OXNVM7FP.js.map +0 -1
  130. package/dist/chunk-2HFJUUFZ.js +0 -250
  131. package/dist/chunk-2HFJUUFZ.js.map +0 -1
  132. package/dist/chunk-3AKCVYDB.js +0 -162
  133. package/dist/chunk-3AKCVYDB.js.map +0 -1
  134. package/dist/chunk-3KTWGODI.cjs +0 -178
  135. package/dist/chunk-3KTWGODI.cjs.map +0 -1
  136. package/dist/chunk-3YELQL7Z.cjs +0 -4
  137. package/dist/chunk-3YELQL7Z.cjs.map +0 -1
  138. package/dist/chunk-4CV4JOE5.js +0 -24
  139. package/dist/chunk-4CV4JOE5.js.map +0 -1
  140. package/dist/chunk-4OCMVGEY.cjs +0 -173
  141. package/dist/chunk-4OCMVGEY.cjs.map +0 -1
  142. package/dist/chunk-4PWRCMTQ.cjs +0 -15
  143. package/dist/chunk-4PWRCMTQ.cjs.map +0 -1
  144. package/dist/chunk-53NYVYVX.js +0 -3243
  145. package/dist/chunk-53NYVYVX.js.map +0 -1
  146. package/dist/chunk-5GFQPHGT.cjs +0 -156
  147. package/dist/chunk-5GFQPHGT.cjs.map +0 -1
  148. package/dist/chunk-5RPRLTTN.js +0 -861
  149. package/dist/chunk-5RPRLTTN.js.map +0 -1
  150. package/dist/chunk-74YSDAWE.cjs +0 -2749
  151. package/dist/chunk-74YSDAWE.cjs.map +0 -1
  152. package/dist/chunk-7OGPN7MP.js +0 -352
  153. package/dist/chunk-7OGPN7MP.js.map +0 -1
  154. package/dist/chunk-7OS7TX2Q.cjs +0 -495
  155. package/dist/chunk-7OS7TX2Q.cjs.map +0 -1
  156. package/dist/chunk-ADLJSJSN.cjs +0 -13
  157. package/dist/chunk-ADLJSJSN.cjs.map +0 -1
  158. package/dist/chunk-B6X3LN25.cjs +0 -6486
  159. package/dist/chunk-B6X3LN25.cjs.map +0 -1
  160. package/dist/chunk-BYBMTIMT.js +0 -419
  161. package/dist/chunk-BYBMTIMT.js.map +0 -1
  162. package/dist/chunk-CF7OL6HR.js +0 -355
  163. package/dist/chunk-CF7OL6HR.js.map +0 -1
  164. package/dist/chunk-CJX74IYK.js +0 -489
  165. package/dist/chunk-CJX74IYK.js.map +0 -1
  166. package/dist/chunk-CKVOU6MX.cjs +0 -52
  167. package/dist/chunk-CKVOU6MX.cjs.map +0 -1
  168. package/dist/chunk-CZLDE2OZ.cjs +0 -28
  169. package/dist/chunk-CZLDE2OZ.cjs.map +0 -1
  170. package/dist/chunk-DPA3KWPY.cjs +0 -205
  171. package/dist/chunk-DPA3KWPY.cjs.map +0 -1
  172. package/dist/chunk-EEJUFDMF.cjs +0 -424
  173. package/dist/chunk-EEJUFDMF.cjs.map +0 -1
  174. package/dist/chunk-FIAMXNTH.js +0 -220
  175. package/dist/chunk-FIAMXNTH.js.map +0 -1
  176. package/dist/chunk-GAOXD3XT.js +0 -175
  177. package/dist/chunk-GAOXD3XT.js.map +0 -1
  178. package/dist/chunk-GTGRLD4Y.js +0 -3
  179. package/dist/chunk-GTGRLD4Y.js.map +0 -1
  180. package/dist/chunk-GUUB5EAG.cjs +0 -223
  181. package/dist/chunk-GUUB5EAG.cjs.map +0 -1
  182. package/dist/chunk-GXFOGU7N.cjs +0 -359
  183. package/dist/chunk-GXFOGU7N.cjs.map +0 -1
  184. package/dist/chunk-GZS4LMR7.js +0 -422
  185. package/dist/chunk-GZS4LMR7.js.map +0 -1
  186. package/dist/chunk-HY6B7B5A.js +0 -150
  187. package/dist/chunk-HY6B7B5A.js.map +0 -1
  188. package/dist/chunk-HZOMOK5Y.js +0 -2728
  189. package/dist/chunk-HZOMOK5Y.js.map +0 -1
  190. package/dist/chunk-IDVRRRAK.cjs +0 -824
  191. package/dist/chunk-IDVRRRAK.cjs.map +0 -1
  192. package/dist/chunk-KC2GDBLS.cjs +0 -84
  193. package/dist/chunk-KC2GDBLS.cjs.map +0 -1
  194. package/dist/chunk-L4EZKIEX.js +0 -185
  195. package/dist/chunk-L4EZKIEX.js.map +0 -1
  196. package/dist/chunk-LNTFRAHF.cjs +0 -473
  197. package/dist/chunk-LNTFRAHF.cjs.map +0 -1
  198. package/dist/chunk-MTIRYI7F.cjs +0 -4
  199. package/dist/chunk-MTIRYI7F.cjs.map +0 -1
  200. package/dist/chunk-N4GN6Q3V.cjs +0 -869
  201. package/dist/chunk-N4GN6Q3V.cjs.map +0 -1
  202. package/dist/chunk-N4H37VN4.cjs +0 -259
  203. package/dist/chunk-N4H37VN4.cjs.map +0 -1
  204. package/dist/chunk-N5QSHUA6.js +0 -1135
  205. package/dist/chunk-N5QSHUA6.js.map +0 -1
  206. package/dist/chunk-NKPKR5BW.cjs +0 -188
  207. package/dist/chunk-NKPKR5BW.cjs.map +0 -1
  208. package/dist/chunk-OIRG6ZRV.cjs +0 -1073
  209. package/dist/chunk-OIRG6ZRV.cjs.map +0 -1
  210. package/dist/chunk-OJ2AM75W.cjs +0 -253
  211. package/dist/chunk-OJ2AM75W.cjs.map +0 -1
  212. package/dist/chunk-OLV7K22H.js +0 -6457
  213. package/dist/chunk-OLV7K22H.js.map +0 -1
  214. package/dist/chunk-OX6GOIPH.js +0 -516
  215. package/dist/chunk-OX6GOIPH.js.map +0 -1
  216. package/dist/chunk-P2YW545G.js +0 -11
  217. package/dist/chunk-P2YW545G.js.map +0 -1
  218. package/dist/chunk-PHJRNPHY.cjs +0 -3291
  219. package/dist/chunk-PHJRNPHY.cjs.map +0 -1
  220. package/dist/chunk-Q72BOAPK.js +0 -817
  221. package/dist/chunk-Q72BOAPK.js.map +0 -1
  222. package/dist/chunk-QU2RFFH4.js +0 -3
  223. package/dist/chunk-QU2RFFH4.js.map +0 -1
  224. package/dist/chunk-RP7VZUEL.js +0 -49
  225. package/dist/chunk-RP7VZUEL.js.map +0 -1
  226. package/dist/chunk-SHTTJMLT.cjs +0 -361
  227. package/dist/chunk-SHTTJMLT.cjs.map +0 -1
  228. package/dist/chunk-SX76DNOO.js +0 -103
  229. package/dist/chunk-SX76DNOO.js.map +0 -1
  230. package/dist/chunk-THBQG64D.cjs +0 -425
  231. package/dist/chunk-THBQG64D.cjs.map +0 -1
  232. package/dist/chunk-TQG7G7YI.cjs +0 -526
  233. package/dist/chunk-TQG7G7YI.cjs.map +0 -1
  234. package/dist/chunk-U3VVLYXG.cjs +0 -189
  235. package/dist/chunk-U3VVLYXG.cjs.map +0 -1
  236. package/dist/chunk-UUDTPZX6.js +0 -193
  237. package/dist/chunk-UUDTPZX6.js.map +0 -1
  238. package/dist/chunk-V5AWATUP.js +0 -1059
  239. package/dist/chunk-V5AWATUP.js.map +0 -1
  240. package/dist/chunk-VAXLFZCV.cjs +0 -110
  241. package/dist/chunk-VAXLFZCV.cjs.map +0 -1
  242. package/dist/chunk-VKREAIBA.cjs +0 -1139
  243. package/dist/chunk-VKREAIBA.cjs.map +0 -1
  244. package/dist/chunk-WDTTHKDS.js +0 -458
  245. package/dist/chunk-WDTTHKDS.js.map +0 -1
  246. package/dist/chunk-WXVB364T.js +0 -218
  247. package/dist/chunk-WXVB364T.js.map +0 -1
  248. package/dist/chunk-X4BPPD6K.js +0 -181
  249. package/dist/chunk-X4BPPD6K.js.map +0 -1
  250. package/dist/chunk-XEB7PH2E.js +0 -81
  251. package/dist/chunk-XEB7PH2E.js.map +0 -1
  252. package/dist/chunk-YT7HXXVN.js +0 -13
  253. package/dist/chunk-YT7HXXVN.js.map +0 -1
  254. package/dist/cli/index.cjs.map +0 -1
  255. package/dist/cli/index.js.map +0 -1
  256. package/dist/client.cjs.map +0 -1
  257. package/dist/client.js.map +0 -1
  258. package/dist/drizzle/index.cjs.map +0 -1
  259. package/dist/drizzle/index.js.map +0 -1
  260. package/dist/fields/index.cjs.map +0 -1
  261. package/dist/fields/index.js.map +0 -1
  262. package/dist/graphql/index.cjs.map +0 -1
  263. package/dist/graphql/index.js.map +0 -1
  264. package/dist/index.cjs.map +0 -1
  265. package/dist/index.js.map +0 -1
  266. package/dist/integration.cjs.map +0 -1
  267. package/dist/integration.js.map +0 -1
  268. package/dist/media-7WDX4BDJ.js +0 -4
  269. package/dist/media-7WDX4BDJ.js.map +0 -1
  270. package/dist/media-TUSLVRQ6.cjs +0 -17
  271. package/dist/media-TUSLVRQ6.cjs.map +0 -1
  272. package/dist/mongo-auth-adapter-GT4S7SCU.cjs +0 -17
  273. package/dist/mongo-auth-adapter-GT4S7SCU.cjs.map +0 -1
  274. package/dist/mongo-auth-adapter-M7VV4LNB.js +0 -4
  275. package/dist/mongo-auth-adapter-M7VV4LNB.js.map +0 -1
  276. package/dist/mongodb/index.cjs.map +0 -1
  277. package/dist/mongodb/index.js.map +0 -1
  278. package/dist/postgres-auth-adapter-AFAPISH7.js +0 -5
  279. package/dist/postgres-auth-adapter-AFAPISH7.js.map +0 -1
  280. package/dist/postgres-auth-adapter-SFDTLONT.cjs +0 -14
  281. package/dist/postgres-auth-adapter-SFDTLONT.cjs.map +0 -1
  282. package/dist/redis-adapter-UQX4EE3B.cjs +0 -13
  283. package/dist/redis-adapter-UQX4EE3B.cjs.map +0 -1
  284. package/dist/redis-adapter-XALOGWY3.js +0 -4
  285. package/dist/redis-adapter-XALOGWY3.js.map +0 -1
  286. package/dist/rest/index.cjs.map +0 -1
  287. package/dist/rest/index.js.map +0 -1
  288. package/dist/schema-6QL3USNB.cjs +0 -67
  289. package/dist/schema-6QL3USNB.cjs.map +0 -1
  290. package/dist/schema-FNNWEAAW.js +0 -6
  291. package/dist/schema-FNNWEAAW.js.map +0 -1
  292. package/dist/sqlite-adapter-AQB5TCGV.cjs +0 -13
  293. package/dist/sqlite-adapter-AQB5TCGV.cjs.map +0 -1
  294. package/dist/sqlite-adapter-N5H6IM2X.js +0 -4
  295. package/dist/sqlite-adapter-N5H6IM2X.js.map +0 -1
  296. package/dist/templates/index.cjs.map +0 -1
  297. package/dist/templates/index.js.map +0 -1
  298. package/dist/trpc/index.cjs.map +0 -1
  299. package/dist/trpc/index.js.map +0 -1
  300. package/dist/ws/index.cjs.map +0 -1
  301. package/dist/ws/index.js.map +0 -1
@@ -1,1059 +0,0 @@
1
- import { AbstractBaseAdapter, applyRLS, DEFAULT_RLS_CONFIG, canAccessDocument } from './chunk-WXVB364T.js';
2
- import { sql, eq, desc, and, or, ne, inArray, like, gt, gte, lt, lte } from 'drizzle-orm';
3
- import { text, uuid, jsonb, timestamp, boolean, decimal, integer as integer$1, varchar, pgTable } from 'drizzle-orm/pg-core';
4
- import { text as text$1, integer, numeric, sqliteTable } from 'drizzle-orm/sqlite-core';
5
- import { drizzle } from 'drizzle-orm/postgres-js';
6
- import postgres from 'postgres';
7
- import { randomBytes } from 'crypto';
8
- import { mkdir } from 'fs/promises';
9
- import { resolve, dirname } from 'path';
10
- import { createRequire } from 'module';
11
-
12
- var _schemaEnsured = false;
13
- function fieldToDrizzleType(field, dialect = "postgres") {
14
- switch (field.type) {
15
- case "text":
16
- case "email":
17
- case "password":
18
- case "color":
19
- return dialect === "sqlite" ? "text" : "varchar";
20
- case "textarea":
21
- case "code":
22
- case "markdown":
23
- case "secret":
24
- return "text";
25
- case "number":
26
- return field.integer ? "integer" : "decimal";
27
- case "checkbox":
28
- return "boolean";
29
- case "date":
30
- return "timestamp";
31
- case "select":
32
- case "radio":
33
- return dialect === "sqlite" ? "text" : "varchar";
34
- case "richtext":
35
- case "json":
36
- case "array":
37
- case "group":
38
- case "blocks":
39
- case "row":
40
- case "collapsible":
41
- case "tabs":
42
- return "jsonb";
43
- case "relationship":
44
- return dialect === "sqlite" ? "text" : "varchar";
45
- case "upload":
46
- return "jsonb";
47
- default:
48
- return "jsonb";
49
- }
50
- }
51
- function collectionToDrizzleSchema(collection, dialect = "postgres") {
52
- const tableName = collection.slug.replace(/-/g, "_");
53
- const lines = [];
54
- lines.push(`export const ${tableName} = pgTable('${tableName}', {`);
55
- lines.push(` id: uuid('id').primaryKey().defaultRandom(),`);
56
- for (const field of collection.fields) {
57
- if (field.name === "id") continue;
58
- const dbType = fieldToDrizzleType(field, dialect);
59
- const isRequired = field.required;
60
- let fieldDef = ` ${field.name}: pg.${dbType}('${field.name}')`;
61
- if (field.unique) fieldDef += ".unique()";
62
- if (!isRequired) fieldDef += ".nullable()";
63
- if (field.defaultValue !== void 0) {
64
- if (typeof field.defaultValue === "string") {
65
- fieldDef += `.default('${field.defaultValue}')`;
66
- } else if (typeof field.defaultValue === "boolean") {
67
- fieldDef += `.default(${field.defaultValue})`;
68
- } else {
69
- fieldDef += `.default(sql\`${JSON.stringify(field.defaultValue)}\`)`;
70
- }
71
- }
72
- fieldDef += ",";
73
- lines.push(fieldDef);
74
- }
75
- if (collection.timestamps) {
76
- lines.push(` createdAt: pg.timestamp('created_at').defaultNow(),`);
77
- lines.push(` updatedAt: pg.timestamp('updated_at').defaultNow(),`);
78
- }
79
- lines.push(` status: ${dialect === "sqlite" ? "sqlite" : "pg"}.varchar('status').default('draft'),`);
80
- lines.push(` hasDraft: ${dialect === "sqlite" ? "sqlite" : "pg"}.boolean('hasDraft').default(false),`);
81
- lines.push("});");
82
- return lines.join("\n");
83
- }
84
- var DrizzleAdapter = class extends AbstractBaseAdapter {
85
- client;
86
- schema;
87
- dialect;
88
- connectionString;
89
- versionsTableReady = false;
90
- constructor(options) {
91
- super();
92
- this.schema = options.schema || {};
93
- if (options.connectionString) {
94
- this.connectionString = options.connectionString;
95
- const connStr = options.connectionString.toLowerCase();
96
- if (connStr.startsWith("postgres://") || connStr.startsWith("postgresql://")) {
97
- this.dialect = "postgres";
98
- } else if (connStr.includes(".db") || connStr.includes("sqlite") || connStr.includes("file:")) {
99
- this.dialect = "sqlite";
100
- } else {
101
- this.dialect = options.type || "postgres";
102
- }
103
- } else {
104
- this.client = options.client;
105
- this.dialect = options.type || "sqlite";
106
- }
107
- }
108
- prepareData(data, config) {
109
- const result = super.prepareData(data, config);
110
- if (result.createdAt && typeof result.createdAt === "string") {
111
- result.createdAt = new Date(result.createdAt);
112
- }
113
- if (result.updatedAt && typeof result.updatedAt === "string") {
114
- result.updatedAt = new Date(result.updatedAt);
115
- }
116
- for (const field of config.fields) {
117
- if (field.type === "date" && field.name) {
118
- const value = result[field.name];
119
- if (value && typeof value === "string") {
120
- result[field.name] = new Date(value);
121
- }
122
- }
123
- }
124
- for (const field of config.fields) {
125
- const dbType = fieldToDrizzleType(field, this.dialect);
126
- const isJsonb = dbType === "jsonb";
127
- if (field.type === "tabs" && "tabs" in field && field.name) {
128
- const tabData = data[field.name];
129
- if (tabData && typeof tabData === "object") {
130
- const processedTabData = {};
131
- for (const [key, value] of Object.entries(tabData)) {
132
- const tabField = field.tabs.flatMap((t) => t.fields).find((f) => f.name === key);
133
- const needsStringify = (tabField?.type === "upload" || tabField?.type === "image" || tabField?.type === "list" || tabField?.type === "relationship-block") && value;
134
- if (needsStringify) {
135
- processedTabData[key] = Array.isArray(value) ? JSON.stringify(value) : typeof value === "object" ? JSON.stringify(value) : value;
136
- } else {
137
- processedTabData[key] = value;
138
- }
139
- }
140
- result[field.name] = isJsonb ? processedTabData : JSON.stringify(processedTabData);
141
- }
142
- }
143
- if (field.type === "upload" || field.type === "image" || field.type === "list" || field.type === "relationship-block") {
144
- if (field.name) {
145
- const value = data[field.name];
146
- if (value) {
147
- result[field.name] = isJsonb ? value : Array.isArray(value) ? JSON.stringify(value) : typeof value === "object" ? JSON.stringify(value) : value;
148
- }
149
- }
150
- }
151
- }
152
- for (const field of config.fields) {
153
- if (field.name && result[field.name] === "") {
154
- const dbType = fieldToDrizzleType(field, this.dialect);
155
- if (dbType === "timestamp" || dbType === "jsonb" || dbType === "decimal" || dbType === "integer" || dbType === "numeric" || dbType === "boolean") {
156
- result[field.name] = null;
157
- }
158
- }
159
- }
160
- return result;
161
- }
162
- async connect() {
163
- if (this.connectionString && !this.client) {
164
- if (this.dialect === "postgres") {
165
- const { default: postgres2 } = await import('postgres');
166
- const { drizzle: drizzle2 } = await import('drizzle-orm/postgres-js');
167
- const sql2 = postgres2(this.connectionString, { onnotice: () => {
168
- } });
169
- this.client = drizzle2(sql2, { schema: this.schema });
170
- } else if (this.dialect === "sqlite") {
171
- const { default: betterSqlite3 } = await import('better-sqlite3');
172
- const { drizzle: drizzle2 } = await import('drizzle-orm/better-sqlite3');
173
- const db = new betterSqlite3(this.connectionString.replace("file:", ""));
174
- this.client = drizzle2(db, { schema: this.schema });
175
- }
176
- }
177
- this.connected = true;
178
- }
179
- async init(collections, globals = []) {
180
- await super.init(collections, globals);
181
- if (this.connectionString && !this.client) {
182
- await this.connect();
183
- }
184
- if (this.client && !_schemaEnsured) {
185
- for (const config of collections) {
186
- const tableName = this.getTableName(config.slug);
187
- if (!this.schema[tableName]) {
188
- this.schema[tableName] = this.createTableFromConfig(config);
189
- }
190
- }
191
- await this.ensureCollectionTables(collections);
192
- const globalCollections = globals.map((g) => ({
193
- slug: `_globals_${g.slug}`,
194
- fields: g.fields,
195
- label: g.label
196
- }));
197
- for (const gc of globalCollections) {
198
- const tableName = this.getTableName(gc.slug);
199
- if (!this.schema[tableName]) {
200
- this.schema[tableName] = this.createTableFromConfig(gc, true);
201
- }
202
- if (!this.collections.has(gc.slug)) {
203
- this.collections.set(gc.slug, gc);
204
- }
205
- }
206
- await this.ensureCollectionTables(globalCollections);
207
- _schemaEnsured = true;
208
- }
209
- }
210
- createTableFromConfig(config, useTextId = false) {
211
- const tableName = this.getTableName(config.slug);
212
- const columns = {
213
- id: useTextId ? text("id").primaryKey() : uuid("id").primaryKey().defaultRandom()
214
- };
215
- for (const field of config.fields) {
216
- if (!field.name || field.name === "id") continue;
217
- const dbType = fieldToDrizzleType(field, this.dialect);
218
- const propName = field.name.replace(/-/g, "_");
219
- const sqlName = propName.replace(/([A-Z])/g, "_$1").toLowerCase();
220
- let col;
221
- if (this.dialect === "sqlite") {
222
- switch (dbType) {
223
- case "varchar":
224
- case "text":
225
- col = text$1(sqlName);
226
- break;
227
- case "integer":
228
- col = integer(sqlName);
229
- break;
230
- case "decimal":
231
- case "numeric":
232
- col = numeric(sqlName);
233
- break;
234
- case "boolean":
235
- col = integer(sqlName, { mode: "boolean" });
236
- break;
237
- case "timestamp":
238
- col = text$1(sqlName);
239
- break;
240
- case "jsonb":
241
- col = text$1(sqlName);
242
- break;
243
- default:
244
- col = text$1(sqlName);
245
- }
246
- } else {
247
- switch (dbType) {
248
- case "varchar":
249
- col = varchar(sqlName, { length: 255 });
250
- break;
251
- case "integer":
252
- col = integer$1(sqlName);
253
- break;
254
- case "decimal":
255
- col = decimal(sqlName);
256
- break;
257
- case "boolean":
258
- col = boolean(sqlName);
259
- break;
260
- case "timestamp":
261
- col = timestamp(sqlName);
262
- break;
263
- case "jsonb":
264
- col = jsonb(sqlName);
265
- break;
266
- default:
267
- col = text(sqlName);
268
- }
269
- }
270
- if (!field.required) col = col.default(null);
271
- columns[propName] = col;
272
- }
273
- if (!columns.createdAt) columns.createdAt = this.dialect === "sqlite" ? text$1("created_at").default((/* @__PURE__ */ new Date()).toISOString()) : timestamp("created_at").defaultNow();
274
- if (!columns.updatedAt) columns.updatedAt = this.dialect === "sqlite" ? text$1("updated_at").default((/* @__PURE__ */ new Date()).toISOString()) : timestamp("updated_at").defaultNow();
275
- columns.status = this.dialect === "sqlite" ? text$1("status").default("draft") : varchar("status", { length: 20 }).default("draft");
276
- columns.hasDraft = this.dialect === "sqlite" ? integer("hasDraft", { mode: "boolean" }).default(false) : boolean("hasDraft").default(false);
277
- return this.dialect === "sqlite" ? sqliteTable(tableName, columns) : pgTable(tableName, columns);
278
- }
279
- async ensureCollectionTables(collections) {
280
- const statements = [];
281
- for (const config of collections) {
282
- const isGlobal = config.slug.startsWith("_globals_");
283
- const tableName = this.getTableName(config.slug);
284
- const colDefs = this.generateCreateColumns(config);
285
- const hasCreated = config.fields.some((f) => f.name === "createdAt");
286
- const hasUpdated = config.fields.some((f) => f.name === "updatedAt");
287
- const hasStatus = config.fields.some((f) => f.name === "status");
288
- const hasDraftField = config.fields.some((f) => f.name === "hasDraft");
289
- if (this.dialect === "postgres") {
290
- const idCol = isGlobal ? '"id" TEXT PRIMARY KEY' : '"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()';
291
- statements.push(`
292
- CREATE TABLE IF NOT EXISTS "${tableName}" (
293
- ${idCol},
294
- ${colDefs}
295
- ${hasCreated ? "" : '"created_at" TIMESTAMP NOT NULL DEFAULT NOW(),'}
296
- ${hasUpdated ? "" : '"updated_at" TIMESTAMP NOT NULL DEFAULT NOW(),'}
297
- ${hasStatus ? "" : `"status" VARCHAR(20) DEFAULT 'draft',`}
298
- ${hasDraftField ? "" : '"hasDraft" BOOLEAN DEFAULT false'}
299
- )
300
- `);
301
- } else {
302
- const idCol = isGlobal ? '"id" TEXT PRIMARY KEY' : '"id" TEXT PRIMARY KEY';
303
- statements.push(`
304
- CREATE TABLE IF NOT EXISTS "${tableName}" (
305
- ${idCol},
306
- ${colDefs}
307
- ${hasCreated ? "" : `"created_at" TEXT NOT NULL DEFAULT (datetime('now')),`}
308
- ${hasUpdated ? "" : `"updated_at" TEXT NOT NULL DEFAULT (datetime('now')),`}
309
- ${hasStatus ? "" : `"status" TEXT DEFAULT 'draft',`}
310
- ${hasDraftField ? "" : '"hasDraft" INTEGER DEFAULT 0'}
311
- )
312
- `);
313
- }
314
- }
315
- if (statements.length > 0) {
316
- if (this.dialect === "postgres") {
317
- await this.client.execute(sql.raw(statements.join(";\n")));
318
- } else {
319
- for (const stmt of statements) {
320
- await this.client.execute(sql.raw(stmt));
321
- }
322
- }
323
- }
324
- for (const config of collections) {
325
- const tableName = this.getTableName(config.slug);
326
- if (tableName === "users" || tableName === "audit_logs") continue;
327
- await this.syncTableColumns(config, tableName);
328
- }
329
- }
330
- getColumnSqlDefinition(field, dialect) {
331
- const dbType = fieldToDrizzleType(field, dialect);
332
- const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
333
- const sqlType = this.columnSqlType(dbType, dialect);
334
- return `"${sqlName}" ${sqlType} DEFAULT NULL`;
335
- }
336
- columnSqlType(dbType, dialect) {
337
- if (dialect === "sqlite") {
338
- switch (dbType) {
339
- case "varchar":
340
- return "TEXT";
341
- case "text":
342
- return "TEXT";
343
- case "integer":
344
- return "INTEGER";
345
- case "decimal":
346
- case "numeric":
347
- return "NUMERIC";
348
- case "boolean":
349
- return "INTEGER";
350
- case "timestamp":
351
- return "TEXT";
352
- case "jsonb":
353
- return "TEXT";
354
- default:
355
- return "TEXT";
356
- }
357
- }
358
- switch (dbType) {
359
- case "varchar":
360
- return "VARCHAR(255)";
361
- case "text":
362
- return "TEXT";
363
- case "integer":
364
- return "INTEGER";
365
- case "decimal":
366
- case "numeric":
367
- return "DECIMAL";
368
- case "boolean":
369
- return "BOOLEAN";
370
- case "timestamp":
371
- return "TIMESTAMP";
372
- case "jsonb":
373
- return "JSONB";
374
- default:
375
- return "TEXT";
376
- }
377
- }
378
- getExpectedColumnDefs(config, tableName) {
379
- const defs = {};
380
- const isGlobal = config.slug.startsWith("_globals_");
381
- const hasCreated = config.fields.some((f) => f.name === "createdAt");
382
- const hasUpdated = config.fields.some((f) => f.name === "updatedAt");
383
- const hasStatus = config.fields.some((f) => f.name === "status");
384
- const hasDraftField = config.fields.some((f) => f.name === "hasDraft");
385
- if (this.dialect === "postgres") {
386
- defs["id"] = isGlobal ? '"id" TEXT PRIMARY KEY' : '"id" UUID PRIMARY KEY DEFAULT gen_random_uuid()';
387
- if (!hasCreated) defs["created_at"] = '"created_at" TIMESTAMP DEFAULT NULL';
388
- if (!hasUpdated) defs["updated_at"] = '"updated_at" TIMESTAMP DEFAULT NULL';
389
- if (!hasStatus) defs["status"] = '"status" VARCHAR(20) DEFAULT NULL';
390
- if (!hasDraftField) defs["hasDraft"] = '"hasDraft" BOOLEAN DEFAULT NULL';
391
- } else {
392
- defs["id"] = '"id" TEXT PRIMARY KEY';
393
- if (!hasCreated) defs["created_at"] = '"created_at" TEXT DEFAULT NULL';
394
- if (!hasUpdated) defs["updated_at"] = '"updated_at" TEXT DEFAULT NULL';
395
- if (!hasStatus) defs["status"] = '"status" TEXT DEFAULT NULL';
396
- if (!hasDraftField) defs["hasDraft"] = '"hasDraft" INTEGER DEFAULT NULL';
397
- }
398
- for (const field of config.fields) {
399
- if (!field.name || field.name === "id") continue;
400
- const def = this.getColumnSqlDefinition(field, this.dialect);
401
- const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
402
- defs[sqlName] = def;
403
- }
404
- return defs;
405
- }
406
- async syncTableColumns(config, tableName) {
407
- let existingCols;
408
- try {
409
- if (this.dialect === "postgres") {
410
- const result = await this.client.execute(
411
- sql`SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = ${tableName}`
412
- );
413
- existingCols = new Map(result.map((r) => [r.column_name, { type: r.data_type, maxLen: r.character_maximum_length }]));
414
- } else {
415
- const result = await this.client.execute(
416
- sql`PRAGMA table_info("${sql.raw(tableName)}")`
417
- );
418
- existingCols = new Map(result.map((r) => [r.name, { type: r.type, maxLen: null }]));
419
- }
420
- } catch {
421
- return;
422
- }
423
- const expected = this.getExpectedColumnDefs(config, tableName);
424
- const missing = Object.keys(expected).filter((k) => !existingCols.has(k));
425
- if (missing.length > 0) {
426
- const alterStmts = missing.map((k) => `ALTER TABLE "${tableName}" ADD COLUMN ${expected[k]}`);
427
- await this.executeRaw(sql.raw(alterStmts.join(";\n")));
428
- }
429
- if (this.dialect === "postgres") {
430
- for (const field of config.fields) {
431
- if (!field.name || field.name === "id") continue;
432
- const expectedDbType = fieldToDrizzleType(field, this.dialect);
433
- const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
434
- const info = existingCols.get(sqlName);
435
- if (!info || info.type !== "character varying") continue;
436
- if (expectedDbType === "text") {
437
- await this.executeRaw(sql.raw(`ALTER TABLE "${tableName}" ALTER COLUMN "${sqlName}" TYPE TEXT`));
438
- } else if (expectedDbType === "jsonb") {
439
- await this.executeRaw(sql.raw(`ALTER TABLE "${tableName}" ALTER COLUMN "${sqlName}" DROP DEFAULT`));
440
- await this.executeRaw(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)`));
441
- }
442
- }
443
- }
444
- }
445
- generateCreateColumns(config) {
446
- const cols = [];
447
- for (const field of config.fields) {
448
- if (!field.name || field.name === "id") continue;
449
- const dbType = fieldToDrizzleType(field, this.dialect);
450
- const sqlName = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
451
- const nullable = field.required ? "NOT NULL" : "DEFAULT NULL";
452
- let sqlType;
453
- if (this.dialect === "sqlite") {
454
- switch (dbType) {
455
- case "varchar":
456
- case "text":
457
- sqlType = `TEXT ${nullable}`;
458
- break;
459
- case "integer":
460
- sqlType = `INTEGER ${nullable}`;
461
- break;
462
- case "decimal":
463
- case "numeric":
464
- sqlType = `NUMERIC ${nullable}`;
465
- break;
466
- case "boolean":
467
- sqlType = `INTEGER ${nullable}`;
468
- break;
469
- case "timestamp":
470
- sqlType = `TEXT ${nullable}`;
471
- break;
472
- case "jsonb":
473
- sqlType = `TEXT ${nullable}`;
474
- break;
475
- default:
476
- sqlType = `TEXT ${nullable}`;
477
- }
478
- } else {
479
- switch (dbType) {
480
- case "varchar":
481
- sqlType = `VARCHAR(255) ${nullable}`;
482
- break;
483
- case "integer":
484
- sqlType = `INTEGER ${nullable}`;
485
- break;
486
- case "decimal":
487
- sqlType = `DECIMAL ${nullable}`;
488
- break;
489
- case "boolean":
490
- sqlType = `BOOLEAN ${nullable}`;
491
- break;
492
- case "timestamp":
493
- sqlType = `TIMESTAMP ${nullable}`;
494
- break;
495
- case "jsonb":
496
- sqlType = `JSONB ${nullable}`;
497
- break;
498
- default:
499
- sqlType = `TEXT ${nullable}`;
500
- }
501
- }
502
- cols.push(`"${sqlName}" ${sqlType}`);
503
- }
504
- return cols.join(",\n ") + (cols.length > 0 ? "," : "");
505
- }
506
- async disconnect() {
507
- this.connected = false;
508
- }
509
- async find(args) {
510
- const { collection: slug, where = {}, sort, limit = 10, page = 1, tenantID, select, draft } = args;
511
- const config = this.getCollection(slug);
512
- const table = this.getTable(slug);
513
- let effectiveWhere = { ...where };
514
- if (this.tenantContext && config.tenantScoped) {
515
- const rlsQuery = applyRLS({ where: effectiveWhere }, slug, this.tenantContext, DEFAULT_RLS_CONFIG);
516
- effectiveWhere = rlsQuery.where || {};
517
- }
518
- const filters = this.buildWhereClause(effectiveWhere, config, table, tenantID);
519
- if (!draft && table.status) {
520
- filters.push(eq(table.status, "published"));
521
- }
522
- const sortOption = this.parseSort(sort);
523
- const countWhere = !draft && table.status ? { ...effectiveWhere, status: "published" } : effectiveWhere;
524
- const totalDocs = await this.count({ collection: slug, where: countWhere, tenantID });
525
- const offset = (page - 1) * limit;
526
- let results = [];
527
- try {
528
- const sortCol = table[sortOption.field] || table.createdAt || table.id;
529
- const sorted = sortOption.direction === "asc" ? sortCol : desc(sortCol);
530
- let query = this.client.select().from(table);
531
- if (filters.length > 0) {
532
- query = query.where(and(...filters));
533
- }
534
- results = await query.orderBy(sorted).limit(limit).offset(offset);
535
- } catch (error) {
536
- console.error(`[DrizzleAdapter] Query error:`, error);
537
- }
538
- let docs = results.map((doc) => this.processResult(doc, config));
539
- if (this.tenantContext && !this.tenantContext.isSuperAdmin) {
540
- docs = docs.filter((doc) => canAccessDocument(doc, slug, this.tenantContext, DEFAULT_RLS_CONFIG));
541
- }
542
- if (draft) {
543
- docs = await Promise.all(docs.map(async (doc) => {
544
- const versions = await this.executeRaw(sql`
545
- SELECT * FROM kyro_versions
546
- WHERE collection_slug = ${slug}
547
- AND document_id = ${doc.id}
548
- ORDER BY created_at DESC
549
- LIMIT 1
550
- `);
551
- if (versions.length > 0) {
552
- const ver = versions[0];
553
- const versionData = typeof ver.data === "string" ? JSON.parse(ver.data) : ver.data;
554
- return { ...doc, ...versionData, status: doc.status };
555
- }
556
- return doc;
557
- }));
558
- }
559
- return {
560
- docs,
561
- ...this.calculatePagination(page, limit, totalDocs)
562
- };
563
- }
564
- async findByID(args) {
565
- const { collection: slug, id, tenantID, draft } = args;
566
- const config = this.getCollection(slug);
567
- const table = this.getTable(slug);
568
- if (this.tenantContext && config.tenantScoped) {
569
- const tempDoc = { id, tenantId: this.tenantContext.tenantId };
570
- if (!canAccessDocument(tempDoc, slug, this.tenantContext, DEFAULT_RLS_CONFIG)) {
571
- return null;
572
- }
573
- }
574
- const conditions = [eq(table.id, id)];
575
- if (tenantID && table.tenantId) conditions.push(eq(table.tenantId, tenantID));
576
- if (!draft && table.status) conditions.push(eq(table.status, "published"));
577
- const whereClause = conditions.length > 1 ? and(...conditions) : conditions[0];
578
- let allRows = await this.client.select().from(table).where(whereClause);
579
- if (allRows.length === 0) return null;
580
- let doc = this.processResult(allRows[0], config);
581
- if (draft) {
582
- const versions = await this.executeRaw(sql`
583
- SELECT * FROM kyro_versions
584
- WHERE collection_slug = ${slug}
585
- AND document_id = ${doc.id}
586
- ORDER BY created_at DESC
587
- LIMIT 1
588
- `);
589
- if (versions.length > 0) {
590
- const ver = versions[0];
591
- const versionData = typeof ver.data === "string" ? JSON.parse(ver.data) : ver.data;
592
- doc = { ...doc, ...versionData, status: doc.status };
593
- }
594
- }
595
- return doc;
596
- }
597
- async create(args) {
598
- const { collection: slug, data, tenantID } = args;
599
- const config = this.getCollection(slug);
600
- const table = this.getTable(slug);
601
- const insertData = this.prepareData(data, config);
602
- if (tenantID) {
603
- insertData.tenantId = tenantID;
604
- }
605
- const result = await this.client.insert(table).values(insertData).returning();
606
- return this.processResult(result[0], config);
607
- }
608
- async update(args) {
609
- const { collection: slug, id, data, tenantID } = args;
610
- const config = this.getCollection(slug);
611
- const table = this.getTable(slug);
612
- const updateData = this.prepareData(data, config);
613
- delete updateData.id;
614
- const conditions = [eq(table.id, id)];
615
- if (tenantID && table.tenantId) {
616
- conditions.push(eq(table.tenantId, tenantID));
617
- }
618
- const result = await this.client.update(table).set(updateData).where(and(...conditions)).returning();
619
- if (result.length === 0) {
620
- throw new Error(`Document not found: ${slug}/${id}`);
621
- }
622
- return this.processResult(result[0], config);
623
- }
624
- async delete(args) {
625
- const { collection: slug, id, tenantID } = args;
626
- const config = this.getCollection(slug);
627
- const table = this.getTable(slug);
628
- const conditions = [eq(table.id, id)];
629
- if (tenantID && table.tenantId) {
630
- conditions.push(eq(table.tenantId, tenantID));
631
- }
632
- const result = await this.client.delete(table).where(and(...conditions)).returning();
633
- if (result.length === 0) {
634
- throw new Error(`Document not found: ${slug}/${id}`);
635
- }
636
- return this.processResult(result[0], config);
637
- }
638
- async count(args) {
639
- const { collection: slug, where = {}, tenantID } = args;
640
- const config = this.getCollection(slug);
641
- const table = this.getTable(slug);
642
- const filters = this.buildWhereClause(where, config, table, tenantID);
643
- try {
644
- let query = this.client.select({ count: sql`count(*)` }).from(table);
645
- if (filters.length > 0) {
646
- query = query.where(and(...filters));
647
- }
648
- const result = await query;
649
- return Number(result[0]?.count || 0);
650
- } catch {
651
- return 0;
652
- }
653
- }
654
- async findOne(args) {
655
- const { collection: slug, where = {}, tenantID, draft } = args;
656
- if (slug.startsWith("_globals_")) {
657
- const globalSlug = slug.replace("_globals_", "");
658
- const globalConfig = this.globals.get(globalSlug);
659
- if (!globalConfig) throw new Error(`Global "${globalSlug}" not found`);
660
- const table = this.getTable(slug);
661
- let query = this.client.select().from(table);
662
- if (!draft && table.status) {
663
- query = query.where(eq(table.status, "published"));
664
- }
665
- const results = await query.limit(1);
666
- if (results.length === 0) return null;
667
- let doc = this.processResult(results[0], globalConfig);
668
- if (draft) {
669
- const versions = await this.executeRaw(sql`
670
- SELECT * FROM kyro_versions
671
- WHERE collection_slug = ${slug}
672
- AND document_id = ${globalSlug}
673
- ORDER BY created_at DESC
674
- LIMIT 1
675
- `);
676
- if (versions.length > 0) {
677
- const ver = versions[0];
678
- const versionData = typeof ver.data === "string" ? JSON.parse(ver.data) : ver.data;
679
- doc = { ...doc, ...versionData, status: doc.status };
680
- }
681
- }
682
- return doc;
683
- }
684
- const result = await this.find({ ...args, limit: 1 });
685
- return result.docs[0] || null;
686
- }
687
- async findVersions(args) {
688
- await this.ensureVersionsTable();
689
- const { collection: slug, documentId, limit = 10, page = 1, tenantID } = args;
690
- const offset = (page - 1) * limit;
691
- const countResult = await this.executeRaw(sql`
692
- SELECT count(*) as count
693
- FROM kyro_versions
694
- WHERE collection_slug = ${slug}
695
- AND document_id = ${documentId}
696
- AND autosave = 0
697
- ${tenantID ? sql`AND tenant_id = ${tenantID}` : sql``}
698
- `);
699
- const totalDocs = parseInt(countResult[0]?.count || "0");
700
- const results = await this.executeRaw(sql`
701
- SELECT *
702
- FROM kyro_versions
703
- WHERE collection_slug = ${slug}
704
- AND document_id = ${documentId}
705
- AND autosave = 0
706
- ${tenantID ? sql`AND tenant_id = ${tenantID}` : sql``}
707
- ORDER BY created_at DESC
708
- LIMIT ${limit}
709
- OFFSET ${offset}
710
- `);
711
- return {
712
- docs: results.map((row) => ({
713
- ...row,
714
- data: typeof row.data === "string" ? JSON.parse(row.data) : row.data
715
- })),
716
- ...this.calculatePagination(page, limit, totalDocs)
717
- };
718
- }
719
- async findVersionByID(args) {
720
- await this.ensureVersionsTable();
721
- const results = await this.executeRaw(sql`
722
- SELECT * FROM kyro_versions
723
- WHERE id = ${args.versionId}
724
- AND collection_slug = ${args.collection}
725
- ${args.tenantID ? sql`AND tenant_id = ${args.tenantID}` : sql``}
726
- LIMIT 1
727
- `);
728
- if (results.length === 0) return null;
729
- const row = results[0];
730
- return {
731
- ...row,
732
- data: typeof row.data === "string" ? JSON.parse(row.data) : row.data
733
- };
734
- }
735
- async createVersion(args) {
736
- await this.ensureVersionsTable();
737
- const now = (/* @__PURE__ */ new Date()).toISOString();
738
- if (args.autosave) {
739
- const existing = await this.executeRaw(sql`
740
- SELECT * FROM kyro_versions
741
- WHERE collection_slug = ${args.collection}
742
- AND document_id = ${args.documentId}
743
- AND autosave = 1
744
- ${args.tenantID ? sql`AND tenant_id = ${args.tenantID}` : sql``}
745
- LIMIT 1
746
- `);
747
- if (existing.length > 0) {
748
- await this.executeRaw(sql`
749
- UPDATE kyro_versions
750
- SET data = ${JSON.stringify(args.data)},
751
- status = ${args.status},
752
- updated_at = ${now}
753
- WHERE id = ${existing[0].id}
754
- `);
755
- return this.findVersionByID({ collection: args.collection, versionId: existing[0].id, tenantID: args.tenantID });
756
- }
757
- }
758
- const id = Math.random().toString(36).substring(2, 15);
759
- await this.executeRaw(sql`
760
- INSERT INTO kyro_versions (
761
- id, collection_slug, document_id, tenant_id, data, status, autosave, created_by, change_description, created_at, updated_at
762
- ) VALUES (
763
- ${id}, ${args.collection}, ${args.documentId}, ${args.tenantID || null},
764
- ${JSON.stringify(args.data)}, ${args.status}, ${args.autosave ? 1 : 0}, ${args.createdBy || null},
765
- ${args.changeDescription || null}, ${now}, ${now}
766
- )
767
- `);
768
- if (!args.autosave) {
769
- const config = this.getCollection(args.collection);
770
- if (config.versions?.maxPerDoc) {
771
- await this.deleteVersions({
772
- collection: args.collection,
773
- documentId: args.documentId,
774
- keepLatest: config.versions.maxPerDoc,
775
- tenantID: args.tenantID
776
- });
777
- }
778
- }
779
- return this.findVersionByID({ collection: args.collection, versionId: id, tenantID: args.tenantID });
780
- }
781
- async updateLatestVersion(args) {
782
- return this.createVersion({ ...args, autosave: true });
783
- }
784
- async deleteVersions(args) {
785
- await this.ensureVersionsTable();
786
- if (args.keepLatest) {
787
- const toKeep = await this.executeRaw(sql`
788
- SELECT id FROM kyro_versions
789
- WHERE collection_slug = ${args.collection}
790
- AND document_id = ${args.documentId}
791
- AND autosave = 0
792
- ${args.tenantID ? sql`AND tenant_id = ${args.tenantID}` : sql``}
793
- ORDER BY created_at DESC
794
- LIMIT ${args.keepLatest}
795
- `);
796
- const keepIds = toKeep.map((r) => r.id);
797
- if (keepIds.length > 0) {
798
- await this.executeRaw(sql`
799
- DELETE FROM kyro_versions
800
- WHERE collection_slug = ${args.collection}
801
- AND document_id = ${args.documentId}
802
- AND autosave = 0
803
- AND id NOT IN (${sql.join(keepIds.map((id) => sql`${id}`), sql`, `)})
804
- `);
805
- }
806
- } else {
807
- await this.executeRaw(sql`
808
- DELETE FROM kyro_versions
809
- WHERE collection_slug = ${args.collection}
810
- AND document_id = ${args.documentId}
811
- ${args.tenantID ? sql`AND tenant_id = ${args.tenantID}` : sql``}
812
- `);
813
- }
814
- }
815
- // ========================================================================
816
- // Helper Methods
817
- // ========================================================================
818
- getTable(slug) {
819
- const tableName = this.getTableName(slug);
820
- const table = this.schema[tableName];
821
- if (!table) {
822
- throw new Error(`Table "${tableName}" not found in schema`);
823
- }
824
- return table;
825
- }
826
- buildWhereClause(where, config, table, tenantID) {
827
- const conditions = [];
828
- if (tenantID && config.tenantScoped && table.tenantId) {
829
- conditions.push(eq(table.tenantId, tenantID));
830
- }
831
- for (const [key, value] of Object.entries(where)) {
832
- if (key === "AND" && Array.isArray(value)) {
833
- const andConditions = value.map((sub) => this.buildWhereClause(sub, config, table)).flat().filter(Boolean);
834
- if (andConditions.length > 0) {
835
- conditions.push(and(...andConditions));
836
- }
837
- } else if (key === "OR" && Array.isArray(value)) {
838
- const orConditions = value.map((sub) => this.buildWhereClause(sub, config, table)).flat().filter(Boolean);
839
- if (orConditions.length > 0) {
840
- conditions.push(or(...orConditions));
841
- }
842
- } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
843
- const col = table[key];
844
- if (!col) continue;
845
- if (value.equals !== void 0) conditions.push(eq(col, value.equals));
846
- if (value.not_equals !== void 0) conditions.push(ne(col, value.not_equals));
847
- if (value.in && Array.isArray(value.in)) conditions.push(inArray(col, value.in));
848
- if (value.like !== void 0) conditions.push(like(col, value.like));
849
- if (value.contains !== void 0) conditions.push(like(col, `%${value.contains}%`));
850
- if (value.greater_than !== void 0) conditions.push(gt(col, value.greater_than));
851
- if (value.greater_than_equal !== void 0) conditions.push(gte(col, value.greater_than_equal));
852
- if (value.less_than !== void 0) conditions.push(lt(col, value.less_than));
853
- if (value.less_than_equal !== void 0) conditions.push(lte(col, value.less_than_equal));
854
- } else {
855
- const col = table[key];
856
- if (col) conditions.push(eq(col, value));
857
- }
858
- }
859
- return conditions;
860
- }
861
- processResult(data, config) {
862
- if (!data) return null;
863
- const result = { ...data };
864
- if (data.id) {
865
- result.id = String(data.id);
866
- }
867
- for (const field of config.fields) {
868
- if (!field.name) continue;
869
- const sqlKey = field.name.replace(/-/g, "_").replace(/([A-Z])/g, "_$1").toLowerCase();
870
- if (sqlKey !== field.name && result[sqlKey] !== void 0 && result[field.name] === void 0) {
871
- result[field.name] = result[sqlKey];
872
- delete result[sqlKey];
873
- }
874
- }
875
- for (const field of config.fields) {
876
- if (["json", "richtext", "array", "group", "blocks", "upload", "image", "list", "relationship-block"].includes(field.type)) {
877
- const f = field;
878
- if (result[f.name] && typeof result[f.name] === "string") {
879
- try {
880
- const parsed = JSON.parse(result[f.name]);
881
- result[f.name] = parsed;
882
- } catch {
883
- }
884
- }
885
- }
886
- if (field.type === "tabs" && "tabs" in field && field.name) {
887
- if (typeof result[field.name] === "object" && result[field.name] !== null && !Array.isArray(result[field.name])) {
888
- for (const tab of field.tabs) {
889
- for (const tabField of tab.fields) {
890
- if ((tabField.type === "upload" || tabField.type === "image") && tabField.name) {
891
- const val = result[field.name][tabField.name];
892
- if (typeof val === "string") {
893
- try {
894
- const parsed = JSON.parse(val);
895
- 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 || "");
896
- } catch {
897
- }
898
- } else if (val && typeof val === "object") {
899
- 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 || "");
900
- }
901
- }
902
- }
903
- }
904
- continue;
905
- }
906
- if (typeof result[field.name] === "string") {
907
- try {
908
- const parsed = JSON.parse(result[field.name]);
909
- if (typeof parsed === "object" && parsed !== null) {
910
- result[field.name] = parsed;
911
- continue;
912
- }
913
- } catch {
914
- }
915
- }
916
- const tabData = {};
917
- for (const tab of field.tabs) {
918
- for (const tabField of tab.fields) {
919
- if (tabField.name && result[tabField.name] !== void 0) {
920
- let value = result[tabField.name];
921
- if (["json", "richtext", "array", "group", "blocks", "upload", "image", "list", "relationship-block"].includes(tabField.type)) {
922
- if (value && typeof value === "string") {
923
- try {
924
- value = JSON.parse(value);
925
- } catch {
926
- }
927
- }
928
- if ((tabField.type === "upload" || tabField.type === "image") && value && typeof value === "object") {
929
- 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 || "");
930
- }
931
- }
932
- tabData[tabField.name] = value;
933
- delete result[tabField.name];
934
- }
935
- }
936
- }
937
- result[field.name] = tabData;
938
- }
939
- }
940
- if (result.createdAt) {
941
- result.createdAt = new Date(result.createdAt).toISOString();
942
- }
943
- if (result.updatedAt) {
944
- result.updatedAt = new Date(result.updatedAt).toISOString();
945
- }
946
- return result;
947
- }
948
- async ensureVersionsTable() {
949
- if (this.versionsTableReady) return;
950
- let createTableSQL;
951
- if (this.dialect === "sqlite") {
952
- createTableSQL = `
953
- CREATE TABLE IF NOT EXISTS kyro_versions (
954
- id text PRIMARY KEY,
955
- collection_slug text NOT NULL,
956
- document_id text NOT NULL,
957
- tenant_id text,
958
- data text NOT NULL,
959
- status text NOT NULL DEFAULT 'draft',
960
- autosave integer NOT NULL DEFAULT 0,
961
- created_by text,
962
- change_description text,
963
- created_at text DEFAULT (datetime('now')),
964
- updated_at text DEFAULT (datetime('now'))
965
- )
966
- `;
967
- } else {
968
- createTableSQL = `
969
- CREATE TABLE IF NOT EXISTS kyro_versions (
970
- id text PRIMARY KEY,
971
- collection_slug text NOT NULL,
972
- document_id text NOT NULL,
973
- tenant_id text,
974
- data text NOT NULL,
975
- status text NOT NULL,
976
- autosave integer NOT NULL DEFAULT 0,
977
- created_by text,
978
- change_description text,
979
- created_at text NOT NULL,
980
- updated_at text NOT NULL
981
- )
982
- `;
983
- }
984
- await this.executeRaw(sql.raw(createTableSQL));
985
- try {
986
- if (this.dialect === "postgres") {
987
- await this.executeRaw(sql.raw(`ALTER TABLE kyro_versions ADD COLUMN IF NOT EXISTS autosave integer NOT NULL DEFAULT 0`));
988
- } else {
989
- await this.executeRaw(sql.raw(`ALTER TABLE kyro_versions ADD COLUMN autosave integer NOT NULL DEFAULT 0`));
990
- }
991
- } catch {
992
- }
993
- this.versionsTableReady = true;
994
- }
995
- async executeRaw(query) {
996
- const result = await this.client.execute(query);
997
- if (Array.isArray(result)) {
998
- return result;
999
- }
1000
- if (Array.isArray(result?.rows)) {
1001
- return result.rows;
1002
- }
1003
- if (Array.isArray(result?.[0])) {
1004
- return result[0];
1005
- }
1006
- return [];
1007
- }
1008
- };
1009
- function createDrizzleAdapter(options) {
1010
- return new DrizzleAdapter(options);
1011
- }
1012
- var _require = createRequire(import.meta.url);
1013
- var modPath = "node:sqlite";
1014
- var { DatabaseSync } = _require(modPath);
1015
- function getDialect() {
1016
- const val = process.env.DB_TYPE;
1017
- if (val === "postgres") return "postgres";
1018
- return "sqlite";
1019
- }
1020
- function genId() {
1021
- return randomBytes(16).toString("hex");
1022
- }
1023
- async function createDatabase() {
1024
- const dialect = getDialect();
1025
- if (dialect === "sqlite") {
1026
- const dbPath = resolve(process.cwd(), "data", "kyro.db");
1027
- await mkdir(dirname(dbPath), { recursive: true });
1028
- const db2 = new DatabaseSync(dbPath);
1029
- db2.exec("PRAGMA journal_mode = WAL");
1030
- return { db: db2, dialect, genId };
1031
- }
1032
- const databaseUrl = process.env.DATABASE_URL || "postgresql://postgres:postgres@localhost:5432/kyro_cms";
1033
- const maxConnections = parseInt(process.env.DB_POOL_MAX || "10", 10);
1034
- const ssl = process.env.DB_SSL === "true";
1035
- const client = postgres(databaseUrl, {
1036
- max: maxConnections,
1037
- ssl: ssl ? "require" : false,
1038
- onnotice: () => {
1039
- }
1040
- });
1041
- const db = drizzle(client);
1042
- return { db, dialect, genId };
1043
- }
1044
- async function runMigrations(_db, _dialect) {
1045
- }
1046
- async function seedDefaultRoles(db) {
1047
- const { roles } = await import('./schema-FNNWEAAW.js');
1048
- await db.insert(roles).values({
1049
- name: "super_admin",
1050
- level: 100,
1051
- inherits: [],
1052
- description: "Full system access across all tenants",
1053
- isSystem: true
1054
- }).onConflictDoNothing();
1055
- }
1056
-
1057
- export { DrizzleAdapter, collectionToDrizzleSchema, createDatabase, createDrizzleAdapter, fieldToDrizzleType, genId, runMigrations, seedDefaultRoles };
1058
- //# sourceMappingURL=chunk-V5AWATUP.js.map
1059
- //# sourceMappingURL=chunk-V5AWATUP.js.map