@kyro-cms/core 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/README.md +57 -589
  2. package/dist/{WebhookService-118ZTFis.d.ts → WebhookService-CUTb9XOy.d.ts} +1 -1
  3. package/dist/{WebhookService-AefJfqX0.d.cts → WebhookService-Yg2UEOB4.d.cts} +1 -1
  4. package/dist/api-handler-graphql.cjs +44 -0
  5. package/dist/api-handler-graphql.cjs.map +1 -0
  6. package/dist/api-handler-graphql.d.cts +6 -0
  7. package/dist/api-handler-graphql.d.ts +6 -0
  8. package/dist/api-handler-graphql.js +41 -0
  9. package/dist/api-handler-graphql.js.map +1 -0
  10. package/dist/api-handler-trpc.cjs +38 -0
  11. package/dist/api-handler-trpc.cjs.map +1 -0
  12. package/dist/api-handler-trpc.d.cts +5 -0
  13. package/dist/api-handler-trpc.d.ts +5 -0
  14. package/dist/api-handler-trpc.js +36 -0
  15. package/dist/api-handler-trpc.js.map +1 -0
  16. package/dist/api-handler.cjs +31 -97
  17. package/dist/api-handler.cjs.map +1 -1
  18. package/dist/api-handler.d.cts +2 -1
  19. package/dist/api-handler.d.ts +2 -1
  20. package/dist/api-handler.js +19 -95
  21. package/dist/api-handler.js.map +1 -1
  22. package/dist/{tenant-B1YB0Jy8.d.ts → base-B71y_EAF.d.cts} +6 -12
  23. package/dist/{tenant-Cpeveji6.d.cts → base-DaqY2GhA.d.ts} +6 -12
  24. package/dist/bootstrap-5NLASFOG.cjs +32 -0
  25. package/dist/{bootstrap-AKAUP6F6.cjs.map → bootstrap-5NLASFOG.cjs.map} +1 -1
  26. package/dist/bootstrap-T5BK77LD.js +7 -0
  27. package/dist/{bootstrap-JCML6NFO.js.map → bootstrap-T5BK77LD.js.map} +1 -1
  28. package/dist/{chunk-35U3FROB.js → chunk-22M4O4ZJ.js} +607 -63
  29. package/dist/chunk-22M4O4ZJ.js.map +1 -0
  30. package/dist/chunk-2HZRBATX.cjs +253 -0
  31. package/dist/chunk-2HZRBATX.cjs.map +1 -0
  32. package/dist/{chunk-VJT6P4N6.cjs → chunk-3HR772HI.cjs} +199 -32
  33. package/dist/chunk-3HR772HI.cjs.map +1 -0
  34. package/dist/chunk-3KTWGODI.cjs +178 -0
  35. package/dist/chunk-3KTWGODI.cjs.map +1 -0
  36. package/dist/{chunk-QXIQWPAP.js → chunk-3UK5XBVJ.js} +4 -134
  37. package/dist/chunk-3UK5XBVJ.js.map +1 -0
  38. package/dist/{chunk-FXYP2HA6.js → chunk-4AO3A3JM.js} +48 -4
  39. package/dist/chunk-4AO3A3JM.js.map +1 -0
  40. package/dist/chunk-4M7X5HAB.cjs +173 -0
  41. package/dist/chunk-4M7X5HAB.cjs.map +1 -0
  42. package/dist/chunk-5EPFQUQD.js +3243 -0
  43. package/dist/chunk-5EPFQUQD.js.map +1 -0
  44. package/dist/{chunk-Y3N7UUDO.js → chunk-7OGPN7MP.js} +5 -2
  45. package/dist/chunk-7OGPN7MP.js.map +1 -0
  46. package/dist/{chunk-WOWUL7ZY.js → chunk-AL5KX63J.js} +4 -3
  47. package/dist/chunk-AL5KX63J.js.map +1 -0
  48. package/dist/{chunk-2OL4O2TH.cjs → chunk-C36TMDTY.cjs} +66 -61
  49. package/dist/chunk-C36TMDTY.cjs.map +1 -0
  50. package/dist/{chunk-ES5HNFFT.js → chunk-CF7OL6HR.js} +4 -2
  51. package/dist/chunk-CF7OL6HR.js.map +1 -0
  52. package/dist/chunk-CJONKRHJ.js +162 -0
  53. package/dist/chunk-CJONKRHJ.js.map +1 -0
  54. package/dist/{chunk-2KVHZE6O.cjs → chunk-COIASRDK.cjs} +202 -46
  55. package/dist/chunk-COIASRDK.cjs.map +1 -0
  56. package/dist/chunk-DEVFAKCQ.cjs +3291 -0
  57. package/dist/chunk-DEVFAKCQ.cjs.map +1 -0
  58. package/dist/{chunk-3ZFYL34R.js → chunk-DYTZ6FQ7.js} +12 -185
  59. package/dist/chunk-DYTZ6FQ7.js.map +1 -0
  60. package/dist/{chunk-QPPDLRNR.js → chunk-EJN2PAOE.js} +197 -41
  61. package/dist/chunk-EJN2PAOE.js.map +1 -0
  62. package/dist/chunk-FAXU7BMP.js +220 -0
  63. package/dist/chunk-FAXU7BMP.js.map +1 -0
  64. package/dist/{chunk-OHVB4AJ7.js → chunk-FOPGUM27.js} +22 -17
  65. package/dist/chunk-FOPGUM27.js.map +1 -0
  66. package/dist/chunk-GAOXD3XT.js +175 -0
  67. package/dist/chunk-GAOXD3XT.js.map +1 -0
  68. package/dist/{chunk-4DA7QPLA.cjs → chunk-GXFOGU7N.cjs} +5 -2
  69. package/dist/chunk-GXFOGU7N.cjs.map +1 -0
  70. package/dist/{chunk-I7HHI6QV.cjs → chunk-IDVRRRAK.cjs} +17 -9
  71. package/dist/chunk-IDVRRRAK.cjs.map +1 -0
  72. package/dist/{chunk-WQBRWOQT.cjs → chunk-JOPVMWTM.cjs} +3 -2
  73. package/dist/chunk-JOPVMWTM.cjs.map +1 -0
  74. package/dist/chunk-KC2GDBLS.cjs +84 -0
  75. package/dist/chunk-KC2GDBLS.cjs.map +1 -0
  76. package/dist/{chunk-K7JPTH3G.cjs → chunk-KNRSROWB.cjs} +132 -74
  77. package/dist/chunk-KNRSROWB.cjs.map +1 -0
  78. package/dist/{chunk-3AJE4SEG.js → chunk-KPA4AN4R.js} +125 -67
  79. package/dist/chunk-KPA4AN4R.js.map +1 -0
  80. package/dist/{chunk-QUW2RZTM.cjs → chunk-L46ROHUS.cjs} +51 -7
  81. package/dist/chunk-L46ROHUS.cjs.map +1 -0
  82. package/dist/chunk-L4EZKIEX.js +185 -0
  83. package/dist/chunk-L4EZKIEX.js.map +1 -0
  84. package/dist/{chunk-REK7AYOC.js → chunk-L5UKKZQN.js} +199 -32
  85. package/dist/chunk-L5UKKZQN.js.map +1 -0
  86. package/dist/chunk-NKPKR5BW.cjs +188 -0
  87. package/dist/chunk-NKPKR5BW.cjs.map +1 -0
  88. package/dist/{chunk-Y3QQN7PN.js → chunk-P2HKJ7P5.js} +13 -4
  89. package/dist/chunk-P2HKJ7P5.js.map +1 -0
  90. package/dist/{chunk-SA7NSSIQ.cjs → chunk-PI73NNOK.cjs} +13 -187
  91. package/dist/chunk-PI73NNOK.cjs.map +1 -0
  92. package/dist/{chunk-HXRD4B37.js → chunk-PU2Z5VWF.js} +1279 -556
  93. package/dist/chunk-PU2Z5VWF.js.map +1 -0
  94. package/dist/{chunk-H727JIG7.js → chunk-Q72BOAPK.js} +16 -8
  95. package/dist/chunk-Q72BOAPK.js.map +1 -0
  96. package/dist/{chunk-IBG6V56E.cjs → chunk-QFLB4EIJ.cjs} +2 -139
  97. package/dist/chunk-QFLB4EIJ.cjs.map +1 -0
  98. package/dist/{chunk-YVUJBEXE.cjs → chunk-RAMGUDJN.cjs} +16 -7
  99. package/dist/chunk-RAMGUDJN.cjs.map +1 -0
  100. package/dist/{chunk-LINKCEG4.cjs → chunk-ROJHKAQ4.cjs} +617 -73
  101. package/dist/chunk-ROJHKAQ4.cjs.map +1 -0
  102. package/dist/{chunk-5KVM3WEY.cjs → chunk-RSF3UU7H.cjs} +1330 -602
  103. package/dist/chunk-RSF3UU7H.cjs.map +1 -0
  104. package/dist/{chunk-V3LKPM3O.cjs → chunk-SHTTJMLT.cjs} +4 -2
  105. package/dist/chunk-SHTTJMLT.cjs.map +1 -0
  106. package/dist/chunk-SPBTLUN6.js +92 -0
  107. package/dist/chunk-SPBTLUN6.js.map +1 -0
  108. package/dist/{chunk-57P6MJKC.js → chunk-TXSZFA4G.js} +3 -3
  109. package/dist/chunk-TXSZFA4G.js.map +1 -0
  110. package/dist/chunk-UERVXYVK.cjs +99 -0
  111. package/dist/chunk-UERVXYVK.cjs.map +1 -0
  112. package/dist/{chunk-PDYFVNUX.cjs → chunk-V2TVSCV5.cjs} +16 -23
  113. package/dist/chunk-V2TVSCV5.cjs.map +1 -0
  114. package/dist/{chunk-DXHRBMGB.js → chunk-VO35MNPH.js} +12 -19
  115. package/dist/chunk-VO35MNPH.js.map +1 -0
  116. package/dist/{chunk-IA6AU5PI.cjs → chunk-WNCYAKF3.cjs} +3 -3
  117. package/dist/chunk-WNCYAKF3.cjs.map +1 -0
  118. package/dist/chunk-XEB7PH2E.js +81 -0
  119. package/dist/chunk-XEB7PH2E.js.map +1 -0
  120. package/dist/cli/index.cjs +5 -5
  121. package/dist/cli/index.cjs.map +1 -1
  122. package/dist/cli/index.js +5 -5
  123. package/dist/cli/index.js.map +1 -1
  124. package/dist/client.cjs +3 -3
  125. package/dist/client.d.cts +3 -3
  126. package/dist/client.d.ts +3 -3
  127. package/dist/client.js +1 -1
  128. package/dist/drizzle/index.cjs +14 -13
  129. package/dist/drizzle/index.d.cts +9 -7
  130. package/dist/drizzle/index.d.ts +9 -7
  131. package/dist/drizzle/index.js +5 -4
  132. package/dist/fields/index.cjs +21 -37
  133. package/dist/fields/index.d.cts +2 -22
  134. package/dist/fields/index.d.ts +2 -22
  135. package/dist/fields/index.js +1 -1
  136. package/dist/graphql/index.cjs +5 -4
  137. package/dist/graphql/index.d.cts +5 -3
  138. package/dist/graphql/index.d.ts +5 -3
  139. package/dist/graphql/index.js +3 -2
  140. package/dist/index-CJXPB_ot.d.ts +276 -0
  141. package/dist/index-CaTNnLGd.d.cts +276 -0
  142. package/dist/index.cjs +304 -162
  143. package/dist/index.cjs.map +1 -1
  144. package/dist/index.d.cts +129 -205
  145. package/dist/index.d.ts +129 -205
  146. package/dist/index.js +172 -33
  147. package/dist/index.js.map +1 -1
  148. package/dist/integration.cjs +2 -2
  149. package/dist/integration.js +1 -1
  150. package/dist/mongo-auth-adapter-ISOM7FSS.cjs +17 -0
  151. package/dist/{mongo-auth-adapter-NHHUJHVH.cjs.map → mongo-auth-adapter-ISOM7FSS.cjs.map} +1 -1
  152. package/dist/mongo-auth-adapter-MO6STCV3.js +4 -0
  153. package/dist/{mongo-auth-adapter-NJQUUCTP.js.map → mongo-auth-adapter-MO6STCV3.js.map} +1 -1
  154. package/dist/mongodb/index.cjs +8 -7
  155. package/dist/mongodb/index.d.cts +5 -7
  156. package/dist/mongodb/index.d.ts +5 -7
  157. package/dist/mongodb/index.js +4 -3
  158. package/dist/postgres-auth-adapter-DWDR7P5G.js +5 -0
  159. package/dist/{postgres-auth-adapter-3T2NKTSE.js.map → postgres-auth-adapter-DWDR7P5G.js.map} +1 -1
  160. package/dist/postgres-auth-adapter-WRWSJD4E.cjs +14 -0
  161. package/dist/{postgres-auth-adapter-7IEENCKQ.cjs.map → postgres-auth-adapter-WRWSJD4E.cjs.map} +1 -1
  162. package/dist/redis-adapter-HGTPWIGV.js +4 -0
  163. package/dist/{redis-adapter-VQXD7ESY.js.map → redis-adapter-HGTPWIGV.js.map} +1 -1
  164. package/dist/redis-adapter-KJ3YOOT6.cjs +13 -0
  165. package/dist/{redis-adapter-D2E2S3GB.cjs.map → redis-adapter-KJ3YOOT6.cjs.map} +1 -1
  166. package/dist/rest/index.cjs +15 -14
  167. package/dist/rest/index.d.cts +4 -4
  168. package/dist/rest/index.d.ts +4 -4
  169. package/dist/rest/index.js +13 -12
  170. package/dist/{schema-5PHL5IVB.js → schema-6I5OFR4Z.js} +3 -3
  171. package/dist/{schema-5PHL5IVB.js.map → schema-6I5OFR4Z.js.map} +1 -1
  172. package/dist/{schema-37SE2F4B.cjs → schema-TTFE4467.cjs} +14 -14
  173. package/dist/{schema-37SE2F4B.cjs.map → schema-TTFE4467.cjs.map} +1 -1
  174. package/dist/sqlite-adapter-6GEUSVXQ.js +4 -0
  175. package/dist/{sqlite-adapter-TR3U3W6Q.js.map → sqlite-adapter-6GEUSVXQ.js.map} +1 -1
  176. package/dist/sqlite-adapter-CSIZE5SX.cjs +13 -0
  177. package/dist/{sqlite-adapter-LVK5PS4T.cjs.map → sqlite-adapter-CSIZE5SX.cjs.map} +1 -1
  178. package/dist/templates/index.cjs +133 -31
  179. package/dist/templates/index.d.cts +52 -9
  180. package/dist/templates/index.d.ts +52 -9
  181. package/dist/templates/index.js +3 -1
  182. package/dist/trpc/index.cjs +13 -12
  183. package/dist/trpc/index.d.cts +55 -49
  184. package/dist/trpc/index.d.ts +55 -49
  185. package/dist/trpc/index.js +4 -3
  186. package/dist/{types-D6ZLRGbH.d.cts → types-CpjuXbe7.d.cts} +2 -0
  187. package/dist/{types-D6ZLRGbH.d.ts → types-CpjuXbe7.d.ts} +2 -0
  188. package/dist/{types-Bs1up4yP.d.ts → types-CyCQ6SAI.d.ts} +28 -2
  189. package/dist/{types-J3R9nVsZ.d.cts → types-DJxD9394.d.cts} +28 -2
  190. package/dist/{types-VtjUxIMp.d.cts → types-Z6FBiqa2.d.cts} +35 -14
  191. package/dist/{types-VtjUxIMp.d.ts → types-Z6FBiqa2.d.ts} +35 -14
  192. package/package.json +22 -4
  193. package/dist/bootstrap-AKAUP6F6.cjs +0 -32
  194. package/dist/bootstrap-JCML6NFO.js +0 -7
  195. package/dist/chunk-2KVHZE6O.cjs.map +0 -1
  196. package/dist/chunk-2OL4O2TH.cjs.map +0 -1
  197. package/dist/chunk-35U3FROB.js.map +0 -1
  198. package/dist/chunk-3AJE4SEG.js.map +0 -1
  199. package/dist/chunk-3J4MFTI3.js +0 -3872
  200. package/dist/chunk-3J4MFTI3.js.map +0 -1
  201. package/dist/chunk-3ZFYL34R.js.map +0 -1
  202. package/dist/chunk-4DA7QPLA.cjs.map +0 -1
  203. package/dist/chunk-57P6MJKC.js.map +0 -1
  204. package/dist/chunk-5KVM3WEY.cjs.map +0 -1
  205. package/dist/chunk-6IMPH6WV.cjs +0 -3897
  206. package/dist/chunk-6IMPH6WV.cjs.map +0 -1
  207. package/dist/chunk-ATBOUGQP.cjs +0 -513
  208. package/dist/chunk-ATBOUGQP.cjs.map +0 -1
  209. package/dist/chunk-DXHRBMGB.js.map +0 -1
  210. package/dist/chunk-ES5HNFFT.js.map +0 -1
  211. package/dist/chunk-FXYP2HA6.js.map +0 -1
  212. package/dist/chunk-H727JIG7.js.map +0 -1
  213. package/dist/chunk-HXRD4B37.js.map +0 -1
  214. package/dist/chunk-I7HHI6QV.cjs.map +0 -1
  215. package/dist/chunk-IA6AU5PI.cjs.map +0 -1
  216. package/dist/chunk-IBG6V56E.cjs.map +0 -1
  217. package/dist/chunk-K7JPTH3G.cjs.map +0 -1
  218. package/dist/chunk-LINKCEG4.cjs.map +0 -1
  219. package/dist/chunk-OHVB4AJ7.js.map +0 -1
  220. package/dist/chunk-PDYFVNUX.cjs.map +0 -1
  221. package/dist/chunk-Q23JB3KL.js +0 -488
  222. package/dist/chunk-Q23JB3KL.js.map +0 -1
  223. package/dist/chunk-QPPDLRNR.js.map +0 -1
  224. package/dist/chunk-QUW2RZTM.cjs.map +0 -1
  225. package/dist/chunk-QXIQWPAP.js.map +0 -1
  226. package/dist/chunk-R3XIBBAW.cjs +0 -34
  227. package/dist/chunk-R3XIBBAW.cjs.map +0 -1
  228. package/dist/chunk-REK7AYOC.js.map +0 -1
  229. package/dist/chunk-SA7NSSIQ.cjs.map +0 -1
  230. package/dist/chunk-SDMNUYVU.js +0 -30
  231. package/dist/chunk-SDMNUYVU.js.map +0 -1
  232. package/dist/chunk-V3LKPM3O.cjs.map +0 -1
  233. package/dist/chunk-VJT6P4N6.cjs.map +0 -1
  234. package/dist/chunk-WOWUL7ZY.js.map +0 -1
  235. package/dist/chunk-WQBRWOQT.cjs.map +0 -1
  236. package/dist/chunk-Y3N7UUDO.js.map +0 -1
  237. package/dist/chunk-Y3QQN7PN.js.map +0 -1
  238. package/dist/chunk-YVUJBEXE.cjs.map +0 -1
  239. package/dist/index-CLp-DRKA.d.ts +0 -64
  240. package/dist/index-DfO7G4kN.d.cts +0 -64
  241. package/dist/mongo-auth-adapter-NHHUJHVH.cjs +0 -17
  242. package/dist/mongo-auth-adapter-NJQUUCTP.js +0 -4
  243. package/dist/postgres-auth-adapter-3T2NKTSE.js +0 -5
  244. package/dist/postgres-auth-adapter-7IEENCKQ.cjs +0 -14
  245. package/dist/redis-adapter-D2E2S3GB.cjs +0 -13
  246. package/dist/redis-adapter-VQXD7ESY.js +0 -4
  247. package/dist/sqlite-adapter-LVK5PS4T.cjs +0 -13
  248. package/dist/sqlite-adapter-TR3U3W6Q.js +0 -4
