@kyro-cms/core 0.10.4 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/dist/api-handler-graphql.cjs +1 -49
  2. package/dist/api-handler-graphql.js +1 -46
  3. package/dist/api-handler-trpc.cjs +1 -38
  4. package/dist/api-handler-trpc.js +1 -36
  5. package/dist/api-handler.cjs +1 -44
  6. package/dist/api-handler.js +1 -27
  7. package/dist/bootstrap-HIAV5ZFT.cjs +1 -0
  8. package/dist/bootstrap-P7QPQYQP.js +1 -0
  9. package/dist/chunk-2BTRHVT3.cjs +20 -0
  10. package/dist/chunk-2W4FK6CJ.js +122 -0
  11. package/dist/chunk-4ORJMSJU.cjs +1 -0
  12. package/dist/chunk-65G73T7Z.cjs +2 -0
  13. package/dist/chunk-7N6NKCRT.js +1 -0
  14. package/dist/chunk-7WOX27LK.js +259 -0
  15. package/dist/chunk-AE6GXUT7.js +1 -0
  16. package/dist/chunk-AJAZ7D3W.cjs +259 -0
  17. package/dist/chunk-ATLSIYRH.cjs +1 -0
  18. package/dist/chunk-AU6IWTBO.js +2 -0
  19. package/dist/chunk-CDL7ARXT.js +133 -0
  20. package/dist/chunk-CUTFS6N2.cjs +1 -0
  21. package/dist/chunk-CVVW4LXZ.cjs +1 -0
  22. package/dist/chunk-DGJUBN33.js +1 -0
  23. package/dist/chunk-DV4LFLPL.cjs +1 -0
  24. package/dist/chunk-EEWCANFX.js +1 -0
  25. package/dist/chunk-ELICKLFM.cjs +3 -0
  26. package/dist/chunk-EQUQJBPP.cjs +2 -0
  27. package/dist/chunk-ET6NN2V2.cjs +122 -0
  28. package/dist/chunk-F7P36SLX.cjs +74 -0
  29. package/dist/chunk-F7SR5IDT.cjs +1 -0
  30. package/dist/chunk-FO3HLBC7.js +1 -0
  31. package/dist/chunk-FS7GL2BR.js +73 -0
  32. package/dist/chunk-G6A7OSIG.js +2 -0
  33. package/dist/chunk-GFU7AOI3.cjs +1 -0
  34. package/dist/chunk-GYQMNXXW.cjs +114 -0
  35. package/dist/chunk-HLSB2MCK.js +1 -0
  36. package/dist/chunk-HVXO3OFB.cjs +1 -0
  37. package/dist/chunk-IFJJ44OQ.cjs +133 -0
  38. package/dist/chunk-ISWMETHJ.cjs +1 -0
  39. package/dist/chunk-K6WUOU6P.js +1 -0
  40. package/dist/chunk-KDNYHLD2.js +1 -0
  41. package/dist/chunk-KIW36TG7.cjs +86 -0
  42. package/dist/chunk-L6CZYN3L.cjs +20 -0
  43. package/dist/chunk-LRGAPGG3.js +74 -0
  44. package/dist/chunk-LZ6YFYQM.js +20 -0
  45. package/dist/chunk-MIOMMB23.cjs +1 -0
  46. package/dist/chunk-NGBJKZMT.js +90 -0
  47. package/dist/chunk-NRLIGDYF.js +1 -0
  48. package/dist/chunk-NY47CFVP.cjs +1 -0
  49. package/dist/chunk-NZ35PV5R.js +2 -0
  50. package/dist/chunk-OG7CNQGU.js +1 -0
  51. package/dist/chunk-OQD3WG6Z.cjs +1 -0
  52. package/dist/chunk-P7CESLDJ.js +1 -0
  53. package/dist/chunk-PP5S2UBV.js +0 -0
  54. package/dist/chunk-Q3Q7BJVQ.cjs +1 -0
  55. package/dist/chunk-Q4CSLXCO.cjs +90 -0
  56. package/dist/chunk-QRXDCV6K.js +0 -0
  57. package/dist/chunk-R7DVVXXI.cjs +73 -0
  58. package/dist/chunk-RHCWCG3O.js +114 -0
  59. package/dist/chunk-SL3LZQCF.js +1 -0
  60. package/dist/chunk-UBHFUFD4.cjs +1 -0
  61. package/dist/chunk-UBRYJP2G.js +1 -0
  62. package/dist/chunk-UDSJGML2.cjs +2 -0
  63. package/dist/chunk-UHFDH3PG.js +20 -0
  64. package/dist/chunk-UJNSOOYZ.cjs +1 -0
  65. package/dist/chunk-URCLFIME.js +86 -0
  66. package/dist/chunk-UVTS2IWM.js +1 -0
  67. package/dist/chunk-V65NPSR5.cjs +1 -0
  68. package/dist/chunk-WIZ6C5QZ.cjs +1 -0
  69. package/dist/chunk-ZAQOSRP6.js +1 -0
  70. package/dist/chunk-ZELCS7IC.js +3 -0
  71. package/dist/cli/index.cjs +35 -405
  72. package/dist/cli/index.js +35 -402
  73. package/dist/client.cjs +1 -55
  74. package/dist/client.js +1 -6
  75. package/dist/drizzle/index.cjs +1 -50
  76. package/dist/drizzle/index.d.cts +1 -2
  77. package/dist/drizzle/index.d.ts +1 -2
  78. package/dist/drizzle/index.js +1 -9
  79. package/dist/fields/index.cjs +1 -89
  80. package/dist/fields/index.js +1 -4
  81. package/dist/graphql/index.cjs +1 -31
  82. package/dist/graphql/index.d.cts +1 -1
  83. package/dist/graphql/index.d.ts +1 -1
  84. package/dist/graphql/index.js +1 -6
  85. package/dist/{index-jLs0zlft.d.ts → index-DXr33e0x.d.ts} +1 -1
  86. package/dist/{index-DHbywDs-.d.cts → index-DuuUzWBq.d.cts} +1 -1
  87. package/dist/index.cjs +29 -2464
  88. package/dist/index.d.cts +2 -2
  89. package/dist/index.d.ts +2 -2
  90. package/dist/index.js +29 -1929
  91. package/dist/integration.cjs +1 -10
  92. package/dist/integration.js +1 -4
  93. package/dist/media-NSSMOB7N.cjs +1 -0
  94. package/dist/media-RNMCZYPZ.js +1 -0
  95. package/dist/mongo-auth-adapter-JYJ4GBZE.cjs +1 -0
  96. package/dist/mongo-auth-adapter-XI7EPURZ.js +1 -0
  97. package/dist/mongodb/index.cjs +1 -29
  98. package/dist/mongodb/index.d.cts +1 -2
  99. package/dist/mongodb/index.d.ts +1 -2
  100. package/dist/mongodb/index.js +1 -8
  101. package/dist/postgres-auth-adapter-E7OGMDD4.cjs +1 -0
  102. package/dist/postgres-auth-adapter-F4KLOGAG.js +1 -0
  103. package/dist/redis-adapter-AQJVABYT.cjs +1 -0
  104. package/dist/redis-adapter-AUKOV74G.js +1 -0
  105. package/dist/rest/index.cjs +1 -31
  106. package/dist/rest/index.d.cts +1 -1
  107. package/dist/rest/index.d.ts +1 -1
  108. package/dist/rest/index.js +1 -18
  109. package/dist/schema-5XNROI7I.js +1 -0
  110. package/dist/schema-6O4JTJRU.cjs +1 -0
  111. package/dist/sqlite-adapter-5XFLNJDH.js +1 -0
  112. package/dist/sqlite-adapter-W53Q32N5.cjs +1 -0
  113. package/dist/templates/index.cjs +1 -207
  114. package/dist/templates/index.js +1 -6
  115. package/dist/trpc/index.cjs +1 -48
  116. package/dist/trpc/index.js +1 -7
  117. package/dist/ws/index.cjs +1 -25
  118. package/dist/ws/index.js +1 -4
  119. package/package.json +44 -13
  120. package/dist/api-handler-graphql.cjs.map +0 -1
  121. package/dist/api-handler-graphql.js.map +0 -1
  122. package/dist/api-handler-trpc.cjs.map +0 -1
  123. package/dist/api-handler-trpc.js.map +0 -1
  124. package/dist/api-handler.cjs.map +0 -1
  125. package/dist/api-handler.js.map +0 -1
  126. package/dist/bootstrap-FUAPY2OF.cjs +0 -32
  127. package/dist/bootstrap-FUAPY2OF.cjs.map +0 -1
  128. package/dist/bootstrap-OXNVM7FP.js +0 -7
  129. package/dist/bootstrap-OXNVM7FP.js.map +0 -1
  130. package/dist/chunk-2HFJUUFZ.js +0 -250
  131. package/dist/chunk-2HFJUUFZ.js.map +0 -1
  132. package/dist/chunk-3AKCVYDB.js +0 -162
  133. package/dist/chunk-3AKCVYDB.js.map +0 -1
  134. package/dist/chunk-3KTWGODI.cjs +0 -178
  135. package/dist/chunk-3KTWGODI.cjs.map +0 -1
  136. package/dist/chunk-3YELQL7Z.cjs +0 -4
  137. package/dist/chunk-3YELQL7Z.cjs.map +0 -1
  138. package/dist/chunk-4CV4JOE5.js +0 -24
  139. package/dist/chunk-4CV4JOE5.js.map +0 -1
  140. package/dist/chunk-4OCMVGEY.cjs +0 -173
  141. package/dist/chunk-4OCMVGEY.cjs.map +0 -1
  142. package/dist/chunk-4PWRCMTQ.cjs +0 -15
  143. package/dist/chunk-4PWRCMTQ.cjs.map +0 -1
  144. package/dist/chunk-53NYVYVX.js +0 -3243
  145. package/dist/chunk-53NYVYVX.js.map +0 -1
  146. package/dist/chunk-5GFQPHGT.cjs +0 -156
  147. package/dist/chunk-5GFQPHGT.cjs.map +0 -1
  148. package/dist/chunk-5RPRLTTN.js +0 -861
  149. package/dist/chunk-5RPRLTTN.js.map +0 -1
  150. package/dist/chunk-74YSDAWE.cjs +0 -2749
  151. package/dist/chunk-74YSDAWE.cjs.map +0 -1
  152. package/dist/chunk-7OGPN7MP.js +0 -352
  153. package/dist/chunk-7OGPN7MP.js.map +0 -1
  154. package/dist/chunk-7OS7TX2Q.cjs +0 -495
  155. package/dist/chunk-7OS7TX2Q.cjs.map +0 -1
  156. package/dist/chunk-ADLJSJSN.cjs +0 -13
  157. package/dist/chunk-ADLJSJSN.cjs.map +0 -1
  158. package/dist/chunk-B6X3LN25.cjs +0 -6486
  159. package/dist/chunk-B6X3LN25.cjs.map +0 -1
  160. package/dist/chunk-BYBMTIMT.js +0 -419
  161. package/dist/chunk-BYBMTIMT.js.map +0 -1
  162. package/dist/chunk-CF7OL6HR.js +0 -355
  163. package/dist/chunk-CF7OL6HR.js.map +0 -1
  164. package/dist/chunk-CJX74IYK.js +0 -489
  165. package/dist/chunk-CJX74IYK.js.map +0 -1
  166. package/dist/chunk-CKVOU6MX.cjs +0 -52
  167. package/dist/chunk-CKVOU6MX.cjs.map +0 -1
  168. package/dist/chunk-CZLDE2OZ.cjs +0 -28
  169. package/dist/chunk-CZLDE2OZ.cjs.map +0 -1
  170. package/dist/chunk-DPA3KWPY.cjs +0 -205
  171. package/dist/chunk-DPA3KWPY.cjs.map +0 -1
  172. package/dist/chunk-EEJUFDMF.cjs +0 -424
  173. package/dist/chunk-EEJUFDMF.cjs.map +0 -1
  174. package/dist/chunk-FIAMXNTH.js +0 -220
  175. package/dist/chunk-FIAMXNTH.js.map +0 -1
  176. package/dist/chunk-GAOXD3XT.js +0 -175
  177. package/dist/chunk-GAOXD3XT.js.map +0 -1
  178. package/dist/chunk-GTGRLD4Y.js +0 -3
  179. package/dist/chunk-GTGRLD4Y.js.map +0 -1
  180. package/dist/chunk-GUUB5EAG.cjs +0 -223
  181. package/dist/chunk-GUUB5EAG.cjs.map +0 -1
  182. package/dist/chunk-GXFOGU7N.cjs +0 -359
  183. package/dist/chunk-GXFOGU7N.cjs.map +0 -1
  184. package/dist/chunk-GZS4LMR7.js +0 -422
  185. package/dist/chunk-GZS4LMR7.js.map +0 -1
  186. package/dist/chunk-HY6B7B5A.js +0 -150
  187. package/dist/chunk-HY6B7B5A.js.map +0 -1
  188. package/dist/chunk-HZOMOK5Y.js +0 -2728
  189. package/dist/chunk-HZOMOK5Y.js.map +0 -1
  190. package/dist/chunk-IDVRRRAK.cjs +0 -824
  191. package/dist/chunk-IDVRRRAK.cjs.map +0 -1
  192. package/dist/chunk-KC2GDBLS.cjs +0 -84
  193. package/dist/chunk-KC2GDBLS.cjs.map +0 -1
  194. package/dist/chunk-L4EZKIEX.js +0 -185
  195. package/dist/chunk-L4EZKIEX.js.map +0 -1
  196. package/dist/chunk-LNTFRAHF.cjs +0 -473
  197. package/dist/chunk-LNTFRAHF.cjs.map +0 -1
  198. package/dist/chunk-MTIRYI7F.cjs +0 -4
  199. package/dist/chunk-MTIRYI7F.cjs.map +0 -1
  200. package/dist/chunk-N4GN6Q3V.cjs +0 -869
  201. package/dist/chunk-N4GN6Q3V.cjs.map +0 -1
  202. package/dist/chunk-N4H37VN4.cjs +0 -259
  203. package/dist/chunk-N4H37VN4.cjs.map +0 -1
  204. package/dist/chunk-N5QSHUA6.js +0 -1135
  205. package/dist/chunk-N5QSHUA6.js.map +0 -1
  206. package/dist/chunk-NKPKR5BW.cjs +0 -188
  207. package/dist/chunk-NKPKR5BW.cjs.map +0 -1
  208. package/dist/chunk-OIRG6ZRV.cjs +0 -1073
  209. package/dist/chunk-OIRG6ZRV.cjs.map +0 -1
  210. package/dist/chunk-OJ2AM75W.cjs +0 -253
  211. package/dist/chunk-OJ2AM75W.cjs.map +0 -1
  212. package/dist/chunk-OLV7K22H.js +0 -6457
  213. package/dist/chunk-OLV7K22H.js.map +0 -1
  214. package/dist/chunk-OX6GOIPH.js +0 -516
  215. package/dist/chunk-OX6GOIPH.js.map +0 -1
  216. package/dist/chunk-P2YW545G.js +0 -11
  217. package/dist/chunk-P2YW545G.js.map +0 -1
  218. package/dist/chunk-PHJRNPHY.cjs +0 -3291
  219. package/dist/chunk-PHJRNPHY.cjs.map +0 -1
  220. package/dist/chunk-Q72BOAPK.js +0 -817
  221. package/dist/chunk-Q72BOAPK.js.map +0 -1
  222. package/dist/chunk-QU2RFFH4.js +0 -3
  223. package/dist/chunk-QU2RFFH4.js.map +0 -1
  224. package/dist/chunk-RP7VZUEL.js +0 -49
  225. package/dist/chunk-RP7VZUEL.js.map +0 -1
  226. package/dist/chunk-SHTTJMLT.cjs +0 -361
  227. package/dist/chunk-SHTTJMLT.cjs.map +0 -1
  228. package/dist/chunk-SX76DNOO.js +0 -103
  229. package/dist/chunk-SX76DNOO.js.map +0 -1
  230. package/dist/chunk-THBQG64D.cjs +0 -425
  231. package/dist/chunk-THBQG64D.cjs.map +0 -1
  232. package/dist/chunk-TQG7G7YI.cjs +0 -526
  233. package/dist/chunk-TQG7G7YI.cjs.map +0 -1
  234. package/dist/chunk-U3VVLYXG.cjs +0 -189
  235. package/dist/chunk-U3VVLYXG.cjs.map +0 -1
  236. package/dist/chunk-UUDTPZX6.js +0 -193
  237. package/dist/chunk-UUDTPZX6.js.map +0 -1
  238. package/dist/chunk-V5AWATUP.js +0 -1059
  239. package/dist/chunk-V5AWATUP.js.map +0 -1
  240. package/dist/chunk-VAXLFZCV.cjs +0 -110
  241. package/dist/chunk-VAXLFZCV.cjs.map +0 -1
  242. package/dist/chunk-VKREAIBA.cjs +0 -1139
  243. package/dist/chunk-VKREAIBA.cjs.map +0 -1
  244. package/dist/chunk-WDTTHKDS.js +0 -458
  245. package/dist/chunk-WDTTHKDS.js.map +0 -1
  246. package/dist/chunk-WXVB364T.js +0 -218
  247. package/dist/chunk-WXVB364T.js.map +0 -1
  248. package/dist/chunk-X4BPPD6K.js +0 -181
  249. package/dist/chunk-X4BPPD6K.js.map +0 -1
  250. package/dist/chunk-XEB7PH2E.js +0 -81
  251. package/dist/chunk-XEB7PH2E.js.map +0 -1
  252. package/dist/chunk-YT7HXXVN.js +0 -13
  253. package/dist/chunk-YT7HXXVN.js.map +0 -1
  254. package/dist/cli/index.cjs.map +0 -1
  255. package/dist/cli/index.js.map +0 -1
  256. package/dist/client.cjs.map +0 -1
  257. package/dist/client.js.map +0 -1
  258. package/dist/drizzle/index.cjs.map +0 -1
  259. package/dist/drizzle/index.js.map +0 -1
  260. package/dist/fields/index.cjs.map +0 -1
  261. package/dist/fields/index.js.map +0 -1
  262. package/dist/graphql/index.cjs.map +0 -1
  263. package/dist/graphql/index.js.map +0 -1
  264. package/dist/index.cjs.map +0 -1
  265. package/dist/index.js.map +0 -1
  266. package/dist/integration.cjs.map +0 -1
  267. package/dist/integration.js.map +0 -1
  268. package/dist/media-7WDX4BDJ.js +0 -4
  269. package/dist/media-7WDX4BDJ.js.map +0 -1
  270. package/dist/media-TUSLVRQ6.cjs +0 -17
  271. package/dist/media-TUSLVRQ6.cjs.map +0 -1
  272. package/dist/mongo-auth-adapter-GT4S7SCU.cjs +0 -17
  273. package/dist/mongo-auth-adapter-GT4S7SCU.cjs.map +0 -1
  274. package/dist/mongo-auth-adapter-M7VV4LNB.js +0 -4
  275. package/dist/mongo-auth-adapter-M7VV4LNB.js.map +0 -1
  276. package/dist/mongodb/index.cjs.map +0 -1
  277. package/dist/mongodb/index.js.map +0 -1
  278. package/dist/postgres-auth-adapter-AFAPISH7.js +0 -5
  279. package/dist/postgres-auth-adapter-AFAPISH7.js.map +0 -1
  280. package/dist/postgres-auth-adapter-SFDTLONT.cjs +0 -14
  281. package/dist/postgres-auth-adapter-SFDTLONT.cjs.map +0 -1
  282. package/dist/redis-adapter-UQX4EE3B.cjs +0 -13
  283. package/dist/redis-adapter-UQX4EE3B.cjs.map +0 -1
  284. package/dist/redis-adapter-XALOGWY3.js +0 -4
  285. package/dist/redis-adapter-XALOGWY3.js.map +0 -1
  286. package/dist/rest/index.cjs.map +0 -1
  287. package/dist/rest/index.js.map +0 -1
  288. package/dist/schema-6QL3USNB.cjs +0 -67
  289. package/dist/schema-6QL3USNB.cjs.map +0 -1
  290. package/dist/schema-FNNWEAAW.js +0 -6
  291. package/dist/schema-FNNWEAAW.js.map +0 -1
  292. package/dist/sqlite-adapter-AQB5TCGV.cjs +0 -13
  293. package/dist/sqlite-adapter-AQB5TCGV.cjs.map +0 -1
  294. package/dist/sqlite-adapter-N5H6IM2X.js +0 -4
  295. package/dist/sqlite-adapter-N5H6IM2X.js.map +0 -1
  296. package/dist/templates/index.cjs.map +0 -1
  297. package/dist/templates/index.js.map +0 -1
  298. package/dist/trpc/index.cjs.map +0 -1
  299. package/dist/trpc/index.js.map +0 -1
  300. package/dist/ws/index.cjs.map +0 -1
  301. package/dist/ws/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,1943 +1,43 @@
