@kyro-cms/core 0.3.2 → 0.3.5

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 (201) hide show
  1. package/dist/{WebhookService-BznDc2AT.d.ts → WebhookService-118ZTFis.d.ts} +2 -2
  2. package/dist/{WebhookService-mZZ75syh.d.cts → WebhookService-AefJfqX0.d.cts} +2 -2
  3. package/dist/api-handler.cjs +52 -0
  4. package/dist/api-handler.cjs.map +1 -0
  5. package/dist/api-handler.d.cts +9 -0
  6. package/dist/api-handler.d.ts +9 -0
  7. package/dist/api-handler.js +46 -0
  8. package/dist/api-handler.js.map +1 -0
  9. package/dist/{base-Hu6ij8sZ.d.ts → base-DvvNqnM-.d.cts} +16 -5
  10. package/dist/{base-Db9LkB1N.d.cts → base-eVegJ_Pr.d.ts} +16 -5
  11. package/dist/bootstrap-DGJ3N7SO.js +6 -0
  12. package/dist/{bootstrap-LL6O7PWO.js.map → bootstrap-DGJ3N7SO.js.map} +1 -1
  13. package/dist/bootstrap-O5UGUTYU.cjs +31 -0
  14. package/dist/{bootstrap-BMWVB2T6.cjs.map → bootstrap-O5UGUTYU.cjs.map} +1 -1
  15. package/dist/{chunk-QKOFKITP.js → chunk-2HFJUUFZ.js} +3 -11
  16. package/dist/chunk-2HFJUUFZ.js.map +1 -0
  17. package/dist/chunk-2UOI5MUC.cjs +1276 -0
  18. package/dist/chunk-2UOI5MUC.cjs.map +1 -0
  19. package/dist/{chunk-DIC236EW.js → chunk-342BJNBI.js} +167 -24
  20. package/dist/chunk-342BJNBI.js.map +1 -0
  21. package/dist/{chunk-OUGKLCYF.js → chunk-3AJE4SEG.js} +4 -3
  22. package/dist/chunk-3AJE4SEG.js.map +1 -0
  23. package/dist/chunk-4UD44U4Z.js +5818 -0
  24. package/dist/chunk-4UD44U4Z.js.map +1 -0
  25. package/dist/chunk-5FTY2DLG.js +1258 -0
  26. package/dist/chunk-5FTY2DLG.js.map +1 -0
  27. package/dist/{chunk-BXMWDUED.js → chunk-A4USRVTQ.js} +2 -2
  28. package/dist/chunk-A4USRVTQ.js.map +1 -0
  29. package/dist/chunk-ADLJSJSN.cjs +13 -0
  30. package/dist/chunk-ADLJSJSN.cjs.map +1 -0
  31. package/dist/chunk-ATBOUGQP.cjs +513 -0
  32. package/dist/chunk-ATBOUGQP.cjs.map +1 -0
  33. package/dist/chunk-BQ2T4WRS.js +140 -0
  34. package/dist/chunk-BQ2T4WRS.js.map +1 -0
  35. package/dist/{chunk-U74F3YZU.js → chunk-DBUYB32X.js} +15 -3
  36. package/dist/chunk-DBUYB32X.js.map +1 -0
  37. package/dist/chunk-DE7OQOMD.cjs +5842 -0
  38. package/dist/chunk-DE7OQOMD.cjs.map +1 -0
  39. package/dist/chunk-DLHUQO25.cjs +1746 -0
  40. package/dist/chunk-DLHUQO25.cjs.map +1 -0
  41. package/dist/{chunk-GE5DMB44.js → chunk-E3BZLMX6.js} +55 -49
  42. package/dist/chunk-E3BZLMX6.js.map +1 -0
  43. package/dist/{chunk-44BF6ALS.cjs → chunk-H4XCAPA6.cjs} +55 -49
  44. package/dist/chunk-H4XCAPA6.cjs.map +1 -0
  45. package/dist/{chunk-VIONYQ2K.cjs → chunk-IBG6V56E.cjs} +16 -32
  46. package/dist/chunk-IBG6V56E.cjs.map +1 -0
  47. package/dist/{chunk-LIJVWQKU.cjs → chunk-IX3ABYKZ.cjs} +43 -31
  48. package/dist/chunk-IX3ABYKZ.cjs.map +1 -0
  49. package/dist/chunk-JYGIFBBS.cjs +146 -0
  50. package/dist/chunk-JYGIFBBS.cjs.map +1 -0
  51. package/dist/{chunk-42JPONZU.cjs → chunk-K7JPTH3G.cjs} +17 -16
  52. package/dist/chunk-K7JPTH3G.cjs.map +1 -0
  53. package/dist/{chunk-RLTG4YZM.cjs → chunk-KOCTZKPV.cjs} +2 -2
  54. package/dist/chunk-KOCTZKPV.cjs.map +1 -0
  55. package/dist/{chunk-EWP5AT6A.cjs → chunk-N4H37VN4.cjs} +2 -11
  56. package/dist/chunk-N4H37VN4.cjs.map +1 -0
  57. package/dist/chunk-P2YW545G.js +11 -0
  58. package/dist/chunk-P2YW545G.js.map +1 -0
  59. package/dist/chunk-Q23JB3KL.js +488 -0
  60. package/dist/chunk-Q23JB3KL.js.map +1 -0
  61. package/dist/{chunk-E5X75WNB.js → chunk-QXIQWPAP.js} +14 -30
  62. package/dist/chunk-QXIQWPAP.js.map +1 -0
  63. package/dist/chunk-R3XIBBAW.cjs +34 -0
  64. package/dist/chunk-R3XIBBAW.cjs.map +1 -0
  65. package/dist/chunk-R4C4O4SE.cjs +622 -0
  66. package/dist/chunk-R4C4O4SE.cjs.map +1 -0
  67. package/dist/{chunk-KWGNR4HM.js → chunk-REK7AYOC.js} +82 -9
  68. package/dist/chunk-REK7AYOC.js.map +1 -0
  69. package/dist/chunk-RGIQKTZ7.js +68 -0
  70. package/dist/chunk-RGIQKTZ7.js.map +1 -0
  71. package/dist/chunk-RYDGMBIG.js +1737 -0
  72. package/dist/chunk-RYDGMBIG.js.map +1 -0
  73. package/dist/chunk-SDMNUYVU.js +30 -0
  74. package/dist/chunk-SDMNUYVU.js.map +1 -0
  75. package/dist/{chunk-FTSSDDZQ.cjs → chunk-VJT6P4N6.cjs} +82 -9
  76. package/dist/chunk-VJT6P4N6.cjs.map +1 -0
  77. package/dist/{chunk-HT6VE4NW.cjs → chunk-W3KPQX7V.cjs} +168 -25
  78. package/dist/chunk-W3KPQX7V.cjs.map +1 -0
  79. package/dist/{chunk-LTRCYJAG.js → chunk-WOWUL7ZY.js} +3 -2
  80. package/dist/chunk-WOWUL7ZY.js.map +1 -0
  81. package/dist/{chunk-7YITG2US.cjs → chunk-WQBRWOQT.cjs} +3 -2
  82. package/dist/chunk-WQBRWOQT.cjs.map +1 -0
  83. package/dist/{chunk-KB6QF4HO.js → chunk-WSCJQI2B.js} +305 -152
  84. package/dist/chunk-WSCJQI2B.js.map +1 -0
  85. package/dist/chunk-X3CU27OO.cjs +78 -0
  86. package/dist/chunk-X3CU27OO.cjs.map +1 -0
  87. package/dist/chunk-Y3TM7WH7.js +617 -0
  88. package/dist/chunk-Y3TM7WH7.js.map +1 -0
  89. package/dist/{chunk-PNBZZ76A.cjs → chunk-Z2OVHWHB.cjs} +305 -151
  90. package/dist/chunk-Z2OVHWHB.cjs.map +1 -0
  91. package/dist/cli/index.cjs +2 -2
  92. package/dist/cli/index.js +2 -2
  93. package/dist/client.cjs +23 -13
  94. package/dist/client.d.cts +4 -2
  95. package/dist/client.d.ts +4 -2
  96. package/dist/client.js +3 -1
  97. package/dist/drizzle/index.cjs +20 -19
  98. package/dist/drizzle/index.d.cts +28 -7
  99. package/dist/drizzle/index.d.ts +28 -7
  100. package/dist/drizzle/index.js +5 -4
  101. package/dist/fields/index.cjs +105 -0
  102. package/dist/fields/index.cjs.map +1 -0
  103. package/dist/fields/index.d.cts +27 -0
  104. package/dist/fields/index.d.ts +27 -0
  105. package/dist/fields/index.js +4 -0
  106. package/dist/fields/index.js.map +1 -0
  107. package/dist/graphql/index.cjs +4 -3
  108. package/dist/graphql/index.d.cts +3 -2
  109. package/dist/graphql/index.d.ts +3 -2
  110. package/dist/graphql/index.js +2 -1
  111. package/dist/{index-Ci6r4xnN.d.ts → index-CLp-DRKA.d.ts} +2 -1
  112. package/dist/{index-11MDNKce.d.cts → index-DfO7G4kN.d.cts} +2 -1
  113. package/dist/index.cjs +2659 -6670
  114. package/dist/index.cjs.map +1 -1
  115. package/dist/index.d.cts +138 -47
  116. package/dist/index.d.ts +138 -47
  117. package/dist/index.js +2356 -6529
  118. package/dist/index.js.map +1 -1
  119. package/dist/integration.cjs +68 -0
  120. package/dist/integration.cjs.map +1 -0
  121. package/dist/integration.d.cts +27 -0
  122. package/dist/integration.d.ts +27 -0
  123. package/dist/integration.js +61 -0
  124. package/dist/integration.js.map +1 -0
  125. package/dist/mongodb/index.cjs +4 -4
  126. package/dist/mongodb/index.d.cts +20 -6
  127. package/dist/mongodb/index.d.ts +20 -6
  128. package/dist/mongodb/index.js +2 -2
  129. package/dist/postgres-auth-adapter-7F3ECO7I.js +5 -0
  130. package/dist/{postgres-auth-adapter-OTRWSTT5.js.map → postgres-auth-adapter-7F3ECO7I.js.map} +1 -1
  131. package/dist/postgres-auth-adapter-Z463NYJZ.cjs +14 -0
  132. package/dist/{postgres-auth-adapter-EVRPO7BQ.cjs.map → postgres-auth-adapter-Z463NYJZ.cjs.map} +1 -1
  133. package/dist/redis-adapter-LPUWLE4Y.cjs +13 -0
  134. package/dist/{redis-adapter-E7PMN5HW.cjs.map → redis-adapter-LPUWLE4Y.cjs.map} +1 -1
  135. package/dist/redis-adapter-THYDCGQR.js +4 -0
  136. package/dist/{redis-adapter-HOO67RBQ.js.map → redis-adapter-THYDCGQR.js.map} +1 -1
  137. package/dist/rest/index.cjs +9 -5
  138. package/dist/rest/index.d.cts +6 -3
  139. package/dist/rest/index.d.ts +6 -3
  140. package/dist/rest/index.js +7 -3
  141. package/dist/{schema-CNB2DDTX.js → schema-6Q4W6AE6.js} +3 -3
  142. package/dist/{schema-CNB2DDTX.js.map → schema-6Q4W6AE6.js.map} +1 -1
  143. package/dist/{schema-Y777CQQS.cjs → schema-TIYTCIKX.cjs} +14 -14
  144. package/dist/{schema-Y777CQQS.cjs.map → schema-TIYTCIKX.cjs.map} +1 -1
  145. package/dist/templates/index.cjs +27 -23
  146. package/dist/templates/index.d.cts +8 -2
  147. package/dist/templates/index.d.ts +8 -2
  148. package/dist/templates/index.js +1 -1
  149. package/dist/trpc/index.cjs +12 -11
  150. package/dist/trpc/index.d.cts +3 -2
  151. package/dist/trpc/index.d.ts +3 -2
  152. package/dist/trpc/index.js +3 -2
  153. package/dist/{types-1u353OHN.d.ts → types-BnTm7oJG.d.cts} +7 -3
  154. package/dist/{types-1u353OHN.d.cts → types-BnTm7oJG.d.ts} +7 -3
  155. package/dist/{types-kGfsGdos.d.cts → types-Bs1up4yP.d.ts} +76 -244
  156. package/dist/{types-kGfsGdos.d.ts → types-J3R9nVsZ.d.cts} +76 -244
  157. package/dist/types-VtjUxIMp.d.cts +246 -0
  158. package/dist/types-VtjUxIMp.d.ts +246 -0
  159. package/package.json +16 -9
  160. package/dist/bootstrap-BMWVB2T6.cjs +0 -31
  161. package/dist/bootstrap-LL6O7PWO.js +0 -6
  162. package/dist/chunk-42JPONZU.cjs.map +0 -1
  163. package/dist/chunk-44BF6ALS.cjs.map +0 -1
  164. package/dist/chunk-4M5PHMUE.cjs +0 -947
  165. package/dist/chunk-4M5PHMUE.cjs.map +0 -1
  166. package/dist/chunk-6MSSF46R.js +0 -941
  167. package/dist/chunk-6MSSF46R.js.map +0 -1
  168. package/dist/chunk-7YITG2US.cjs.map +0 -1
  169. package/dist/chunk-BTOE3VUK.js +0 -330
  170. package/dist/chunk-BTOE3VUK.js.map +0 -1
  171. package/dist/chunk-BXMWDUED.js.map +0 -1
  172. package/dist/chunk-DIC236EW.js.map +0 -1
  173. package/dist/chunk-E5X75WNB.js.map +0 -1
  174. package/dist/chunk-E63IF3MD.cjs +0 -951
  175. package/dist/chunk-E63IF3MD.cjs.map +0 -1
  176. package/dist/chunk-EWP5AT6A.cjs.map +0 -1
  177. package/dist/chunk-FTSSDDZQ.cjs.map +0 -1
  178. package/dist/chunk-GE5DMB44.js.map +0 -1
  179. package/dist/chunk-GVFB5C6O.cjs +0 -345
  180. package/dist/chunk-GVFB5C6O.cjs.map +0 -1
  181. package/dist/chunk-HT6VE4NW.cjs.map +0 -1
  182. package/dist/chunk-HVSQDZZJ.cjs +0 -765
  183. package/dist/chunk-HVSQDZZJ.cjs.map +0 -1
  184. package/dist/chunk-HYC4GNHX.js +0 -758
  185. package/dist/chunk-HYC4GNHX.js.map +0 -1
  186. package/dist/chunk-KB6QF4HO.js.map +0 -1
  187. package/dist/chunk-KWGNR4HM.js.map +0 -1
  188. package/dist/chunk-LIJVWQKU.cjs.map +0 -1
  189. package/dist/chunk-LTRCYJAG.js.map +0 -1
  190. package/dist/chunk-OUGKLCYF.js.map +0 -1
  191. package/dist/chunk-PNBZZ76A.cjs.map +0 -1
  192. package/dist/chunk-QKOFKITP.js.map +0 -1
  193. package/dist/chunk-RLTG4YZM.cjs.map +0 -1
  194. package/dist/chunk-RRYXQMZG.js +0 -935
  195. package/dist/chunk-RRYXQMZG.js.map +0 -1
  196. package/dist/chunk-U74F3YZU.js.map +0 -1
  197. package/dist/chunk-VIONYQ2K.cjs.map +0 -1
  198. package/dist/postgres-auth-adapter-EVRPO7BQ.cjs +0 -14
  199. package/dist/postgres-auth-adapter-OTRWSTT5.js +0 -5
  200. package/dist/redis-adapter-E7PMN5HW.cjs +0 -13
  201. package/dist/redis-adapter-HOO67RBQ.js +0 -4