@@ -1,12 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunkK7JPTH3G_cjs = require('./chunk-K7JPTH3G.cjs');
4
- var chunk5KVM3WEY_cjs = require('./chunk-5KVM3WEY.cjs');
5
- var chunkIBG6V56E_cjs = require('./chunk-IBG6V56E.cjs');
6
- var chunkVJT6P4N6_cjs = require('./chunk-VJT6P4N6.cjs');
3
+ var chunk3KTWGODI_cjs = require('./chunk-3KTWGODI.cjs');
4
+ var chunkKNRSROWB_cjs = require('./chunk-KNRSROWB.cjs');
5
+ var chunk3HR772HI_cjs = require('./chunk-3HR772HI.cjs');
6
+ var chunkRSF3UU7H_cjs = require('./chunk-RSF3UU7H.cjs');
7
+ var chunkQFLB4EIJ_cjs = require('./chunk-QFLB4EIJ.cjs');
8
+ var chunk4M7X5HAB_cjs = require('./chunk-4M7X5HAB.cjs');
7
9
  var chunkDVD5P72E_cjs = require('./chunk-DVD5P72E.cjs');
8
- var chunkSA7NSSIQ_cjs = require('./chunk-SA7NSSIQ.cjs');
10
+ var chunkPI73NNOK_cjs = require('./chunk-PI73NNOK.cjs');
9
11
  var zod = require('zod');