1
- export { RedisAuthAdapter } from './chunk-CF7OL6HR.js';
2
- export { allSettingsGlobals, blogCollections, blogGlobals, coreSettingsGlobals, createTemplateConfig, ecommerceCollections, ecommerceGlobals, kitchenSinkCollections, mediaCollections, minimalCollections, templateCollections } from './chunk-53NYVYVX.js';
3
- export { kyro } from './chunk-X4BPPD6K.js';
4
- export { ConfigValidationError, Kyro, LocalAdapter, Registry, collectionToCreateZod, collectionToUpdateZod, collectionToWhereZod, collectionToZod, createKyro, createLocalAdapter, createRegistry, fieldToZod, getRegistry, globalToZod, resetRegistry, validateCollection, validateConfig, validateFields, validateGlobal } from './chunk-HZOMOK5Y.js';
5
- export { autoBootstrap, bootstrapAdmin, bootstrapWithRetry, getBootstrapFromEnv } from './chunk-HY6B7B5A.js';
6
- import './chunk-GAOXD3XT.js';
7
- export { CSSGenerator, createAdminStyling, defaultDarkTheme, defaultFieldStyling, defaultLightTheme, ecommerce2026Theme, generateCSSVariables, generateTailwindConfig } from './chunk-2HFJUUFZ.js';
8
- export { ALL_FIELD_TYPES, COMPLEX_FIELD_TYPES, LAYOUT_FIELD_TYPES, PRIMITIVE_FIELD_TYPES, RELATIONAL_FIELD_TYPES, isArrayField, isBlocksField, isGroupField, isImageField, isLayoutField, isNumberField, isRelationshipField, isRichTextField, isSelectField, isTextField, isUploadField, normalizeRichTextValue, renderRichText, richTextStyles } from './chunk-FIAMXNTH.js';
9
- export { createContext, createCountProcedure, createCreateProcedure, createDeleteProcedure, createDynamicRouter, createFindByIDProcedure, createFindProcedure, createKyroServer, createUpdateProcedure } from './chunk-OX6GOIPH.js';
10
- export { buildGraphQLSchema, createGraphQLSchema } from './chunk-5RPRLTTN.js';
11
- import { init_secret, AuditLogger, InMemoryRateLimiter, InMemoryAuditLogger, AuthRoutes } from './chunk-OLV7K22H.js';
12
- export { AuditLogger, InMemoryAuditLogger, InMemoryRateLimiter, MediaService, createAuditContext, createHonoApp, createLocalStorage, createRESTAPI, getAppSecret, getEncryptionKey, getSessionConfig, loadSecrets, resolveProvider, setDbAdapter } from './chunk-OLV7K22H.js';
13
- import { EmailTransport, PasswordPolicy } from './chunk-N5QSHUA6.js';
14
- export { ConfigService, EmailTransport, PasswordPolicy } from './chunk-N5QSHUA6.js';
15
- import './chunk-YT7HXXVN.js';
16
- import './chunk-XEB7PH2E.js';
17
- import { SQLiteAuthAdapter } from './chunk-Q72BOAPK.js';
18
- export { SQLiteAuthAdapter } from './chunk-Q72BOAPK.js';
19
- import './chunk-P2YW545G.js';
20
- export { ALL_WEBHOOK_EVENTS, WEBHOOK_COLLECTION, WEBHOOK_DELIVERY_COLLECTION, WEBHOOK_EVENTS, WebhookService, buildDeliveryRecord, createTestPayload, createWebhookService, deliverWebhook, deliverWithRetry, generateWebhookSecret, signPayload } from './chunk-WDTTHKDS.js';
21
- export { evaluateAccess, getWhereClause, mergeWhereClauses } from './chunk-3AKCVYDB.js';
22
- export { KyroPubSub, KyroWSServer, PubSub, createWSServer } from './chunk-BYBMTIMT.js';
23
- import './chunk-QU2RFFH4.js';
24
- export { DrizzleAdapter, collectionToDrizzleSchema, createDatabase, createDrizzleAdapter, fieldToDrizzleType, runMigrations, seedDefaultRoles } from './chunk-V5AWATUP.js';
25
- import { PostgresAuthAdapter } from './chunk-CJX74IYK.js';
26
- export { PostgresAuthAdapter } from './chunk-CJX74IYK.js';
27
- import './chunk-UUDTPZX6.js';
28
- import './chunk-GTGRLD4Y.js';
29
- export { MongoDBAdapter, createMongoDBAdapter } from './chunk-GZS4LMR7.js';
30
- import { MongoDBAuthAdapter } from './chunk-7OGPN7MP.js';
31
- export { MongoDBAuthAdapter } from './chunk-7OGPN7MP.js';
32
- export { AbstractBaseAdapter } from './chunk-WXVB364T.js';
33
- import './chunk-L4EZKIEX.js';
34
- import './chunk-4CV4JOE5.js';
35
- import crypto2, { randomBytes } from 'crypto';
36
- import { readFileSync } from 'fs';
37
- import path, { join, resolve } from 'path';
38
- export { z } from 'zod';
39
- import { createStorage } from 'unstorage';
40
- import indexedbDriver from 'unstorage/drivers/indexedb';
41
- import fsDriver from 'unstorage/drivers/fs';
42
-
43
- // src/hooks/types.ts
44
- async function runHooks(hooks, args) {
45
- let result = args.data;
46
- for (const hook of hooks) {
47
- const hookResult = await hook({
48
- ...args,
49
- data: result
50
- });
51
- if (hookResult !== void 0) {
52
- result = hookResult;
53
- }
54
- }
55
- return result;
56
- }
57
- async function runFieldHooks(hooks, args) {
58
- return runHooks(hooks, args);
59
- }
60
-
61
- // src/plugins/index.ts
62
- var KyroPlugin = class {
63
- name;
64
- version;
65
- description;
66
- hooks = {};
67
- collections = [];
68
- globals = [];
69
- fields = [];
70
- extensions = { collections: [], globals: [] };
71
- adminComponents = {};
72
- adminStyles = [];
73
- serverMiddleware;
74
- clientMiddleware;
75
- constructor(name) {
76
- this.name = name;
77
- }
78
- async init(api) {
79
- }
80
- async beforeInit(api) {
81
- }
82
- async afterInit(api) {
83
- }
84
- getCollections() {
85
- return this.collections;
86
- }
87
- getGlobals() {
88
- return this.globals;
89
- }
90
- getHooks() {
91
- return this.hooks;
92
- }
93
- };
94
- var PluginManager = class {
95
- plugins = /* @__PURE__ */ new Map();
96
- hooks = /* @__PURE__ */ new Map();
97
- register(plugin) {
98
- if (this.plugins.has(plugin.name)) {
99
- throw new Error(`Plugin "${plugin.name}" is already registered`);
100
- }
101
- this.plugins.set(plugin.name, plugin);
102
- const pluginHooks = plugin.getHooks?.() || {};
103
- for (const [event, handlers] of Object.entries(pluginHooks)) {
104
- if (Array.isArray(handlers)) {
105
- for (const handler of handlers) {
106
- this.registerHook(event, handler);
107
- }
108
- }
109
- }
110
- }
111
- unregister(name) {
112
- const plugin = this.plugins.get(name);
113
- if (!plugin) return;
114
- const pluginHooks = plugin.getHooks?.() || {};
115
- for (const [event, handlers] of Object.entries(pluginHooks)) {
116
- if (Array.isArray(handlers)) {
117
- for (const handler of handlers) {
118
- this.unregisterHook(event, handler);
119
- }
120
- }
121
- }
122
- this.plugins.delete(name);
123
- }
124
- get(name) {
125
- return this.plugins.get(name);
126
- }
127
- getAll() {
128
- return Array.from(this.plugins.values());
129
- }
130
- has(name) {
131
- return this.plugins.has(name);
132
- }
133
- registerHook(event, handler) {
134
- if (!this.hooks.has(event)) {
135
- this.hooks.set(event, []);
136
- }
137
- this.hooks.get(event).push(handler);
138
- }
139
- unregisterHook(event, handler) {
140
- const handlers = this.hooks.get(event);
141
- if (handlers) {
142
- const index = handlers.indexOf(handler);
143
- if (index > -1) {
144
- handlers.splice(index, 1);
145
- }
146
- }
147
- }
148
- async executeHook(event, args) {
149
- const handlers = this.hooks.get(event) || [];
150
- let result = args;
151
- for (const handler of handlers) {
152
- try {
153
- const hookResult = await handler({ ...args, data: result });
154
- if (hookResult !== void 0) {
155
- result = hookResult;
156
- }
157
- } catch (error) {
158
- console.error(`[PluginManager] Error in hook "${event}":`, error);
159
- }
160
- }
161
- return result;
162
- }
163
- // ========================================================================
164
- // Collection/Field Extensions
165
- // ========================================================================
166
- getAllCollections() {
167
- const collections = [];
168
- for (const plugin of this.plugins.values()) {
169
- const pluginCollections = plugin.getCollections?.() || [];
170
- collections.push(...pluginCollections);
171
- }
172
- return collections;
173
- }
174
- getAllGlobals() {
175
- const globals = [];
176
- for (const plugin of this.plugins.values()) {
177
- const pluginGlobals = plugin.getGlobals?.() || [];
178
- globals.push(...pluginGlobals);
179
- }
180
- return globals;
181
- }
182
- getAllFields() {
183
- const fields = [];
184
- for (const plugin of this.plugins.values()) {
185
- fields.push(...plugin.fields);
186
- }
187
- return fields;
188
- }
189
- getAdminComponents() {
190
- const components = {};
191
- for (const plugin of this.plugins.values()) {
192
- Object.assign(components, plugin.adminComponents);
193
- }
194
- return components;
195
- }
196
- getAdminStyles() {
197
- const styles = [];
198
- for (const plugin of this.plugins.values()) {
199
- styles.push(...plugin.adminStyles);
200
- }
201
- return styles;
202
- }
203
- };
204
- var SEOPLugin = class extends KyroPlugin {
205
- constructor() {
206
- super("seo");
207
- this.description = "Advanced SEO features including sitemaps, robots.txt, and structured data";
208
- this.collections.push({
209
- slug: "seo-settings",
210
- label: "SEO Settings",
211
- fields: [
212
- {
213
- name: "sitemap",
214
- type: "checkbox",
215
- label: "Enable Sitemap",
216
- defaultValue: true
217
- },
218
- { name: "robotsTxt", type: "richtext", label: "robots.txt Content" },
219
- {
220
- name: "canonicalUrl",
221
- type: "text",
222
- variant: "url",
223
- label: "Canonical URL"
224
- },
225
- { name: "ogImage", type: "text", label: "Default OG Image URL" }
226
- ]
227
- });
228
- }
229
- };
230
- var AnalyticsPlugin = class extends KyroPlugin {
231
- constructor() {
232
- super("analytics");
233
- this.description = "Analytics integration for tracking page views and events";
234
- this.collections.push({
235
- slug: "analytics-events",
236
- label: "Analytics Events",
237
- fields: [
238
- { name: "name", type: "text", required: true },
239
- { name: "properties", type: "json", label: "Event Properties" },
240
- { name: "timestamp", type: "date", required: true },
241
- { name: "userId", type: "text", label: "User ID" },
242
- { name: "sessionId", type: "text", label: "Session ID" }
243
- ]
244
- });
245
- this.adminComponents["AnalyticsDashboard"] = {};
246
- }
247
- };
248
- var CommentsPlugin = class extends KyroPlugin {
249
- constructor() {
250
- super("comments");
251
- this.description = "Commenting system for products and posts";
252
- this.collections.push({
253
- slug: "comments",
254
- label: "Comments",
255
- fields: [
256
- { name: "content", type: "richtext", required: true },
257
- { name: "author", type: "text", required: true },
258
- { name: "email", type: "email" },
259
- { name: "approved", type: "checkbox", defaultValue: false },
260
- { name: "parent", type: "text", label: "Parent Comment ID" },
261
- { name: "resourceType", type: "text", required: true },
262
- { name: "resourceId", type: "text", required: true }
263
- ]
264
- });
265
- this.adminComponents["CommentModeration"] = {};
266
- }
267
- };
268
- var ReviewsPlugin = class extends KyroPlugin {
269
- constructor() {
270
- super("reviews");
271
- this.description = "Product reviews and ratings";
272
- this.collections.push({
273
- slug: "reviews",
274
- label: "Reviews",
275
- fields: [
276
- { name: "rating", type: "number", required: true, min: 1, max: 5 },
277
- { name: "title", type: "text" },
278
- { name: "content", type: "richtext", required: true },
279
- { name: "author", type: "relationship", relationTo: "customers" },
280
- {
281
- name: "product",
282
- type: "relationship",
283
- relationTo: "products",
284
- required: true
285
- },
286
- { name: "approved", type: "checkbox", defaultValue: false },
287
- { name: "verified", type: "checkbox", label: "Verified Purchase" },
288
- {
289
- name: "helpful",
290
- type: "number",
291
- label: "Helpful Count",
292
- defaultValue: 0
293
- }
294
- ]
295
- });
296
- this.adminComponents["ReviewModeration"] = {};
297
- }
298
- };
299
- var WishlistPlugin = class extends KyroPlugin {
300
- constructor() {
301
- super("wishlist");
302
- this.description = "Customer wishlists";
303
- this.collections.push({
304
- slug: "wishlists",
305
- label: "Wishlists",
306
- fields: [
307
- {
308
- name: "customer",
309
- type: "relationship",
310
- relationTo: "customers",
311
- required: true
312
- },
313
- {
314
- name: "name",
315
- type: "text",
316
- label: "Wishlist Name",
317
- defaultValue: "My Wishlist"
318
- },
319
- {
320
- name: "items",
321
- type: "blocks",
322
- label: "Items",
323
- blocks: [
324
- {
325
- slug: "wishlist-item",
326
- label: "Item",
327
- fields: [
328
- {
329
- name: "product",
330
- type: "relationship",
331
- relationTo: "products"
332
- },
333
- { name: "quantity", type: "number", defaultValue: 1 },
334
- { name: "addedAt", type: "date" },
335
- {
336
- name: "priority",
337
- type: "select",
338
- options: [
339
- { label: "Low", value: "low" },
340
- { label: "Medium", value: "medium" },
341
- { label: "High", value: "high" }
342
- ]
343
- }
344
- ]
345
- }
346
- ]
347
- }
348
- ]
349
- });
350
- }
351
- };
352
- var presetPlugins = {
353
- SEO: SEOPLugin,
354
- Analytics: AnalyticsPlugin,
355
- Comments: CommentsPlugin,
356
- Reviews: ReviewsPlugin,
357
- Wishlist: WishlistPlugin
358
- };
359
-
360
- // src/auth/security/lockout.ts
361
- var DEFAULT_LOCKOUT_CONFIG = {
362
- maxAttempts: 5,
363
- lockDuration: 9e5,
364
- notifyUser: true,
365
- notifyAdmin: true,
366
- adminNotifyAfter: 3
367
- };
368
- var AccountLockout = class {
369
- redis;
370
- prefix;
371
- config;
372
- constructor(redis, config = {}, prefix = "kyro:lockout:") {
373
- this.redis = redis;
374
- this.prefix = prefix;
375
- this.config = { ...DEFAULT_LOCKOUT_CONFIG, ...config };
376
- }
377
- lockKey(userId) {
378
- return `${this.prefix}${userId}`;
379
- }
380
- historyKey(userId) {
381
- return `${this.prefix}${userId}:history`;
382
- }
383
- async checkLockout(userId) {
384
- const key = this.lockKey(userId);
385
- const data = await this.redis.hgetall(key);
386
- if (!data || Object.keys(data).length === 0) {
387
- return {
388
- locked: false,
389
- attemptsRemaining: this.config.maxAttempts,
390
- totalAttempts: 0
391
- };
392
- }
393
- const attempts = parseInt(data.attempts, 10);
394
- const lockedUntil = data.lockedUntil ? new Date(parseInt(data.lockedUntil, 10)) : void 0;
395
- if (lockedUntil && lockedUntil > /* @__PURE__ */ new Date()) {
396
- return {
397
- locked: true,
398
- attemptsRemaining: 0,
399
- lockedUntil,
400
- totalAttempts: attempts
401
- };
402
- }
403
- if (lockedUntil && lockedUntil <= /* @__PURE__ */ new Date()) {
404
- await this.unlockAccount(userId);
405
- return {
406
- locked: false,
407
- attemptsRemaining: this.config.maxAttempts,
408
- totalAttempts: 0
409
- };
410
- }
411
- return {
412
- locked: false,
413
- attemptsRemaining: Math.max(0, this.config.maxAttempts - attempts),
414
- totalAttempts: attempts
415
- };
416
- }
417
- async recordFailedAttempt(userId) {
418
- const key = this.lockKey(userId);
419
- const historyKey = this.historyKey(userId);
420
- const now = Date.now();
421
- const current = await this.redis.hincrby(key, "attempts", 1);
422
- await this.redis.hset(key, "lastAttempt", now.toString());
423
- await this.redis.lpush(historyKey, now.toString());
424
- await this.redis.ltrim(historyKey, 0, 99);
425
- if (current >= this.config.maxAttempts) {
426
- const lockedUntil = new Date(now + this.config.lockDuration);
427
- await this.redis.hset(key, {
428
- lockedAt: now.toString(),
429
- lockedUntil: lockedUntil.getTime().toString()
430
- });
431
- await this.redis.expire(
432
- key,
433
- Math.ceil(this.config.lockDuration / 1e3) + 3600
434
- );
435
- return {
436
- locked: true,
437
- attemptsRemaining: 0,
438
- lockedUntil,
439
- totalAttempts: current
440
- };
441
- }
442
- return {
443
- locked: false,
444
- attemptsRemaining: Math.max(0, this.config.maxAttempts - current),
445
- totalAttempts: current
446
- };
447
- }
448
- async lockAccount(userId, duration) {
449
- const key = this.lockKey(userId);
450
- const now = Date.now();
451
- const lockDuration = duration || this.config.lockDuration;
452
- const lockedUntil = new Date(now + lockDuration);
453
- const pipeline = this.redis.pipeline();
454
- pipeline.hset(key, {
455
- attempts: this.config.maxAttempts.toString(),
456
- lockedAt: now.toString(),
457
- lockedUntil: lockedUntil.getTime().toString()
458
- });
459
- pipeline.expire(key, Math.ceil(lockDuration / 1e3) + 3600);
460
- await pipeline.exec();
461
- }
462
- async unlockAccount(userId) {
463
- const key = this.lockKey(userId);
464
- await this.redis.del(key);
465
- }
466
- async resetAttempts(userId) {
467
- const key = this.lockKey(userId);
468
- const data = await this.redis.hgetall(key);
469
- if (data.lockedAt) {
470
- await this.redis.hset(key, {
471
- attempts: "0",
472
- lockedAt: "",
473
- lockedUntil: ""
474
- });
475
- } else {
476
- await this.redis.del(key);
477
- }
478
- }
479
- async getLockoutHistory(userId, limit = 10) {
480
- const historyKey = this.historyKey(userId);
481
- const timestamps = await this.redis.lrange(historyKey, 0, limit - 1);
482
- return timestamps.map((ts) => new Date(parseInt(ts, 10)));
483
- }
484
- async getLockoutStats(userId) {
485
- const historyKey = this.historyKey(userId);
486
- const timestamps = await this.redis.lrange(historyKey, 0, -1);
487
- const lockouts = timestamps.filter((_, i) => {
488
- const attemptNum = i + 1;
489
- return attemptNum % this.config.maxAttempts === 0;
490
- }).length;
491
- const lastLockoutData = await this.redis.hget(
492
- this.lockKey(userId),
493
- "lockedAt"
494
- );
495
- return {
496
- totalFailedAttempts: timestamps.length,
497
- lockoutCount: lockouts,
498
- lastLockout: lastLockoutData ? new Date(parseInt(lastLockoutData, 10)) : null,
499
- averageAttemptsBeforeLockout: lockouts > 0 ? this.config.maxAttempts : 0
500
- };
501
- }
502
- shouldNotifyAdmin(currentAttempts) {
503
- return this.config.notifyAdmin && currentAttempts >= this.config.adminNotifyAfter;
504
- }
505
- getConfig() {
506
- return { ...this.config };
507
- }
508
- setConfig(config) {
509
- this.config = { ...this.config, ...config };
510
- }
511
- };
512
-
513
- // src/auth/security/rate-limit.ts
514
- var DEFAULT_RATE_LIMITS = {
515
- "auth:login": { window: 9e5, max: 5 },
516
- "auth:register": { window: 36e5, max: 3 },
517
- "auth:forgot": { window: 36e5, max: 3 },
518
- "auth:reset": { window: 36e5, max: 5 },
519
- "auth:verify": { window: 36e5, max: 5 },
520
- "api:general": { window: 6e4, max: 100 },
521
- "api:authenticated": { window: 6e4, max: 200 }
522
- };
523
- var RateLimiter = class {
524
- redis;
525
- prefix;
526
- limits;
527
- userLimits;
528
- constructor(redis, limits, userLimits, prefix = "kyro:ratelimit:") {
529
- this.redis = redis;
530
- this.prefix = prefix;
531
- this.limits = { ...DEFAULT_RATE_LIMITS, ...limits };
532
- this.userLimits = userLimits || {
533
- "user:api": { window: 6e4, max: 500 },
534
- "user:write": { window: 36e5, max: 100 }
535
- };
536
- }
537
- getKey(type, identifier) {
538
- return `${this.prefix}${type}:${identifier}`;
539
- }
540
- async check(type, identifier) {
541
- const config = this.limits[type] || this.limits["api:general"];
542
- const key = this.getKey(type, identifier);
543
- const now = Date.now();
544
- const windowStart = now - config.window;
545
- const pipeline = this.redis.pipeline();
546
- pipeline.zremrangebyscore(key, 0, windowStart);
547
- pipeline.zcard(key);
548
- pipeline.zadd(key, now, `${now}:${Math.random()}`);
549
- pipeline.expire(key, Math.ceil(config.window / 1e3) + 1);
550
- const results = await pipeline.exec();
551
- const count = results?.[1]?.[1] || 0;
552
- if (count >= config.max) {
553
- const oldestTimestamp = await this.redis.zrange(key, 0, 0, "WITHSCORES");
554
- const resetAt = oldestTimestamp.length > 1 ? parseInt(oldestTimestamp[1], 10) + config.window : now + config.window;
555
- return {
556
- allowed: false,
557
- remaining: 0,
558
- resetAt,
559
- retryAfter: Math.ceil((resetAt - now) / 1e3)
560
- };
561
- }
562
- return {
563
- allowed: true,
564
- remaining: config.max - count - 1,
565
- resetAt: now + config.window
566
- };
567
- }
568
- async checkUser(type, userId, identifier) {
569
- const config = this.userLimits[type] || this.userLimits["user:api"];
570
- const key = this.getKey(`user:${type}:${userId}`, identifier);
571
- const now = Date.now();
572
- const windowStart = now - config.window;
573
- const pipeline = this.redis.pipeline();
574
- pipeline.zremrangebyscore(key, 0, windowStart);
575
- pipeline.zcard(key);
576
- pipeline.zadd(key, now, `${now}:${Math.random()}`);
577
- pipeline.expire(key, Math.ceil(config.window / 1e3) + 1);
578
- const results = await pipeline.exec();
579
- const count = results?.[1]?.[1] || 0;
580
- if (count >= config.max) {
581
- const oldestTimestamp = await this.redis.zrange(key, 0, 0, "WITHSCORES");
582
- const resetAt = oldestTimestamp.length > 1 ? parseInt(oldestTimestamp[1], 10) + config.window : now + config.window;
583
- return {
584
- allowed: false,
585
- remaining: 0,
586
- resetAt,
587
- retryAfter: Math.ceil((resetAt - now) / 1e3)
588
- };
589
- }
590
- return {
591
- allowed: true,
592
- remaining: config.max - count - 1,
593
- resetAt: now + config.window
594
- };
595
- }
596
- async reset(type, identifier) {
597
- const key = this.getKey(type, identifier);
598
- await this.redis.del(key);
599
- }
600
- async resetUser(type, userId, identifier) {
601
- const key = this.getKey(`user:${type}:${userId}`, identifier);
602
- await this.redis.del(key);
603
- }
604
- async getStatus(type, identifier) {
605
- const config = this.limits[type] || this.limits["api:general"];
606
- const key = this.getKey(type, identifier);
607
- const now = Date.now();
608
- const windowStart = now - config.window;
609
- await this.redis.zremrangebyscore(key, 0, windowStart);
610
- const count = await this.redis.zcard(key);
611
- return {
612
- count,
613
- limit: config.max,
614
- remaining: Math.max(0, config.max - count),
615
- resetAt: now + config.window
616
- };
617
- }
618
- setLimit(type, config) {
619
- this.limits[type] = config;
620
- }
621
- setUserLimit(type, config) {
622
- this.userLimits[type] = config;
623
- }
624
- };
625
- var InMemoryAuthAdapter = class {
626
- users = /* @__PURE__ */ new Map();
627
- sessions = /* @__PURE__ */ new Map();
628
- refreshTokens = /* @__PURE__ */ new Map();
629
- emailToUserId = /* @__PURE__ */ new Map();
630
- passwordHistory = /* @__PURE__ */ new Map();
631
- emailVerificationTokens = /* @__PURE__ */ new Map();
632
- passwordResetTokens = /* @__PURE__ */ new Map();
633
- auditLogs = [];
634
- externalDb = false;
635
- constructor() {
636
- }
637
- async connect() {
638
- }
639
- async disconnect() {
640
- this.users.clear();
641
- this.sessions.clear();
642
- this.refreshTokens.clear();
643
- this.emailToUserId.clear();
644
- this.passwordHistory.clear();
645
- }
646
- async createUser(data) {
647
- const userId = randomBytes(16).toString("hex");
648
- const now = (/* @__PURE__ */ new Date()).toISOString();
649
- const passwordHash = await this.hashPassword(data.password);
650
- const user = {
651
- id: userId,
652
- email: data.email.toLowerCase(),
653
- passwordHash,
654
- role: data.role || "customer",
655
- tenantId: data.tenantId,
656
- createdAt: now,
657
- updatedAt: now
658
- };
659
- this.users.set(userId, user);
660
- this.emailToUserId.set(data.email.toLowerCase(), userId);
661
- this.passwordHistory.set(userId, []);
662
- return user;
663
- }
664
- async findUserByEmail(email) {
665
- const userId = this.emailToUserId.get(email.toLowerCase());
666
- if (!userId) return null;
667
- return this.findUserById(userId);
668
- }
669
- async findUserById(userId) {
670
- return this.users.get(userId) || null;
671
- }
672
- async updateUser(userId, data) {
673
- const existing = await this.findUserById(userId);
674
- if (!existing) return null;
675
- const updated = {
676
- ...existing,
677
- ...data,
678
- id: userId,
679
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
680
- };
681
- if (data.email && data.email !== existing.email) {
682
- this.emailToUserId.delete(existing.email.toLowerCase());
683
- this.emailToUserId.set(data.email.toLowerCase(), userId);
684
- }
685
- this.users.set(userId, updated);
686
- return updated;
687
- }
688
- async deleteUser(userId) {
689
- const user = await this.findUserById(userId);
690
- if (!user) return false;
691
- this.users.delete(userId);
692
- this.emailToUserId.delete(user.email.toLowerCase());
693
- this.refreshTokens.forEach((sessionId, refreshToken) => {
694
- if (this.sessions.get(sessionId)?.userId === userId) {
695
- this.refreshTokens.delete(refreshToken);
696
- this.sessions.delete(sessionId);
697
- }
698
- });
699
- this.passwordHistory.delete(userId);
700
- this.sessions.forEach((session, sessionId) => {
701
- if (session.userId === userId) {
702
- this.sessions.delete(sessionId);
703
- }
704
- });
705
- return true;
706
- }
707
- async hashPassword(password) {
708
- const bcrypt = (await import('bcryptjs')).default;
709
- return bcrypt.hash(password, 12);
710
- }
711
- async verifyPassword(email, password) {
712
- const user = await this.findUserByEmail(email);
713
- if (!user || !user.passwordHash) return null;
714
- const bcrypt = (await import('bcryptjs')).default;
715
- const valid = await bcrypt.compare(password, user.passwordHash);
716
- return valid ? user : null;
717
- }
718
- async createSession(userId, data = {}) {
719
- const sessionId = randomBytes(32).toString("hex");
720
- const token = randomBytes(32).toString("base64url");
721
- const refreshToken = randomBytes(32).toString("base64url");
722
- const now = /* @__PURE__ */ new Date();
723
- const session = {
724
- id: sessionId,
725
- userId,
726
- token,
727
- refreshToken,
728
- expiresAt: new Date(now.getTime() + 86400 * 1e3).toISOString(),
729
- // 24 hours
730
- createdAt: now.toISOString(),
731
- ipAddress: data.ipAddress,
732
- userAgent: data.userAgent
733
- };
734
- this.sessions.set(sessionId, session);
735
- this.refreshTokens.set(refreshToken, sessionId);
736
- return session;
737
- }
738
- async findSessionByToken(token) {
739
- return this.sessions.get(token) || null;
740
- }
741
- async findSessionByRefreshToken(refreshToken) {
742
- const sessionId = this.refreshTokens.get(refreshToken);
743
- if (!sessionId) return null;
744
- const session = this.sessions.get(sessionId);
745
- return session || null;
746
- }
747
- async deleteSession(sessionId) {
748
- const session = this.sessions.get(sessionId);
749
- if (!session) return false;
750
- if (session.refreshToken) {
751
- this.refreshTokens.delete(session.refreshToken);
752
- }
753
- this.sessions.delete(sessionId);
754
- return true;
755
- }
756
- async deleteUserSessions(userId) {
757
- let deleted = 0;
758
- this.sessions.forEach((session, sessionId) => {
759
- if (session.userId === userId) {
760
- if (session.refreshToken) {
761
- this.refreshTokens.delete(session.refreshToken);
762
- }
763
- this.sessions.delete(sessionId);
764
- deleted++;
765
- }
766
- });
767
- return deleted;
768
- }
769
- async addPasswordToHistory(userId, passwordHash) {
770
- const history = this.passwordHistory.get(userId) || [];
771
- history.push(passwordHash);
772
- if (history.length > 5) {
773
- history.splice(0, history.length - 5);
774
- }
775
- this.passwordHistory.set(userId, history);
776
- }
777
- async getPasswordHistory(userId, count = 5) {
778
- return this.passwordHistory.get(userId) || [];
779
- }
780
- async isPasswordInHistory(password, userId, historyCount = 5) {
781
- const history = await this.getPasswordHistory(userId, historyCount);
782
- const bcrypt = (await import('bcryptjs')).default;
783
- for (const hash of history) {
784
- if (await bcrypt.compare(password, hash)) {
785
- return true;
786
- }
787
- }
788
- return false;
789
- }
790
- async createEmailVerificationToken(userId) {
791
- const token = randomBytes(32).toString("hex");
792
- const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1e3);
793
- this.emailVerificationTokens.set(token, { userId, expiresAt });
794
- return { token, expiresAt };
795
- }
796
- async verifyEmailToken(token) {
797
- const data = this.emailVerificationTokens.get(token);
798
- if (!data || data.expiresAt < /* @__PURE__ */ new Date()) {
799
- this.emailVerificationTokens.delete(token);
800
- return { success: false, error: "Invalid or expired token" };
801
- }
802
- this.emailVerificationTokens.delete(token);
803
- return { success: true, userId: data.userId };
804
- }
805
- async createPasswordResetToken(email) {
806
- const user = await this.findUserByEmail(email);
807
- if (!user) {
808
- return { token: "", expiresAt: /* @__PURE__ */ new Date(), error: "User not found" };
809
- }
810
- const token = randomBytes(32).toString("hex");
811
- const expiresAt = new Date(Date.now() + 60 * 60 * 1e3);
812
- this.passwordResetTokens.set(token, { userId: user.id, expiresAt });
813
- return { token, expiresAt };
814
- }
815
- async resetPasswordWithToken(token, newPassword) {
816
- const data = this.passwordResetTokens.get(token);
817
- if (!data || data.expiresAt < /* @__PURE__ */ new Date()) {
818
- this.passwordResetTokens.delete(token);
819
- return { success: false, error: "Invalid or expired token" };
820
- }
821
- const passwordHash = await this.hashPassword(newPassword);
822
- await this.updateUser(data.userId, { passwordHash });
823
- this.passwordResetTokens.delete(token);
824
- return { success: true };
825
- }
826
- async hasAnyUsers() {
827
- return this.users.size > 0;
828
- }
829
- async findAuditLogs(filter) {
830
- const { limit = 50, offset = 0 } = filter;
831
- let logs = this.auditLogs.slice().reverse();
832
- if (filter.userId) logs = logs.filter((l) => l.userId === filter.userId);
833
- if (filter.action) {
834
- if (Array.isArray(filter.action)) {
835
- logs = logs.filter((l) => filter.action.includes(String(l.action)));
836
- } else {
837
- logs = logs.filter((l) => l.action === filter.action);
838
- }
839
- }
840
- if (filter.resource)
841
- logs = logs.filter((l) => l.resource === filter.resource);
842
- if (filter.success !== void 0)
843
- logs = logs.filter((l) => l.success === filter.success);
844
- return { logs: logs.slice(offset, offset + limit), total: logs.length };
845
- }
846
- async createAuditLog(data) {
847
- const id = randomBytes(16).toString("hex");
848
- const timestamp = /* @__PURE__ */ new Date();
849
- const log = { ...data, id, timestamp };
850
- this.auditLogs.push(log);
851
- return log;
852
- }
853
- };
854
-
855
- // src/auth/security/in-memory-lockout.ts
856
- var InMemoryAccountLockout = class {
857
- storage = /* @__PURE__ */ new Map();
858
- history = /* @__PURE__ */ new Map();
859
- // userId -> attempt timestamps
860
- config;
861
- constructor(config = {}) {
862
- this.config = {
863
- maxAttempts: 5,
864
- lockDuration: 9e5,
865
- // 15 minutes
866
- notifyUser: true,
867
- notifyAdmin: true,
868
- adminNotifyAfter: 3,
869
- ...config
870
- };
871
- }
872
- async checkLockout(userId) {
873
- const now = Date.now();
874
- const record = this.storage.get(userId);
875
- if (record && record.lockedUntil !== null && record.lockedUntil <= now) {
876
- await this.resetAttempts(userId);
877
- return {
878
- locked: false,
879
- attemptsRemaining: this.config.maxAttempts,
880
- totalAttempts: 0
881
- };
882
- }
883
- if (!record) {
884
- return {
885
- locked: false,
886
- attemptsRemaining: this.config.maxAttempts,
887
- totalAttempts: 0
888
- };
889
- }
890
- const { attempts, lockedUntil } = record;
891
- if (lockedUntil !== null && lockedUntil > now) {
892
- return {
893
- locked: true,
894
- attemptsRemaining: 0,
895
- lockedUntil: new Date(lockedUntil),
896
- totalAttempts: attempts
897
- };
898
- }
899
- return {
900
- locked: false,
901
- attemptsRemaining: Math.max(0, this.config.maxAttempts - attempts),
902
- totalAttempts: attempts
903
- };
904
- }
905
- async recordFailedAttempt(userId) {
906
- const now = Date.now();
907
- const record = this.storage.get(userId) || {
908
- attempts: 0,
909
- lastAttempt: null,
910
- lockedAt: null,
911
- lockedUntil: null
912
- };
913
- record.attempts += 1;
914
- record.lastAttempt = now;
915
- let history = this.history.get(userId) || [];
916
- history.push(now);
917
- if (history.length > 100) {
918
- history.splice(0, history.length - 100);
919
- }
920
- this.history.set(userId, history);
921
- this.storage.set(userId, record);
922
- if (record.attempts >= this.config.maxAttempts) {
923
- const lockedUntil = new Date(now + this.config.lockDuration);
924
- record.lockedAt = now;
925
- record.lockedUntil = lockedUntil.getTime();
926
- this.storage.set(userId, record);
927
- return {
928
- locked: true,
929
- attemptsRemaining: 0,
930
- lockedUntil,
931
- totalAttempts: record.attempts
932
- };
933
- }
934
- return {
935
- locked: false,
936
- attemptsRemaining: Math.max(0, this.config.maxAttempts - record.attempts),
937
- totalAttempts: record.attempts
938
- };
939
- }
940
- async lockAccount(userId, duration) {
941
- const now = Date.now();
942
- const lockDuration = duration || this.config.lockDuration;
943
- const lockedUntil = new Date(now + lockDuration);
944
- const record = this.storage.get(userId) || {
945
- attempts: 0,
946
- lastAttempt: null,
947
- lockedAt: null,
948
- lockedUntil: null
949
- };
950
- record.attempts = this.config.maxAttempts;
951
- record.lockedAt = now;
952
- record.lockedUntil = lockedUntil.getTime();
953
- this.storage.set(userId, record);
954
- }
955
- async unlockAccount(userId) {
956
- await this.resetAttempts(userId);
957
- }
958
- async resetAttempts(userId) {
959
- const record = this.storage.get(userId);
960
- if (record) {
961
- record.attempts = 0;
962
- record.lockedAt = null;
963
- record.lockedUntil = null;
964
- this.storage.set(userId, record);
965
- }
966
- this.history.delete(userId);
967
- }
968
- async getLockoutHistory(userId, limit = 10) {
969
- const history = this.history.get(userId) || [];
970
- return history.slice(-limit).reverse().map((timestamp) => new Date(timestamp));
971
- }
972
- async getLockoutStats(userId) {
973
- const history = this.history.get(userId) || [];
974
- const totalFailedAttempts = history.length;
975
- const lockoutCount = Math.floor(
976
- totalFailedAttempts / this.config.maxAttempts
977
- );
978
- let lastLockout = null;
979
- const record = this.storage.get(userId);
980
- if (record && record.lockedAt !== null) {
981
- lastLockout = new Date(record.lockedAt);
982
- }
983
- const averageAttemptsBeforeLockout = lockoutCount > 0 ? this.config.maxAttempts : 0;
984
- return {
985
- totalFailedAttempts,
986
- lockoutCount,
987
- lastLockout,
988
- averageAttemptsBeforeLockout
989
- };
990
- }
991
- shouldNotifyAdmin(currentAttempts) {
992
- return this.config.notifyAdmin && currentAttempts >= this.config.adminNotifyAfter;
993
- }
994
- getConfig() {
995
- return { ...this.config };
996
- }
997
- setConfig(config) {
998
- this.config = { ...this.config, ...config };
999
- }
1000
- };
1001
- function getEnv(key, fallback = "") {
1002
- return process.env[key] || fallback;
1003
- }
1004
- function getEnvBool(key, fallback = false) {
1005
- const val = process.env[key];
1006
- if (!val) return fallback;
1007
- return val.toLowerCase() === "true";
1008
- }
1009
- function getEnvNum(key, fallback = 0) {
1010
- const val = process.env[key];
1011
- if (!val) return fallback;
1012
- return parseInt(val, 10);
1013
- }
1014
- function detectDatabaseType() {
1015
- const envDb = process.env.KYRO_AUTH_DATABASE?.toLowerCase();
1016
- if (envDb && ["sqlite", "postgres", "mongodb", "memory"].includes(envDb)) {
1017
- return envDb;
1018
- }
1019
- try {
1020
- const configPath = join(process.cwd(), "kyro.config.ts");
1021
- const configContent = readFileSync(configPath, "utf8");
1022
- if (configContent.includes("createLocalAdapter")) {
1023
- return "sqlite";
1024
- } else if (configContent.includes("createDrizzleAdapter")) {
1025
- if (configContent.includes("postgres") || configContent.includes("postgresql")) {
1026
- return "postgres";
1027
- }
1028
- return "postgres";
1029
- } else if (configContent.includes("createMongoDBAdapter")) {
1030
- return "mongodb";
1031
- }
1032
- } catch {
1033
- }
1034
- return "memory";
1035
- }
1036
- async function createAuthAdapter(databaseType) {
1037
- const cwd = process.cwd();
1038
- const rootDir = cwd.endsWith("admin") ? join(cwd, "..") : cwd;
1039
- const defaultAuthDbPath = resolve(rootDir, "data", "auth.db");
1040
- switch (databaseType) {
1041
- case "sqlite":
1042
- return new SQLiteAuthAdapter({
1043
- path: getEnv("KYRO_AUTH_DB_PATH", defaultAuthDbPath)
1044
- });
1045
- case "postgres": {
1046
- try {
1047
- const databaseUrl = getEnv("DATABASE_URL", "");
1048
- if (databaseUrl) {
1049
- const { drizzle } = await import('drizzle-orm/postgres-js');
1050
- const postgres = await import('postgres');
1051
- const sql = postgres.default(databaseUrl, { onnotice: () => {
1052
- } });
1053
- const drizzleDb = drizzle(sql);
1054
- return new PostgresAuthAdapter({ db: drizzleDb });
1055
- }
1056
- } catch (e) {
1057
- console.warn("[Auth] Could not create PostgresAuthAdapter, falling back to SQLite auth adapter.");
1058
- }
1059
- return new SQLiteAuthAdapter({
1060
- path: getEnv("KYRO_AUTH_DB_PATH", defaultAuthDbPath)
1061
- });
1062
- }
1063
- case "mongodb": {
1064
- try {
1065
- const mongoUri = getEnv("MONGODB_URI", "");
1066
- if (mongoUri) {
1067
- const { MongoClient } = await import('mongodb');
1068
- const client = new MongoClient(mongoUri);
1069
- await client.connect();
1070
- const url = new URL(mongoUri);
1071
- const dbName = url.pathname.replace(/^\//, "") || "kyro_cms";
1072
- const mongoDb = client.db(dbName);
1073
- return new MongoDBAuthAdapter({ db: mongoDb });
1074
- }
1075
- } catch (e) {
1076
- console.warn("[Auth] Could not create MongoDBAuthAdapter, falling back to SQLite auth adapter.");
1077
- }
1078
- return new SQLiteAuthAdapter({
1079
- path: getEnv("KYRO_AUTH_DB_PATH", defaultAuthDbPath)
1080
- });
1081
- }
1082
- case "memory":
1083
- default:
1084
- return new InMemoryAuthAdapter();
1085
- }
1086
- }
1087
- async function createAuthConfig(databaseType, db) {
1088
- const distributed = getEnvBool("KYRO_DISTRIBUTED", false);
1089
- let authAdapter;
1090
- if (distributed) {
1091
- const { RedisAuthAdapter: RedisAuthAdapter2 } = await import('./redis-adapter-XALOGWY3.js');
1092
- const redisUrl = getEnv("REDIS_URL", "redis://localhost:6379");
1093
- const redisTls = getEnvBool("REDIS_TLS", false);
1094
- const redisAdapter = new RedisAuthAdapter2({ url: redisUrl, tls: redisTls });
1095
- await redisAdapter.connect?.();
1096
- authAdapter = redisAdapter;
1097
- } else {
1098
- const initialDbType = databaseType || detectDatabaseType();
1099
- authAdapter = await createAuthAdapter(initialDbType);
1100
- if (authAdapter.connect) {
1101
- await authAdapter.connect();
1102
- }
1103
- }
1104
- const email = db ? await EmailTransport.fromConfig(db).catch(() => null) || EmailTransport.fromEnv() || void 0 : EmailTransport.fromEnv() || void 0;
1105
- const passwordPolicy = new PasswordPolicy({
1106
- minLength: getEnvNum("PASSWORD_MIN_LENGTH", 12),
1107
- requireUppercase: getEnvBool("PASSWORD_REQUIRE_UPPERCASE", true),
1108
- requireLowercase: getEnvBool("PASSWORD_REQUIRE_LOWERCASE", true),
1109
- requireNumbers: getEnvBool("PASSWORD_REQUIRE_NUMBERS", true),
1110
- requireSpecialChars: getEnvBool("PASSWORD_REQUIRE_SPECIAL", true),
1111
- preventReuse: getEnvNum("PASSWORD_PREVENT_REUSE", 5),
1112
- maxLength: getEnvNum("PASSWORD_MAX_LENGTH", 128)
1113
- });
1114
- let lockout;
1115
- let rateLimiter;
1116
- let auditLogger;
1117
- if (distributed) {
1118
- const redis = authAdapter;
1119
- const redisClient = redis.redis;
1120
- lockout = new AccountLockout(redisClient, {
1121
- maxAttempts: getEnvNum("LOCKOUT_MAX_ATTEMPTS", 5),
1122
- lockDuration: getEnvNum("LOCKOUT_DURATION_MINUTES", 15) * 60 * 1e3
1123
- });
1124
- rateLimiter = new RateLimiter(redisClient, {
1125
- "auth:login": {
1126
- window: getEnvNum("RATE_LIMIT_AUTH_WINDOW_MS", 9e5),
1127
- max: getEnvNum("RATE_LIMIT_AUTH_MAX_REQUESTS", 10)
1128
- },
1129
- "api:general": {
1130
- window: getEnvNum("RATE_LIMIT_WINDOW_MS", 6e4),
1131
- max: getEnvNum("RATE_LIMIT_MAX_REQUESTS", 100)
1132
- }
1133
- });
1134
- auditLogger = new AuditLogger(
1135
- redisClient,
1136
- getEnvNum("AUDIT_LOG_RETENTION_DAYS", 30)
1137
- );
1138
- } else {
1139
- lockout = new InMemoryAccountLockout({
1140
- maxAttempts: getEnvNum("LOCKOUT_MAX_ATTEMPTS", 5),
1141
- lockDuration: getEnvNum("LOCKOUT_DURATION_MINUTES", 15) * 60 * 1e3
1142
- });
1143
- rateLimiter = new InMemoryRateLimiter({
1144
- "auth:login": {
1145
- window: getEnvNum("RATE_LIMIT_AUTH_WINDOW_MS", 9e5),
1146
- max: getEnvNum("RATE_LIMIT_AUTH_MAX_REQUESTS", 10)
1147
- },
1148
- "api:general": {
1149
- window: getEnvNum("RATE_LIMIT_WINDOW_MS", 6e4),
1150
- max: getEnvNum("RATE_LIMIT_MAX_REQUESTS", 100)
1151
- }
1152
- });
1153
- auditLogger = getEnvBool("AUDIT_LOG_ENABLED", true) ? new InMemoryAuditLogger(getEnvNum("AUDIT_LOG_RETENTION_DAYS", 30)) : void 0;
1154
- }
1155
- const routes = new AuthRoutes({
1156
- redis: authAdapter,
1157
- email,
1158
- jwtSecret: getEnv("APP_SECRET", "change-me"),
1159
- jwtExpiresIn: getEnv("JWT_EXPIRES_IN", "24h"),
1160
- jwtIssuer: getEnv("JWT_ISSUER", "kyro-cms"),
1161
- jwtAudience: getEnv("JWT_AUDIENCE", "kyro-cms-client"),
1162
- passwordPolicy,
1163
- lockout,
1164
- rateLimiter,
1165
- auditLogger,
1166
- baseUrl: getEnv("EMAIL_BASE_URL", "http://localhost:4321"),
1167
- emailVerificationRequired: getEnvBool("EMAIL_VERIFICATION_REQUIRED", true)
1168
- });
1169
- const actualDbType = distributed ? "distributed" : databaseType || detectDatabaseType();
1170
- return {
1171
- authAdapter,
1172
- databaseType: actualDbType,
1173
- email,
1174
- passwordPolicy,
1175
- lockout,
1176
- rateLimiter,
1177
- auditLogger,
1178
- routes
1179
- };
1180
- }
1181
- var authConfig = createAuthConfig().catch((err) => {
1182
- console.warn("[AuthConfig] Failed to initialize auth config:", err.message);
1183
- return null;
1184
- });
1185
-
1186
- // src/auth/index.ts
1187
- var DEFAULT_SALT_ROUNDS = 12;
1188
- var DEFAULT_EXPIRES_IN = "24h";
1189
- var DEFAULT_REFRESH_EXPIRES_IN = "7d";
1190
- var Auth = class {
1191
- adapter;
1192
- config;
1193
- constructor(adapter, config) {
1194
- this.adapter = adapter;
1195
- this.config = {
1196
- secret: config.secret,
1197
- expiresIn: config.expiresIn ?? DEFAULT_EXPIRES_IN,
1198
- refreshExpiresIn: config.refreshExpiresIn ?? DEFAULT_REFRESH_EXPIRES_IN,
1199
- issuer: config.issuer ?? "kyro-cms",
1200
- audience: config.audience ?? [],
1201
- saltRounds: config.saltRounds ?? DEFAULT_SALT_ROUNDS
1202
- };
1203
- }
1204
- async register(data) {
1205
- try {
1206
- const existing = await this.adapter.findUserByEmail(data.email);
1207
- if (existing) {
1208
- return { success: false, error: "Email already registered" };
1209
- }
1210
- const user = await this.adapter.createUser({
1211
- email: data.email,
1212
- password: data.password,
1213
- role: data.role ?? "customer",
1214
- tenantId: data.tenantId
1215
- });
1216
- return this.createSessionForUser(user);
1217
- } catch (error) {
1218
- return { success: false, error: String(error) };
1219
- }
1220
- }
1221
- async login(credentials) {
1222
- try {
1223
- const user = await this.adapter.verifyPassword(
1224
- credentials.email,
1225
- credentials.password
1226
- );
1227
- if (!user) {
1228
- return { success: false, error: "Invalid credentials" };
1229
- }
1230
- return this.createSessionForUser(user);
1231
- } catch (error) {
1232
- return { success: false, error: String(error) };
1233
- }
1234
- }
1235
- async logout(token) {
1236
- await this.adapter.deleteSession(token);
1237
- }
1238
- async refreshToken(refreshToken) {
1239
- try {
1240
- const session = await this.adapter.findSessionByToken(refreshToken);
1241
- if (!session || new Date(session.expiresAt) < /* @__PURE__ */ new Date()) {
1242
- return { success: false, error: "Invalid or expired refresh token" };
1243
- }
1244
- const user = await this.adapter.findUserById(session.userId);
1245
- if (!user) {
1246
- return { success: false, error: "User not found" };
1247
- }
1248
- await this.adapter.deleteSession(refreshToken);
1249
- return this.createSessionForUser(user);
1250
- } catch (error) {
1251
- return { success: false, error: String(error) };
1252
- }
1253
- }
1254
- async verifyToken(token) {
1255
- try {
1256
- const { default: jwtModule } = await import('jsonwebtoken');
1257
- const decoded = jwtModule.verify(token, this.config.secret, {
1258
- issuer: this.config.issuer,
1259
- audience: this.config.audience.length > 0 ? this.config.audience[0] : void 0
1260
- });
1261
- return decoded;
1262
- } catch {
1263
- return null;
1264
- }
1265
- }
1266
- async getUserFromToken(token) {
1267
- const payload = await this.verifyToken(token);
1268
- if (!payload) return null;
1269
- return this.adapter.findUserById(payload.sub);
1270
- }
1271
- async changePassword(userId, currentPassword, newPassword) {
1272
- try {
1273
- const user = await this.adapter.findUserById(userId);
1274
- if (!user) {
1275
- return { success: false, error: "User not found" };
1276
- }
1277
- const valid = await this.adapter.verifyPassword(
1278
- user.email,
1279
- currentPassword
1280
- );
1281
- if (!valid) {
1282
- return { success: false, error: "Current password is incorrect" };
1283
- }
1284
- await this.adapter.updateUser(userId, { password: newPassword });
1285
- await this.adapter.deleteUserSessions(userId);
1286
- return { success: true, user };
1287
- } catch (error) {
1288
- return { success: false, error: String(error) };
1289
- }
1290
- }
1291
- async resetPassword(email, newPassword) {
1292
- try {
1293
- const user = await this.adapter.findUserByEmail(email);
1294
- if (!user) {
1295
- return { success: false, error: "User not found" };
1296
- }
1297
- await this.adapter.updateUser(user.id, { password: newPassword });
1298
- await this.adapter.deleteUserSessions(user.id);
1299
- return { success: true, user };
1300
- } catch (error) {
1301
- return { success: false, error: String(error) };
1302
- }
1303
- }
1304
- async sendEmailVerification(userId) {
1305
- try {
1306
- const { token, expiresAt } = await this.adapter.createEmailVerificationToken(userId);
1307
- return { success: true };
1308
- } catch (error) {
1309
- return { success: false, error: String(error) };
1310
- }
1311
- }
1312
- async verifyEmail(token) {
1313
- try {
1314
- return await this.adapter.verifyEmailToken(token);
1315
- } catch (error) {
1316
- return { success: false, error: String(error) };
1317
- }
1318
- }
1319
- async requestPasswordReset(email) {
1320
- try {
1321
- const result = await this.adapter.createPasswordResetToken(email);
1322
- if (result.error) {
1323
- return { success: false, error: result.error };
1324
- }
1325
- return { success: true };
1326
- } catch (error) {
1327
- return { success: false, error: String(error) };
1328
- }
1329
- }
1330
- async resetPasswordWithToken(token, newPassword) {
1331
- try {
1332
- return await this.adapter.resetPasswordWithToken(token, newPassword);
1333
- } catch (error) {
1334
- return { success: false, error: String(error) };
1335
- }
1336
- }
1337
- async deleteAccount(userId) {
1338
- try {
1339
- const user = await this.adapter.findUserById(userId);
1340
- if (!user) {
1341
- return { success: false, error: "User not found" };
1342
- }
1343
- await this.adapter.deleteUserSessions(userId);
1344
- await this.adapter.deleteUser(userId);
1345
- return { success: true };
1346
- } catch (error) {
1347
- return { success: false, error: String(error) };
1348
- }
1349
- }
1350
- async createSessionForUser(user) {
1351
- const token = await this.generateToken(user);
1352
- const session = await this.adapter.createSession(user.id);
1353
- return {
1354
- success: true,
1355
- user,
1356
- session,
1357
- token
1358
- };
1359
- }
1360
- async generateToken(user) {
1361
- const { default: jwtModule } = await import('jsonwebtoken');
1362
- const payload = {
1363
- sub: user.id,
1364
- email: user.email,
1365
- role: user.role,
1366
- tenantId: user.tenantId
1367
- };
1368
- const signOptions = {
1369
- expiresIn: this.parseExpiresIn(this.config.expiresIn) / 1e3,
1370
- issuer: this.config.issuer
1371
- };
1372
- if (this.config.audience.length > 0) {
1373
- signOptions.audience = this.config.audience[0];
1374
- }
1375
- return jwtModule.sign(payload, this.config.secret, signOptions);
1376
- }
1377
- async hashPassword(password) {
1378
- const { default: bcrypt } = await import('bcryptjs');
1379
- return bcrypt.hash(password, this.config.saltRounds);
1380
- }
1381
- parseExpiresIn(value) {
1382
- if (typeof value === "number") return value;
1383
- const match = value.match(/^(\d+)([smhd])$/);
1384
- if (!match) return 864e5;
1385
- const num = parseInt(match[1], 10);
1386
- switch (match[2]) {
1387
- case "s":
1388
- return num * 1e3;
1389
- case "m":
1390
- return num * 6e4;
1391
- case "h":
1392
- return num * 36e5;
1393
- case "d":
1394
- return num * 864e5;
1395
- default:
1396
- return 864e5;
1397
- }
1398
- }
1399
- };
1400
- function createAuth(adapter, config) {
1401
- return new Auth(adapter, config);
1402
- }
1403
-
1404
- // src/versions/types.ts
1405
- function getDefaultDraftPublishConfig() {
1406
- return {
1407
- enabled: true,
1408
- draftsEnabled: true,
1409
- publishEnabled: true,
1410
- scheduleEnabled: false,
1411
- versioningEnabled: true,
1412
- maxVersionsPerDocument: 50,
1413
- autoPublish: false,
1414
- requirePublishPermission: true
1415
- };
1416
- }
1417
-
1418
- // src/versions/index.ts
1419
- var VersionManager = class {
1420
- adapter;
1421
- config;
1422
- constructor(adapter, config) {
1423
- this.adapter = adapter;
1424
- this.config = { ...getDefaultDraftPublishConfig(), ...config };
1425
- }
1426
- async createVersion(options) {
1427
- const latestVersion = await this.adapter.getLatestVersion(options.collection, options.documentId);
1428
- const nextVersion = (latestVersion?.version ?? 0) + 1;
1429
- const versionOptions = {
1430
- ...options,
1431
- version: nextVersion
1432
- };
1433
- const version = await this.adapter.createVersion(versionOptions);
1434
- if (this.config.maxVersionsPerDocument > 0) {
1435
- await this.pruneOldVersions(options.collection, options.documentId);
1436
- }
1437
- return version;
1438
- }
1439
- async publishVersion(options) {
1440
- const version = await this.adapter.getVersion(options.collection, options.versionId);
1441
- if (!version) {
1442
- throw new Error("Version not found");
1443
- }
1444
- if (version.status === "published") {
1445
- throw new Error("Version is already published");
1446
- }
1447
- await this.adapter.publishVersion(options);
1448
- }
1449
- async unpublishDocument(collection, documentId) {
1450
- const versions = await this.adapter.getVersions({
1451
- collection,
1452
- documentId,
1453
- limit: 1e3
1454
- });
1455
- for (const version of versions) {
1456
- if (version.status === "published") {
1457
- await this.createVersion({
1458
- collection,
1459
- documentId,
1460
- data: version.data,
1461
- status: "draft",
1462
- createdBy: "system",
1463
- changeDescription: "Unpublished document"
1464
- });
1465
- break;
1466
- }
1467
- }
1468
- }
1469
- async revertToVersion(collection, documentId, versionId, userId) {
1470
- const targetVersion = await this.adapter.getVersion(collection, versionId);
1471
- if (!targetVersion) {
1472
- throw new Error("Version not found");
1473
- }
1474
- const newVersion = await this.adapter.revertToVersion({
1475
- collection,
1476
- documentId,
1477
- versionId,
1478
- userId
1479
- });
1480
- return newVersion;
1481
- }
1482
- async getVersionHistory(collection, documentId, limit = 20, offset = 0) {
1483
- return this.adapter.getVersions({
1484
- collection,
1485
- documentId,
1486
- limit,
1487
- offset
1488
- });
1489
- }
1490
- async compareTwoVersions(collection, documentId, versionA, versionB) {
1491
- return this.adapter.compareVersions({
1492
- collection,
1493
- documentId,
1494
- versionA,
1495
- versionB
1496
- });
1497
- }
1498
- async getLatestDraft(collection, documentId) {
1499
- return this.adapter.getLatestVersion(collection, documentId);
1500
- }
1501
- async getPublishedVersion(collection, documentId) {
1502
- return this.adapter.getPublishedVersion(collection, documentId);
1503
- }
1504
- async getVersion(collection, versionId) {
1505
- return this.adapter.getVersion(collection, versionId);
1506
- }
1507
- async schedulePublish(collection, documentId, versionId, scheduledFor) {
1508
- if (!this.config.scheduleEnabled) {
1509
- throw new Error("Scheduled publishing is not enabled");
1510
- }
1511
- const version = await this.adapter.getVersion(collection, versionId);
1512
- if (!version) {
1513
- throw new Error("Version not found");
1514
- }
1515
- }
1516
- async deleteVersionHistory(collection, documentId) {
1517
- await this.adapter.deleteVersions(collection, documentId);
1518
- }
1519
- async pruneOldVersions(collection, documentId) {
1520
- const versions = await this.adapter.getVersions({
1521
- collection,
1522
- documentId,
1523
- limit: this.config.maxVersionsPerDocument + 100
1524
- });
1525
- if (versions.length <= this.config.maxVersionsPerDocument) {
1526
- return;
1527
- }
1528
- versions.slice(0, this.config.maxVersionsPerDocument);
1529
- const versionsToDelete = versions.slice(this.config.maxVersionsPerDocument);
1530
- for (const version of versionsToDelete) {
1531
- if (version.status !== "published") {
1532
- await this.adapter.deleteVersions(collection, documentId);
1533
- break;
1534
- }
1535
- }
1536
- }
1537
- };
1538
- function createVersionManager(adapter, config) {
1539
- return new VersionManager(adapter, config);
1540
- }
1541
- function isPublished(status) {
1542
- return status === "published";
1543
- }
1544
- function isDraft(status) {
1545
- return status === "draft";
1546
- }
1547
- function isArchived(status) {
1548
- return status === "archived";
1549
- }
1550
-
1551
- // src/registry/config.ts
1552
- function normalizeCollections(collections) {
1553
- if (!collections) return [];
1554
- if (Array.isArray(collections)) return collections;
1555
- return Object.values(collections);
1556
- }
1557
- function normalizeGlobals(globals) {
1558
- if (!globals) return [];
1559
- if (Array.isArray(globals)) return globals;
1560
- return Object.values(globals);
1561
- }
1562
- function defineConfig(config) {
1563
- return {
1564
- collections: normalizeCollections(config.collections),
1565
- globals: normalizeGlobals(config.globals),
1566
- adapter: config.adapter,
1567
- plugins: config.plugins,
1568
- auth: config.auth,
1569
- cors: config.cors,
1570
- admin: config.admin,
1571
- upload: config.upload,
1572
- graphQL: config.graphQL,
1573
- typescript: config.typescript,
1574
- localization: config.localization,
1575
- rateLimit: config.rateLimit,
1576
- debug: config.debug
1577
- };
1578
- }
1579
- var defineKyroConfig = defineConfig;
1580
-
1581
- // src/lib/seo.ts
1582
- function generateSeoTags(options) {
1583
- const { siteSettings, seoSettings, title, description, image, url } = options;
1584
- if (!siteSettings) return "";
1585
- const siteName = siteSettings.siteName || "";
1586
- const rawTitle = title || seoSettings?.defaultTitle || siteName;
1587
- const titleTemplate = seoSettings?.titleTemplate;
1588
- const separator = seoSettings?.separator || " | ";
1589
- const siteNameInTitle = seoSettings?.siteNameInTitle !== false;
1590
- const finalTitle = titleTemplate ? titleTemplate.replace(/\{\{title\}\}/g, rawTitle).replace(/\{\{siteName\}\}/g, siteNameInTitle ? siteName : "").replace(/\{\{separator\}\}/g, separator).replace(/\s+/g, " ").trim() : rawTitle;
1591
- const finalDesc = description || seoSettings?.defaultDescription || siteSettings.siteDescription || "";
1592
- const finalImage = image || siteSettings.siteOgImage?.url || "";
1593
- const finalUrl = url || siteSettings.siteUrl || "";
1594
- let tags = `
1595
- <title>${finalTitle}</title>
1596
- <meta name="description" content="${finalDesc}">
1597
- `;
1598
- if (siteSettings.siteFavicon?.url) {
1599
- tags += `
1600
- <link rel="icon" type="${siteSettings.siteFavicon.mimeType || "image/x-icon"}" href="${siteSettings.siteFavicon.url}">`;
1601
- }
1602
- const robots = seoSettings?.meta?.robots;
1603
- if (robots) {
1604
- tags += `
1605
- <meta name="robots" content="${robots}">`;
1606
- }
1607
- const canonical = seoSettings?.meta?.canonicalUrl || finalUrl;
1608
- if (canonical) {
1609
- tags += `
1610
- <link rel="canonical" href="${canonical}">`;
1611
- }
1612
- const ogType = seoSettings?.meta?.ogType || "website";
1613
- tags += `
1614
- <meta property="og:type" content="${ogType}">
1615
- <meta property="og:title" content="${finalTitle}">
1616
- <meta property="og:description" content="${finalDesc}">
1617
- <meta property="og:site_name" content="${siteName}">
1618
- `;
1619
- if (finalUrl) tags += `
1620
- <meta property="og:url" content="${finalUrl}">`;
1621
- if (finalImage) tags += `
1622
- <meta property="og:image" content="${finalImage}">`;
1623
- if (seoSettings?.social?.fbAppId) {
1624
- tags += `
1625
- <meta property="fb:app_id" content="${seoSettings.social.fbAppId}">`;
1626
- }
1627
- const twitterCard = seoSettings?.social?.twitterCardType || "summary_large_image";
1628
- tags += `
1629
- <meta name="twitter:card" content="${twitterCard}">
1630
- <meta name="twitter:title" content="${finalTitle}">
1631
- <meta name="twitter:description" content="${finalDesc}">
1632
- `;
1633
- if (seoSettings?.social?.twitterHandle) {
1634
- tags += `
1635
- <meta name="twitter:site" content="${seoSettings.social.twitterHandle}">`;
1636
- }
1637
- if (finalImage) tags += `
1638
- <meta name="twitter:image" content="${finalImage}">`;
1639
- if (siteSettings.enableI18n && siteSettings.i18n?.language) {
1640
- tags += `
1641
- <meta http-equiv="content-language" content="${siteSettings.i18n.language}">`;
1642
- }
1643
- return tags;
1644
- }
1645
- function generateAnalyticsTags(siteSettings) {
1646
- if (!siteSettings || !siteSettings.analyticsEnabled || !siteSettings.analytics) {
1647
- return "";
1648
- }
1649
- const { googleAnalyticsId, googleTagManagerId, plausibleDomain } = siteSettings.analytics;
1650
- let scripts = "";
1651
- if (googleAnalyticsId) {
1652
- scripts += `
1
+ export{a as RedisAuthAdapter}from'./chunk-AU6IWTBO.js';export{P as allSettingsGlobals,c as blogCollections,d as blogGlobals,Q as coreSettingsGlobals,U as createTemplateConfig,e as ecommerceCollections,f as ecommerceGlobals,g as kitchenSinkCollections,i as mediaCollections,a as minimalCollections,T as templateCollections}from'./chunk-ZELCS7IC.js';export{a as kyro}from'./chunk-LZ6YFYQM.js';export{a as ConfigValidationError,p as Kyro,r as LocalAdapter,l as Registry,h as collectionToCreateZod,i as collectionToUpdateZod,j as collectionToWhereZod,g as collectionToZod,q as createKyro,s as createLocalAdapter,o as createRegistry,f as fieldToZod,m as getRegistry,k as globalToZod,n as resetRegistry,b as validateCollection,e as validateConfig,d as validateFields,c as validateGlobal}from'./chunk-FS7GL2BR.js';export{d as autoBootstrap,a as bootstrapAdmin,e as bootstrapWithRetry,c as getBootstrapFromEnv}from'./chunk-FO3HLBC7.js';import'./chunk-NZ35PV5R.js';export{a as CSSGenerator,g as createAdminStyling,d as defaultDarkTheme,h as defaultFieldStyling,c as defaultLightTheme,e as ecommerce2026Theme,f as generateCSSVariables,b as generateTailwindConfig}from'./chunk-UHFDH3PG.js';export{p as ALL_FIELD_TYPES,m as COMPLEX_FIELD_TYPES,o as LAYOUT_FIELD_TYPES,l as PRIMITIVE_FIELD_TYPES,n as RELATIONAL_FIELD_TYPES,d as isArrayField,f as isBlocksField,e as isGroupField,h as isImageField,k as isLayoutField,b as isNumberField,c as isRelationshipField,i as isRichTextField,j as isSelectField,a as isTextField,g as isUploadField,s as normalizeRichTextValue,t as renderRichText,r as richTextStyles}from'./chunk-NGBJKZMT.js';export{a as createContext,g as createCountProcedure,d as createCreateProcedure,f as createDeleteProcedure,h as createDynamicRouter,c as createFindByIDProcedure,b as createFindProcedure,i as createKyroServer,e as createUpdateProcedure}from'./chunk-7N6NKCRT.js';export{I as buildGraphQLSchema,J as createGraphQLSchema}from'./chunk-LRGAPGG3.js';import {l,n,m,p as p$1,q}from'./chunk-URCLFIME.js';export{n as AuditLogger,p as InMemoryAuditLogger,m as InMemoryRateLimiter,r as MediaService,o as createAuditContext,s as createHonoApp,e as createLocalStorage,t as createRESTAPI,i as getAppSecret,j as getEncryptionKey,k as getSessionConfig,h as loadSecrets,d as resolveProvider,g as setDbAdapter}from'./chunk-URCLFIME.js';import {b as b$1,c}from'./chunk-7WOX27LK.js';export{a as ConfigService,b as EmailTransport,c as PasswordPolicy}from'./chunk-7WOX27LK.js';import'./chunk-K6WUOU6P.js';import'./chunk-AE6GXUT7.js';import {a as a$1}from'./chunk-2W4FK6CJ.js';export{a as SQLiteAuthAdapter}from'./chunk-2W4FK6CJ.js';import'./chunk-NRLIGDYF.js';export{d as ALL_WEBHOOK_EVENTS,e as WEBHOOK_COLLECTION,f as WEBHOOK_DELIVERY_COLLECTION,c as WEBHOOK_EVENTS,m as WebhookService,k as buildDeliveryRecord,l as createTestPayload,n as createWebhookService,i as deliverWebhook,j as deliverWithRetry,h as generateWebhookSecret,g as signPayload}from'./chunk-UVTS2IWM.js';export{a as evaluateAccess,c as getWhereClause,b as mergeWhereClauses}from'./chunk-HLSB2MCK.js';export{b as KyroPubSub,c as KyroWSServer,a as PubSub,d as createWSServer}from'./chunk-SL3LZQCF.js';import'./chunk-PP5S2UBV.js';export{c as DrizzleAdapter,b as collectionToDrizzleSchema,f as createDatabase,d as createDrizzleAdapter,a as fieldToDrizzleType,g as runMigrations,h as seedDefaultRoles}from'./chunk-CDL7ARXT.js';import {a as a$2}from'./chunk-RHCWCG3O.js';export{a as PostgresAuthAdapter}from'./chunk-RHCWCG3O.js';import'./chunk-OG7CNQGU.js';import'./chunk-QRXDCV6K.js';export{a as MongoDBAdapter,b as createMongoDBAdapter}from'./chunk-G6A7OSIG.js';import {a}from'./chunk-P7CESLDJ.js';export{a as MongoDBAuthAdapter}from'./chunk-P7CESLDJ.js';export{a as AbstractBaseAdapter}from'./chunk-ZAQOSRP6.js';import'./chunk-KDNYHLD2.js';import'./chunk-DGJUBN33.js';import q$1,{randomBytes}from'crypto';import {readFileSync}from'fs';import Me,{join,resolve}from'path';export{z}from'zod';import {createStorage}from'unstorage';import $r from'unstorage/drivers/indexedb';import zr from'unstorage/drivers/fs';async function Ie(s,e){let t=e.data;for(let r of s){let o=await r({...e,data:t});o!==void 0&&(t=o);}return t}async function br(s,e){return Ie(s,e)}var b=class{name;version;description;hooks={};collections=[];globals=[];fields=[];extensions={collections:[],globals:[]};adminComponents={};adminStyles=[];serverMiddleware;clientMiddleware;constructor(e){this.name=e;}async init(e){}async beforeInit(e){}async afterInit(e){}getCollections(){return this.collections}getGlobals(){return this.globals}getHooks(){return this.hooks}},$=class{plugins=new Map;hooks=new Map;register(e){if(this.plugins.has(e.name))throw new Error(`Plugin "${e.name}" is already registered`);this.plugins.set(e.name,e);let t=e.getHooks?.()||{};for(let[r,o]of Object.entries(t))if(Array.isArray(o))for(let i of o)this.registerHook(r,i);}unregister(e){let t=this.plugins.get(e);if(!t)return;let r=t.getHooks?.()||{};for(let[o,i]of Object.entries(r))if(Array.isArray(i))for(let n of i)this.unregisterHook(o,n);this.plugins.delete(e);}get(e){return this.plugins.get(e)}getAll(){return Array.from(this.plugins.values())}has(e){return this.plugins.has(e)}registerHook(e,t){this.hooks.has(e)||this.hooks.set(e,[]),this.hooks.get(e).push(t);}unregisterHook(e,t){let r=this.hooks.get(e);if(r){let o=r.indexOf(t);o>-1&&r.splice(o,1);}}async executeHook(e,t){let r=this.hooks.get(e)||[],o=t;for(let i of r)try{let n=await i({...t,data:o});n!==void 0&&(o=n);}catch(n){console.error(`[PluginManager] Error in hook "${e}":`,n);}return o}getAllCollections(){let e=[];for(let t of this.plugins.values()){let r=t.getCollections?.()||[];e.push(...r);}return e}getAllGlobals(){let e=[];for(let t of this.plugins.values()){let r=t.getGlobals?.()||[];e.push(...r);}return e}getAllFields(){let e=[];for(let t of this.plugins.values())e.push(...t.fields);return e}getAdminComponents(){let e={};for(let t of this.plugins.values())Object.assign(e,t.adminComponents);return e}getAdminStyles(){let e=[];for(let t of this.plugins.values())e.push(...t.adminStyles);return e}},L=class extends b{constructor(){super("seo"),this.description="Advanced SEO features including sitemaps, robots.txt, and structured data",this.collections.push({slug:"seo-settings",label:"SEO Settings",fields:[{name:"sitemap",type:"checkbox",label:"Enable Sitemap",defaultValue:true},{name:"robotsTxt",type:"richtext",label:"robots.txt Content"},{name:"canonicalUrl",type:"text",variant:"url",label:"Canonical URL"},{name:"ogImage",type:"text",label:"Default OG Image URL"}]});}},E=class extends b{constructor(){super("analytics"),this.description="Analytics integration for tracking page views and events",this.collections.push({slug:"analytics-events",label:"Analytics Events",fields:[{name:"name",type:"text",required:true},{name:"properties",type:"json",label:"Event Properties"},{name:"timestamp",type:"date",required:true},{name:"userId",type:"text",label:"User ID"},{name:"sessionId",type:"text",label:"Session ID"}]}),this.adminComponents.AnalyticsDashboard={};}},U=class extends b{constructor(){super("comments"),this.description="Commenting system for products and posts",this.collections.push({slug:"comments",label:"Comments",fields:[{name:"content",type:"richtext",required:true},{name:"author",type:"text",required:true},{name:"email",type:"email"},{name:"approved",type:"checkbox",defaultValue:false},{name:"parent",type:"text",label:"Parent Comment ID"},{name:"resourceType",type:"text",required:true},{name:"resourceId",type:"text",required:true}]}),this.adminComponents.CommentModeration={};}},V=class extends b{constructor(){super("reviews"),this.description="Product reviews and ratings",this.collections.push({slug:"reviews",label:"Reviews",fields:[{name:"rating",type:"number",required:true,min:1,max:5},{name:"title",type:"text"},{name:"content",type:"richtext",required:true},{name:"author",type:"relationship",relationTo:"customers"},{name:"product",type:"relationship",relationTo:"products",required:true},{name:"approved",type:"checkbox",defaultValue:false},{name:"verified",type:"checkbox",label:"Verified Purchase"},{name:"helpful",type:"number",label:"Helpful Count",defaultValue:0}]}),this.adminComponents.ReviewModeration={};}},O=class extends b{constructor(){super("wishlist"),this.description="Customer wishlists",this.collections.push({slug:"wishlists",label:"Wishlists",fields:[{name:"customer",type:"relationship",relationTo:"customers",required:true},{name:"name",type:"text",label:"Wishlist Name",defaultValue:"My Wishlist"},{name:"items",type:"blocks",label:"Items",blocks:[{slug:"wishlist-item",label:"Item",fields:[{name:"product",type:"relationship",relationTo:"products"},{name:"quantity",type:"number",defaultValue:1},{name:"addedAt",type:"date"},{name:"priority",type:"select",options:[{label:"Low",value:"low"},{label:"Medium",value:"medium"},{label:"High",value:"high"}]}]}]}]});}},Ar={SEO:L,Analytics:E,Comments:U,Reviews:V,Wishlist:O};var wr={maxAttempts:5,lockDuration:9e5,notifyUser:true,notifyAdmin:true,adminNotifyAfter:3},x=class{redis;prefix;config;constructor(e,t={},r="kyro:lockout:"){this.redis=e,this.prefix=r,this.config={...wr,...t};}lockKey(e){return `${this.prefix}${e}`}historyKey(e){return `${this.prefix}${e}:history`}async checkLockout(e){let t=this.lockKey(e),r=await this.redis.hgetall(t);if(!r||Object.keys(r).length===0)return {locked:false,attemptsRemaining:this.config.maxAttempts,totalAttempts:0};let o=parseInt(r.attempts,10),i=r.lockedUntil?new Date(parseInt(r.lockedUntil,10)):void 0;return i&&i>new Date?{locked:true,attemptsRemaining:0,lockedUntil:i,totalAttempts:o}:i&&i<=new Date?(await this.unlockAccount(e),{locked:false,attemptsRemaining:this.config.maxAttempts,totalAttempts:0}):{locked:false,attemptsRemaining:Math.max(0,this.config.maxAttempts-o),totalAttempts:o}}async recordFailedAttempt(e){let t=this.lockKey(e),r=this.historyKey(e),o=Date.now(),i=await this.redis.hincrby(t,"attempts",1);if(await this.redis.hset(t,"lastAttempt",o.toString()),await this.redis.lpush(r,o.toString()),await this.redis.ltrim(r,0,99),i>=this.config.maxAttempts){let n=new Date(o+this.config.lockDuration);return await this.redis.hset(t,{lockedAt:o.toString(),lockedUntil:n.getTime().toString()}),await this.redis.expire(t,Math.ceil(this.config.lockDuration/1e3)+3600),{locked:true,attemptsRemaining:0,lockedUntil:n,totalAttempts:i}}return {locked:false,attemptsRemaining:Math.max(0,this.config.maxAttempts-i),totalAttempts:i}}async lockAccount(e,t){let r=this.lockKey(e),o=Date.now(),i=t||this.config.lockDuration,n=new Date(o+i),a=this.redis.pipeline();a.hset(r,{attempts:this.config.maxAttempts.toString(),lockedAt:o.toString(),lockedUntil:n.getTime().toString()}),a.expire(r,Math.ceil(i/1e3)+3600),await a.exec();}async unlockAccount(e){let t=this.lockKey(e);await this.redis.del(t);}async resetAttempts(e){let t=this.lockKey(e);(await this.redis.hgetall(t)).lockedAt?await this.redis.hset(t,{attempts:"0",lockedAt:"",lockedUntil:""}):await this.redis.del(t);}async getLockoutHistory(e,t=10){let r=this.historyKey(e);return (await this.redis.lrange(r,0,t-1)).map(i=>new Date(parseInt(i,10)))}async getLockoutStats(e){let t=this.historyKey(e),r=await this.redis.lrange(t,0,-1),o=r.filter((n,a)=>(a+1)%this.config.maxAttempts===0).length,i=await this.redis.hget(this.lockKey(e),"lockedAt");return {totalFailedAttempts:r.length,lockoutCount:o,lastLockout:i?new Date(parseInt(i,10)):null,averageAttemptsBeforeLockout:o>0?this.config.maxAttempts:0}}shouldNotifyAdmin(e){return this.config.notifyAdmin&&e>=this.config.adminNotifyAfter}getConfig(){return {...this.config}}setConfig(e){this.config={...this.config,...e};}};var kr={"auth:login":{window:9e5,max:5},"auth:register":{window:36e5,max:3},"auth:forgot":{window:36e5,max:3},"auth:reset":{window:36e5,max:5},"auth:verify":{window:36e5,max:5},"api:general":{window:6e4,max:100},"api:authenticated":{window:6e4,max:200}},S=class{redis;prefix;limits;userLimits;constructor(e,t,r,o="kyro:ratelimit:"){this.redis=e,this.prefix=o,this.limits={...kr,...t},this.userLimits=r||{"user:api":{window:6e4,max:500},"user:write":{window:36e5,max:100}};}getKey(e,t){return `${this.prefix}${e}:${t}`}async check(e,t){let r=this.limits[e]||this.limits["api:general"],o=this.getKey(e,t),i=Date.now(),n=i-r.window,a=this.redis.pipeline();a.zremrangebyscore(o,0,n),a.zcard(o),a.zadd(o,i,`${i}:${Math.random()}`),a.expire(o,Math.ceil(r.window/1e3)+1);let c=(await a.exec())?.[1]?.[1]||0;if(c>=r.max){let g=await this.redis.zrange(o,0,0,"WITHSCORES"),d=g.length>1?parseInt(g[1],10)+r.window:i+r.window;return {allowed:false,remaining:0,resetAt:d,retryAfter:Math.ceil((d-i)/1e3)}}return {allowed:true,remaining:r.max-c-1,resetAt:i+r.window}}async checkUser(e,t,r){let o=this.userLimits[e]||this.userLimits["user:api"],i=this.getKey(`user:${e}:${t}`,r),n=Date.now(),a=n-o.window,l=this.redis.pipeline();l.zremrangebyscore(i,0,a),l.zcard(i),l.zadd(i,n,`${n}:${Math.random()}`),l.expire(i,Math.ceil(o.window/1e3)+1);let g=(await l.exec())?.[1]?.[1]||0;if(g>=o.max){let d=await this.redis.zrange(i,0,0,"WITHSCORES"),u=d.length>1?parseInt(d[1],10)+o.window:n+o.window;return {allowed:false,remaining:0,resetAt:u,retryAfter:Math.ceil((u-n)/1e3)}}return {allowed:true,remaining:o.max-g-1,resetAt:n+o.window}}async reset(e,t){let r=this.getKey(e,t);await this.redis.del(r);}async resetUser(e,t,r){let o=this.getKey(`user:${e}:${t}`,r);await this.redis.del(o);}async getStatus(e,t){let r=this.limits[e]||this.limits["api:general"],o=this.getKey(e,t),i=Date.now(),n=i-r.window;await this.redis.zremrangebyscore(o,0,n);let a=await this.redis.zcard(o);return {count:a,limit:r.max,remaining:Math.max(0,r.max-a),resetAt:i+r.window}}setLimit(e,t){this.limits[e]=t;}setUserLimit(e,t){this.userLimits[e]=t;}};var P=class{users=new Map;sessions=new Map;refreshTokens=new Map;emailToUserId=new Map;passwordHistory=new Map;emailVerificationTokens=new Map;passwordResetTokens=new Map;auditLogs=[];externalDb=false;constructor(){}async connect(){}async disconnect(){this.users.clear(),this.sessions.clear(),this.refreshTokens.clear(),this.emailToUserId.clear(),this.passwordHistory.clear();}async createUser(e){let t=randomBytes(16).toString("hex"),r=new Date().toISOString(),o=await this.hashPassword(e.password),i={id:t,email:e.email.toLowerCase(),passwordHash:o,role:e.role||"customer",tenantId:e.tenantId,createdAt:r,updatedAt:r};return this.users.set(t,i),this.emailToUserId.set(e.email.toLowerCase(),t),this.passwordHistory.set(t,[]),i}async findUserByEmail(e){let t=this.emailToUserId.get(e.toLowerCase());return t?this.findUserById(t):null}async findUserById(e){return this.users.get(e)||null}async updateUser(e,t){let r=await this.findUserById(e);if(!r)return null;let o={...r,...t,id:e,updatedAt:new Date().toISOString()};return t.email&&t.email!==r.email&&(this.emailToUserId.delete(r.email.toLowerCase()),this.emailToUserId.set(t.email.toLowerCase(),e)),this.users.set(e,o),o}async deleteUser(e){let t=await this.findUserById(e);return t?(this.users.delete(e),this.emailToUserId.delete(t.email.toLowerCase()),this.refreshTokens.forEach((r,o)=>{this.sessions.get(r)?.userId===e&&(this.refreshTokens.delete(o),this.sessions.delete(r));}),this.passwordHistory.delete(e),this.sessions.forEach((r,o)=>{r.userId===e&&this.sessions.delete(o);}),true):false}async hashPassword(e){return (await import('bcryptjs')).default.hash(e,12)}async verifyPassword(e,t){let r=await this.findUserByEmail(e);return !r||!r.passwordHash?null:await(await import('bcryptjs')).default.compare(t,r.passwordHash)?r:null}async createSession(e,t={}){let r=randomBytes(32).toString("hex"),o=randomBytes(32).toString("base64url"),i=randomBytes(32).toString("base64url"),n=new Date,a={id:r,userId:e,token:o,refreshToken:i,expiresAt:new Date(n.getTime()+86400*1e3).toISOString(),createdAt:n.toISOString(),ipAddress:t.ipAddress,userAgent:t.userAgent};return this.sessions.set(r,a),this.refreshTokens.set(i,r),a}async findSessionByToken(e){return this.sessions.get(e)||null}async findSessionByRefreshToken(e){let t=this.refreshTokens.get(e);return t&&this.sessions.get(t)||null}async deleteSession(e){let t=this.sessions.get(e);return t?(t.refreshToken&&this.refreshTokens.delete(t.refreshToken),this.sessions.delete(e),true):false}async deleteUserSessions(e){let t=0;return this.sessions.forEach((r,o)=>{r.userId===e&&(r.refreshToken&&this.refreshTokens.delete(r.refreshToken),this.sessions.delete(o),t++);}),t}async addPasswordToHistory(e,t){let r=this.passwordHistory.get(e)||[];r.push(t),r.length>5&&r.splice(0,r.length-5),this.passwordHistory.set(e,r);}async getPasswordHistory(e,t=5){return this.passwordHistory.get(e)||[]}async isPasswordInHistory(e,t,r=5){let o=await this.getPasswordHistory(t,r),i=(await import('bcryptjs')).default;for(let n of o)if(await i.compare(e,n))return true;return false}async createEmailVerificationToken(e){let t=randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.emailVerificationTokens.set(t,{userId:e,expiresAt:r}),{token:t,expiresAt:r}}async verifyEmailToken(e){let t=this.emailVerificationTokens.get(e);return !t||t.expiresAt<new Date?(this.emailVerificationTokens.delete(e),{success:false,error:"Invalid or expired token"}):(this.emailVerificationTokens.delete(e),{success:true,userId:t.userId})}async createPasswordResetToken(e){let t=await this.findUserByEmail(e);if(!t)return {token:"",expiresAt:new Date,error:"User not found"};let r=randomBytes(32).toString("hex"),o=new Date(Date.now()+3600*1e3);return this.passwordResetTokens.set(r,{userId:t.id,expiresAt:o}),{token:r,expiresAt:o}}async resetPasswordWithToken(e,t){let r=this.passwordResetTokens.get(e);if(!r||r.expiresAt<new Date)return this.passwordResetTokens.delete(e),{success:false,error:"Invalid or expired token"};let o=await this.hashPassword(t);return await this.updateUser(r.userId,{passwordHash:o}),this.passwordResetTokens.delete(e),{success:true}}async hasAnyUsers(){return this.users.size>0}async findAuditLogs(e){let{limit:t=50,offset:r=0}=e,o=this.auditLogs.slice().reverse();return e.userId&&(o=o.filter(i=>i.userId===e.userId)),e.action&&(Array.isArray(e.action)?o=o.filter(i=>e.action.includes(String(i.action))):o=o.filter(i=>i.action===e.action)),e.resource&&(o=o.filter(i=>i.resource===e.resource)),e.success!==void 0&&(o=o.filter(i=>i.success===e.success)),{logs:o.slice(r,r+t),total:o.length}}async createAuditLog(e){let t=randomBytes(16).toString("hex"),o={...e,id:t,timestamp:new Date};return this.auditLogs.push(o),o}};var C=class{storage=new Map;history=new Map;config;constructor(e={}){this.config={maxAttempts:5,lockDuration:9e5,notifyUser:true,notifyAdmin:true,adminNotifyAfter:3,...e};}async checkLockout(e){let t=Date.now(),r=this.storage.get(e);if(r&&r.lockedUntil!==null&&r.lockedUntil<=t)return await this.resetAttempts(e),{locked:false,attemptsRemaining:this.config.maxAttempts,totalAttempts:0};if(!r)return {locked:false,attemptsRemaining:this.config.maxAttempts,totalAttempts:0};let{attempts:o,lockedUntil:i}=r;return i!==null&&i>t?{locked:true,attemptsRemaining:0,lockedUntil:new Date(i),totalAttempts:o}:{locked:false,attemptsRemaining:Math.max(0,this.config.maxAttempts-o),totalAttempts:o}}async recordFailedAttempt(e){let t=Date.now(),r=this.storage.get(e)||{attempts:0,lastAttempt:null,lockedAt:null,lockedUntil:null};r.attempts+=1,r.lastAttempt=t;let o=this.history.get(e)||[];if(o.push(t),o.length>100&&o.splice(0,o.length-100),this.history.set(e,o),this.storage.set(e,r),r.attempts>=this.config.maxAttempts){let i=new Date(t+this.config.lockDuration);return r.lockedAt=t,r.lockedUntil=i.getTime(),this.storage.set(e,r),{locked:true,attemptsRemaining:0,lockedUntil:i,totalAttempts:r.attempts}}return {locked:false,attemptsRemaining:Math.max(0,this.config.maxAttempts-r.attempts),totalAttempts:r.attempts}}async lockAccount(e,t){let r=Date.now(),o=t||this.config.lockDuration,i=new Date(r+o),n=this.storage.get(e)||{attempts:0,lastAttempt:null,lockedAt:null,lockedUntil:null};n.attempts=this.config.maxAttempts,n.lockedAt=r,n.lockedUntil=i.getTime(),this.storage.set(e,n);}async unlockAccount(e){await this.resetAttempts(e);}async resetAttempts(e){let t=this.storage.get(e);t&&(t.attempts=0,t.lockedAt=null,t.lockedUntil=null,this.storage.set(e,t)),this.history.delete(e);}async getLockoutHistory(e,t=10){return (this.history.get(e)||[]).slice(-t).reverse().map(o=>new Date(o))}async getLockoutStats(e){let r=(this.history.get(e)||[]).length,o=Math.floor(r/this.config.maxAttempts),i=null,n=this.storage.get(e);n&&n.lockedAt!==null&&(i=new Date(n.lockedAt));let a=o>0?this.config.maxAttempts:0;return {totalFailedAttempts:r,lockoutCount:o,lastLockout:i,averageAttemptsBeforeLockout:a}}shouldNotifyAdmin(e){return this.config.notifyAdmin&&e>=this.config.adminNotifyAfter}getConfig(){return {...this.config}}setConfig(e){this.config={...this.config,...e};}};function h(s,e=""){return process.env[s]||e}function A(s,e=false){let t=process.env[s];return t?t.toLowerCase()==="true":e}function p(s,e=0){let t=process.env[s];return t?parseInt(t,10):e}function Le(){let s=process.env.KYRO_AUTH_DATABASE?.toLowerCase();if(s&&["sqlite","postgres","mongodb","memory"].includes(s))return s;try{let e=join(process.cwd(),"kyro.config.ts"),t=readFileSync(e,"utf8");if(t.includes("createLocalAdapter"))return "sqlite";if(t.includes("createDrizzleAdapter"))return t.includes("postgres")||t.includes("postgresql"),"postgres";if(t.includes("createMongoDBAdapter"))return "mongodb"}catch{}return "memory"}async function Pr(s){let e=process.cwd(),t=e.endsWith("admin")?join(e,".."):e,r=resolve(t,"data","auth.db");switch(s){case "sqlite":return new a$1({path:h("KYRO_AUTH_DB_PATH",r)});case "postgres":{try{let o=h("DATABASE_URL","");if(o){let{drizzle:i}=await import('drizzle-orm/postgres-js'),a=(await import('postgres')).default(o,{onnotice:()=>{}}),l=i(a);return new a$2({db:l})}}catch{console.warn("[Auth] Could not create PostgresAuthAdapter, falling back to SQLite auth adapter.");}return new a$1({path:h("KYRO_AUTH_DB_PATH",r)})}case "mongodb":{try{let o=h("MONGODB_URI","");if(o){let{MongoClient:i}=await import('mongodb'),n=new i(o);await n.connect();let l=new URL(o).pathname.replace(/^\//,"")||"kyro_cms",c=n.db(l);return new a({db:c})}}catch{console.warn("[Auth] Could not create MongoDBAuthAdapter, falling back to SQLite auth adapter.");}return new a$1({path:h("KYRO_AUTH_DB_PATH",r)})}default:return new P}}async function W(s,e){let t=A("KYRO_DISTRIBUTED",false),r;if(t){let{RedisAuthAdapter:d}=await import('./redis-adapter-AUKOV74G.js'),u=h("REDIS_URL","redis://localhost:6379"),y=A("REDIS_TLS",false),f=new d({url:u,tls:y});await f.connect?.(),r=f;}else {let d=s||Le();r=await Pr(d),r.connect&&await r.connect();}let o=e?await b$1.fromConfig(e).catch(()=>null)||b$1.fromEnv()||void 0:b$1.fromEnv()||void 0,i=new c({minLength:p("PASSWORD_MIN_LENGTH",12),requireUppercase:A("PASSWORD_REQUIRE_UPPERCASE",true),requireLowercase:A("PASSWORD_REQUIRE_LOWERCASE",true),requireNumbers:A("PASSWORD_REQUIRE_NUMBERS",true),requireSpecialChars:A("PASSWORD_REQUIRE_SPECIAL",true),preventReuse:p("PASSWORD_PREVENT_REUSE",5),maxLength:p("PASSWORD_MAX_LENGTH",128)}),n$1,a,l;if(t){let u=r.redis;n$1=new x(u,{maxAttempts:p("LOCKOUT_MAX_ATTEMPTS",5),lockDuration:p("LOCKOUT_DURATION_MINUTES",15)*60*1e3}),a=new S(u,{"auth:login":{window:p("RATE_LIMIT_AUTH_WINDOW_MS",9e5),max:p("RATE_LIMIT_AUTH_MAX_REQUESTS",10)},"api:general":{window:p("RATE_LIMIT_WINDOW_MS",6e4),max:p("RATE_LIMIT_MAX_REQUESTS",100)}}),l=new n(u,p("AUDIT_LOG_RETENTION_DAYS",30));}else n$1=new C({maxAttempts:p("LOCKOUT_MAX_ATTEMPTS",5),lockDuration:p("LOCKOUT_DURATION_MINUTES",15)*60*1e3}),a=new m({"auth:login":{window:p("RATE_LIMIT_AUTH_WINDOW_MS",9e5),max:p("RATE_LIMIT_AUTH_MAX_REQUESTS",10)},"api:general":{window:p("RATE_LIMIT_WINDOW_MS",6e4),max:p("RATE_LIMIT_MAX_REQUESTS",100)}}),l=A("AUDIT_LOG_ENABLED",true)?new p$1(p("AUDIT_LOG_RETENTION_DAYS",30)):void 0;let c$1=new q({redis:r,email:o,jwtSecret:h("APP_SECRET","change-me"),jwtExpiresIn:h("JWT_EXPIRES_IN","24h"),jwtIssuer:h("JWT_ISSUER","kyro-cms"),jwtAudience:h("JWT_AUDIENCE","kyro-cms-client"),passwordPolicy:i,lockout:n$1,rateLimiter:a,auditLogger:l,baseUrl:h("EMAIL_BASE_URL","http://localhost:4321"),emailVerificationRequired:A("EMAIL_VERIFICATION_REQUIRED",true)}),g=t?"distributed":s||Le();return {authAdapter:r,databaseType:g,email:o,passwordPolicy:i,lockout:n$1,rateLimiter:a,auditLogger:l,routes:c$1}}var Ue=W().catch(s=>(console.warn("[AuthConfig] Failed to initialize auth config:",s.message),null));var Cr=12,Tr="24h",vr="7d",H=class{adapter;config;constructor(e,t){this.adapter=e,this.config={secret:t.secret,expiresIn:t.expiresIn??Tr,refreshExpiresIn:t.refreshExpiresIn??vr,issuer:t.issuer??"kyro-cms",audience:t.audience??[],saltRounds:t.saltRounds??Cr};}async register(e){try{if(await this.adapter.findUserByEmail(e.email))return {success:!1,error:"Email already registered"};let r=await this.adapter.createUser({email:e.email,password:e.password,role:e.role??"customer",tenantId:e.tenantId});return this.createSessionForUser(r)}catch(t){return {success:false,error:String(t)}}}async login(e){try{let t=await this.adapter.verifyPassword(e.email,e.password);return t?this.createSessionForUser(t):{success:!1,error:"Invalid credentials"}}catch(t){return {success:false,error:String(t)}}}async logout(e){await this.adapter.deleteSession(e);}async refreshToken(e){try{let t=await this.adapter.findSessionByToken(e);if(!t||new Date(t.expiresAt)<new Date)return {success:!1,error:"Invalid or expired refresh token"};let r=await this.adapter.findUserById(t.userId);return r?(await this.adapter.deleteSession(e),this.createSessionForUser(r)):{success:!1,error:"User not found"}}catch(t){return {success:false,error:String(t)}}}async verifyToken(e){try{let{default:t}=await import('jsonwebtoken');return t.verify(e,this.config.secret,{issuer:this.config.issuer,audience:this.config.audience.length>0?this.config.audience[0]:void 0})}catch{return null}}async getUserFromToken(e){let t=await this.verifyToken(e);return t?this.adapter.findUserById(t.sub):null}async changePassword(e,t,r){try{let o=await this.adapter.findUserById(e);return o?await this.adapter.verifyPassword(o.email,t)?(await this.adapter.updateUser(e,{password:r}),await this.adapter.deleteUserSessions(e),{success:!0,user:o}):{success:!1,error:"Current password is incorrect"}:{success:!1,error:"User not found"}}catch(o){return {success:false,error:String(o)}}}async resetPassword(e,t){try{let r=await this.adapter.findUserByEmail(e);return r?(await this.adapter.updateUser(r.id,{password:t}),await this.adapter.deleteUserSessions(r.id),{success:!0,user:r}):{success:!1,error:"User not found"}}catch(r){return {success:false,error:String(r)}}}async sendEmailVerification(e){try{let{token:t,expiresAt:r}=await this.adapter.createEmailVerificationToken(e);return {success:!0}}catch(t){return {success:false,error:String(t)}}}async verifyEmail(e){try{return await this.adapter.verifyEmailToken(e)}catch(t){return {success:false,error:String(t)}}}async requestPasswordReset(e){try{let t=await this.adapter.createPasswordResetToken(e);return t.error?{success:!1,error:t.error}:{success:!0}}catch(t){return {success:false,error:String(t)}}}async resetPasswordWithToken(e,t){try{return await this.adapter.resetPasswordWithToken(e,t)}catch(r){return {success:false,error:String(r)}}}async deleteAccount(e){try{return await this.adapter.findUserById(e)?(await this.adapter.deleteUserSessions(e),await this.adapter.deleteUser(e),{success:!0}):{success:!1,error:"User not found"}}catch(t){return {success:false,error:String(t)}}}async createSessionForUser(e){let t=await this.generateToken(e),r=await this.adapter.createSession(e.id);return {success:true,user:e,session:r,token:t}}async generateToken(e){let{default:t}=await import('jsonwebtoken'),r={sub:e.id,email:e.email,role:e.role,tenantId:e.tenantId},o={expiresIn:this.parseExpiresIn(this.config.expiresIn)/1e3,issuer:this.config.issuer};return this.config.audience.length>0&&(o.audience=this.config.audience[0]),t.sign(r,this.config.secret,o)}async hashPassword(e){let{default:t}=await import('bcryptjs');return t.hash(e,this.config.saltRounds)}parseExpiresIn(e){if(typeof e=="number")return e;let t=e.match(/^(\d+)([smhd])$/);if(!t)return 864e5;let r=parseInt(t[1],10);switch(t[2]){case "s":return r*1e3;case "m":return r*6e4;case "h":return r*36e5;case "d":return r*864e5;default:return 864e5}}};function Rr(s,e){return new H(s,e)}function _(){return {enabled:true,draftsEnabled:true,publishEnabled:true,scheduleEnabled:false,versioningEnabled:true,maxVersionsPerDocument:50,autoPublish:false,requirePublishPermission:true}}var M=class{adapter;config;constructor(e,t){this.adapter=e,this.config={..._(),...t};}async createVersion(e){let r=((await this.adapter.getLatestVersion(e.collection,e.documentId))?.version??0)+1,o={...e,version:r},i=await this.adapter.createVersion(o);return this.config.maxVersionsPerDocument>0&&await this.pruneOldVersions(e.collection,e.documentId),i}async publishVersion(e){let t=await this.adapter.getVersion(e.collection,e.versionId);if(!t)throw new Error("Version not found");if(t.status==="published")throw new Error("Version is already published");await this.adapter.publishVersion(e);}async unpublishDocument(e,t){let r=await this.adapter.getVersions({collection:e,documentId:t,limit:1e3});for(let o of r)if(o.status==="published"){await this.createVersion({collection:e,documentId:t,data:o.data,status:"draft",createdBy:"system",changeDescription:"Unpublished document"});break}}async revertToVersion(e,t,r,o){if(!await this.adapter.getVersion(e,r))throw new Error("Version not found");return await this.adapter.revertToVersion({collection:e,documentId:t,versionId:r,userId:o})}async getVersionHistory(e,t,r=20,o=0){return this.adapter.getVersions({collection:e,documentId:t,limit:r,offset:o})}async compareTwoVersions(e,t,r,o){return this.adapter.compareVersions({collection:e,documentId:t,versionA:r,versionB:o})}async getLatestDraft(e,t){return this.adapter.getLatestVersion(e,t)}async getPublishedVersion(e,t){return this.adapter.getPublishedVersion(e,t)}async getVersion(e,t){return this.adapter.getVersion(e,t)}async schedulePublish(e,t,r,o){if(!this.config.scheduleEnabled)throw new Error("Scheduled publishing is not enabled");if(!await this.adapter.getVersion(e,r))throw new Error("Version not found")}async deleteVersionHistory(e,t){await this.adapter.deleteVersions(e,t);}async pruneOldVersions(e,t){let r=await this.adapter.getVersions({collection:e,documentId:t,limit:this.config.maxVersionsPerDocument+100});if(r.length<=this.config.maxVersionsPerDocument)return;r.slice(0,this.config.maxVersionsPerDocument);let i=r.slice(this.config.maxVersionsPerDocument);for(let n of i)if(n.status!=="published"){await this.adapter.deleteVersions(e,t);break}}};function Dr(s,e){return new M(s,e)}function Ir(s){return s==="published"}function Lr(s){return s==="draft"}function Er(s){return s==="archived"}function Ur(s){return s?Array.isArray(s)?s:Object.values(s):[]}function Vr(s){return s?Array.isArray(s)?s:Object.values(s):[]}function Ve(s){return {collections:Ur(s.collections),globals:Vr(s.globals),adapter:s.adapter,plugins:s.plugins,auth:s.auth,cors:s.cors,admin:s.admin,upload:s.upload,graphQL:s.graphQL,typescript:s.typescript,localization:s.localization,rateLimit:s.rateLimit,debug:s.debug}}var Or=Ve;function Hr(s){let{siteSettings:e,seoSettings:t,title:r,description:o,image:i,url:n}=s;if(!e)return "";let a=e.siteName||"",l=r||t?.defaultTitle||a,c=t?.titleTemplate,g=t?.separator||" | ",d=t?.siteNameInTitle!==false,u=c?c.replace(/\{\{title\}\}/g,l).replace(/\{\{siteName\}\}/g,d?a:"").replace(/\{\{separator\}\}/g,g).replace(/\s+/g," ").trim():l,y=o||t?.defaultDescription||e.siteDescription||"",f=i||e.siteOgImage?.url||"",F=n||e.siteUrl||"",m=`
2
+ <title>${u}</title>
3
+ <meta name="description" content="${y}">
4
+ `;e.siteFavicon?.url&&(m+=`
5
+ <link rel="icon" type="${e.siteFavicon.mimeType||"image/x-icon"}" href="${e.siteFavicon.url}">`);let X=t?.meta?.robots;X&&(m+=`
6
+ <meta name="robots" content="${X}">`);let J=t?.meta?.canonicalUrl||F;J&&(m+=`
7
+ <link rel="canonical" href="${J}">`);let Be=t?.meta?.ogType||"website";m+=`
8
+ <meta property="og:type" content="${Be}">
9
+ <meta property="og:title" content="${u}">
10
+ <meta property="og:description" content="${y}">
11
+ <meta property="og:site_name" content="${a}">
12
+ `,F&&(m+=`
13
+ <meta property="og:url" content="${F}">`),f&&(m+=`
14
+ <meta property="og:image" content="${f}">`),t?.social?.fbAppId&&(m+=`
15
+ <meta property="fb:app_id" content="${t.social.fbAppId}">`);let Ne=t?.social?.twitterCardType||"summary_large_image";return m+=`
16
+ <meta name="twitter:card" content="${Ne}">
17
+ <meta name="twitter:title" content="${u}">
18
+ <meta name="twitter:description" content="${y}">
19
+ `,t?.social?.twitterHandle&&(m+=`
20
+ <meta name="twitter:site" content="${t.social.twitterHandle}">`),f&&(m+=`
21
+ <meta name="twitter:image" content="${f}">`),e.enableI18n&&e.i18n?.language&&(m+=`
22
+ <meta http-equiv="content-language" content="${e.i18n.language}">`),m}function _r(s){if(!s||!s.analyticsEnabled||!s.analytics)return "";let{googleAnalyticsId:e,googleTagManagerId:t,plausibleDomain:r}=s.analytics,o="";return e&&(o+=`
1653
23
  <!-- Google Analytics -->
1654
- <script async src="https://www.googletagmanager.com/gtag/js?id=${googleAnalyticsId}"></script>
24
+ <script async src="https://www.googletagmanager.com/gtag/js?id=${e}"></script>
1655
25
  <script>
1656
26
  window.dataLayer = window.dataLayer || [];
1657
27
  function gtag(){dataLayer.push(arguments);}
1658
28
  gtag('js', new Date());
1659
- gtag('config', '${googleAnalyticsId}');
29
+ gtag('config', '${e}');
1660
30
  </script>
1661
- `;
1662
- }
1663
- if (googleTagManagerId) {
1664
- scripts += `
31
+ `),t&&(o+=`
1665
32
  <!-- Google Tag Manager -->
1666
33
  <script>
1667
34
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
1668
35
  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
1669
36
  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
1670
37
  'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
1671
- })(window,document,'script','dataLayer','${googleTagManagerId}');
38
+ })(window,document,'script','dataLayer','${t}');
1672
39
  </script>