@@ -0,0 +1,1276 @@
1
+ 'use strict';
2
+
3
+ var chunkK7JPTH3G_cjs = require('./chunk-K7JPTH3G.cjs');
4
+ var chunkDE7OQOMD_cjs = require('./chunk-DE7OQOMD.cjs');
5
+ var chunkIBG6V56E_cjs = require('./chunk-IBG6V56E.cjs');
6
+ var chunkVJT6P4N6_cjs = require('./chunk-VJT6P4N6.cjs');
7
+ var chunkDVD5P72E_cjs = require('./chunk-DVD5P72E.cjs');
8
+ var zod = require('zod');
9
+
10
+ // src/registry/validator.ts
11
+ function findFieldByName(fields, name) {
12
+ for (const field of fields) {
13
+ if (field.name === name) {
14
+ return true;
15
+ }
16
+ if ("tabs" in field && field.tabs) {
17
+ for (const tab of field.tabs) {
18
+ if (findFieldByName(tab.fields, name)) {
19
+ return true;
20
+ }
21
+ }
22
+ }
23
+ if ("fields" in field && field.fields) {
24
+ if (findFieldByName(field.fields, name)) {
25
+ return true;
26
+ }
27
+ }
28
+ }
29
+ return false;
30
+ }
31
+ var ConfigValidationError = class extends Error {
32
+ errors;
33
+ constructor(errors) {
34
+ super(`Configuration validation failed:
35
+ ${errors.join("\n")}`);
36
+ this.name = "ConfigValidationError";
37
+ this.errors = errors;
38
+ }
39
+ };
40
+ function validateCollection(config) {
41
+ const errors = [];
42
+ if (!config.slug) {
43
+ errors.push(`Collection is missing a "slug" property`);
44
+ } else if (!/^[a-z][a-z0-9_-]*$/.test(config.slug)) {
45
+ errors.push(`Collection slug "${config.slug}" must be lowercase alphanumeric with dashes`);
46
+ }
47
+ if (!config.fields || config.fields.length === 0) {
48
+ errors.push(`Collection "${config.slug}" has no fields defined`);
49
+ } else {
50
+ const fieldErrors = validateFields(config.fields, config.slug);
51
+ errors.push(...fieldErrors);
52
+ }
53
+ if (config.access) {
54
+ for (const [action, handler] of Object.entries(config.access)) {
55
+ if (typeof handler !== "boolean" && typeof handler !== "function") {
56
+ errors.push(`Collection "${config.slug}" has invalid access.${action} (must be boolean or function)`);
57
+ }
58
+ }
59
+ }
60
+ if (config.admin?.useAsTitle) {
61
+ const fieldExists = findFieldByName(config.fields, config.admin.useAsTitle);
62
+ if (!fieldExists) {
63
+ errors.push(`Collection "${config.slug}" admin.useAsTitle references unknown field "${config.admin.useAsTitle}"`);
64
+ }
65
+ }
66
+ if (config.admin?.defaultColumns) {
67
+ for (const col of config.admin.defaultColumns) {
68
+ const fieldExists = findFieldByName(config.fields, col);
69
+ if (!fieldExists) {
70
+ errors.push(`Collection "${config.slug}" admin.defaultColumns references unknown field "${col}"`);
71
+ }
72
+ }
73
+ }
74
+ if (config.upload) {
75
+ if (config.upload.fileSize && config.upload.fileSize <= 0) {
76
+ errors.push(`Collection "${config.slug}" upload.fileSize must be positive`);
77
+ }
78
+ }
79
+ if (config.versions) {
80
+ if (config.versions.maxPerDoc && config.versions.maxPerDoc <= 0) {
81
+ errors.push(`Collection "${config.slug}" versions.maxPerDoc must be positive`);
82
+ }
83
+ }
84
+ if (config.auth) {
85
+ const hasEmailField = config.fields.some((f) => f.name === "email");
86
+ const hasPasswordField = config.fields.some((f) => f.name === "password");
87
+ if (!hasEmailField) {
88
+ errors.push(`Collection "${config.slug}" with auth enabled requires an "email" field`);
89
+ }
90
+ if (!hasPasswordField) {
91
+ errors.push(`Collection "${config.slug}" with auth enabled requires a "password" field`);
92
+ }
93
+ }
94
+ return errors;
95
+ }
96
+ function validateGlobal(config) {
97
+ const errors = [];
98
+ if (!config.slug) {
99
+ errors.push(`Global is missing a "slug" property`);
100
+ } else if (!/^[a-z][a-z0-9_-]*$/.test(config.slug)) {
101
+ errors.push(`Global slug "${config.slug}" must be lowercase alphanumeric with dashes`);
102
+ }
103
+ if (!config.fields || config.fields.length === 0) {
104
+ errors.push(`Global "${config.slug}" has no fields defined`);
105
+ } else {
106
+ const fieldErrors = validateFields(config.fields, `global:${config.slug}`);
107
+ errors.push(...fieldErrors);
108
+ }
109
+ return errors;
110
+ }
111
+ function validateFields(fields, context) {
112
+ const errors = [];
113
+ const fieldNames = /* @__PURE__ */ new Set();
114
+ for (let i = 0; i < fields.length; i++) {
115
+ const field = fields[i];
116
+ if (field.type === "row" || field.type === "collapsible" || field.type === "tabs") {
117
+ if ("fields" in field && field.fields) {
118
+ const nestedErrors = validateFields(field.fields, context);
119
+ errors.push(...nestedErrors);
120
+ } else if ("tabs" in field) {
121
+ for (const tab of field.tabs) {
122
+ const tabErrors = validateFields(tab.fields, context);
123
+ errors.push(...tabErrors);
124
+ }
125
+ }
126
+ continue;
127
+ }
128
+ const fieldName = field.name;
129
+ if (!fieldName) {
130
+ errors.push(`${context}: Field at index ${i} is missing a "name" property`);
131
+ continue;
132
+ }
133
+ if (fieldNames.has(fieldName)) {
134
+ errors.push(`${context}: Duplicate field name "${fieldName}"`);
135
+ }
136
+ fieldNames.add(fieldName);
137
+ if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(fieldName)) {
138
+ errors.push(`${context}: Field name "${fieldName}" must be alphanumeric with underscores`);
139
+ }
140
+ if (!field.type) {
141
+ errors.push(`${context}: Field "${fieldName}" is missing a "type" property`);
142
+ continue;
143
+ }
144
+ switch (field.type) {
145
+ case "relationship":
146
+ if (!field.relationTo) {
147
+ errors.push(`${context}: Relationship field "${fieldName}" is missing "relationTo"`);
148
+ }
149
+ break;
150
+ case "array":
151
+ if (!field.fields || field.fields.length === 0) {
152
+ errors.push(`${context}: Array field "${fieldName}" has no fields defined`);
153
+ } else {
154
+ const arrayErrors = validateFields(field.fields, `${context}.${fieldName}`);
155
+ errors.push(...arrayErrors);
156
+ }
157
+ break;
158
+ case "group":
159
+ if (!field.fields || field.fields.length === 0) {
160
+ errors.push(`${context}: Group field "${fieldName}" has no fields defined`);
161
+ } else {
162
+ const groupErrors = validateFields(field.fields, `${context}.${fieldName}`);
163
+ errors.push(...groupErrors);
164
+ }
165
+ break;
166
+ case "blocks":
167
+ if (!field.blocks || field.blocks.length === 0) {
168
+ errors.push(`${context}: Blocks field "${fieldName}" has no blocks defined`);
169
+ } else {
170
+ const blockErrors = validateBlocks(field.blocks, `${context}.${fieldName}`);
171
+ errors.push(...blockErrors);
172
+ }
173
+ break;
174
+ case "select":
175
+ case "radio":
176
+ if (!field.options || field.options.length === 0) {
177
+ errors.push(`${context}: ${field.type} field "${fieldName}" has no options defined`);
178
+ } else {
179
+ const values = field.options.map((o) => o.value);
180
+ const uniqueValues = new Set(values);
181
+ if (values.length !== uniqueValues.size) {
182
+ errors.push(`${context}: ${field.type} field "${fieldName}" has duplicate option values`);
183
+ }
184
+ }
185
+ break;
186
+ case "upload":
187
+ if (!field.relationTo) {
188
+ errors.push(`${context}: Upload field "${fieldName}" is missing "relationTo"`);
189
+ }
190
+ break;
191
+ }
192
+ if ("min" in field && "max" in field && field.min > field.max) {
193
+ errors.push(`${context}: Field "${fieldName}" has min greater than max`);
194
+ }
195
+ if ("minLength" in field && "maxLength" in field && field.minLength > field.maxLength) {
196
+ errors.push(`${context}: Field "${fieldName}" has minLength greater than maxLength`);
197
+ }
198
+ if ("minRows" in field && "maxRows" in field && field.minRows > field.maxRows) {
199
+ errors.push(`${context}: Field "${fieldName}" has minRows greater than maxRows`);
200
+ }
201
+ }
202
+ return errors;
203
+ }
204
+ function validateBlocks(blocks, context) {
205
+ const errors = [];
206
+ const slugs = /* @__PURE__ */ new Set();
207
+ for (const block of blocks) {
208
+ if (!block.slug) {
209
+ errors.push(`${context}: Block is missing a "slug" property`);
210
+ continue;
211
+ }
212
+ if (slugs.has(block.slug)) {
213
+ errors.push(`${context}: Duplicate block slug "${block.slug}"`);
214
+ }
215
+ slugs.add(block.slug);
216
+ if (!block.label) {
217
+ errors.push(`${context}: Block "${block.slug}" is missing a "label" property`);
218
+ }
219
+ if (!block.fields || block.fields.length === 0) {
220
+ errors.push(`${context}: Block "${block.slug}" has no fields defined`);
221
+ } else {
222
+ const blockErrors = validateFields(block.fields, `${context}.${block.slug}`);
223
+ errors.push(...blockErrors);
224
+ }
225
+ }
226
+ return errors;
227
+ }
228
+ function validateConfig(collections, globals = []) {
229
+ const errors = [];
230
+ const slugs = /* @__PURE__ */ new Set();
231
+ for (const collection of collections) {
232
+ if (slugs.has(collection.slug)) {
233
+ errors.push(`Duplicate collection slug "${collection.slug}"`);
234
+ }
235
+ slugs.add(collection.slug);
236
+ }
237
+ for (const global of globals) {
238
+ if (slugs.has(global.slug)) {
239
+ errors.push(`Duplicate global slug "${global.slug}"`);
240
+ }
241
+ slugs.add(global.slug);
242
+ }
243
+ for (const collection of collections) {
244
+ const collectionErrors = validateCollection(collection);
245
+ errors.push(...collectionErrors);
246
+ }
247
+ for (const global of globals) {
248
+ const globalErrors = validateGlobal(global);
249
+ errors.push(...globalErrors);
250
+ }
251
+ for (const collection of collections) {
252
+ const relationshipErrors = validateRelationships(collection.fields, collections);
253
+ errors.push(...relationshipErrors);
254
+ }
255
+ if (errors.length > 0) {
256
+ throw new ConfigValidationError(errors);
257
+ }
258
+ }
259
+ function validateRelationships(fields, collections) {
260
+ const errors = [];
261
+ const collectionSlugs = new Set(collections.map((c) => c.slug));
262
+ for (const field of fields) {
263
+ if (field.type === "relationship") {
264
+ const targets = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo];
265
+ for (const target of targets) {
266
+ if (!collectionSlugs.has(target)) {
267
+ errors.push(`Relationship field "${field.name}" references unknown collection "${target}"`);
268
+ }
269
+ }
270
+ }
271
+ if (field.type === "upload") {
272
+ const targets = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo];
273
+ for (const target of targets) {
274
+ if (!collectionSlugs.has(target)) {
275
+ errors.push(`Upload field "${field.name}" references unknown collection "${target}"`);
276
+ }
277
+ }
278
+ }
279
+ if ("fields" in field && field.fields) {
280
+ const nestedErrors = validateRelationships(field.fields, collections);
281
+ errors.push(...nestedErrors);
282
+ }
283
+ if ("tabs" in field) {
284
+ for (const tab of field.tabs) {
285
+ const tabErrors = validateRelationships(tab.fields, collections);
286
+ errors.push(...tabErrors);
287
+ }
288
+ }
289
+ if ("blocks" in field) {
290
+ for (const block of field.blocks) {
291
+ const blockErrors = validateRelationships(block.fields, collections);
292
+ errors.push(...blockErrors);
293
+ }
294
+ }
295
+ }
296
+ return errors;
297
+ }
298
+ function fieldToZod(field) {
299
+ switch (field.type) {
300
+ case "text":
301
+ return textToZod(field);
302
+ case "number":
303
+ return numberToZod(field);
304
+ case "checkbox":
305
+ return checkboxToZod(field);
306
+ case "date":
307
+ return dateToZod(field);
308
+ case "email":
309
+ return emailToZod(field);
310
+ case "password":
311
+ return passwordToZod(field);
312
+ case "textarea":
313
+ return textareaToZod(field);
314
+ case "select":
315
+ return selectToZod(field);
316
+ case "radio":
317
+ return radioToZod(field);
318
+ case "color":
319
+ return colorToZod(field);
320
+ case "richtext":
321
+ return richTextToZod(field);
322
+ case "json":
323
+ return jsonToZod(field);
324
+ case "code":
325
+ return codeToZod(field);
326
+ case "upload":
327
+ return uploadToZod(field);
328
+ case "image":
329
+ return uploadToZod(field);
330
+ case "markdown":
331
+ return markdownToZod(field);
332
+ case "relationship":
333
+ return relationshipToZod(field);
334
+ case "relationship-block":
335
+ return relationshipToZod(field);
336
+ case "array":
337
+ return arrayToZod(field);
338
+ case "list":
339
+ return listToZod(field);
340
+ case "group":
341
+ return groupToZod(field);
342
+ case "blocks":
343
+ return blocksToZod(field);
344
+ case "row":
345
+ return rowToZod(field);
346
+ case "collapsible":
347
+ return collapsibleToZod(field);
348
+ case "tabs":
349
+ return tabsToZod(field);
350
+ default:
351
+ return zod.z.any();
352
+ }
353
+ }
354
+ function textToZod(field) {
355
+ let schema = zod.z.string();
356
+ if (field.minLength) schema = schema.min(field.minLength);
357
+ if (field.maxLength) schema = schema.max(field.maxLength);
358
+ if (field.pattern) schema = schema.regex(new RegExp(field.pattern));
359
+ if (field.variant === "email") schema = schema.email();
360
+ if (field.variant === "url") schema = schema.url();
361
+ if (field.hasMany) schema = zod.z.array(schema);
362
+ if (!field.required) schema = schema.optional().nullable();
363
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
364
+ return schema;
365
+ }
366
+ function numberToZod(field) {
367
+ let schema = field.integer ? zod.z.number().int() : zod.z.number();
368
+ if (field.min !== void 0) schema = schema.min(field.min);
369
+ if (field.max !== void 0) schema = schema.max(field.max);
370
+ if (field.step) {
371
+ schema = schema.refine(
372
+ (val) => Number.isInteger(val / field.step),
373
+ `Value must be divisible by ${field.step}`
374
+ );
375
+ }
376
+ if (field.hasMany) schema = zod.z.array(schema);
377
+ if (!field.required) schema = schema.optional().nullable();
378
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
379
+ return schema;
380
+ }
381
+ function checkboxToZod(field) {
382
+ let schema = zod.z.boolean();
383
+ if (!field.required) schema = schema.optional().nullable();
384
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
385
+ return schema;
386
+ }
387
+ function dateToZod(field) {
388
+ let schema = zod.z.string().refine((val) => !isNaN(Date.parse(val)), "Invalid date format");
389
+ if (field.minDate) {
390
+ schema = schema.refine(
391
+ (val) => new Date(val) >= new Date(field.minDate),
392
+ `Date must be after ${field.minDate}`
393
+ );
394
+ }
395
+ if (field.maxDate) {
396
+ schema = schema.refine(
397
+ (val) => new Date(val) <= new Date(field.maxDate),
398
+ `Date must be before ${field.maxDate}`
399
+ );
400
+ }
401
+ if (!field.required) schema = schema.optional().nullable();
402
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
403
+ return schema;
404
+ }
405
+ function emailToZod(field) {
406
+ let schema = zod.z.string().email("Invalid email");
407
+ if (!field.required) schema = schema.optional().nullable();
408
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
409
+ return schema;
410
+ }
411
+ function passwordToZod(field) {
412
+ let schema = zod.z.string().min(6, "Password must be at least 6 characters");
413
+ if (!field.required) schema = schema.optional().nullable();
414
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
415
+ return schema;
416
+ }
417
+ function textareaToZod(field) {
418
+ let schema = zod.z.string();
419
+ if (field.minLength) schema = schema.min(field.minLength);
420
+ if (field.maxLength) schema = schema.max(field.maxLength);
421
+ if (!field.required) schema = schema.optional().nullable();
422
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
423
+ return schema;
424
+ }
425
+ function selectToZod(field) {
426
+ const values = field.options.map((opt) => opt.value);
427
+ let schema;
428
+ if (field.hasMany) {
429
+ schema = zod.z.array(zod.z.enum(values));
430
+ } else {
431
+ schema = zod.z.enum(values);
432
+ }
433
+ if (!field.required) schema = schema.optional().nullable();
434
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
435
+ return schema;
436
+ }
437
+ function radioToZod(field) {
438
+ const values = field.options.map((opt) => opt.value);
439
+ let schema = zod.z.enum(values);
440
+ if (!field.required) schema = schema.optional().nullable();
441
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
442
+ return schema;
443
+ }
444
+ function colorToZod(field) {
445
+ let schema = zod.z.string();
446
+ if (field.format === "hex")
447
+ schema = schema.regex(/^#[0-9A-Fa-f]{6}$/);
448
+ if (field.format === "rgb")
449
+ schema = schema.regex(
450
+ /^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)$/
451
+ );
452
+ if (field.format === "hsl")
453
+ schema = schema.regex(
454
+ /^hsl\(\s*\d{1,3}\s*,\s*\d{1,3}%\s*,\s*\d{1,3}%\s*\)$/
455
+ );
456
+ if (!field.required) schema = schema.optional().nullable();
457
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
458
+ return schema;
459
+ }
460
+ function richTextToZod(field) {
461
+ let schema = zod.z.union([
462
+ zod.z.array(zod.z.record(zod.z.any())),
463
+ zod.z.string()
464
+ ]);
465
+ if (!field.required) schema = schema.optional().nullable();
466
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
467
+ return schema;
468
+ }
469
+ function jsonToZod(field) {
470
+ let schema = zod.z.union([zod.z.record(zod.z.any()), zod.z.array(zod.z.any())]);
471
+ if (!field.required) schema = schema.optional().nullable();
472
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
473
+ return schema;
474
+ }
475
+ function codeToZod(field) {
476
+ let schema = zod.z.string();
477
+ if (!field.required) schema = schema.optional().nullable();
478
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
479
+ return schema;
480
+ }
481
+ function uploadToZod(field) {
482
+ let schema;
483
+ if (field.relationTo) {
484
+ const mediaSchema = zod.z.object({
485
+ id: zod.z.string(),
486
+ url: zod.z.string().optional(),
487
+ filename: zod.z.string().optional(),
488
+ mimeType: zod.z.string().optional()
489
+ });
490
+ schema = zod.z.union([zod.z.string(), mediaSchema]);
491
+ } else {
492
+ schema = zod.z.string();
493
+ }
494
+ if (field.hasMany) {
495
+ schema = zod.z.array(schema);
496
+ }
497
+ if (!field.required) {
498
+ schema = schema.optional().nullable();
499
+ }
500
+ if (field.validate) {
501
+ schema = addCustomValidation(schema, field.validate);
502
+ }
503
+ return schema;
504
+ }
505
+ function markdownToZod(field) {
506
+ let schema = zod.z.string();
507
+ if (!field.required) schema = schema.optional().nullable();
508
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
509
+ return schema;
510
+ }
511
+ function relationshipToZod(field) {
512
+ let schema;
513
+ if (Array.isArray(field.relationTo)) {
514
+ schema = zod.z.object({
515
+ relationTo: zod.z.enum(field.relationTo),
516
+ value: zod.z.string()
517
+ });
518
+ } else {
519
+ schema = zod.z.union([
520
+ zod.z.string(),
521
+ zod.z.object({ relationTo: zod.z.string(), value: zod.z.string() })
522
+ ]);
523
+ }
524
+ if (field.hasMany) schema = zod.z.array(schema);
525
+ if (!field.required) schema = schema.optional().nullable();
526
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
527
+ return schema;
528
+ }
529
+ function arrayToZod(field) {
530
+ const itemSchema = zod.z.object(
531
+ Object.fromEntries(
532
+ field.fields.filter((f) => f.name).map((f) => [f.name, fieldToZod(f)])
533
+ )
534
+ );
535
+ let schema = zod.z.array(itemSchema);
536
+ if (field.minRows) schema = schema.min(field.minRows);
537
+ if (field.maxRows) schema = schema.max(field.maxRows);
538
+ if (!field.required) schema = schema.optional().nullable();
539
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
540
+ return schema;
541
+ }
542
+ function listToZod(field) {
543
+ let schema = zod.z.array(zod.z.string());
544
+ if (!field.required) schema = schema.optional().nullable();
545
+ return schema;
546
+ }
547
+ function groupToZod(field) {
548
+ const schema = zod.z.object(
549
+ Object.fromEntries(
550
+ field.fields.filter((f) => f.name).map((f) => [f.name, fieldToZod(f)])
551
+ )
552
+ );
553
+ if (!field.required) return schema.optional().nullable();
554
+ return schema;
555
+ }
556
+ function blocksToZod(field) {
557
+ const blocks = field.blocks || [];
558
+ blocks.map((block) => {
559
+ return zod.z.object({
560
+ blockType: zod.z.literal(block.slug),
561
+ ...Object.fromEntries(
562
+ block.fields.filter((f) => f.name).map((f) => [f.name, fieldToZod(f)])
563
+ )
564
+ });
565
+ });
566
+ const knownTypes = blocks.map((b) => b.slug);
567
+ let schema;
568
+ if (knownTypes.length > 0) {
569
+ const knownSchema = zod.z.object({
570
+ blockType: zod.z.enum(knownTypes)
571
+ }).catchall(zod.z.any());
572
+ const unknownSchema = zod.z.object({
573
+ blockType: zod.z.string()
574
+ }).catchall(zod.z.any());
575
+ schema = zod.z.array(zod.z.union([knownSchema, unknownSchema]));
576
+ } else {
577
+ schema = zod.z.array(zod.z.object({ blockType: zod.z.string() }).catchall(zod.z.any()));
578
+ }
579
+ if (field.minRows) schema = schema.min(field.minRows);
580
+ if (field.maxRows) schema = schema.max(field.maxRows);
581
+ if (!field.required) schema = schema.optional().nullable();
582
+ if (field.validate) schema = addCustomValidation(schema, field.validate);
583
+ return schema;
584
+ }
585
+ function rowToZod(field) {
586
+ const schema = zod.z.object(
587
+ Object.fromEntries(
588
+ field.fields.filter((f) => f.name).map((f) => [f.name, fieldToZod(f)])
589
+ )
590
+ );
591
+ return schema;
592
+ }
593
+ function collapsibleToZod(field) {
594
+ const schema = zod.z.object(
595
+ Object.fromEntries(
596
+ field.fields.filter((f) => f.name).map((f) => [f.name, fieldToZod(f)])
597
+ )
598
+ );
599
+ return schema;
600
+ }
601
+ function tabsToZod(field) {
602
+ const schemas = {};
603
+ for (const tab of field.tabs) {
604
+ for (const f of tab.fields) {
605
+ if (f.name) {
606
+ schemas[f.name] = fieldToZod(f);
607
+ }
608
+ }
609
+ }
610
+ return zod.z.object(schemas);
611
+ }
612
+ function addCustomValidation(schema, validate) {
613
+ return schema.refine(
614
+ async (val) => {
615
+ const result = await validate(val, { required: false });
616
+ return result === true;
617
+ },
618
+ {
619
+ message: "Custom validation failed"
620
+ }
621
+ );
622
+ }
623
+ function buildNestedShape(fields) {
624
+ const shape = {};
625
+ for (const field of fields) {
626
+ if (!field.name) continue;
627
+ if (field.type === "tabs" && "tabs" in field) {
628
+ const tabShape = {};
629
+ for (const tab of field.tabs) {
630
+ const nestedShape = buildNestedShape(tab.fields);
631
+ Object.assign(tabShape, nestedShape);
632
+ }
633
+ shape[field.name] = zod.z.object(tabShape);
634
+ } else if (field.type === "row" && "fields" in field) {
635
+ const rowShape = buildNestedShape(field.fields);
636
+ Object.assign(shape, rowShape);
637
+ } else if (field.type === "collapsible" && "fields" in field) {
638
+ shape[field.name] = zod.z.object(buildNestedShape(field.fields));
639
+ } else {
640
+ shape[field.name] = fieldToZod(field);
641
+ }
642
+ }
643
+ return shape;
644
+ }
645
+ function collectionToZod(collection) {
646
+ const shape = buildNestedShape(collection.fields);
647
+ if (collection.timestamps) {
648
+ shape["createdAt"] = zod.z.string().optional();
649
+ shape["updatedAt"] = zod.z.string().optional();
650
+ }
651
+ if (collection.tenantScoped) {
652
+ shape["tenantID"] = zod.z.string().optional();
653
+ }
654
+ shape["id"] = zod.z.string().optional();
655
+ return zod.z.object(shape).passthrough();
656
+ }
657
+ function collectionToCreateZod(collection) {
658
+ const shape = buildNestedShape(collection.fields);
659
+ return zod.z.object(shape).passthrough();
660
+ }
661
+ function collectionToUpdateZod(collection) {
662
+ const shape = {};
663
+ for (const field of collection.fields) {
664
+ if (!field.name) continue;
665
+ if (field.type === "tabs" && "tabs" in field) {
666
+ const tabShape = {};
667
+ for (const tab of field.tabs) {
668
+ for (const tabField of tab.fields) {
669
+ if (tabField.name) {
670
+ tabShape[tabField.name] = fieldToZod(tabField).optional().nullable();
671
+ }
672
+ }
673
+ }
674
+ shape[field.name] = zod.z.object(tabShape).optional().nullable();
675
+ } else if (field.type === "row" && "fields" in field) {
676
+ const rowShape = {};
677
+ for (const rowField of field.fields) {
678
+ if (rowField.name) {
679
+ rowShape[rowField.name] = fieldToZod(rowField).optional().nullable();
680
+ }
681
+ }
682
+ Object.assign(shape, rowShape);
683
+ } else if (field.type === "collapsible" && "fields" in field) {
684
+ shape[field.name] = zod.z.object(buildNestedShape(field.fields)).optional().nullable();
685
+ } else {
686
+ shape[field.name] = fieldToZod(field).optional().nullable();
687
+ }
688
+ }
689
+ return zod.z.object(shape).passthrough();
690
+ }
691
+ function collectionToWhereZod(collection) {
692
+ const shape = {};
693
+ for (const field of collection.fields) {
694
+ if (field.name) {
695
+ shape[field.name] = zod.z.object({
696
+ equals: zod.z.any().optional(),
697
+ not_equals: zod.z.any().optional(),
698
+ in: zod.z.array(zod.z.any()).optional(),
699
+ not_in: zod.z.array(zod.z.any()).optional(),
700
+ greater_than: zod.z.number().optional(),
701
+ greater_than_equal: zod.z.number().optional(),
702
+ less_than: zod.z.number().optional(),
703
+ less_than_equal: zod.z.number().optional(),
704
+ like: zod.z.string().optional(),
705
+ not_like: zod.z.string().optional(),
706
+ contains: zod.z.string().optional(),
707
+ exists: zod.z.boolean().optional()
708
+ }).optional();
709
+ }
710
+ }
711
+ shape["AND"] = zod.z.array(zod.z.lazy(() => zod.z.object(shape))).optional();
712
+ shape["OR"] = zod.z.array(zod.z.lazy(() => zod.z.object(shape))).optional();
713
+ return zod.z.object(shape).optional();
714
+ }
715
+ function globalToZod(global) {
716
+ const shape = buildNestedShape(global.fields);
717
+ shape["id"] = zod.z.string().optional();
718
+ return zod.z.object(shape).passthrough();
719
+ }
720
+
721
+ // src/registry/index.ts
722
+ var Registry = class {
723
+ collections = /* @__PURE__ */ new Map();
724
+ globals = /* @__PURE__ */ new Map();
725
+ plugins = [];
726
+ schemaCache = /* @__PURE__ */ new Map();
727
+ initialized = false;
728
+ // ========================================================================
729
+ // Collection Management
730
+ // ========================================================================
731
+ addCollection(config) {
732
+ if (this.initialized) {
733
+ throw new Error(
734
+ "Cannot add collections after Registry has been initialized"
735
+ );
736
+ }
737
+ if (this.collections.has(config.slug)) {
738
+ console.warn(
739
+ `[Registry] Duplicate collection slug "${config.slug}" \u2014 skipping`
740
+ );
741
+ return;
742
+ }
743
+ let finalConfig = { ...config };
744
+ for (const plugin of this.plugins) {
745
+ if (plugin.extendCollection) {
746
+ finalConfig = plugin.extendCollection(finalConfig.slug, finalConfig);
747
+ }
748
+ }
749
+ finalConfig.fields = this.applyFieldDefaults(finalConfig);
750
+ const errors = validateCollection(finalConfig);
751
+ if (errors.length > 0) {
752
+ throw new Error(`Invalid collection config: ${errors.join(", ")}`);
753
+ }
754
+ this.collections.set(finalConfig.slug, finalConfig);
755
+ this.clearSchemaCache(finalConfig.slug);
756
+ }
757
+ addCollections(configs) {
758
+ for (const config of configs) {
759
+ this.addCollection(config);
760
+ }
761
+ }
762
+ getCollection(slug) {
763
+ return this.collections.get(slug);
764
+ }
765
+ getCollections() {
766
+ return Array.from(this.collections.values());
767
+ }
768
+ getCollectionSlugs() {
769
+ return Array.from(this.collections.keys());
770
+ }
771
+ hasCollection(slug) {
772
+ return this.collections.has(slug);
773
+ }
774
+ removeCollection(slug) {
775
+ if (this.initialized) {
776
+ throw new Error(
777
+ "Cannot remove collections after Registry has been initialized"
778
+ );
779
+ }
780
+ this.clearSchemaCache(slug);
781
+ return this.collections.delete(slug);
782
+ }
783
+ // ========================================================================
784
+ // Global Management
785
+ // ========================================================================
786
+ addGlobal(config) {
787
+ if (this.initialized) {
788
+ throw new Error("Cannot add globals after Registry has been initialized");
789
+ }
790
+ if (this.globals.has(config.slug)) {
791
+ console.warn(
792
+ `[Registry] Duplicate global slug "${config.slug}" \u2014 skipping`
793
+ );
794
+ return;
795
+ }
796
+ const errors = validateGlobal(config);
797
+ if (errors.length > 0) {
798
+ throw new Error(`Invalid global config: ${errors.join(", ")}`);
799
+ }
800
+ let finalConfig = { ...config };
801
+ for (const plugin of this.plugins) {
802
+ if (plugin.extendGlobal) {
803
+ finalConfig = plugin.extendGlobal(finalConfig.slug, finalConfig);
804
+ }
805
+ }
806
+ this.globals.set(finalConfig.slug, finalConfig);
807
+ this.clearSchemaCache(`global:${finalConfig.slug}`);
808
+ }
809
+ addGlobals(configs) {
810
+ for (const config of configs) {
811
+ this.addGlobal(config);
812
+ }
813
+ }
814
+ getGlobal(slug) {
815
+ return this.globals.get(slug);
816
+ }
817
+ getGlobals() {
818
+ return Array.from(this.globals.values());
819
+ }
820
+ getGlobalSlugs() {
821
+ return Array.from(this.globals.keys());
822
+ }
823
+ hasGlobal(slug) {
824
+ return this.globals.has(slug);
825
+ }
826
+ removeGlobal(slug) {
827
+ if (this.initialized) {
828
+ throw new Error(
829
+ "Cannot remove globals after Registry has been initialized"
830
+ );
831
+ }
832
+ this.clearSchemaCache(`global:${slug}`);
833
+ return this.globals.delete(slug);
834
+ }
835
+ // ========================================================================
836
+ // Plugin Management
837
+ // ========================================================================
838
+ addPlugin(plugin) {
839
+ if (this.initialized) {
840
+ throw new Error("Cannot add plugins after Registry has been initialized");
841
+ }
842
+ this.plugins.push(plugin);
843
+ }
844
+ getPlugins() {
845
+ return [...this.plugins];
846
+ }
847
+ // ========================================================================
848
+ // Schema Generation
849
+ // ========================================================================
850
+ getZodSchema(slug) {
851
+ const cached = this.schemaCache.get(slug);
852
+ if (cached) return cached;
853
+ const collection = this.collections.get(slug);
854
+ if (collection) {
855
+ const schema = collectionToZod(collection);
856
+ this.schemaCache.set(slug, schema);
857
+ return schema;
858
+ }
859
+ const global = this.globals.get(slug);
860
+ if (global) {
861
+ const schema = globalToZod(global);
862
+ this.schemaCache.set(`global:${slug}`, schema);
863
+ return schema;
864
+ }
865
+ throw new Error(`No collection or global found with slug "${slug}"`);
866
+ }
867
+ getCreateZodSchema(slug) {
868
+ const cacheKey = `${slug}:create`;
869
+ const cached = this.schemaCache.get(cacheKey);
870
+ if (cached) return cached;
871
+ const collection = this.collections.get(slug);
872
+ if (collection) {
873
+ const schema = collectionToCreateZod(collection);
874
+ this.schemaCache.set(cacheKey, schema);
875
+ return schema;
876
+ }
877
+ throw new Error(`No collection found with slug "${slug}"`);
878
+ }
879
+ getUpdateZodSchema(slug) {
880
+ const cacheKey = `${slug}:update`;
881
+ const cached = this.schemaCache.get(cacheKey);
882
+ if (cached) return cached;
883
+ const collection = this.collections.get(slug);
884
+ if (collection) {
885
+ const schema = collectionToUpdateZod(collection);
886
+ this.schemaCache.set(cacheKey, schema);
887
+ return schema;
888
+ }
889
+ throw new Error(`No collection found with slug "${slug}"`);
890
+ }
891
+ getWhereZodSchema(slug) {
892
+ const cacheKey = `${slug}:where`;
893
+ const cached = this.schemaCache.get(cacheKey);
894
+ if (cached) return cached;
895
+ const collection = this.collections.get(slug);
896
+ if (collection) {
897
+ const schema = collectionToWhereZod(collection);
898
+ this.schemaCache.set(cacheKey, schema);
899
+ return schema;
900
+ }
901
+ throw new Error(`No collection found with slug "${slug}"`);
902
+ }
903
+ getFieldZodSchema(field) {
904
+ return fieldToZod(field);
905
+ }
906
+ clearSchemaCache(slug) {
907
+ this.schemaCache.delete(slug);
908
+ this.schemaCache.delete(`${slug}:create`);
909
+ this.schemaCache.delete(`${slug}:update`);
910
+ this.schemaCache.delete(`${slug}:where`);
911
+ }
912
+ // ========================================================================
913
+ // Field Helpers
914
+ // ========================================================================
915
+ applyFieldDefaults(config) {
916
+ const fields = [...config.fields];
917
+ if (!fields.some((f) => f.name === "id")) {
918
+ fields.unshift({
919
+ name: "id",
920
+ type: "text",
921
+ admin: { readOnly: true, hidden: true }
922
+ });
923
+ }
924
+ if (config.tenantScoped && !fields.some((f) => f.name === "tenantID")) {
925
+ fields.push({
926
+ name: "tenantID",
927
+ type: "text",
928
+ required: true,
929
+ admin: { readOnly: true, hidden: true }
930
+ });
931
+ }
932
+ if (config.timestamps && !fields.some((f) => f.name === "createdAt")) {
933
+ fields.push({
934
+ name: "createdAt",
935
+ type: "date",
936
+ admin: { readOnly: true, hidden: true }
937
+ });
938
+ fields.push({
939
+ name: "updatedAt",
940
+ type: "date",
941
+ admin: { readOnly: true, hidden: true }
942
+ });
943
+ }
944
+ if (config.auth && !fields.some((f) => f.name === "password")) {
945
+ fields.push({
946
+ name: "password",
947
+ type: "password",
948
+ required: true,
949
+ admin: { hidden: true }
950
+ });
951
+ }
952
+ return fields;
953
+ }
954
+ getFields(slug) {
955
+ const collection = this.collections.get(slug);
956
+ if (collection) return collection.fields;
957
+ const global = this.globals.get(slug);
958
+ if (global) return global.fields;
959
+ throw new Error(`No collection or global found with slug "${slug}"`);
960
+ }
961
+ getFieldMap(slug) {
962
+ const fields = this.getFields(slug);
963
+ const map = /* @__PURE__ */ new Map();
964
+ const addFields = (fields2) => {
965
+ for (const field of fields2) {
966
+ if (field.name) {
967
+ map.set(field.name, field);
968
+ }
969
+ if ("fields" in field && field.fields) {
970
+ addFields(field.fields);
971
+ }
972
+ if ("tabs" in field) {
973
+ for (const tab of field.tabs) {
974
+ addFields(tab.fields);
975
+ }
976
+ }
977
+ if ("blocks" in field) {
978
+ for (const block of field.blocks) {
979
+ addFields(block.fields);
980
+ }
981
+ }
982
+ }
983
+ };
984
+ addFields(fields);
985
+ return map;
986
+ }
987
+ getVisibleFields(slug) {
988
+ const fields = this.getFields(slug);
989
+ return fields.filter((f) => !f.admin?.hidden);
990
+ }
991
+ // ========================================================================
992
+ // Initialization
993
+ // ========================================================================
994
+ validate() {
995
+ const collections = this.getCollections();
996
+ const globals = this.getGlobals();
997
+ validateConfig(collections, globals);
998
+ }
999
+ async init() {
1000
+ this.validate();
1001
+ for (const plugin of this.plugins) {
1002
+ if (plugin.init) {
1003
+ await plugin.init(this);
1004
+ }
1005
+ }
1006
+ this.initialized = true;
1007
+ }
1008
+ isInitialized() {
1009
+ return this.initialized;
1010
+ }
1011
+ // ========================================================================
1012
+ // Query Helpers
1013
+ // ========================================================================
1014
+ getPaginationDefaults(slug) {
1015
+ const collection = this.collections.get(slug);
1016
+ return {
1017
+ defaultLimit: collection?.admin?.pagination?.defaultLimit || 10,
1018
+ limits: collection?.admin?.pagination?.limits || [10, 25, 50, 100]
1019
+ };
1020
+ }
1021
+ getDefaultSort(slug) {
1022
+ const collection = this.collections.get(slug);
1023
+ const useAsTitle = collection?.admin?.useAsTitle;
1024
+ if (useAsTitle) return useAsTitle;
1025
+ return "createdAt";
1026
+ }
1027
+ getDefaultColumns(slug) {
1028
+ const collection = this.collections.get(slug);
1029
+ if (collection?.admin?.defaultColumns) {
1030
+ return collection.admin.defaultColumns;
1031
+ }
1032
+ const fields = this.getVisibleFields(slug);
1033
+ return fields.slice(0, 4).map((f) => f.name);
1034
+ }
1035
+ // ========================================================================
1036
+ // Admin Helpers
1037
+ // ========================================================================
1038
+ getAdminTitle(slug) {
1039
+ const collection = this.collections.get(slug);
1040
+ return collection?.label || collection?.admin?.description || slug;
1041
+ }
1042
+ getAdminLabel(slug) {
1043
+ const collection = this.collections.get(slug);
1044
+ return collection?.singularLabel || collection?.label || slug;
1045
+ }
1046
+ getAdminGroup(slug) {
1047
+ return this.collections.get(slug)?.admin?.group;
1048
+ }
1049
+ // ========================================================================
1050
+ // Debug / Stats
1051
+ // ========================================================================
1052
+ getStats() {
1053
+ let totalFields = 0;
1054
+ for (const collection of this.collections.values()) {
1055
+ totalFields += collection.fields.length;
1056
+ }
1057
+ for (const global of this.globals.values()) {
1058
+ totalFields += global.fields.length;
1059
+ }
1060
+ return {
1061
+ collections: this.collections.size,
1062
+ globals: this.globals.size,
1063
+ plugins: this.plugins.length,
1064
+ fields: totalFields
1065
+ };
1066
+ }
1067
+ toJSON() {
1068
+ return {
1069
+ collections: this.getCollections(),
1070
+ globals: this.getGlobals()
1071
+ };
1072
+ }
1073
+ };
1074
+ var instance = null;
1075
+ function getRegistry() {
1076
+ if (!instance) {
1077
+ instance = new Registry();
1078
+ }
1079
+ return instance;
1080
+ }
1081
+ function resetRegistry() {
1082
+ instance = null;
1083
+ }
1084
+ function createRegistry() {
1085
+ instance = new Registry();
1086
+ return instance;
1087
+ }
1088
+ var Kyro = class {
1089
+ registry;
1090
+ db;
1091
+ pubsub;
1092
+ webhookService;
1093
+ settings;
1094
+ wsServer;
1095
+ config;
1096
+ constructor(config) {
1097
+ this.config = config;
1098
+ this.registry = createRegistry();
1099
+ this.db = config.adapter;
1100
+ this.pubsub = new chunkDVD5P72E_cjs.KyroPubSub(this.registry);
1101
+ this.webhookService = chunkIBG6V56E_cjs.createWebhookService(this.db);
1102
+ if (config.collections) {
1103
+ this.registry.addCollections(config.collections);
1104
+ }
1105
+ if (config.globals) {
1106
+ this.registry.addGlobals(config.globals);
1107
+ }
1108
+ if (config.plugins) {
1109
+ for (const plugin of config.plugins) {
1110
+ this.registry.addPlugin(plugin);
1111
+ }
1112
+ }
1113
+ }
1114
+ async init() {
1115
+ await this.registry.init();
1116
+ if (!this.db) {
1117
+ throw new Error(
1118
+ `Database adapter is null \u2014 failed to load at startup. Check the server console for the exact error.`
1119
+ );
1120
+ }
1121
+ const systemCollection = {
1122
+ slug: chunkIBG6V56E_cjs.API_KEY_COLLECTION,
1123
+ fields: [
1124
+ { name: "userId", type: "text", required: true },
1125
+ { name: "name", type: "text", required: true },
1126
+ { name: "key", type: "text", required: true },
1127
+ { name: "keyPrefix", type: "text", required: true },
1128
+ { name: "permissions", type: "json" },
1129
+ { name: "lastUsedAt", type: "date" },
1130
+ { name: "expiresAt", type: "date" }
1131
+ ]
1132
+ };
1133
+ const webhookCollection = {
1134
+ slug: chunkIBG6V56E_cjs.WEBHOOK_COLLECTION,
1135
+ fields: [
1136
+ { name: "name", type: "text", required: true },
1137
+ { name: "url", type: "text", required: true },
1138
+ { name: "events", type: "json", required: true },
1139
+ { name: "status", type: "text", required: true },
1140
+ { name: "secret", type: "text" },
1141
+ { name: "headers", type: "json" },
1142
+ { name: "lastTriggered", type: "date" },
1143
+ { name: "lastError", type: "text" }
1144
+ ]
1145
+ };
1146
+ const webhookDeliveryCollection = {
1147
+ slug: chunkIBG6V56E_cjs.WEBHOOK_DELIVERY_COLLECTION,
1148
+ fields: [
1149
+ { name: "webhookId", type: "text", required: true },
1150
+ { name: "event", type: "text", required: true },
1151
+ { name: "payload", type: "json", required: true },
1152
+ { name: "attempt", type: "number", required: true },
1153
+ { name: "status", type: "text", required: true },
1154
+ { name: "responseStatus", type: "number" },
1155
+ { name: "responseBody", type: "text" },
1156
+ { name: "error", type: "text" },
1157
+ { name: "duration", type: "number" },
1158
+ { name: "deliveredAt", type: "date" },
1159
+ { name: "nextRetryAt", type: "date" }
1160
+ ]
1161
+ };
1162
+ await this.db.init(
1163
+ [
1164
+ ...this.registry.getCollections(),
1165
+ systemCollection,
1166
+ webhookCollection,
1167
+ webhookDeliveryCollection
1168
+ ],
1169
+ this.registry.getGlobals()
1170
+ );
1171
+ this.pubsub.autoRegisterHooks();
1172
+ console.log("\u2705 Kyro CMS initialized");
1173
+ console.log(` Collections: ${this.registry.getCollections().length}`);
1174
+ console.log(` Globals: ${this.registry.getGlobals().length}`);
1175
+ }
1176
+ // ============================================================================
1177
+ // API Methods
1178
+ // ============================================================================
1179
+ // Load settings from globals if not already loaded
1180
+ async loadSettings() {
1181
+ if (this.settings) return this.settings;
1182
+ try {
1183
+ const accessSettings = await this.db.findOne({
1184
+ collection: "_globals",
1185
+ where: { slug: "access-settings" }
1186
+ });
1187
+ if (accessSettings) {
1188
+ this.settings = accessSettings.data;
1189
+ }
1190
+ } catch (e) {
1191
+ console.log("\u26A0\uFE0F No access-settings found, using defaults");
1192
+ }
1193
+ return this.settings || {};
1194
+ }
1195
+ getREST(options) {
1196
+ const authObj = typeof this.config.auth === "object" ? this.config.auth : null;
1197
+ const authSecret = authObj?.secret;
1198
+ const checkSession = authObj?.checkSession !== false;
1199
+ return chunkDE7OQOMD_cjs.createHonoApp({
1200
+ registry: this.registry,
1201
+ db: this.db,
1202
+ authSecret,
1203
+ authAdapter: this.config.authAdapter,
1204
+ checkSession,
1205
+ ...options,
1206
+ cors: this.config.cors,
1207
+ webhookService: this.webhookService,
1208
+ settings: this.settings
1209
+ });
1210
+ }
1211
+ getGraphQL(options) {
1212
+ return chunkVJT6P4N6_cjs.buildGraphQLSchema({
1213
+ registry: this.registry,
1214
+ db: this.db,
1215
+ ...options,
1216
+ settings: this.settings
1217
+ });
1218
+ }
1219
+ getTRPC(options) {
1220
+ return chunkK7JPTH3G_cjs.createKyroServer({
1221
+ registry: this.registry,
1222
+ db: this.db,
1223
+ req: options?.req || { headers: {} },
1224
+ ...options,
1225
+ settings: this.settings
1226
+ });
1227
+ }
1228
+ async startWebSocket(options) {
1229
+ const apiAccess = this.settings?.access?.apiAccess;
1230
+ if (apiAccess?.websocketEnabled === false) {
1231
+ console.log("\u26A0\uFE0F WebSocket is disabled in settings");
1232
+ return null;
1233
+ }
1234
+ this.wsServer = chunkDVD5P72E_cjs.createWSServer({
1235
+ pubsub: this.pubsub,
1236
+ port: options?.port || 8080,
1237
+ requireAuth: options?.requireAuth ?? apiAccess?.requireAuth,
1238
+ verifyToken: options?.verifyToken
1239
+ });
1240
+ console.log(`\u{1F50C} WebSocket server started on port ${options?.port || 8080}`);
1241
+ return this.wsServer;
1242
+ }
1243
+ // ============================================================================
1244
+ // Lifecycle
1245
+ // ============================================================================
1246
+ async shutdown() {
1247
+ if (this.wsServer) {
1248
+ await this.wsServer.close();
1249
+ }
1250
+ await this.db.disconnect();
1251
+ console.log("\u{1F44B} Kyro CMS shut down");
1252
+ }
1253
+ };
1254
+ function createKyro(config) {
1255
+ return new Kyro(config);
1256
+ }
1257
+
1258
+ exports.ConfigValidationError = ConfigValidationError;
1259
+ exports.Kyro = Kyro;
1260
+ exports.Registry = Registry;
1261
+ exports.collectionToCreateZod = collectionToCreateZod;
1262
+ exports.collectionToUpdateZod = collectionToUpdateZod;
1263
+ exports.collectionToWhereZod = collectionToWhereZod;
1264
+ exports.collectionToZod = collectionToZod;
1265
+ exports.createKyro = createKyro;
1266
+ exports.createRegistry = createRegistry;
1267
+ exports.fieldToZod = fieldToZod;
1268
+ exports.getRegistry = getRegistry;
1269
+ exports.globalToZod = globalToZod;
1270
+ exports.resetRegistry = resetRegistry;
1271
+ exports.validateCollection = validateCollection;
1272
+ exports.validateConfig = validateConfig;
1273
+ exports.validateFields = validateFields;
1274
+ exports.validateGlobal = validateGlobal;
1275
+ //# sourceMappingURL=chunk-2UOI5MUC.cjs.map
1276
+ //# sourceMappingURL=chunk-2UOI5MUC.cjs.map