12
+ var graphql = require('graphql');
10
13
  var module$1 = require('module');
11
14
  var crypto = require('crypto');
12
15
 
@@ -177,9 +180,9 @@ function validateFields(fields, context) {
177
180
  break;
178
181
  case "select":
179
182
  case "radio":
180
- if (!field.options || field.options.length === 0) {
183
+ if ((!field.options || field.options.length === 0) && !field.dynamicOptions) {
181
184
  errors.push(`${context}: ${field.type} field "${fieldName}" has no options defined`);
182
- } else {
185
+ } else if (field.options) {
183
186
  const values = field.options.map((o) => o.value);
184
187
  const uniqueValues = new Set(values);
185
188
  if (values.length !== uniqueValues.size) {
@@ -268,7 +271,7 @@ function validateRelationships(fields, collections) {
268
271
  const targets = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo];
269
272
  for (const target of targets) {
270
273
  if (!collectionSlugs.has(target)) {
271
- errors.push(`Relationship field "${field.name}" references unknown collection "${target}"`);
274
+ console.warn(`[Kyro Config Warning]: Relationship field "${field.name}" references unknown collection "${target}". Select options will not be available until this collection is registered.`);
272
275
  }
273
276
  }
274
277
  }
@@ -368,7 +371,7 @@ function textToZod(field) {
368
371
  return schema;
369
372
  }
370
373
  function numberToZod(field) {
371
- let schema = field.integer ? zod.z.number().int() : zod.z.number();
374
+ let schema = field.integer ? zod.z.coerce.number().int() : zod.z.coerce.number();
372
375
  if (field.min !== void 0) schema = schema.min(field.min);
373
376
  if (field.max !== void 0) schema = schema.max(field.max);
374
377
  if (field.step) {
@@ -427,12 +430,16 @@ function textareaToZod(field) {
427
430
  return schema;
428
431
  }
429
432
  function selectToZod(field) {
430
- const values = field.options.map((opt) => opt.value);
431
433
  let schema;
432
- if (field.hasMany) {
433
- schema = zod.z.array(zod.z.enum(values));
434
+ if (field.options && field.options.length > 0) {
435
+ const values = field.options.map((opt) => opt.value);
436
+ if (field.hasMany) {
437
+ schema = zod.z.array(zod.z.enum(values));
438
+ } else {
439
+ schema = zod.z.enum(values);
440
+ }
434
441
  } else {
435
- schema = zod.z.enum(values);
442
+ schema = field.hasMany ? zod.z.array(zod.z.string()) : zod.z.string();
436
443
  }
437
444
  if (!field.required) schema = schema.optional().nullable();
438
445
  if (field.validate) schema = addCustomValidation(schema, field.validate);
@@ -462,10 +469,7 @@ function colorToZod(field) {
462
469
  return schema;
463
470
  }
464
471
  function richTextToZod(field) {
465
- let schema = zod.z.union([
466
- zod.z.array(zod.z.record(zod.z.any())),
467
- zod.z.string()
468
- ]);
472
+ let schema = zod.z.array(zod.z.record(zod.z.any()));
469
473
  if (!field.required) schema = schema.optional().nullable();
470
474
  if (field.validate) schema = addCustomValidation(schema, field.validate);
471
475
  return schema;
@@ -576,9 +580,9 @@ function blocksToZod(field) {
576
580
  const unknownSchema = zod.z.object({
577
581
  blockType: zod.z.string()
578
582
  }).catchall(zod.z.any());
579
- schema = zod.z.array(zod.z.union([knownSchema, unknownSchema]));
583
+ schema = zod.z.array(zod.z.union([knownSchema, unknownSchema, zod.z.record(zod.z.any())]));
580
584
  } else {
581
- schema = zod.z.array(zod.z.object({ blockType: zod.z.string() }).catchall(zod.z.any()));
585
+ schema = zod.z.array(zod.z.union([zod.z.object({ blockType: zod.z.string() }).catchall(zod.z.any()), zod.z.record(zod.z.any())]));
582
586
  }
583
587
  if (field.minRows) schema = schema.min(field.minRows);
584
588
  if (field.maxRows) schema = schema.max(field.maxRows);
@@ -724,6 +728,7 @@ function globalToZod(global) {
724
728
 
725
729
  // src/registry/index.ts
726
730
  var Registry = class {
731
+ storageProviders = chunkRSF3UU7H_cjs.getDefaultRegistry();
727
732
  collections = /* @__PURE__ */ new Map();
728
733
  globals = /* @__PURE__ */ new Map();
729
734
  plugins = [];
@@ -791,6 +796,19 @@ var Registry = class {
791
796
  if (this.initialized) {
792
797
  throw new Error("Cannot add globals after Registry has been initialized");
793
798
  }
799
+ this._addGlobalUnsafe(config);
800
+ }
801
+ /**
802
+ * Add a global after the registry is already initialized.
803
+ * Only for internal use (e.g. storage settings form built at startup).
804
+ */
805
+ addGlobalPostInit(config) {
806
+ if (this.globals.has(config.slug)) {
807
+ this.globals.delete(config.slug);
808
+ }
809
+ this._addGlobalUnsafe(config);
810
+ }
811
+ _addGlobalUnsafe(config) {
794
812
  if (this.globals.has(config.slug)) {
795
813
  console.warn(
796
814
  `[Registry] Duplicate global slug "${config.slug}" \u2014 skipping`
@@ -945,6 +963,17 @@ var Registry = class {
945
963
  admin: { readOnly: true, hidden: true }
946
964
  });
947
965
  }
966
+ if (config.versions?.drafts && !fields.some((f) => f.name === "publishStatus")) {
967
+ fields.push({
968
+ name: "publishStatus",
969
+ type: "select",
970
+ options: [
971
+ { value: "draft", label: "Draft" },
972
+ { value: "published", label: "Published" }
973
+ ],
974
+ admin: { readOnly: true, hidden: true }
975
+ });
976
+ }
948
977
  if (config.auth && !fields.some((f) => f.name === "password")) {
949
978
  fields.push({
950
979
  name: "password",
@@ -1089,6 +1118,296 @@ function createRegistry() {
1089
1118
  instance = new Registry();
1090
1119
  return instance;
1091
1120
  }
1121
+
1122
+ // src/plugins/storage-s3.ts
1123
+ var s3Variants = {
1124
+ aws: {
1125
+ type: "aws",
1126
+ configKey: "s3",
1127
+ displayName: "S3 Compatible (AWS, Backblaze, Wasabi, etc.)",
1128
+ configFields: [
1129
+ { name: "bucket", type: "text", label: "Bucket Name", required: true },
1130
+ { name: "region", type: "text", label: "Region", defaultValue: "us-east-1", admin: { placeholder: "us-east-1" } },
1131
+ { name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
1132
+ { name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
1133
+ { name: "endpoint", type: "text", label: "Endpoint URL", admin: { placeholder: "https://s3.custom.com" } },
1134
+ { name: "cdnUrl", type: "text", label: "CDN URL", admin: { placeholder: "https://cdn.example.com" } },
1135
+ { name: "prefix", type: "text", label: "Path Prefix", admin: { placeholder: "uploads" } }
1136
+ ]
1137
+ },
1138
+ r2: {
1139
+ type: "r2",
1140
+ configKey: "r2",
1141
+ displayName: "Cloudflare R2",
1142
+ configFields: [
1143
+ { name: "accountId", type: "text", label: "Account ID", required: true, admin: { placeholder: "Your Cloudflare Account ID" } },
1144
+ { name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
1145
+ { name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
1146
+ { name: "bucket", type: "text", label: "Bucket Name", required: true },
1147
+ {
1148
+ name: "publicDevUrl",
1149
+ type: "text",
1150
+ label: "Public Dev URL ID",
1151
+ admin: {
1152
+ placeholder: "pub-xxxxxxxxxxxxxxxx",
1153
+ description: "Enter ONLY the ID (e.g., pub-b8d8c4cc8bcf4d868ddd95efc1b305aa). Do NOT include https:// or the full URL. Found in R2 Dashboard \u2192 Public Dev URL."
1154
+ }
1155
+ },
1156
+ { name: "cdnUrl", type: "text", label: "Custom CDN URL", admin: { placeholder: "https://assets.example.com (optional)" } },
1157
+ { name: "prefix", type: "text", label: "Path Prefix", admin: { placeholder: "uploads (optional)", description: "Optional prefix for all object keys. Do not use '/' as prefix." } }
1158
+ ]
1159
+ },
1160
+ gcs: {
1161
+ type: "gcs",
1162
+ configKey: "gcs",
1163
+ displayName: "Google Cloud Storage",
1164
+ configFields: [
1165
+ { name: "bucket", type: "text", label: "Bucket Name", required: true },
1166
+ { name: "projectId", type: "text", label: "Project ID" },
1167
+ { name: "clientEmail", type: "text", label: "Client Email" },
1168
+ { name: "privateKey", type: "password", label: "Private Key" },
1169
+ { name: "cdnUrl", type: "text", label: "CDN URL" },
1170
+ { name: "prefix", type: "text", label: "Path Prefix" }
1171
+ ]
1172
+ },
1173
+ digitalocean: {
1174
+ type: "digitalocean",
1175
+ configKey: "digitalocean",
1176
+ displayName: "DigitalOcean Spaces",
1177
+ configFields: [
1178
+ { name: "bucket", type: "text", label: "Bucket Name", required: true },
1179
+ { name: "region", type: "text", label: "Region", defaultValue: "nyc3" },
1180
+ { name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
1181
+ { name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
1182
+ { name: "cdnUrl", type: "text", label: "CDN URL" },
1183
+ { name: "prefix", type: "text", label: "Path Prefix" }
1184
+ ]
1185
+ },
1186
+ backblaze: {
1187
+ type: "backblaze",
1188
+ configKey: "backblaze",
1189
+ displayName: "Backblaze B2",
1190
+ configFields: [
1191
+ { name: "bucket", type: "text", label: "Bucket Name", required: true },
1192
+ { name: "accountId", type: "text", label: "Account ID" },
1193
+ { name: "applicationKeyId", type: "text", label: "Application Key ID", required: true },
1194
+ { name: "applicationKey", type: "password", label: "Application Key", required: true },
1195
+ { name: "cdnUrl", type: "text", label: "CDN URL" },
1196
+ { name: "prefix", type: "text", label: "Path Prefix" }
1197
+ ]
1198
+ },
1199
+ wasabi: {
1200
+ type: "wasabi",
1201
+ configKey: "wasabi",
1202
+ displayName: "Wasabi",
1203
+ configFields: [
1204
+ { name: "bucket", type: "text", label: "Bucket Name", required: true },
1205
+ { name: "region", type: "text", label: "Region", defaultValue: "us-east-1" },
1206
+ { name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
1207
+ { name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
1208
+ { name: "cdnUrl", type: "text", label: "CDN URL" },
1209
+ { name: "prefix", type: "text", label: "Path Prefix" }
1210
+ ]
1211
+ }
1212
+ };
1213
+ function getEndpoint(type, config) {
1214
+ switch (type) {
1215
+ case "r2":
1216
+ return config?.endpoint || `https://${config?.accountId || ""}.r2.cloudflarestorage.com`;
1217
+ case "digitalocean":
1218
+ return config?.endpoint || `https://${config?.region || "nyc3"}.digitaloceanspaces.com`;
1219
+ case "backblaze":
1220
+ return config?.endpoint || `https://s3.backblazeb2.com`;
1221
+ case "wasabi":
1222
+ return config?.endpoint || `https://s3.${config?.region || "us-east-1"}.wasabisys.com`;
1223
+ default:
1224
+ return config?.endpoint;
1225
+ }
1226
+ }
1227
+ function buildS3Config(type, c) {
1228
+ return {
1229
+ provider: type,
1230
+ bucket: c?.bucket || "",
1231
+ region: c?.region || "us-east-1",
1232
+ accessKeyId: c?.accessKeyId || c?.clientEmail || c?.applicationKeyId || "",
1233
+ secretAccessKey: c?.secretAccessKey || c?.privateKey || c?.applicationKey || "",
1234
+ endpoint: getEndpoint(type, c),
1235
+ cdnUrl: c?.cdnUrl,
1236
+ prefix: c?.prefix,
1237
+ accountId: c?.accountId,
1238
+ publicDevUrl: c?.publicDevUrl
1239
+ };
1240
+ }
1241
+ function buildS3ConfigFromStorageConfig(type, def, sc) {
1242
+ const c = sc[def.configKey] || {};
1243
+ return buildS3Config(type, c);
1244
+ }
1245
+ function buildS3ConfigFromRaw(type, def, raw) {
1246
+ const c = raw?.[def.configKey] || raw;
1247
+ return buildS3Config(type, c);
1248
+ }
1249
+ var s3StoragePlugin = {
1250
+ name: "@kyro-cms/storage-s3",
1251
+ version: "1.0.0",
1252
+ description: "S3-compatible storage (AWS R2 GCS DigitalOcean Backblaze Wasabi)",
1253
+ init: (kyro) => {
1254
+ const registry = kyro.storageProviders;
1255
+ if (!registry) return;
1256
+ const pluginName = "@kyro-cms/storage-s3";
1257
+ for (const v of Object.values(s3Variants)) {
1258
+ registry.register({
1259
+ type: v.type,
1260
+ displayName: v.displayName,
1261
+ pluginName,
1262
+ configKey: v.configKey,
1263
+ configFields: v.configFields,
1264
+ extractConfig: (sc) => buildS3ConfigFromStorageConfig(v.type, v, sc),
1265
+ extractRawConfig: (raw) => buildS3ConfigFromRaw(v.type, v, raw),
1266
+ factory: (c) => chunkRSF3UU7H_cjs.createS3Storage(c)
1267
+ });
1268
+ }
1269
+ }
1270
+ };
1271
+
1272
+ // src/plugins/storage-cloudinary.ts
1273
+ var cloudinaryStoragePlugin = {
1274
+ name: "@kyro-cms/storage-cloudinary",
1275
+ version: "1.0.0",
1276
+ description: "Cloudinary image and video storage",
1277
+ init: (kyro) => {
1278
+ const registry = kyro.storageProviders;
1279
+ if (!registry) return;
1280
+ registry.register({
1281
+ type: "cloudinary",
1282
+ displayName: "Cloudinary",
1283
+ pluginName: "@kyro-cms/storage-cloudinary",
1284
+ configKey: "cloudinary",
1285
+ configFields: [
1286
+ { name: "cloudName", type: "text", label: "Cloud Name", required: true },
1287
+ { name: "apiKey", type: "text", label: "API Key", required: true },
1288
+ { name: "apiSecret", type: "password", label: "API Secret", required: true },
1289
+ { name: "folder", type: "text", label: "Folder", admin: { placeholder: "Optional folder path" } },
1290
+ {
1291
+ name: "uploadPreset",
1292
+ type: "text",
1293
+ label: "Upload Preset (optional)",
1294
+ admin: { placeholder: "Leave empty for signed uploads", description: "If not set, uploads will be signed with API Secret" }
1295
+ }
1296
+ ],
1297
+ extractConfig: (sc) => ({
1298
+ cloudName: sc.cloudinary?.cloudName || "",
1299
+ apiKey: sc.cloudinary?.apiKey || "",
1300
+ apiSecret: sc.cloudinary?.apiSecret || "",
1301
+ folder: sc.cloudinary?.folder,
1302
+ uploadPreset: sc.cloudinary?.uploadPreset
1303
+ }),
1304
+ extractRawConfig: (c) => {
1305
+ const cl = c?.cloudinary || c;
1306
+ return {
1307
+ cloudName: cl?.cloudName || "",
1308
+ apiKey: cl?.apiKey || "",
1309
+ apiSecret: cl?.apiSecret || "",
1310
+ folder: cl?.folder,
1311
+ uploadPreset: cl?.uploadPreset
1312
+ };
1313
+ },
1314
+ factory: (c) => chunkRSF3UU7H_cjs.createCloudinaryStorage(c)
1315
+ });
1316
+ }
1317
+ };
1318
+
1319
+ // src/plugins/storage-ftp.ts
1320
+ var ftpStoragePlugin = {
1321
+ name: "@kyro-cms/storage-ftp",
1322
+ version: "1.0.0",
1323
+ description: "FTP/SFTP storage provider",
1324
+ init: (kyro) => {
1325
+ const registry = kyro.storageProviders;
1326
+ if (!registry) return;
1327
+ registry.register({
1328
+ type: "ftp",
1329
+ displayName: "FTP",
1330
+ pluginName: "@kyro-cms/storage-ftp",
1331
+ configKey: "ftp",
1332
+ configFields: [
1333
+ { name: "host", type: "text", label: "Host", required: true, admin: { placeholder: "ftp.example.com" } },
1334
+ { name: "port", type: "number", label: "Port", defaultValue: 21, admin: { placeholder: "21 for FTP" } },
1335
+ { name: "user", type: "text", label: "Username", required: true },
1336
+ { name: "password", type: "password", label: "Password", required: true },
1337
+ { name: "secure", type: "checkbox", label: "Use TLS/SSL", defaultValue: false, admin: { description: "Enable TLS/SSL for secure connections (FTP only)" } },
1338
+ { name: "baseUrl", type: "text", label: "Base URL", required: true, admin: { placeholder: "https://files.example.com" } },
1339
+ { name: "prefix", type: "text", label: "Path Prefix", admin: { placeholder: "uploads" } }
1340
+ ],
1341
+ extractConfig: (sc) => ({
1342
+ host: sc.ftp?.host || "",
1343
+ port: sc.ftp?.port || 21,
1344
+ user: sc.ftp?.user || "",
1345
+ password: sc.ftp?.password || "",
1346
+ secure: sc.ftp?.secure || false,
1347
+ baseUrl: sc.ftp?.baseUrl || "",
1348
+ prefix: sc.ftp?.prefix,
1349
+ type: "ftp"
1350
+ }),
1351
+ extractRawConfig: (c) => {
1352
+ const ftp = c?.ftp || c;
1353
+ return {
1354
+ host: ftp?.host || "",
1355
+ port: ftp?.port || 21,
1356
+ user: ftp?.user || "",
1357
+ password: ftp?.password || "",
1358
+ secure: ftp?.secure || false,
1359
+ baseUrl: ftp?.baseUrl || "",
1360
+ prefix: ftp?.prefix,
1361
+ type: "ftp"
1362
+ };
1363
+ },
1364
+ factory: (c) => chunkRSF3UU7H_cjs.createFtpStorage(c)
1365
+ });
1366
+ }
1367
+ };
1368
+ var builtinStoragePlugins = [
1369
+ s3StoragePlugin,
1370
+ cloudinaryStoragePlugin,
1371
+ ftpStoragePlugin
1372
+ ];
1373
+ function updateFieldByPath(fields, path, updates) {
1374
+ const parts = path.split(".");
1375
+ if (parts.length === 0) return false;
1376
+ const currentPart = parts[0];
1377
+ const remainingPath = parts.slice(1).join(".");
1378
+ for (const field of fields) {
1379
+ if (field.name === currentPart) {
1380
+ if (remainingPath) {
1381
+ if (field.fields && Array.isArray(field.fields)) {
1382
+ return updateFieldByPath(field.fields, remainingPath, updates);
1383
+ }
1384
+ if (field.type === "array" && field.fields && Array.isArray(field.fields)) {
1385
+ return updateFieldByPath(field.fields, remainingPath, updates);
1386
+ }
1387
+ return false;
1388
+ } else {
1389
+ Object.assign(field, updates);
1390
+ return true;
1391
+ }
1392
+ }
1393
+ }
1394
+ return false;
1395
+ }
1396
+ function applyCollectionOverrides(collections, overrides) {
1397
+ if (!overrides) return;
1398
+ for (const col of collections) {
1399
+ const override = overrides[col.slug];
1400
+ if (override) {
1401
+ const { fields: fieldOverrides, ...adminOverrides } = override;
1402
+ col.admin = { ...col.admin, ...adminOverrides };
1403
+ if (fieldOverrides && col.fields && Array.isArray(col.fields)) {
1404
+ for (const [fieldPath, fieldUpdates] of Object.entries(fieldOverrides)) {
1405
+ updateFieldByPath(col.fields, fieldPath, fieldUpdates);
1406
+ }
1407
+ }
1408
+ }
1409
+ }
1410
+ }
1092
1411
  var Kyro = class {
1093
1412
  registry;
1094
1413
  db;
@@ -1102,13 +1421,19 @@ var Kyro = class {
1102
1421
  this.registry = createRegistry();
1103
1422
  this.db = config.adapter;
1104
1423
  this.pubsub = new chunkDVD5P72E_cjs.KyroPubSub(this.registry);
1105
- this.webhookService = chunkIBG6V56E_cjs.createWebhookService(this.db);
1424
+ this.webhookService = chunkQFLB4EIJ_cjs.createWebhookService(this.db);
1425
+ if (config.collections && config.admin?.collectionOverrides) {
1426
+ applyCollectionOverrides(config.collections, config.admin.collectionOverrides);
1427
+ }
1106
1428
  if (config.collections) {
1107
1429
  this.registry.addCollections(config.collections);
1108
1430
  }
1109
1431
  if (config.globals) {
1110
1432
  this.registry.addGlobals(config.globals);
1111
1433
  }
1434
+ for (const plugin of builtinStoragePlugins) {
1435
+ this.registry.addPlugin(plugin);
1436
+ }
1112
1437
  if (config.plugins) {
1113
1438
  for (const plugin of config.plugins) {
1114
1439
  this.registry.addPlugin(plugin);
@@ -1117,13 +1442,24 @@ var Kyro = class {
1117
1442
  }
1118
1443
  async init() {
1119
1444
  await this.registry.init();
1445
+ const storageGlobal = chunk3KTWGODI_cjs.createStorageSettingsGlobal(
1446
+ this.registry.storageProviders,
1447
+ (name) => this.registry.storageProviders.isPluginEnabled(name)
1448
+ );
1449
+ this.registry.addGlobalPostInit(storageGlobal);
1450
+ const pluginSettingsGlobal = {
1451
+ slug: "plugin-settings",
1452
+ admin: { hidden: true },
1453
+ fields: [{ name: "states", type: "json" }]
1454
+ };
1455
+ this.registry.addGlobalPostInit(pluginSettingsGlobal);
1120
1456
  if (!this.db) {
1121
1457
  throw new Error(
1122
1458
  `Database adapter is null \u2014 failed to load at startup. Check the server console for the exact error.`
1123
1459
  );
1124
1460
  }
1125
1461
  const systemCollection = {
1126
- slug: chunkIBG6V56E_cjs.API_KEY_COLLECTION,
1462
+ slug: chunk4M7X5HAB_cjs.API_KEY_COLLECTION,
1127
1463
  fields: [
1128
1464
  { name: "userId", type: "text", required: true },
1129
1465
  { name: "name", type: "text", required: true },
@@ -1135,7 +1471,7 @@ var Kyro = class {
1135
1471
  ]
1136
1472
  };
1137
1473
  const webhookCollection = {
1138
- slug: chunkIBG6V56E_cjs.WEBHOOK_COLLECTION,
1474
+ slug: chunkQFLB4EIJ_cjs.WEBHOOK_COLLECTION,
1139
1475
  fields: [
1140
1476
  { name: "name", type: "text", required: true },
1141
1477
  { name: "url", type: "text", required: true },
@@ -1148,7 +1484,7 @@ var Kyro = class {
1148
1484
  ]
1149
1485
  };
1150
1486
  const webhookDeliveryCollection = {
1151
- slug: chunkIBG6V56E_cjs.WEBHOOK_DELIVERY_COLLECTION,
1487
+ slug: chunkQFLB4EIJ_cjs.WEBHOOK_DELIVERY_COLLECTION,
1152
1488
  fields: [
1153
1489
  { name: "webhookId", type: "text", required: true },
1154
1490
  { name: "event", type: "text", required: true },
@@ -1163,6 +1499,7 @@ var Kyro = class {
1163
1499
  { name: "nextRetryAt", type: "date" }
1164
1500
  ]
1165
1501
  };
1502
+ const allGlobals = this.registry.getGlobals();
1166
1503
  await this.db.init(
1167
1504
  [
1168
1505
  ...this.registry.getCollections(),
@@ -1170,12 +1507,13 @@ var Kyro = class {
1170
1507
  webhookCollection,
1171
1508
  webhookDeliveryCollection
1172
1509
  ],
1173
- this.registry.getGlobals()
1510
+ allGlobals
1174
1511
  );
1512
+ await this.loadPluginState();
1175
1513
  this.pubsub.autoRegisterHooks();
1176
1514
  console.log("\u2705 Kyro CMS initialized");
1177
1515
  console.log(` Collections: ${this.registry.getCollections().length}`);
1178
- console.log(` Globals: ${this.registry.getGlobals().length}`);
1516
+ console.log(` Globals: ${allGlobals.length}`);
1179
1517
  }
1180
1518
  // ============================================================================
1181
1519
  // API Methods
@@ -1184,23 +1522,43 @@ var Kyro = class {
1184
1522
  async loadSettings() {
1185
1523
  if (this.settings) return this.settings;
1186
1524
  try {
1187
- const accessSettings = await this.db.findOne({
1188
- collection: "_globals",
1189
- where: { slug: "access-settings" }
1525
+ const doc = await this.db.findOne({
1526
+ collection: "_globals_access-settings",
1527
+ where: {}
1190
1528
  });
1191
- if (accessSettings) {
1192
- this.settings = accessSettings.data;
1529
+ if (doc) {
1530
+ this.settings = { access: doc };
1193
1531
  }
1194
1532
  } catch (e) {
1195
1533
  console.log("\u26A0\uFE0F No access-settings found, using defaults");
1196
1534
  }
1197
1535
  return this.settings || {};
1198
1536
  }
1537
+ async loadPluginState() {
1538
+ const storageRegistry = this.registry.storageProviders;
1539
+ const pluginNames = storageRegistry.getAllPluginNames();
1540
+ let pluginStates = {};
1541
+ try {
1542
+ const doc = await this.db.findOne({
1543
+ collection: "_globals_plugin-settings",
1544
+ where: {}
1545
+ });
1546
+ if (doc && doc.states) {
1547
+ pluginStates = doc.states;
1548
+ }
1549
+ } catch (e) {
1550
+ }
1551
+ for (const name of pluginNames) {
1552
+ if (pluginStates[name] !== void 0) {
1553
+ storageRegistry.setPluginEnabled(name, pluginStates[name]);
1554
+ }
1555
+ }
1556
+ }
1199
1557
  getREST(options) {
1200
1558
  const authObj = typeof this.config.auth === "object" ? this.config.auth : null;
1201
1559
  const authSecret = authObj?.secret;
1202
1560
  const checkSession = authObj?.checkSession !== false;
1203
- return chunk5KVM3WEY_cjs.createHonoApp({
1561
+ return chunkRSF3UU7H_cjs.createHonoApp({
1204
1562
  registry: this.registry,
1205
1563
  db: this.db,
1206
1564
  authSecret,
@@ -1213,33 +1571,196 @@ var Kyro = class {
1213
1571
  });
1214
1572
  }
1215
1573
  getGraphQL(options) {
1216
- return chunkVJT6P4N6_cjs.buildGraphQLSchema({
1574
+ const defaultSchema = chunk3HR772HI_cjs.buildGraphQLSchema({
1217
1575
  registry: this.registry,
1218
1576
  db: this.db,
1219
- ...options,
1220
- settings: this.settings
1577
+ settings: this.settings,
1578
+ user: options?.user,
1579
+ req: options?.req,
1580
+ tenantID: options?.tenantID
1221
1581
  });
1582
+ return {
1583
+ fetch: async (request, _locals) => {
1584
+ const apiKeyRaw = chunk4M7X5HAB_cjs.extractApiKeyFromRequest(request);
1585
+ let gqlUser;
1586
+ let apiKeyCtx;
1587
+ if (apiKeyRaw && this.db) {
1588
+ const apiKeyResult = await chunk4M7X5HAB_cjs.validateApiKey(apiKeyRaw, this.db);
1589
+ if (!apiKeyResult.valid) {
1590
+ return new Response(
1591
+ JSON.stringify({ errors: [{ message: apiKeyResult.error || "Invalid API key" }] }),
1592
+ { status: 401, headers: { "Content-Type": "application/json" } }
1593
+ );
1594
+ }
1595
+ if (apiKeyResult.user) {
1596
+ gqlUser = apiKeyResult.user;
1597
+ apiKeyCtx = chunk4M7X5HAB_cjs.createApiKeyContext(apiKeyResult);
1598
+ }
1599
+ }
1600
+ const mustRebuild = gqlUser !== options?.user || apiKeyCtx !== void 0;
1601
+ const schema = mustRebuild ? chunk3HR772HI_cjs.buildGraphQLSchema({
1602
+ registry: this.registry,
1603
+ db: this.db,
1604
+ settings: this.settings,
1605
+ user: gqlUser,
1606
+ req: request,
1607
+ tenantID: options?.tenantID,
1608
+ apiKey: apiKeyCtx
1609
+ }) : defaultSchema;
1610
+ const body = request.method === "POST" ? await request.json().catch(() => ({})) : {};
1611
+ const query = body.query || "";
1612
+ const variables = body.variables || {};
1613
+ if (!query) {
1614
+ return new Response(
1615
+ JSON.stringify({ error: "No GraphQL query provided" }),
1616
+ { status: 400, headers: { "Content-Type": "application/json" } }
1617
+ );
1618
+ }
1619
+ try {
1620
+ const document = graphql.parse(query);
1621
+ const result = await graphql.execute({
1622
+ schema,
1623
+ document,
1624
+ variableValues: variables,
1625
+ contextValue: {
1626
+ db: this.db,
1627
+ registry: this.registry,
1628
+ settings: this.settings,
1629
+ user: gqlUser,
1630
+ req: request,
1631
+ tenantID: options?.tenantID
1632
+ }
1633
+ });
1634
+ return new Response(JSON.stringify(result), {
1635
+ status: 200,
1636
+ headers: { "Content-Type": "application/json" }
1637
+ });
1638
+ } catch (err) {
1639
+ return new Response(
1640
+ JSON.stringify({ errors: [{ message: err.message }] }),
1641
+ { status: 400, headers: { "Content-Type": "application/json" } }
1642
+ );
1643
+ }
1644
+ },
1645
+ schema: defaultSchema
1646
+ };
1222
1647
  }
1223
1648
  getTRPC(options) {
1224
- return chunkK7JPTH3G_cjs.createKyroServer({
1225
- registry: this.registry,
1226
- db: this.db,
1227
- req: options?.req || { headers: {} },
1228
- ...options,
1229
- settings: this.settings
1230
- });
1649
+ return {
1650
+ fetch: async (request, locals) => {
1651
+ const url = new URL(request.url);
1652
+ const path = url.pathname.replace(/^\/api\/trpc\//, "");
1653
+ const [slug, ...rest] = path.split(".");
1654
+ let procedureName = rest.join(".");
1655
+ procedureName = procedureName.replace(/\.(query|mutate|subscribe)$/, "");
1656
+ if (!slug || !procedureName) {
1657
+ return new Response(
1658
+ JSON.stringify({
1659
+ error: {
1660
+ message: "Invalid tRPC path",
1661
+ code: -32600,
1662
+ data: { code: "BAD_REQUEST", httpStatus: 400 }
1663
+ }
1664
+ }),
1665
+ { status: 400, headers: { "Content-Type": "application/json" } }
1666
+ );
1667
+ }
1668
+ const ctx = await chunkKNRSROWB_cjs.createContext({
1669
+ db: this.db,
1670
+ registry: this.registry,
1671
+ req: request,
1672
+ user: options?.user,
1673
+ tenantID: options?.tenantID,
1674
+ settings: this.settings
1675
+ });
1676
+ const kyroRouter = chunkKNRSROWB_cjs.createKyroServer(ctx);
1677
+ const collectionRouter = kyroRouter[slug];
1678
+ if (!collectionRouter) {
1679
+ return new Response(
1680
+ JSON.stringify({
1681
+ error: {
1682
+ message: `Collection '${slug}' not found`,
1683
+ code: -32601,
1684
+ data: { code: "NOT_FOUND", httpStatus: 404 }
1685
+ }
1686
+ }),
1687
+ { status: 404, headers: { "Content-Type": "application/json" } }
1688
+ );
1689
+ }
1690
+ const procedure = collectionRouter[procedureName];
1691
+ if (typeof procedure !== "function") {
1692
+ return new Response(
1693
+ JSON.stringify({
1694
+ error: {
1695
+ message: `Procedure '${procedureName}' not found`,
1696
+ code: -32601,
1697
+ data: { code: "NOT_FOUND", httpStatus: 404 }
1698
+ }
1699
+ }),
1700
+ { status: 404, headers: { "Content-Type": "application/json" } }
1701
+ );
1702
+ }
1703
+ try {
1704
+ let raw = {};
1705
+ if (request.method === "POST" || request.method === "PATCH") {
1706
+ raw = await request.json().catch(() => ({}));
1707
+ } else {
1708
+ const qs = new URL(request.url).searchParams.get("input");
1709
+ if (qs) {
1710
+ try {
1711
+ raw = JSON.parse(decodeURIComponent(qs));
1712
+ } catch {
1713
+ }
1714
+ }
1715
+ }
1716
+ const input = raw?.["0"] ?? raw;
1717
+ const result = await procedure({ ...input, collection: slug });
1718
+ return new Response(JSON.stringify({ result: { data: result } }), {
1719
+ status: 200,
1720
+ headers: { "Content-Type": "application/json" }
1721
+ });
1722
+ } catch (err) {
1723
+ const msg = err.message || "Internal error";
1724
+ const httpStatus = msg.includes("not found") ? 404 : msg.includes("denied") || msg.includes("authentication required") ? 403 : msg.includes("conflict") ? 409 : 500;
1725
+ const code = httpStatus === 404 ? -32601 : httpStatus === 403 ? -32001 : httpStatus === 409 ? -32002 : -32603;
1726
+ return new Response(
1727
+ JSON.stringify({
1728
+ error: {
1729
+ message: msg,
1730
+ code,
1731
+ data: {
1732
+ code: "INTERNAL_SERVER_ERROR",
1733
+ httpStatus
1734
+ }
1735
+ }
1736
+ }),
1737
+ { status: httpStatus, headers: { "Content-Type": "application/json" } }
1738
+ );
1739
+ }
1740
+ },
1741
+ router: null
1742
+ };
1743
+ }
1744
+ getWS() {
1745
+ return this.wsServer;
1231
1746
  }
1232
1747
  async startWebSocket(options) {
1233
1748
  const apiAccess = this.settings?.access?.apiAccess;
1234
- if (apiAccess?.websocketEnabled === false) {
1749
+ if (apiAccess?.wsEnabled === false) {
1235
1750
  console.log("\u26A0\uFE0F WebSocket is disabled in settings");
1236
1751
  return null;
1237
1752
  }
1753
+ const defaultVerifyToken = async (token) => {
1754
+ const result = await chunk4M7X5HAB_cjs.validateApiKey(token, this.db);
1755
+ if (!result.valid) throw new Error(result.error || "Invalid API key");
1756
+ if (!result.user) throw new Error("API key has no associated user");
1757
+ return result.user;
1758
+ };
1238
1759
  this.wsServer = chunkDVD5P72E_cjs.createWSServer({
1239
1760
  pubsub: this.pubsub,
1240
1761
  port: options?.port || 8080,
1241
1762
  requireAuth: options?.requireAuth ?? apiAccess?.requireAuth,
1242
- verifyToken: options?.verifyToken
1763
+ verifyToken: options?.verifyToken || defaultVerifyToken
1243
1764
  });
1244
1765
  console.log(`\u{1F50C} WebSocket server started on port ${options?.port || 8080}`);
1245
1766
  return this.wsServer;
@@ -1258,7 +1779,7 @@ var Kyro = class {
1258
1779
  function createKyro(config) {
1259
1780
  return new Kyro(config);
1260
1781
  }
1261
- var _require = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-LINKCEG4.cjs', document.baseURI).href)));
1782
+ var _require = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-ROJHKAQ4.cjs', document.baseURI).href)));
1262
1783
  var modPath = "node:sqlite";
1263
1784
  var { DatabaseSync } = _require(modPath);
1264
1785
  function flattenFields(fields) {
@@ -1358,19 +1879,12 @@ function getTableColumns(db, tableName) {
1358
1879
  return [];
1359
1880
  }
1360
1881
  }
1361
- var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1882
+ var LocalAdapter = class extends chunkPI73NNOK_cjs.AbstractBaseAdapter {
1362
1883
  db;
1363
1884
  path;
1364
1885
  migrations = /* @__PURE__ */ new Map();
1365
1886
  draftsTableName = "kyro_drafts";
1366
1887
  versionsTableName = "kyro_versions";
1367
- tenantContext;
1368
- setTenantContext(context) {
1369
- this.tenantContext = context;
1370
- }
1371
- getTenantContext() {
1372
- return this.tenantContext;
1373
- }
1374
1888
  constructor(options) {
1375
1889
  super();
1376
1890
  this.path = options.path;
@@ -1384,6 +1898,34 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1384
1898
  if (!this.db) {
1385
1899
  this.db = new DatabaseSync(this.path || ":memory:");
1386
1900
  }
1901
+ if (this.db && typeof this.db.prepare === "function" && !this.db.prepare.__wrapped) {
1902
+ const originalPrepare = this.db.prepare.bind(this.db);
1903
+ const wrappedPrepare = (sql) => {
1904
+ const stmt = originalPrepare(sql);
1905
+ const serialize = (val) => {
1906
+ if (typeof val === "boolean") return val ? 1 : 0;
1907
+ if (val === void 0) return null;
1908
+ return val;
1909
+ };
1910
+ return new Proxy(stmt, {
1911
+ get(target, prop, receiver) {
1912
+ if (prop === "all") {
1913
+ return (...params) => target.all(...params.map(serialize));
1914
+ }
1915
+ if (prop === "get") {
1916
+ return (...params) => target.get(...params.map(serialize));
1917
+ }
1918
+ if (prop === "run") {
1919
+ return (...params) => target.run(...params.map(serialize));
1920
+ }
1921
+ const val = Reflect.get(target, prop, receiver);
1922
+ return typeof val === "function" ? val.bind(target) : val;
1923
+ }
1924
+ });
1925
+ };
1926
+ wrappedPrepare.__wrapped = true;
1927
+ this.db.prepare = wrappedPrepare;
1928
+ }
1387
1929
  this.db.exec("PRAGMA journal_mode = WAL");
1388
1930
  this.db.exec("PRAGMA foreign_keys = ON");
1389
1931
  this.connected = true;
@@ -1411,8 +1953,8 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1411
1953
  }
1412
1954
  columns.push(`${this.col("createdAt")} TEXT DEFAULT (datetime('now'))`);
1413
1955
  columns.push(`${this.col("updatedAt")} TEXT DEFAULT (datetime('now'))`);
1414
- columns.push(`_status TEXT DEFAULT 'published'`);
1415
- columns.push(`_has_draft INTEGER DEFAULT 0`);
1956
+ columns.push(`publishStatus TEXT DEFAULT 'draft'`);
1957
+ columns.push(`hasDraft INTEGER DEFAULT 0`);
1416
1958
  if (config.tenantScoped) {
1417
1959
  columns.push(`tenant_id TEXT NOT NULL`);
1418
1960
  }
@@ -1420,7 +1962,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1420
1962
  if (existingColumns.length === 0) {
1421
1963
  const createSQL = `CREATE TABLE IF NOT EXISTS ${name} (${columns.join(", ")})`;
1422
1964
  this.db.exec(createSQL);
1423
- this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${name}__status ON ${name}(_status)`);
1965
+ this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${name}_publishStatus ON ${name}(publishStatus)`);
1424
1966
  for (const field of flattenFields(config.fields)) {
1425
1967
  if (field.name && field.indexed) {
1426
1968
  this.db.exec(
@@ -1439,9 +1981,9 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1439
1981
  const colName = colDef.split(" ")[0].replace(/^"/, "").replace(/"$/, "");
1440
1982
  if (!existingSet.has(colName) && colName !== "id") {
1441
1983
  try {
1442
- if (colName === "_status") {
1984
+ if (colName === "publishStatus") {
1443
1985
  this.db.exec(`ALTER TABLE ${name} ADD COLUMN ${this.col(colName)} TEXT DEFAULT 'published'`);
1444
- } else if (colName === "_has_draft") {
1986
+ } else if (colName === "hasDraft") {
1445
1987
  this.db.exec(`ALTER TABLE ${name} ADD COLUMN ${this.col(colName)} INTEGER DEFAULT 0`);
1446
1988
  } else {
1447
1989
  this.db.exec(`ALTER TABLE ${name} ADD COLUMN ${this.col(colName)} TEXT`);
@@ -1474,7 +2016,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1474
2016
  `CREATE INDEX IF NOT EXISTS idx_${this.versionsTableName}_doc ON ${this.versionsTableName}(collection_slug, document_id)`
1475
2017
  );
1476
2018
  this.db.exec(
1477
- `CREATE INDEX IF NOT EXISTS idx_${this.versionsTableName}_status ON ${this.versionsTableName}(status)`
2019
+ `CREATE INDEX IF NOT EXISTS idx_${this.versionsTableName}publishStatus ON ${this.versionsTableName}(status)`
1478
2020
  );
1479
2021
  }
1480
2022
  ensureDraftsTable() {
@@ -1571,11 +2113,11 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1571
2113
  const conditions = [];
1572
2114
  let effectiveWhere = { ...where };
1573
2115
  if (this.tenantContext && config.tenantScoped) {
1574
- const rlsQuery = chunkSA7NSSIQ_cjs.applyRLS({ where: effectiveWhere }, slug, this.tenantContext, chunkSA7NSSIQ_cjs.DEFAULT_RLS_CONFIG);
2116
+ const rlsQuery = chunkPI73NNOK_cjs.applyRLS({ where: effectiveWhere }, slug, this.tenantContext, chunkPI73NNOK_cjs.DEFAULT_RLS_CONFIG);
1575
2117
  effectiveWhere = rlsQuery.where || {};
1576
2118
  }
1577
2119
  if (!draft && config.versions?.drafts) {
1578
- conditions.push(`_status = ?`);
2120
+ conditions.push(`publishStatus = ?`);
1579
2121
  params.push("published");
1580
2122
  }
1581
2123
  if (tenantID && config.tenantScoped) {
@@ -1616,11 +2158,11 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1616
2158
  const rows = this.db.prepare(sql).all(...params);
1617
2159
  let docs = rows.map((row) => this.rowToDoc(row, config));
1618
2160
  if (this.tenantContext && !this.tenantContext.isSuperAdmin) {
1619
- docs = docs.filter((doc) => chunkSA7NSSIQ_cjs.canAccessDocument(doc, slug, this.tenantContext, chunkSA7NSSIQ_cjs.DEFAULT_RLS_CONFIG));
2161
+ docs = docs.filter((doc) => chunkPI73NNOK_cjs.canAccessDocument(doc, slug, this.tenantContext, chunkPI73NNOK_cjs.DEFAULT_RLS_CONFIG));
1620
2162
  }
1621
2163
  if (draft) {
1622
2164
  docs = await Promise.all(docs.map(async (doc) => {
1623
- if (doc._has_draft) {
2165
+ if (doc.hasDraft) {
1624
2166
  const versions = await this.findVersions({
1625
2167
  collection: slug,
1626
2168
  documentId: doc.id,
@@ -1628,7 +2170,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1628
2170
  sort: "-createdAt"
1629
2171
  });
1630
2172
  if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
1631
- return { ...doc, ...versions.docs[0].data, _has_draft: true, _status: doc._status };
2173
+ return { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
1632
2174
  }
1633
2175
  }
1634
2176
  return doc;
@@ -1657,12 +2199,12 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1657
2199
  const params = [id];
1658
2200
  if (this.tenantContext && config.tenantScoped) {
1659
2201
  const tempDoc = { id, tenant_id: this.tenantContext.tenantId };
1660
- if (!chunkSA7NSSIQ_cjs.canAccessDocument(tempDoc, slug, this.tenantContext, chunkSA7NSSIQ_cjs.DEFAULT_RLS_CONFIG)) {
2202
+ if (!chunkPI73NNOK_cjs.canAccessDocument(tempDoc, slug, this.tenantContext, chunkPI73NNOK_cjs.DEFAULT_RLS_CONFIG)) {
1661
2203
  return null;
1662
2204
  }
1663
2205
  }
1664
2206
  if (!draft && config.versions?.drafts) {
1665
- sql += ` AND _status = ?`;
2207
+ sql += ` AND publishStatus = ?`;
1666
2208
  params.push("published");
1667
2209
  }
1668
2210
  if (tenantID && config.tenantScoped) {
@@ -1672,7 +2214,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1672
2214
  const row = this.db.prepare(sql).get(...params);
1673
2215
  if (!row) return null;
1674
2216
  let doc = this.rowToDoc(row, config);
1675
- if (draft && doc._has_draft) {
2217
+ if (draft && doc.hasDraft) {
1676
2218
  const versions = await this.findVersions({
1677
2219
  collection: slug,
1678
2220
  documentId: doc.id,
@@ -1680,7 +2222,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1680
2222
  sort: "-createdAt"
1681
2223
  });
1682
2224
  if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
1683
- doc = { ...doc, ...versions.docs[0].data, _has_draft: true, _status: doc._status };
2225
+ doc = { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
1684
2226
  }
1685
2227
  }
1686
2228
  return doc;
@@ -1711,7 +2253,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1711
2253
  const quotedColumns = filteredColumns.map((c) => this.col(c));
1712
2254
  const placeholders = filteredColumns.map(() => "?").join(", ");
1713
2255
  const values = Object.values(filteredData).map(
1714
- (v) => typeof v === "object" ? JSON.stringify(v) : v
2256
+ (v) => v !== null && typeof v === "object" ? JSON.stringify(v) : v
1715
2257
  );
1716
2258
  this.db.prepare(
1717
2259
  `INSERT OR REPLACE INTO ${tableName} (${quotedColumns.join(", ")}) VALUES (${placeholders})`
@@ -1791,7 +2333,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1791
2333
  const conditions = [];
1792
2334
  const params = [];
1793
2335
  if (!args.draft && globalConfig.versions) {
1794
- conditions.push("_status = 'published'");
2336
+ conditions.push("publishStatus = 'published'");
1795
2337
  }
1796
2338
  if (conditions.length > 0) {
1797
2339
  sql += ` WHERE ${conditions.join(" AND ")}`;
@@ -1800,7 +2342,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1800
2342
  const result2 = this.db.prepare(sql).get(...params);
1801
2343
  if (result2) {
1802
2344
  let doc = this.rowToDoc(result2, globalConfig);
1803
- if (args.draft && doc._has_draft) {
2345
+ if (args.draft && doc.hasDraft) {
1804
2346
  const versions = await this.findVersions({
1805
2347
  collection: args.collection,
1806
2348
  documentId: parsed.globalSlug,
@@ -1808,7 +2350,7 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
1808
2350
  sort: "-createdAt"
1809
2351
  });
1810
2352
  if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
1811
- doc = { ...doc, ...versions.docs[0].data, _has_draft: true, _status: doc._status };
2353
+ doc = { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
1812
2354
  }
1813
2355
  }
1814
2356
  return doc;
@@ -2150,6 +2692,8 @@ var LocalAdapter = class extends chunkSA7NSSIQ_cjs.AbstractBaseAdapter {
2150
2692
  if (config.tenantScoped) {
2151
2693
  doc.tenantID = row.tenant_id;
2152
2694
  }
2695
+ doc.publishStatus = row.publishStatus ?? "published";
2696
+ doc.hasDraft = row.hasDraft ? Boolean(row.hasDraft) : false;
2153
2697
  return doc;
2154
2698
  }
2155
2699
  generateId() {
@@ -2253,5 +2797,5 @@ exports.validateCollection = validateCollection;
2253
2797
  exports.validateConfig = validateConfig;
2254
2798
  exports.validateFields = validateFields;
2255
2799
  exports.validateGlobal = validateGlobal;
2256
- //# sourceMappingURL=chunk-LINKCEG4.cjs.map
2257
- //# sourceMappingURL=chunk-LINKCEG4.cjs.map
2800
+ //# sourceMappingURL=chunk-ROJHKAQ4.cjs.map
2801
+ //# sourceMappingURL=chunk-ROJHKAQ4.cjs.map