1673
- `;
1674
- }
1675
- if (plausibleDomain) {
1676
- scripts += `
40
+ `),r&&(o+=`
1677
41
  <!-- Plausible Analytics -->
1678
- <script defer data-domain="${plausibleDomain}" src="https://plausible.io/js/script.js"></script>
1679
- `;
1680
- }
1681
- return scripts;
1682
- }
1683
-
1684
- // src/lib/social.ts
1685
- var PLATFORM_META = {
1686
- facebook: { label: "Facebook" },
1687
- twitter: { label: "Twitter / X" },
1688
- instagram: { label: "Instagram" },
1689
- linkedin: { label: "LinkedIn" },
1690
- youtube: { label: "YouTube" },
1691
- tiktok: { label: "TikTok" },
1692
- pinterest: { label: "Pinterest" },
1693
- discord: { label: "Discord" },
1694
- twitch: { label: "Twitch" },
1695
- github: { label: "GitHub" },
1696
- mastodon: { label: "Mastodon" }
1697
- };
1698
- var ALL_PLATFORMS = [
1699
- "facebook",
1700
- "twitter",
1701
- "instagram",
1702
- "linkedin",
1703
- "youtube",
1704
- "tiktok",
1705
- "pinterest",
1706
- "discord",
1707
- "twitch",
1708
- "github",
1709
- "mastodon"
1710
- ];
1711
- function getSocialLinksFromSettings(socialSettings) {
1712
- if (!socialSettings) return [];
1713
- const showAll = socialSettings.showAll === true;
1714
- const links = [];
1715
- for (const platform of ALL_PLATFORMS) {
1716
- const url = socialSettings[platform];
1717
- if (!url) continue;
1718
- const isNiche = ["tiktok", "pinterest", "discord", "twitch", "github", "mastodon"].includes(platform);
1719
- if (isNiche && !showAll) continue;
1720
- const meta = PLATFORM_META[platform];
1721
- links.push({
1722
- platform,
1723
- url,
1724
- label: meta?.label || platform
1725
- });
1726
- }
1727
- return links;
1728
- }
1729
- async function getSocialLinks(db, options) {
1730
- try {
1731
- const doc = await db.findOne({
1732
- collection: "_globals_social-settings",
1733
- where: {},
1734
- draft: options?.draft ?? false
1735
- });
1736
- return getSocialLinksFromSettings(doc);
1737
- } catch {
1738
- return [];
1739
- }
1740
- }
1741
-
1742
- // src/lib/store.ts
1743
- function getStoreConfigFromSettings(settings) {
1744
- if (!settings) return {};
1745
- return {
1746
- storeName: settings.storeName,
1747
- storeEmail: settings.storeEmail,
1748
- storePhone: settings.storePhone,
1749
- address: settings.address,
1750
- currency: settings.currency,
1751
- tax: settings.tax,
1752
- shipping: settings.shipping,
1753
- orders: settings.orders
1754
- };
1755
- }
1756
- async function getStoreConfig(db, options) {
1757
- try {
1758
- const doc = await db.findOne({
1759
- collection: "_globals_store-settings",
1760
- where: {},
1761
- draft: options?.draft ?? false
1762
- });
1763
- return getStoreConfigFromSettings(doc);
1764
- } catch {
1765
- return {};
1766
- }
1767
- }
1768
-
1769
- // src/lib/payment.ts
1770
- function getPaymentConfigFromSettings(settings) {
1771
- if (!settings) return {};
1772
- return {
1773
- testMode: settings.testMode,
1774
- provider: settings.provider,
1775
- stripe: settings.stripe,
1776
- paypal: settings.paypal,
1777
- square: settings.square,
1778
- methods: settings.methods,
1779
- bankTransfer: settings.bankTransfer
1780
- };
1781
- }
1782
- async function getPaymentConfig(db, options) {
1783
- try {
1784
- const doc = await db.findOne({
1785
- collection: "_globals_payment-settings",
1786
- where: {},
1787
- draft: options?.draft ?? false
1788
- });
1789
- return getPaymentConfigFromSettings(doc);
1790
- } catch {
1791
- return {};
1792
- }
1793
- }
1794
- async function createBrowserStorage(options = {}) {
1795
- const { namespace = "kyro", ttl } = options;
1796
- const store = createStorage({
1797
- driver: indexedbDriver({
1798
- dbName: "kyro-cms",
1799
- storeName: namespace
1800
- })
1801
- });
1802
- const prefix = namespace ? `${namespace}:` : "";
1803
- const storage = {
1804
- getItem: async (name) => {
1805
- const key = `${prefix}${name}`;
1806
- const raw = await store.getItem(key);
1807
- if (raw == null) return null;
1808
- try {
1809
- const parsed = JSON.parse(raw);
1810
- if (parsed.expiry && Date.now() > parsed.expiry) {
1811
- await store.removeItem(key);
1812
- return null;
1813
- }
1814
- return parsed.value;
1815
- } catch {
1816
- return raw;
1817
- }
1818
- },
1819
- setItem: async (name, value) => {
1820
- const key = `${prefix}${name}`;
1821
- const data = JSON.stringify(
1822
- ttl ? { value, expiry: Date.now() + ttl } : { value }
1823
- );
1824
- await store.setItem(key, data);
1825
- },
1826
- removeItem: async (name) => {
1827
- await store.removeItem(`${prefix}${name}`);
1828
- }
1829
- };
1830
- return {
1831
- storage,
1832
- cleanup: async () => {
1833
- await store.dispose?.();
1834
- }
1835
- };
1836
- }
1837
- function getEncryptionKey2(secret) {
1838
- const appSecret = secret || process.env.APP_SECRET || process.env.AUTH_SECRET || "development-secret-key";
1839
- return crypto2.createHash("sha256").update(appSecret).digest("hex");
1840
- }
1841
- function encrypt(text, key) {
1842
- const iv = crypto2.randomBytes(16);
1843
- const cipher = crypto2.createCipheriv("aes-256-gcm", Buffer.from(key, "hex").subarray(0, 32), iv);
1844
- let encrypted = cipher.update(text, "utf8", "hex");
1845
- encrypted += cipher.final("hex");
1846
- const authTag = cipher.getAuthTag().toString("hex");
1847
- return `${iv.toString("hex")}:${authTag}:${encrypted}`;
1848
- }
1849
- function decrypt(encryptedText, key) {
1850
- const [ivHex, authTagHex, encrypted] = encryptedText.split(":");
1851
- const iv = Buffer.from(ivHex, "hex");
1852
- const authTag = Buffer.from(authTagHex, "hex");
1853
- const decipher = crypto2.createDecipheriv("aes-256-gcm", Buffer.from(key, "hex").subarray(0, 32), iv);
1854
- decipher.setAuthTag(authTag);
1855
- let decrypted = decipher.update(encrypted, "hex", "utf8");
1856
- decrypted += decipher.final("utf8");
1857
- return decrypted;
1858
- }
1859
- async function createNodeStorage(options = {}) {
1860
- const {
1861
- namespace = "kyro",
1862
- ttl,
1863
- encryption = true,
1864
- secret,
1865
- basePath
1866
- } = options;
1867
- const defaultPath = basePath ? path.join(basePath, ".astro", "kyro.json") : path.join(process.cwd(), ".astro", "kyro.json");
1868
- const store = createStorage({
1869
- driver: fsDriver({ base: defaultPath })
1870
- });
1871
- const encKey = encryption ? getEncryptionKey2(secret) : null;
1872
- const prefix = namespace ? `${namespace}:` : "";
1873
- return {
1874
- storage: {
1875
- getItem: async (name) => {
1876
- const key = `${prefix}${name}`;
1877
- const raw = await store.getItem(key);
1878
- if (raw == null) return null;
1879
- try {
1880
- const data = encKey ? decrypt(raw, encKey) : raw;
1881
- const parsed = JSON.parse(data);
1882
- if (parsed.expiry && Date.now() > parsed.expiry) {
1883
- await store.removeItem(key);
1884
- return null;
1885
- }
1886
- return parsed.value;
1887
- } catch {
1888
- return raw;
1889
- }
1890
- },
1891
- setItem: async (name, value) => {
1892
- const key = `${prefix}${name}`;
1893
- const data = JSON.stringify(
1894
- ttl ? { value, expiry: Date.now() + ttl } : { value }
1895
- );
1896
- await store.setItem(key, encKey ? encrypt(data, encKey) : data);
1897
- },
1898
- removeItem: async (name) => {
1899
- await store.removeItem(`${prefix}${name}`);
1900
- }
1901
- },
1902
- cleanup: async () => {
1903
- await store.dispose?.();
1904
- }
1905
- };
1906
- }
1907
-
1908
- // src/lib/storage/factory.ts
1909
- async function createStorage3(config) {
1910
- const { environment, adapter, connectionString, encryption } = config;
1911
- const secret = process.env.APP_SECRET || process.env.AUTH_SECRET;
1912
- const encryptionOptions = {
1913
- enabled: encryption?.enabled ?? true,
1914
- algorithm: encryption?.algorithm
1915
- };
1916
- if (environment === "browser") {
1917
- return createBrowserStorage({
1918
- namespace: "kyro"
1919
- });
1920
- }
1921
- return createNodeStorage({
1922
- namespace: "kyro",
1923
- encryption: encryptionOptions.enabled,
1924
- secret
1925
- });
1926
- }
1927
- async function createAuthStorage(config) {
1928
- const storageConfig = {
1929
- ...config,
1930
- encryption: {
1931
- enabled: true,
1932
- algorithm: config.encryption?.algorithm
1933
- }
1934
- };
1935
- return createStorage3(storageConfig);
1936
- }
1937
-
1938
- // src/index.ts
1939
- init_secret();
1940
-
1941
- export { AccountLockout, AnalyticsPlugin, Auth, CommentsPlugin, InMemoryAccountLockout, InMemoryAuthAdapter, KyroPlugin, PluginManager, RateLimiter, ReviewsPlugin, SEOPLugin, VersionManager, WishlistPlugin, authConfig, createAuth, createAuthConfig, createAuthStorage, createStorage3 as createStorage, createVersionManager, defineConfig, defineKyroConfig, generateAnalyticsTags, generateSeoTags, getDefaultDraftPublishConfig, getPaymentConfig, getPaymentConfigFromSettings, getSocialLinks, getSocialLinksFromSettings, getStoreConfig, getStoreConfigFromSettings, isArchived, isDraft, isPublished, presetPlugins, runFieldHooks, runHooks };
1942
- //# sourceMappingURL=index.js.map
1943
- //# sourceMappingURL=index.js.map
42
+ <script defer data-domain="${r}" src="https://plausible.io/js/script.js"></script>
43
+ `),o}var Mr={facebook:{label:"Facebook"},twitter:{label:"Twitter / X"},instagram:{label:"Instagram"},linkedin:{label:"LinkedIn"},youtube:{label:"YouTube"},tiktok:{label:"TikTok"},pinterest:{label:"Pinterest"},discord:{label:"Discord"},twitch:{label:"Twitch"},github:{label:"GitHub"},mastodon:{label:"Mastodon"}},Fr=["facebook","twitter","instagram","linkedin","youtube","tiktok","pinterest","discord","twitch","github","mastodon"];function Oe(s){if(!s)return [];let e=s.showAll===true,t=[];for(let r of Fr){let o=s[r];if(!o||["tiktok","pinterest","discord","twitch","github","mastodon"].includes(r)&&!e)continue;let n=Mr[r];t.push({platform:r,url:o,label:n?.label||r});}return t}async function Br(s,e){try{let t=await s.findOne({collection:"_globals_social-settings",where:{},draft:e?.draft??!1});return Oe(t)}catch{return []}}function He(s){return s?{storeName:s.storeName,storeEmail:s.storeEmail,storePhone:s.storePhone,address:s.address,currency:s.currency,tax:s.tax,shipping:s.shipping,orders:s.orders}:{}}async function Nr(s,e){try{let t=await s.findOne({collection:"_globals_store-settings",where:{},draft:e?.draft??!1});return He(t)}catch{return {}}}function _e(s){return s?{testMode:s.testMode,provider:s.provider,stripe:s.stripe,paypal:s.paypal,square:s.square,methods:s.methods,bankTransfer:s.bankTransfer}:{}}async function Kr(s,e){try{let t=await s.findOne({collection:"_globals_payment-settings",where:{},draft:e?.draft??!1});return _e(t)}catch{return {}}}async function G(s={}){let{namespace:e="kyro",ttl:t}=s,r=createStorage({driver:$r({dbName:"kyro-cms",storeName:e})}),o=e?`${e}:`:"";return {storage:{getItem:async n=>{let a=`${o}${n}`,l=await r.getItem(a);if(l==null)return null;try{let c=JSON.parse(l);return c.expiry&&Date.now()>c.expiry?(await r.removeItem(a),null):c.value}catch{return l}},setItem:async(n,a)=>{let l=`${o}${n}`,c=JSON.stringify(t?{value:a,expiry:Date.now()+t}:{value:a});await r.setItem(l,c);},removeItem:async n=>{await r.removeItem(`${o}${n}`);}},cleanup:async()=>{await r.dispose?.();}}}function z(s){let e=s||process.env.APP_SECRET||process.env.AUTH_SECRET||"development-secret-key";return q$1.createHash("sha256").update(e).digest("hex")}function qr(s,e){let t=q$1.randomBytes(16),r=q$1.createCipheriv("aes-256-gcm",Buffer.from(e,"hex").subarray(0,32),t),o=r.update(s,"utf8","hex");o+=r.final("hex");let i=r.getAuthTag().toString("hex");return `${t.toString("hex")}:${i}:${o}`}function Qr(s,e){let[t,r,o]=s.split(":"),i=Buffer.from(t,"hex"),n=Buffer.from(r,"hex"),a=q$1.createDecipheriv("aes-256-gcm",Buffer.from(e,"hex").subarray(0,32),i);a.setAuthTag(n);let l=a.update(o,"hex","utf8");return l+=a.final("utf8"),l}async function Q(s={}){let{namespace:e="kyro",ttl:t,encryption:r=true,secret:o,basePath:i}=s,n=i?Me.join(i,".astro","kyro.json"):Me.join(process.cwd(),".astro","kyro.json"),a=createStorage({driver:zr({base:n})}),l=r?z(o):null,c=e?`${e}:`:"";return {storage:{getItem:async g=>{let d=`${c}${g}`,u=await a.getItem(d);if(u==null)return null;try{let y=l?Qr(u,l):u,f=JSON.parse(y);return f.expiry&&Date.now()>f.expiry?(await a.removeItem(d),null):f.value}catch{return u}},setItem:async(g,d)=>{let u=`${c}${g}`,y=JSON.stringify(t?{value:d,expiry:Date.now()+t}:{value:d});await a.setItem(u,l?qr(y,l):y);},removeItem:async g=>{await a.removeItem(`${c}${g}`);}},cleanup:async()=>{await a.dispose?.();}}}async function Y(s){let{environment:e,adapter:t,connectionString:r,encryption:o}=s,i=process.env.APP_SECRET||process.env.AUTH_SECRET,n={enabled:o?.enabled??true,algorithm:o?.algorithm};return e==="browser"?G({namespace:"kyro"}):Q({namespace:"kyro",encryption:n.enabled,secret:i})}async function Fe(s){let e={...s,encryption:{enabled:true,algorithm:s.encryption?.algorithm}};return Y(e)}l();export{x as AccountLockout,E as AnalyticsPlugin,H as Auth,U as CommentsPlugin,C as InMemoryAccountLockout,P as InMemoryAuthAdapter,b as KyroPlugin,$ as PluginManager,S as RateLimiter,V as ReviewsPlugin,L as SEOPLugin,M as VersionManager,O as WishlistPlugin,Ue as authConfig,Rr as createAuth,W as createAuthConfig,Fe as createAuthStorage,Y as createStorage,Dr as createVersionManager,Ve as defineConfig,Or as defineKyroConfig,_r as generateAnalyticsTags,Hr as generateSeoTags,_ as getDefaultDraftPublishConfig,Kr as getPaymentConfig,_e as getPaymentConfigFromSettings,Br as getSocialLinks,Oe as getSocialLinksFromSettings,Nr as getStoreConfig,He as getStoreConfigFromSettings,Er as isArchived,Lr as isDraft,Ir as isPublished,Ar as presetPlugins,br as runFieldHooks,Ie as runHooks};