@sonicjs-cms/core 2.19.0 → 3.0.0-beta.11

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 (230) hide show
  1. package/README.md +52 -52
  2. package/dist/admin-documents-form.template-DDSH6ROU.js +6 -0
  3. package/dist/{admin-layout-catalyst.template-UMTIN66R.js.map → admin-documents-form.template-DDSH6ROU.js.map} +1 -1
  4. package/dist/admin-documents-form.template-LSZKGA5J.cjs +19 -0
  5. package/dist/{admin-layout-catalyst.template-HFD37TY5.cjs.map → admin-documents-form.template-LSZKGA5J.cjs.map} +1 -1
  6. package/dist/{filter-bar.template-DlVYMk-T.d.cts → admin-layout-catalyst.template-DrwDUfsE.d.cts} +25 -1
  7. package/dist/{filter-bar.template-DlVYMk-T.d.ts → admin-layout-catalyst.template-DrwDUfsE.d.ts} +25 -1
  8. package/dist/admin-layout-catalyst.template-KDHKVLXR.cjs +21 -0
  9. package/dist/admin-layout-catalyst.template-KDHKVLXR.cjs.map +1 -0
  10. package/dist/admin-layout-catalyst.template-YQ4EMF2J.js +7 -0
  11. package/dist/admin-layout-catalyst.template-YQ4EMF2J.js.map +1 -0
  12. package/dist/app-Bo0X1OWX.d.ts +1268 -0
  13. package/dist/app-Do66yCcV.d.cts +1268 -0
  14. package/dist/cache-DDARE4QE.js +4 -0
  15. package/dist/cache-DDARE4QE.js.map +1 -0
  16. package/dist/cache-LVYS4BPL.cjs +33 -0
  17. package/dist/cache-LVYS4BPL.cjs.map +1 -0
  18. package/dist/chunk-2CB4KY7I.cjs +771 -0
  19. package/dist/chunk-2CB4KY7I.cjs.map +1 -0
  20. package/dist/{chunk-4NPCDK6B.js → chunk-3PU4WVU6.js} +557 -90
  21. package/dist/chunk-3PU4WVU6.js.map +1 -0
  22. package/dist/chunk-4BTBSXMR.cjs +912 -0
  23. package/dist/chunk-4BTBSXMR.cjs.map +1 -0
  24. package/dist/{chunk-55RDMDOP.js → chunk-5V62WT6M.js} +181 -57
  25. package/dist/chunk-5V62WT6M.js.map +1 -0
  26. package/dist/chunk-6H66MSSL.js +273 -0
  27. package/dist/chunk-6H66MSSL.js.map +1 -0
  28. package/dist/chunk-AI663NBO.js +821 -0
  29. package/dist/chunk-AI663NBO.js.map +1 -0
  30. package/dist/chunk-BLMTL57B.js +767 -0
  31. package/dist/chunk-BLMTL57B.js.map +1 -0
  32. package/dist/{chunk-4ZSNJDLS.cjs → chunk-CRGUD4KC.cjs} +9 -9
  33. package/dist/chunk-CRGUD4KC.cjs.map +1 -0
  34. package/dist/chunk-GCDZZNIN.js +192 -0
  35. package/dist/chunk-GCDZZNIN.js.map +1 -0
  36. package/dist/chunk-HIKBY7MS.cjs +70 -0
  37. package/dist/chunk-HIKBY7MS.cjs.map +1 -0
  38. package/dist/chunk-HPAJKZAQ.js +387 -0
  39. package/dist/chunk-HPAJKZAQ.js.map +1 -0
  40. package/dist/chunk-IESEVHXL.js +66 -0
  41. package/dist/chunk-IESEVHXL.js.map +1 -0
  42. package/dist/chunk-IVPRUGTY.js +242 -0
  43. package/dist/chunk-IVPRUGTY.js.map +1 -0
  44. package/dist/{chunk-JZVHLLSI.cjs → chunk-IXUHXTHW.cjs} +2 -151
  45. package/dist/chunk-IXUHXTHW.cjs.map +1 -0
  46. package/dist/chunk-J6JTWD2A.cjs +100 -0
  47. package/dist/chunk-J6JTWD2A.cjs.map +1 -0
  48. package/dist/chunk-JEQ7FLOD.cjs +199 -0
  49. package/dist/chunk-JEQ7FLOD.cjs.map +1 -0
  50. package/dist/{chunk-ON5ZMSU4.js → chunk-JQISFW6U.js} +3 -3
  51. package/dist/chunk-JQISFW6U.js.map +1 -0
  52. package/dist/chunk-K25XHMM3.js +566 -0
  53. package/dist/chunk-K25XHMM3.js.map +1 -0
  54. package/dist/{chunk-R4FOLLFB.cjs → chunk-K342JMA3.cjs} +8730 -11520
  55. package/dist/chunk-K342JMA3.cjs.map +1 -0
  56. package/dist/{chunk-UYJ6TJHX.cjs → chunk-K623Q6WD.cjs} +181 -56
  57. package/dist/chunk-K623Q6WD.cjs.map +1 -0
  58. package/dist/chunk-KV3CM5RK.cjs +158 -0
  59. package/dist/chunk-KV3CM5RK.cjs.map +1 -0
  60. package/dist/{chunk-ABB34XUS.cjs → chunk-MKKGA3C4.cjs} +667 -19
  61. package/dist/chunk-MKKGA3C4.cjs.map +1 -0
  62. package/dist/chunk-N32OWET6.cjs +327 -0
  63. package/dist/chunk-N32OWET6.cjs.map +1 -0
  64. package/dist/chunk-NUKJ54GA.cjs +245 -0
  65. package/dist/chunk-NUKJ54GA.cjs.map +1 -0
  66. package/dist/{chunk-XWIA3HVX.js → chunk-OBA2RYZN.js} +6 -1249
  67. package/dist/chunk-OBA2RYZN.js.map +1 -0
  68. package/dist/chunk-ORF4CT74.cjs +276 -0
  69. package/dist/chunk-ORF4CT74.cjs.map +1 -0
  70. package/dist/{chunk-TFNTM3OA.js → chunk-PDYRDYXI.js} +645 -15
  71. package/dist/chunk-PDYRDYXI.js.map +1 -0
  72. package/dist/{chunk-OHYBNCVL.cjs → chunk-PXNTCCPE.cjs} +10 -1256
  73. package/dist/chunk-PXNTCCPE.cjs.map +1 -0
  74. package/dist/{chunk-E4YFJBM2.cjs → chunk-QJNKSFDJ.cjs} +876 -829
  75. package/dist/chunk-QJNKSFDJ.cjs.map +1 -0
  76. package/dist/chunk-QLFTG3QJ.js +1828 -0
  77. package/dist/chunk-QLFTG3QJ.js.map +1 -0
  78. package/dist/{chunk-BU7SFHGP.js → chunk-QZGABF2M.js} +3 -149
  79. package/dist/chunk-QZGABF2M.js.map +1 -0
  80. package/dist/chunk-RMRJGMDE.js +323 -0
  81. package/dist/chunk-RMRJGMDE.js.map +1 -0
  82. package/dist/chunk-RNZFGN4R.js +88 -0
  83. package/dist/chunk-RNZFGN4R.js.map +1 -0
  84. package/dist/chunk-RQ6N3FTV.js +900 -0
  85. package/dist/chunk-RQ6N3FTV.js.map +1 -0
  86. package/dist/{chunk-OCL3HMEG.js → chunk-SXLVXD2X.js} +7004 -9807
  87. package/dist/chunk-SXLVXD2X.js.map +1 -0
  88. package/dist/chunk-UHRHZXVR.cjs +408 -0
  89. package/dist/chunk-UHRHZXVR.cjs.map +1 -0
  90. package/dist/chunk-YA3TJ65D.cjs +575 -0
  91. package/dist/chunk-YA3TJ65D.cjs.map +1 -0
  92. package/dist/{chunk-7A4CB7T3.cjs → chunk-YJEBDJDV.cjs} +561 -91
  93. package/dist/chunk-YJEBDJDV.cjs.map +1 -0
  94. package/dist/chunk-YP7GW2G5.cjs +866 -0
  95. package/dist/chunk-YP7GW2G5.cjs.map +1 -0
  96. package/dist/chunk-ZUEIQFE5.js +154 -0
  97. package/dist/chunk-ZUEIQFE5.js.map +1 -0
  98. package/dist/{collection-config-B4PG-AaF.d.cts → collection-config-JgHOpFCG.d.cts} +30 -2
  99. package/dist/{collection-config-B4PG-AaF.d.ts → collection-config-JgHOpFCG.d.ts} +30 -2
  100. package/dist/config-HFXANXCC.js +6 -0
  101. package/dist/config-HFXANXCC.js.map +1 -0
  102. package/dist/config-ON6FNMYX.cjs +19 -0
  103. package/dist/config-ON6FNMYX.cjs.map +1 -0
  104. package/dist/define-plugin-BzNHc1ZI.d.ts +1321 -0
  105. package/dist/define-plugin-IWDKYaVm.d.cts +1321 -0
  106. package/dist/document-projection-TDWRJX3Z.cjs +13 -0
  107. package/dist/document-projection-TDWRJX3Z.cjs.map +1 -0
  108. package/dist/document-projection-YYMC6I4U.js +4 -0
  109. package/dist/document-projection-YYMC6I4U.js.map +1 -0
  110. package/dist/index.cjs +13739 -4328
  111. package/dist/index.cjs.map +1 -1
  112. package/dist/index.d.cts +331 -493
  113. package/dist/index.d.ts +331 -493
  114. package/dist/index.js +13456 -4067
  115. package/dist/index.js.map +1 -1
  116. package/dist/middleware.cjs +38 -32
  117. package/dist/middleware.d.cts +50 -7
  118. package/dist/middleware.d.ts +50 -7
  119. package/dist/middleware.js +9 -3
  120. package/dist/migrations-XQLBY7E5.js +4 -0
  121. package/dist/{migrations-H5IXZNCO.js.map → migrations-XQLBY7E5.js.map} +1 -1
  122. package/dist/migrations-ZXJEUTFA.cjs +13 -0
  123. package/dist/{migrations-566IIPS2.cjs.map → migrations-ZXJEUTFA.cjs.map} +1 -1
  124. package/dist/{plugin-bootstrap-DfVerYV4.d.cts → plugin-bootstrap-B8ThJU21.d.cts} +4315 -1661
  125. package/dist/{plugin-bootstrap-P_ciLp_C.d.ts → plugin-bootstrap-qu8hJgUt.d.ts} +4315 -1661
  126. package/dist/plugins.cjs +171 -12
  127. package/dist/plugins.d.cts +36 -2
  128. package/dist/plugins.d.ts +36 -2
  129. package/dist/plugins.js +5 -2
  130. package/dist/rbac-O73MFKDA.js +5 -0
  131. package/dist/rbac-O73MFKDA.js.map +1 -0
  132. package/dist/rbac-VONLJJKB.cjs +14 -0
  133. package/dist/rbac-VONLJJKB.cjs.map +1 -0
  134. package/dist/routes.cjs +42 -46
  135. package/dist/routes.d.cts +56 -146
  136. package/dist/routes.d.ts +56 -146
  137. package/dist/routes.js +18 -10
  138. package/dist/services.cjs +43 -76
  139. package/dist/services.d.cts +93 -55
  140. package/dist/services.d.ts +93 -55
  141. package/dist/services.js +6 -3
  142. package/dist/{telemetry-B9vIV4wh.d.cts → telemetry-Cku1ax74.d.cts} +1 -1
  143. package/dist/{telemetry-B9vIV4wh.d.ts → telemetry-Cku1ax74.d.ts} +1 -1
  144. package/dist/templates.cjs +17 -29
  145. package/dist/templates.d.cts +2 -89
  146. package/dist/templates.d.ts +2 -89
  147. package/dist/templates.js +3 -3
  148. package/dist/types-Dea1eNxU.d.cts +286 -0
  149. package/dist/types-Dea1eNxU.d.ts +286 -0
  150. package/dist/types.d.cts +2 -2
  151. package/dist/types.d.ts +2 -2
  152. package/dist/utils.cjs +21 -20
  153. package/dist/utils.d.cts +2 -2
  154. package/dist/utils.d.ts +2 -2
  155. package/dist/utils.js +3 -2
  156. package/migrations/0001_core.sql +184 -0
  157. package/migrations/0002_documents.sql +163 -0
  158. package/package.json +12 -7
  159. package/dist/admin-layout-catalyst.template-HFD37TY5.cjs +0 -17
  160. package/dist/admin-layout-catalyst.template-UMTIN66R.js +0 -7
  161. package/dist/app-C9esKLmh.d.cts +0 -112
  162. package/dist/app-C9esKLmh.d.ts +0 -112
  163. package/dist/chunk-4NPCDK6B.js.map +0 -1
  164. package/dist/chunk-4ZSNJDLS.cjs.map +0 -1
  165. package/dist/chunk-55RDMDOP.js.map +0 -1
  166. package/dist/chunk-635JAMSE.cjs +0 -653
  167. package/dist/chunk-635JAMSE.cjs.map +0 -1
  168. package/dist/chunk-7A4CB7T3.cjs.map +0 -1
  169. package/dist/chunk-ABB34XUS.cjs.map +0 -1
  170. package/dist/chunk-BU7SFHGP.js.map +0 -1
  171. package/dist/chunk-E4YFJBM2.cjs.map +0 -1
  172. package/dist/chunk-EXNEW5US.js +0 -648
  173. package/dist/chunk-EXNEW5US.js.map +0 -1
  174. package/dist/chunk-JZV22DEV.js +0 -1783
  175. package/dist/chunk-JZV22DEV.js.map +0 -1
  176. package/dist/chunk-JZVHLLSI.cjs.map +0 -1
  177. package/dist/chunk-OCL3HMEG.js.map +0 -1
  178. package/dist/chunk-OHYBNCVL.cjs.map +0 -1
  179. package/dist/chunk-ON5ZMSU4.js.map +0 -1
  180. package/dist/chunk-QFWHAFEO.js +0 -1843
  181. package/dist/chunk-QFWHAFEO.js.map +0 -1
  182. package/dist/chunk-R4FOLLFB.cjs.map +0 -1
  183. package/dist/chunk-RLMUFFUD.cjs +0 -2219
  184. package/dist/chunk-RLMUFFUD.cjs.map +0 -1
  185. package/dist/chunk-TFNTM3OA.js.map +0 -1
  186. package/dist/chunk-UYJ6TJHX.cjs.map +0 -1
  187. package/dist/chunk-WAEQXGCX.cjs +0 -1898
  188. package/dist/chunk-WAEQXGCX.cjs.map +0 -1
  189. package/dist/chunk-XWIA3HVX.js.map +0 -1
  190. package/dist/chunk-ZYAYUIZE.js +0 -2217
  191. package/dist/chunk-ZYAYUIZE.js.map +0 -1
  192. package/dist/migrations-566IIPS2.cjs +0 -13
  193. package/dist/migrations-H5IXZNCO.js +0 -4
  194. package/dist/plugin-manager-BoM3Q7o7.d.cts +0 -328
  195. package/dist/plugin-manager-Efx9RyDX.d.ts +0 -328
  196. package/migrations/001_initial_schema.sql +0 -170
  197. package/migrations/002_faq_plugin.sql +0 -86
  198. package/migrations/003_stage5_enhancements.sql +0 -121
  199. package/migrations/004_stage6_user_management.sql +0 -183
  200. package/migrations/005_stage7_workflow_automation.sql +0 -294
  201. package/migrations/006_plugin_system.sql +0 -155
  202. package/migrations/007_demo_login_plugin.sql +0 -23
  203. package/migrations/008_fix_slug_validation.sql +0 -22
  204. package/migrations/009_system_logging.sql +0 -57
  205. package/migrations/011_config_managed_collections.sql +0 -15
  206. package/migrations/012_testimonials_plugin.sql +0 -80
  207. package/migrations/013_code_examples_plugin.sql +0 -177
  208. package/migrations/014_fix_plugin_registry.sql +0 -88
  209. package/migrations/015_add_remaining_plugins.sql +0 -89
  210. package/migrations/016_remove_duplicate_cache_plugin.sql +0 -17
  211. package/migrations/017_auth_configurable_fields.sql +0 -49
  212. package/migrations/018_settings_table.sql +0 -23
  213. package/migrations/019_remove_blog_posts_collection.sql +0 -15
  214. package/migrations/020_add_email_plugin.sql +0 -22
  215. package/migrations/021_add_magic_link_auth_plugin.sql +0 -42
  216. package/migrations/022_add_tinymce_plugin.sql +0 -25
  217. package/migrations/023_add_easy_mdx_plugin.sql +0 -25
  218. package/migrations/024_add_quill_editor_plugin.sql +0 -25
  219. package/migrations/025_add_easymde_plugin.sql +0 -25
  220. package/migrations/026_add_otp_login.sql +0 -42
  221. package/migrations/027_fix_slug_field_type.sql +0 -18
  222. package/migrations/028_fix_slug_field_type_in_schemas.sql +0 -30
  223. package/migrations/029_add_forms_system.sql +0 -184
  224. package/migrations/030_add_turnstile_to_forms.sql +0 -14
  225. package/migrations/031_ai_search_plugin.sql +0 -45
  226. package/migrations/032_user_profiles.sql +0 -37
  227. package/migrations/033_form_content_integration.sql +0 -19
  228. package/migrations/034_security_audit_plugin.sql +0 -27
  229. package/migrations/035_user_profiles_data_column.sql +0 -16
  230. package/migrations/036_analytics_events.sql +0 -22
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/templates/alert.template.ts","../src/templates/confirmation-dialog.template.ts","../src/templates/pagination.template.ts","../src/templates/table.template.ts","../src/templates/layouts/admin-layout-v2.template.ts","../src/templates/pages/admin-checkboxes.template.ts","../src/templates/form.template.ts"],"names":["renderAdminLayoutCatalyst"],"mappings":";;;;;AAaO,SAAS,YAAY,IAAA,EAAyB;AACnD,EAAA,MAAM,WAAA,GAAc;AAAA,IAClB,OAAA,EAAS,sFAAA;AAAA,IACT,KAAA,EAAO,6DAAA;AAAA,IACP,OAAA,EAAS,sFAAA;AAAA,IACT,IAAA,EAAM;AAAA,GACR;AAEA,EAAA,MAAM,WAAA,GAAc;AAAA,IAClB,OAAA,EAAS,oCAAA;AAAA,IACT,KAAA,EAAO,gCAAA;AAAA,IACP,OAAA,EAAS,oCAAA;AAAA,IACT,IAAA,EAAM;AAAA,GACR;AAEA,EAAA,MAAM,WAAA,GAAc;AAAA,IAClB,OAAA,EAAS,oCAAA;AAAA,IACT,KAAA,EAAO,gCAAA;AAAA,IACP,OAAA,EAAS,oCAAA;AAAA,IACT,IAAA,EAAM;AAAA,GACR;AAEA,EAAA,MAAM,kBAAA,GAAqB;AAAA,IACzB,OAAA,EAAS,oCAAA;AAAA,IACT,KAAA,EAAO,gCAAA;AAAA,IACP,OAAA,EAAS,oCAAA;AAAA,IACT,IAAA,EAAM;AAAA,GACR;AAEA,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,OAAA,EAAS,CAAA,0LAAA,CAAA;AAAA,IACT,KAAA,EAAO,CAAA,4QAAA,CAAA;AAAA,IACP,OAAA,EAAS,CAAA,sQAAA,CAAA;AAAA,IACT,IAAA,EAAM,CAAA,qLAAA;AAAA,GACR;AAEA,EAAA,OAAO;AAAA,+BAAA,EACwB,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,SAAA,IAAa,EAAE,CAAA,EAAA,EAAK,IAAA,CAAK,WAAA,GAAc,wBAAA,GAA2B,EAAE,CAAA;AAAA;AAAA,QAAA,EAE1H,IAAA,CAAK,SAAS,KAAA,GAAQ;AAAA;AAAA,gCAAA,EAEE,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,cAAA,EACxC,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC;AAAA;AAAA;AAAA,QAAA,CAAA,GAGpB,EAAE;AAAA,oBAAA,EACQ,IAAA,CAAK,IAAA,KAAS,KAAA,GAAQ,MAAA,GAAS,EAAE,CAAA;AAAA,UAAA,EAC3C,KAAK,KAAA,GAAQ;AAAA,6CAAA,EACsB,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,cAAA,EACrD,UAAA,CAAW,IAAA,CAAK,KAAK,CAAC;AAAA;AAAA,UAAA,CAAA,GAExB,EAAE;AAAA,sBAAA,EACQ,IAAA,CAAK,QAAQ,cAAA,GAAiB,SAAS,IAAI,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,eAAA,EAC/E,UAAA,CAAW,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA;AAAA;AAAA,QAAA,EAG/B,KAAK,WAAA,GAAc;AAAA;AAAA;AAAA;AAAA;AAAA,oDAAA,EAKyB,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAAA,CAAA,GAUhE,EAAE;AAAA;AAAA;AAAA,EAAA,CAAA;AAId;;;AC7EO,SAAS,yBAAyB,OAAA,EAA4C;AACnF,EAAA,MAAM;AAAA,IACJ,EAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA,GAAc,SAAA;AAAA,IACd,UAAA,GAAa,QAAA;AAAA,IACb,YAAA,GAAe,6BAAA;AAAA,IACf,SAAA,GAAY,KAAA;AAAA,IACZ,SAAA,GAAY;AAAA,GACd,GAAI,OAAA;AAEJ,EAAA,MAAM,gBAAA,GAAmB;AAAA,IACvB,GAAA,EAAK,4BAAA;AAAA,IACL,MAAA,EAAQ,kCAAA;AAAA,IACR,IAAA,EAAM;AAAA,GACR;AAEA,EAAA,OAAO;AAAA;AAAA;AAAA,YAAA,EAGK,EAAE,CAAA;AAAA,yBAAA,EACW,EAAE,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,iGAAA,EAQsE,gBAAA,CAAiB,SAAS,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAA,EAMpG,EAAE,sDAAsD,KAAK,CAAA;AAAA;AAAA,mDAAA,EAElC,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAA,EAOjC,SAAS,8BAA8B,EAAE,CAAA;AAAA;AAAA,4BAAA,EAEtC,EAAE,CAAA;AAAA,mFAAA,EACqD,YAAY,CAAA;AAAA;AAAA,gBAAA,EAE/E,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,4BAAA,EAKC,EAAE,CAAA;AAAA;AAAA;AAAA,gBAAA,EAGd,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAQ5B;AAMO,SAAS,2BAAA,GAAsC;AACpD,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAWT;;;AChFO,SAAS,iBAAiB,IAAA,EAA8B;AAE7D,EAAA,MAAM,oBAAA,GAAuB,KAAK,UAAA,GAAa,CAAA,IAAM,KAAK,oBAAA,KAAyB,KAAA,IAAS,KAAK,UAAA,GAAa,CAAA;AAE9G,EAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAW,CAAC,IAAA,EAAc,KAAA,KAA2B;AACzD,IAAA,MAAM,SAAS,IAAI,eAAA,CAAgB,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AACzD,IAAA,MAAA,CAAO,GAAA,CAAI,MAAA,EAAQ,IAAA,CAAK,QAAA,EAAU,CAAA;AAClC,IAEA,IAAW,IAAA,CAAK,YAAA,KAAiB,EAAA,EAAI;AACnC,MAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,YAAA,CAAa,UAAU,CAAA;AAAA,IAClD;AACA,IAAA,OAAO,GAAG,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,MAAA,CAAO,UAAU,CAAA,CAAA;AAAA,EAC7C,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAA0B;AAClD,IAAA,MAAM,SAAS,IAAI,eAAA,CAAgB,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AACzD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAQ,GAAG,CAAA;AACtB,IAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,KAAA,CAAM,QAAA,EAAU,CAAA;AACpC,IAAA,OAAO,GAAG,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,MAAA,CAAO,UAAU,CAAA,CAAA;AAAA,EAC7C,CAAA;AAEA,EAAA,MAAM,sBAAsB,MAAgB;AAC1C,IAAA,MAAM,UAAA,GAAa,KAAK,cAAA,IAAkB,CAAA;AAC1C,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,CAAC,CAAA;AACtC,IAAA,IAAI,QAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,cAAc,IAAI,CAAA;AAC/C,IAAA,IAAI,MAAM,IAAA,CAAK,GAAA,CAAI,KAAK,UAAA,EAAY,KAAA,GAAQ,aAAa,CAAC,CAAA;AAG1D,IAAA,IAAI,GAAA,GAAM,KAAA,GAAQ,CAAA,GAAI,UAAA,EAAY;AAChC,MAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAA,GAAM,aAAa,CAAC,CAAA;AAAA,IAC1C;AAEA,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,KAAA,IAAS,CAAA,GAAI,KAAA,EAAO,CAAA,IAAK,GAAA,EAAK,CAAA,EAAA,EAAK;AACjC,MAAA,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,IACd;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA;AAAA,MAAA,EAED,IAAA,CAAK,aAAa,CAAA,GAAI;AAAA;AAAA;AAAA,UAAA,EAGlB,IAAA,CAAK,cAAc,CAAA,GAAI;AAAA,qBAAA,EACZ,QAAA,CAAS,IAAA,CAAK,WAAA,GAAc,CAAC,CAAC,CAAA;AAAA;AAAA;AAAA,UAAA,CAAA,GAGvC;AAAA;AAAA,UAAA,CAEH;;AAAA,UAAA,EAEC,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK,UAAA,GAAa;AAAA,qBAAA,EAC1B,QAAA,CAAS,IAAA,CAAK,WAAA,GAAc,CAAC,CAAC,CAAA;AAAA;AAAA;AAAA,UAAA,CAAA,GAGvC;AAAA;AAAA,UAAA,CAEH;AAAA;AAAA,MAAA,CAAA,GAED,EAAE;;AAAA;AAAA;AAAA;AAAA;AAAA,4EAAA,EAMkE,KAAK,SAAS,CAAA;AAAA,oEAAA,EACtB,KAAK,OAAO,CAAA;AAAA,oEAAA,EACZ,KAAK,UAAU,CAAA;AAAA;AAAA,UAAA,EAEzE,IAAA,CAAK,yBAAyB,KAAA,GAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAA,EAAA,CAS7B,IAAA,CAAK,mBAAmB,CAAC,EAAA,EAAI,IAAI,EAAA,EAAI,GAAG,CAAA,EAAG,GAAA,CAAI,CAAA,IAAA,KAAQ;AAAA,mCAAA,EACvC,gBAAA,CAAiB,IAAI,CAAC,CAAA,EAAA,EAAK,SAAS,IAAA,CAAK,YAAA,GAAe,aAAa,EAAE,CAAA;AAAA,sBAAA,EACpF,IAAI;AAAA;AAAA,kBAAA,CAET,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAAA,CAAA,GAOf,EAAE;AAAA;;AAAA,QAAA,EAGN,IAAA,CAAK,aAAa,CAAA,GAAI;AAAA;AAAA;AAAA,YAAA,EAGlB,IAAA,CAAK,cAAc,CAAA,GAAI;AAAA,qBAAA,EACd,QAAA,CAAS,IAAA,CAAK,WAAA,GAAc,CAAC,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA,UAAA,CAAA,GAIvC,EAAE;;AAAA;AAAA,UAAA,EAGJ,IAAA,CAAK,oBAAoB,KAAA,GAAQ;AAAA;AAAA,YAAA,EAAA,CAE9B,MAAM;AACP,IAAA,MAAM,cAAc,mBAAA,EAAoB;AACxC,IAAA,MAAM,YAAY,WAAA,CAAY,MAAA,GAAS,CAAA,GAAI,WAAA,CAAY,CAAC,CAAA,GAAI,IAAA;AAC5D,IAAA,OAAO,SAAA,IAAa,YAAY,CAAA,GAAI;AAAA,yBAAA,EACvB,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA,gBAAA,EAIpB,YAAY,CAAA,GAAI;AAAA;AAAA,gBAAA,CAAA,GAEd,EAAE;AAAA,cAAA,CAAA,GACJ,EAAA;AAAA,EACN,IAAI;;AAAA;AAAA,YAAA,EAGF,mBAAA,EAAoB,CAAE,GAAA,CAAI,CAAA,OAAA,KAAW;AAAA,cAAA,EACnC,OAAA,KAAY,KAAK,WAAA,GAAc;AAAA;AAAA,kBAAA,EAE3B,OAAO;AAAA;AAAA,cAAA,CAAA,GAET;AAAA,yBAAA,EACS,QAAA,CAAS,OAAO,CAAC,CAAA;AAAA;AAAA,kBAAA,EAExB,OAAO;AAAA;AAAA,cAAA,CAEZ;AAAA,YAAA,CACF,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;;AAAA;AAAA,YAAA,EAAA,CAGR,MAAM;AACP,IAAA,MAAM,cAAc,mBAAA,EAAoB;AACxC,IAAA,MAAM,WAAA,GAAc,YAAY,MAAA,GAAS,CAAA,GAAI,YAAY,KAAA,CAAM,EAAE,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA;AACxE,IAAA,OAAO,WAAA,IAAe,WAAA,GAAc,IAAA,CAAK,UAAA,GAAa;AAAA,gBAAA,EAClD,WAAA,GAAc,IAAA,CAAK,UAAA,GAAa,CAAA,GAAI;AAAA;AAAA,gBAAA,CAAA,GAElC,EAAE;AAAA,yBAAA,EACK,QAAA,CAAS,IAAA,CAAK,UAAU,CAAC,CAAA;AAAA;AAAA,kBAAA,EAEhC,KAAK,UAAU;AAAA;AAAA,cAAA,CAAA,GAEjB,EAAA;AAAA,EACN,IAAI;AAAA,UAAA,CAAA,GACF,EAAE;;AAAA;AAAA,UAAA,EAGJ,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK,UAAA,GAAa;AAAA,qBAAA,EAC1B,QAAA,CAAS,IAAA,CAAK,WAAA,GAAc,CAAC,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA,UAAA,CAAA,GAIvC,EAAE;AAAA;AAAA,QAAA,CAAA,GAEJ,EAAE;AAAA;AAAA;AAAA,EAAA,CAAA;AAId;;;ACjKO,SAAS,YAAqB,IAAA,EAA4B;AAC/D,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,CAAA,MAAA,EAAS,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,MAAA,CAAO,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA;AAEhF,EAAA,IAAI,IAAA,CAAK,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG;AAC1B,IAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mEAAA,EAM0D,IAAA,CAAK,gBAAgB,mBAAmB,CAAA;AAAA;AAAA;AAAA,IAAA,CAAA;AAAA,EAI3G;AAEA,EAAA,OAAO;AAAA,gBAAA,EACS,IAAA,CAAK,SAAA,IAAa,EAAE,CAAA,MAAA,EAAS,OAAO,CAAA;AAAA,MAAA,EAC9C,KAAK,KAAA,GAAQ;AAAA;AAAA,4EAAA,EAEyD,KAAK,KAAK,CAAA;AAAA;AAAA,MAAA,CAAA,GAE9E,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,cAAA,EAKI,KAAK,UAAA,GAAa;AAAA;AAAA;AAAA;AAAA,4DAAA,EAI4B,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAAA,CAAA,GAQnD,EAAE;AAAA,cAAA,EACJ,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,QAAQ,KAAA,KAAU;AACpC,IAAA,MAAM,OAAA,GAAU,KAAA,KAAU,CAAA,IAAK,CAAC,IAAA,CAAK,UAAA;AACrC,IAAA,MAAM,MAAA,GAAS,KAAA,KAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,CAAA;AAC/C,IAAA,OAAO;AAAA,qGAAA,EACgF,OAAA,GAAU,SAAA,GAAY,EAAE,CAAA,CAAA,EAAI,MAAA,GAAS,YAAY,EAAE,CAAA,CAAA,EAAI,MAAA,CAAO,SAAA,IAAa,EAAE,CAAA;AAAA,kBAAA,EAChK,OAAO,QAAA,GAAW;AAAA;AAAA;AAAA,mCAAA,EAGD,OAAO,GAAG,CAAA;AAAA,sCAAA,EACP,MAAA,CAAO,YAAY,QAAQ,CAAA;AAAA;AAAA,0CAAA,EAEvB,OAAO,CAAA,IAAA,EAAO,MAAA,CAAO,GAAG,CAAA,IAAA,EAAO,MAAA,CAAO,YAAY,QAAQ,CAAA;AAAA;AAAA,4BAAA,EAExE,OAAO,KAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAA,CAAA,GAUpB,OAAO,KAAK;AAAA;AAAA,cAAA,CAAA;AAAA,EAEnB,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,YAAA,EAIZ,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,KAAQ;AACvB,IAAA,IAAI,CAAC,KAAK,OAAO,EAAA;AACjB,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,YAAA,GAAe,gBAAA,GAAmB,EAAA;AAC9D,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,WAAA,GAAc,kCAAkC,IAAA,CAAK,WAAA,CAAY,GAAG,CAAC,CAAA,EAAA,CAAA,GAAO,EAAA;AAC3H,IAAA,OAAO;AAAA,4VAAA,EACyU,cAAc,KAAK,YAAY,CAAA;AAAA,kBAAA,EACzW,KAAK,UAAA,GAAa;AAAA;AAAA;AAAA;AAAA,wDAAA,EAIqB,GAAA,CAAY,MAAM,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAA,CAAA,GAQzD,EAAE;AAAA,kBAAA,EACJ,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,QAAQ,QAAA,KAAa;AACvC,MAAA,MAAM,KAAA,GAAS,GAAA,CAAY,MAAA,CAAO,GAAG,CAAA;AACrC,MAAA,MAAM,eAAe,MAAA,CAAO,MAAA,GAAS,OAAO,MAAA,CAAO,KAAA,EAAO,GAAG,CAAA,GAAI,KAAA;AACjE,MAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,GAAA,KAAQ,SAAA,GAAY,mCAAA,GAAsC,EAAA;AACzF,MAAA,MAAM,OAAA,GAAU,QAAA,KAAa,CAAA,IAAK,CAAC,IAAA,CAAK,UAAA;AACxC,MAAA,MAAM,MAAA,GAAS,QAAA,KAAa,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,CAAA;AAClD,MAAA,OAAO;AAAA,oFAAA,EAC2D,OAAA,GAAU,mDAAA,GAAsD,EAAE,CAAA,CAAA,EAAI,MAAA,GAAS,SAAA,GAAY,EAAE,CAAA,CAAA,EAAI,MAAA,CAAO,SAAA,IAAa,EAAE,CAAA,EAAA,EAAK,eAAe,CAAA;AAAA,wBAAA,EACvM,gBAAgB,EAAE;AAAA;AAAA,oBAAA,CAAA;AAAA,IAG1B,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA,cAAA,CAAA;AAAA,EAGjB,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AA+GvB;;;ACzOA,kBAAA,EAAA;AAuBO,SAAS,kBAAkB,IAAA,EAA+B;AAE/D,EAAA,MAAM;AAAA,IACJ,yBAAA,EAAAA;AAAA,GACF,IAAI,mCAAA,EAAA,EAAA,YAAA,CAAA,sCAAA,CAAA,CAAA;AACJ,EAAA,OAAOA,2BAA0B,IAAI,CAAA;AACvC;AAEO,SAAS,cAAc,IAAA,EAA+B;AAC3D,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAA,EAKE,KAAK,KAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EA+NjB,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,IAAI,CAAC,KAAA,KAAU,CAAA,6BAAA,EAAgC,KAAK,CAAA,EAAA,CAAI,CAAA,CAAE,IAAA,CAAK,MAAM,IAAI,EAAE;AAAA,EAAA,EACrG,IAAA,CAAK,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAC,MAAA,KAAW,CAAA,aAAA,EAAgB,MAAM,CAAA,WAAA,CAAa,CAAA,CAAE,IAAA,CAAK,MAAM,IAAI,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,EAQhG,aAAa,IAAA,CAAK,SAAA,IAAa,WAAA,EAAa,IAAA,CAAK,IAAI,CAAC;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAAA,EAOhD,aAAA,CAAc,KAAK,WAAA,IAAe,GAAA,EAAK,KAAK,IAAA,EAAM,IAAA,CAAK,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,UAAA,EAKxE,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAAA,CAAA;AAyNxB;AAEA,SAAS,aAAA,CACP,WAAA,EACA,IAAA,EACA,gBAAA,EAKQ;AACR,EAAA,MAAM,aAAA,GAAgB;AAAA,IACpB;AAAA,MACE,KAAA,EAAO,SAAA;AAAA,MACP,IAAA,EAAM,gBAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,aAAA;AAAA,MACP,IAAA,EAAM,oBAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,OAAA;AAAA,MACP,IAAA,EAAM,cAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,OAAA;AAAA,MACP,IAAA,EAAM,cAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,SAAA;AAAA,MACP,IAAA,EAAM,gBAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,OAAA;AAAA,MACP,IAAA,EAAM,cAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,MAAA;AAAA,MACP,IAAA,EAAM,aAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,UAAA;AAAA,MACP,IAAA,EAAM,iBAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,eAAA;AAAA,MACP,IAAA,EAAM,sBAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,aAAA;AAAA,MACP,IAAA,EAAM,oBAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA,KAGR;AAAA,IACA;AAAA,MACE,KAAA,EAAO,UAAA;AAAA,MACP,IAAA,EAAM,MAAA;AAAA,MACN,MAAA,EAAQ,QAAA;AAAA,MACR,IAAA,EAAM,CAAA;AAAA;AAAA,YAAA;AAAA;AAGR,GACF;AAGA,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,aAAa,CAAA;AAGtC,EAAA,IAAI,gBAAA,IAAoB,gBAAA,CAAiB,MAAA,GAAS,CAAA,EAAG;AACnD,IAAA,MAAM,aAAa,YAAA,CAAa,SAAA;AAAA,MAC9B,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,KAAS;AAAA,KAC1B;AACA,IAAA,IAAI,eAAe,EAAA,EAAI;AACrB,MAAA,YAAA,CAAa,MAAA,CAAO,UAAA,GAAa,CAAA,EAAG,CAAA,EAAG,GAAG,gBAAgB,CAAA;AAAA,IAC5D,CAAA,MAAO;AAEL,MAAA,YAAA,CAAa,IAAA,CAAK,GAAG,gBAAgB,CAAA;AAAA,IACvC;AAAA,EACF;AAEA,EAAA,OAAO;AAAA;AAAA;AAAA,QAAA,EAGC,YAAA,CACC,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,MAAM,QAAA,GACJ,WAAA,KAAgB,IAAA,CAAK,IAAA,IACpB,IAAA,CAAK,SAAS,QAAA,IAAY,WAAA,CAAY,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA;AAC7D,IAAA,MAAM,aAAc,IAAA,CAAa,MAAA,GAC7B,CAAA,SAAA,EAAa,IAAA,CAAa,MAAM,CAAA,CAAA,CAAA,GAChC,EAAA;AACJ,IAAA,OAAO;AAAA,qBAAA,EACI,KAAK,IAAI,CAAA,CAAA,EAAI,UAAU,CAAA,oCAAA,EAAuC,QAAA,GAAW,2BAA2B,gCAAgC,CAAA;AAAA,cAAA,EAC3I,KAAK,IAAI;AAAA,oBAAA,EACH,KAAK,KAAK,CAAA;AAAA;AAAA,UAAA,CAAA;AAAA,EAGtB,CAAC,CAAA,CACA,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA;AAAA,EAAA,CAAA;AAInB;AAEA,SAAS,YAAA,CAAa,WAAmB,IAAA,EAAoB;AAC3D,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,YAAA,EAKK,UAAA,CAAW,EAAE,IAAA,EAAM,IAAA,EAAM,UAAU,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAA,EA4I5D,IAAA,GACI;AAAA;AAAA;AAAA;AAAA,iEAAA,EAAA,CAIkD,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA,IAAS,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAa,CAAA;AAAA;AAAA;AAAA,gEAAA,EAGzD,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,KAAA,IAAS,MAAM,CAAA;AAAA,uDAAA,EAC1C,IAAA,CAAK,QAAQ,eAAe,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iEAAA,EAWlB,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,KAAA,IAAS,MAAM,CAAA;AAAA,qDAAA,EAC7C,IAAA,CAAK,SAAS,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAA,CAAA,GAkBrD;AAAA;AAAA;AAAA;AAAA,YAAA,CAKN;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAKZ;;;AC1zBA,mCAAA,EAAA;AAUO,SAAS,mBAAmB,IAAA,EAAgC;AACjE,EAAA,MAAM,WAAA,GAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAqLpB,EAAA,MAAM,UAAA,GAAsC;AAAA,IAC1C,KAAA,EAAO,qBAAA;AAAA,IACP,SAAA,EAAW,qBAAA;AAAA,IACX,WAAA,EAAa,mBAAA;AAAA,IACb,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AAEA,EAAA,OAAO,0BAA0B,UAAU,CAAA;AAC7C;;;AChKO,SAAS,WAAW,IAAA,EAAwB;AACjD,EAAA,OAAO;AAAA;AAAA,MAAA,EAED,KAAK,EAAA,GAAK,CAAA,IAAA,EAAO,IAAA,CAAK,EAAE,MAAM,EAAE;AAAA,MAAA,EAChC,KAAK,MAAA,GAAS,CAAA,SAAA,EAAY,KAAK,MAAM,CAAA,CAAA,CAAA,GAAM,KAAK,KAAA,GAAQ,CAAA,QAAA,EAAW,IAAA,CAAK,KAAK,MAAM,IAAA,CAAK,MAAA,GAAS,WAAW,IAAA,CAAK,MAAM,MAAM,EAAE;AAAA,MAAA,EAC/H,KAAK,QAAA,GAAW,CAAA,WAAA,EAAc,IAAA,CAAK,QAAQ,MAAM,EAAE;AAAA,cAAA,EAC3C,IAAA,CAAK,UAAU,MAAM,CAAA;AAAA,aAAA,EACtB,IAAA,CAAK,aAAa,WAAW,CAAA;AAAA,MAAA,EACpC,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,MAAM,CAAA,GAAI,+BAAA,GAAkC,EAAE;AAAA;AAAA,MAAA,EAE/E,KAAK,SAAA,GAAY,CAAA,yCAAA,EAA4C,IAAA,CAAK,SAAS,OAAO,EAAE;AAAA,MAAA,EACpF,KAAK,KAAA,GAAQ;AAAA;AAAA,sDAAA,EAEmC,KAAK,KAAK,CAAA;AAAA,UAAA,EACtD,KAAK,WAAA,GAAc,CAAA,oCAAA,EAAuC,IAAA,CAAK,WAAW,SAAS,EAAE;AAAA;AAAA,MAAA,CAAA,GAEvF,EAAE;AAAA;AAAA;AAAA;AAAA,MAAA,EAIJ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,CAAA,KAAA,KAAS,eAAA,CAAgB,KAAK,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,UAAA,EAIrD,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,CAAA,MAAA,KAAU;AAAA;AAAA,oBAAA,EAEvB,MAAA,CAAO,QAAQ,QAAQ,CAAA;AAAA,cAAA,EAC7B,OAAO,IAAA,GAAO,CAAA,MAAA,EAAS,MAAA,CAAO,IAAI,MAAM,EAAE;AAAA,cAAA,EAC1C,OAAO,KAAA,GAAQ,CAAA,OAAA,EAAU,MAAA,CAAO,KAAK,MAAM,EAAE;AAAA,cAAA,EAC7C,OAAO,OAAA,GAAU,CAAA,SAAA,EAAY,MAAA,CAAO,OAAO,MAAM,EAAE;AAAA,yBAAA,EACxC,MAAA,CAAO,aAAa,aAAa,CAAA;AAAA;AAAA,cAAA,EAE5C,OAAO,KAAK;AAAA;AAAA,UAAA,CAEjB,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAKrB;AAEO,SAAS,gBAAgB,KAAA,EAA0B;AACxD,EAAA,MAAM,OAAA,GAAU,CAAA,MAAA,EAAS,KAAA,CAAM,IAAI,CAAA,CAAA;AACnC,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,GAAW,UAAA,GAAa,EAAA;AAC/C,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,GAAW,UAAA,GAAa,EAAA;AAC/C,EAAA,MAAM,cAAc,KAAA,CAAM,WAAA,GAAc,CAAA,aAAA,EAAgB,KAAA,CAAM,WAAW,CAAA,CAAA,CAAA,GAAM,EAAA;AAE/E,EAAA,IAAI,SAAA,GAAY,EAAA;AAEhB,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,MAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,QAAA;AAAA,IACL,KAAK,MAAA;AACH,MAAA,SAAA,GAAY;AAAA;AAAA,gBAAA,EAEA,KAAA,CAAM,IAAA,KAAS,MAAA,GAAS,gBAAA,GAAmB,MAAM,IAAI,CAAA;AAAA,cAAA,EACvD,OAAO,CAAA;AAAA,gBAAA,EACL,MAAM,IAAI,CAAA;AAAA,iBAAA,EACT,KAAA,CAAM,SAAS,EAAE,CAAA;AAAA,4BAAA,EACN,KAAA,CAAM,aAAa,EAAE,CAAA;AAAA,UAAA,EACvC,WAAW;AAAA,UAAA,EACX,QAAQ;AAAA,UAAA,EACR,QAAQ;AAAA,UAAA,EACR,KAAA,CAAM,YAAY,GAAA,KAAQ,MAAA,GAAY,QAAQ,KAAA,CAAM,UAAA,CAAW,GAAG,CAAA,CAAA,CAAA,GAAM,EAAE;AAAA,UAAA,EAC1E,KAAA,CAAM,YAAY,GAAA,KAAQ,MAAA,GAAY,QAAQ,KAAA,CAAM,UAAA,CAAW,GAAG,CAAA,CAAA,CAAA,GAAM,EAAE;AAAA,UAAA,EAC1E,KAAA,CAAM,YAAY,OAAA,GAAU,CAAA,SAAA,EAAY,MAAM,UAAA,CAAW,OAAO,MAAM,EAAE;AAAA;AAAA,MAAA,CAAA;AAG9E,MAAA;AAAA,IAEF,KAAK,UAAA;AACH,MAAA,SAAA,GAAY;AAAA;AAAA,cAAA,EAEF,OAAO,CAAA;AAAA,gBAAA,EACL,MAAM,IAAI,CAAA;AAAA,+BAAA,EACK,KAAA,CAAM,aAAa,EAAE,CAAA;AAAA,gBAAA,EACpC,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,UAAA,EACrB,WAAW;AAAA,UAAA,EACX,QAAQ;AAAA,SAAA,EACT,KAAA,CAAM,SAAS,EAAE,CAAA;AAAA,MAAA,CAAA;AAEtB,MAAA;AAAA,IAEF,KAAK,WAAA;AACH,MAAA,MAAM,WAAW,CAAA,EAAG,KAAA,CAAM,IAAI,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,CAAA;AAC5C,MAAA,SAAA,GAAY;AAAA;AAAA,wBAAA,EAEQ,QAAQ,CAAA,QAAA,EAAW,KAAA,CAAM,IAAI,CAAA,iCAAA,EAAoC,KAAA,CAAM,SAAS,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA,kDAAA,EAIxD,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAAA,EAM7B,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAA,CAAA;AAYjC,MAAA;AAAA,IAEF,KAAK,QAAA;AACH,MAAA,SAAA,GAAY;AAAA;AAAA,cAAA,EAEF,OAAO,CAAA;AAAA,gBAAA,EACL,MAAM,IAAI,CAAA;AAAA,4BAAA,EACE,KAAA,CAAM,aAAa,EAAE,CAAA;AAAA,UAAA,EACvC,QAAQ;AAAA;AAAA,UAAA,EAER,KAAA,CAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,MAAA,KAAU;AAAA,2BAAA,EAC3B,MAAA,CAAO,KAAK,CAAA,EAAA,EAAK,MAAA,CAAO,QAAA,IAAY,MAAM,KAAA,KAAU,MAAA,CAAO,KAAA,GAAQ,UAAA,GAAa,EAAE,CAAA;AAAA,cAAA,EAC/F,OAAO,KAAK;AAAA;AAAA,UAAA,CAEjB,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,GAAI,EAAE;AAAA;AAAA,MAAA,CAAA;AAGpB,MAAA;AAAA,IAEF,KAAK,cAAA;AACH,MAAA,SAAA,GAAY;AAAA;AAAA,cAAA,EAEF,OAAO,CAAA;AAAA,gBAAA,EACL,MAAM,IAAI,CAAA;AAAA,4BAAA,EACE,KAAA,CAAM,aAAa,EAAE,CAAA;AAAA;AAAA,UAAA,EAEvC,QAAQ;AAAA;AAAA,UAAA,EAER,KAAA,CAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,MAAA,KAAU;AAAA,2BAAA,EAC3B,OAAO,KAAK,CAAA,EAAA,EAAK,MAAA,CAAO,QAAA,GAAW,aAAa,EAAE,CAAA;AAAA,cAAA,EAC/D,OAAO,KAAK;AAAA;AAAA,UAAA,CAEjB,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,GAAI,EAAE;AAAA;AAAA,MAAA,CAAA;AAGpB,MAAA;AAAA,IAEF,KAAK,UAAA;AACH,MAAA,SAAA,GAAY;AAAA;AAAA;AAAA,cAAA,EAGF,OAAO,CAAA;AAAA,gBAAA,EACL,MAAM,IAAI,CAAA;AAAA;AAAA,0MAAA,EAEgL,KAAA,CAAM,aAAa,EAAE,CAAA;AAAA,UAAA,EACrN,KAAA,CAAM,KAAA,GAAQ,SAAA,GAAY,EAAE;AAAA,UAAA,EAC5B,QAAQ;AAAA;AAAA,oBAAA,EAEE,OAAO,CAAA,kCAAA,EAAqC,KAAA,CAAM,KAAK,CAAA;AAAA,MAAA,CAAA;AAEvE,MAAA;AAAA,IAEF;AACE,MAAA,SAAA,GAAY;AAAA;AAAA;AAAA,cAAA,EAGF,OAAO,CAAA;AAAA,gBAAA,EACL,MAAM,IAAI,CAAA;AAAA,iBAAA,EACT,KAAA,CAAM,SAAS,EAAE,CAAA;AAAA,4BAAA,EACN,KAAA,CAAM,aAAa,EAAE,CAAA;AAAA,UAAA,EACvC,WAAW,CAAA;AAAA,UAAA,EACX,QAAQ;AAAA;AAAA,MAAA,CAAA;AAGd,MAAA;AAAA;AAIJ,EAAA,IAAI,KAAA,CAAM,SAAS,UAAA,EAAY;AAC7B,IAAA,OAAO;AAAA;AAAA;AAAA,UAAA,EAGC,SAAS;AAAA;AAAA,QAAA,EAEX,MAAM,QAAA,GAAW,CAAA,8DAAA,EAAiE,KAAA,CAAM,QAAQ,SAAS,EAAE;AAAA;AAAA,IAAA,CAAA;AAAA,EAGnH;AAEA,EAAA,OAAO;AAAA;AAAA,kBAAA,EAEW,OAAO,CAAA;AAAA,QAAA,EACjB,MAAM,KAAK,CAAA,EAAG,KAAA,CAAM,QAAA,GAAW,OAAO,EAAE;AAAA;AAAA,MAAA,EAE1C,SAAS;AAAA,MAAA,EACT,MAAM,QAAA,GAAW,CAAA,yDAAA,EAA4D,KAAA,CAAM,QAAQ,SAAS,EAAE;AAAA;AAAA,EAAA,CAAA;AAG9G","file":"chunk-OBA2RYZN.js","sourcesContent":["import { escapeHtml } from '../utils/sanitize'\n\nexport type AlertType = 'success' | 'error' | 'warning' | 'info'\n\nexport interface AlertData {\n type: AlertType\n title?: string\n message: string\n dismissible?: boolean\n className?: string\n icon?: boolean\n}\n\nexport function renderAlert(data: AlertData): string {\n const typeClasses = {\n success: 'bg-green-50 dark:bg-green-500/10 border border-green-600/20 dark:border-green-500/20',\n error: 'bg-error/10 border border-red-600/20 dark:border-red-500/20',\n warning: 'bg-amber-50 dark:bg-amber-500/10 border border-amber-600/20 dark:border-amber-500/20',\n info: 'bg-blue-50 dark:bg-blue-500/10 border border-blue-600/20 dark:border-blue-500/20'\n }\n\n const iconClasses = {\n success: 'text-green-600 dark:text-green-400',\n error: 'text-red-600 dark:text-red-400',\n warning: 'text-amber-600 dark:text-amber-400',\n info: 'text-blue-600 dark:text-blue-400'\n }\n\n const textClasses = {\n success: 'text-green-900 dark:text-green-300',\n error: 'text-red-900 dark:text-red-300',\n warning: 'text-amber-900 dark:text-amber-300',\n info: 'text-blue-900 dark:text-blue-300'\n }\n\n const messageTextClasses = {\n success: 'text-green-700 dark:text-green-400',\n error: 'text-red-700 dark:text-red-400',\n warning: 'text-amber-700 dark:text-amber-400',\n info: 'text-blue-700 dark:text-blue-400'\n }\n\n const icons = {\n success: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />`,\n error: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\" />`,\n warning: `<path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />`,\n info: `<path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\" />`\n }\n\n return `\n <div class=\"rounded-lg p-4 ${typeClasses[data.type]} ${data.className || ''}\" ${data.dismissible ? 'id=\"dismissible-alert\"' : ''}>\n <div class=\"flex\">\n ${data.icon !== false ? `\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 ${iconClasses[data.type]}\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n ${icons[data.type]}\n </svg>\n </div>\n ` : ''}\n <div class=\"${data.icon !== false ? 'ml-3' : ''}\">\n ${data.title ? `\n <h3 class=\"text-sm font-semibold ${textClasses[data.type]}\">\n ${escapeHtml(data.title)}\n </h3>\n ` : ''}\n <div class=\"${data.title ? 'mt-1 text-sm' : 'text-sm'} ${messageTextClasses[data.type]}\">\n <p>${escapeHtml(data.message)}</p>\n </div>\n </div>\n ${data.dismissible ? `\n <div class=\"ml-auto pl-3\">\n <div class=\"-mx-1.5 -my-1.5\">\n <button\n type=\"button\"\n class=\"inline-flex rounded-md p-1.5 ${iconClasses[data.type]} hover:bg-opacity-20 focus:outline-none focus:ring-2 focus:ring-offset-2\"\n onclick=\"document.getElementById('dismissible-alert').remove()\"\n >\n <span class=\"sr-only\">Dismiss</span>\n <svg class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n </div>\n </div>\n ` : ''}\n </div>\n </div>\n `\n}\n\nexport function renderSuccessAlert(message: string, title?: string): string {\n return renderAlert({ type: 'success', message, title })\n}\n\nexport function renderErrorAlert(message: string, title?: string): string {\n return renderAlert({ type: 'error', message, title })\n}\n\nexport function renderWarningAlert(message: string, title?: string): string {\n return renderAlert({ type: 'warning', message, title })\n}\n\nexport function renderInfoAlert(message: string, title?: string): string {\n return renderAlert({ type: 'info', message, title })\n}","export interface ConfirmationDialogOptions {\n id: string\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n confirmClass?: string\n iconColor?: 'red' | 'yellow' | 'blue'\n onConfirm?: string // JavaScript code to execute on confirm\n}\n\nexport function renderConfirmationDialog(options: ConfirmationDialogOptions): string {\n const {\n id,\n title,\n message,\n confirmText = 'Confirm',\n cancelText = 'Cancel',\n confirmClass = 'bg-red-500 hover:bg-red-400',\n iconColor = 'red',\n onConfirm = ''\n } = options\n\n const iconColorClasses = {\n red: 'bg-red-500/10 text-red-400',\n yellow: 'bg-yellow-500/10 text-yellow-400',\n blue: 'bg-blue-500/10 text-blue-400'\n }\n\n return `\n <el-dialog>\n <dialog\n id=\"${id}\"\n aria-labelledby=\"${id}-title\"\n class=\"fixed inset-0 m-0 size-auto max-h-none max-w-none overflow-y-auto bg-transparent p-0 backdrop:bg-transparent\"\n >\n <el-dialog-backdrop class=\"fixed inset-0 bg-gray-900/50 transition-opacity data-[closed]:opacity-0 data-[enter]:duration-300 data-[leave]:duration-200 data-[enter]:ease-out data-[leave]:ease-in\"></el-dialog-backdrop>\n\n <div tabindex=\"0\" class=\"flex min-h-full items-end justify-center p-4 text-center focus:outline focus:outline-0 sm:items-center sm:p-0\">\n <el-dialog-panel class=\"relative transform overflow-hidden rounded-lg bg-gray-800 px-4 pb-4 pt-5 text-left shadow-xl outline outline-1 -outline-offset-1 outline-white/10 transition-all data-[closed]:translate-y-4 data-[closed]:opacity-0 data-[enter]:duration-300 data-[leave]:duration-200 data-[enter]:ease-out data-[leave]:ease-in sm:my-8 sm:w-full sm:max-w-lg sm:p-6 data-[closed]:sm:translate-y-0 data-[closed]:sm:scale-95\">\n <div class=\"sm:flex sm:items-start\">\n <div class=\"mx-auto flex size-12 shrink-0 items-center justify-center rounded-full ${iconColorClasses[iconColor]} sm:mx-0 sm:size-10\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" data-slot=\"icon\" aria-hidden=\"true\" class=\"size-6\">\n <path d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div class=\"mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left\">\n <h3 id=\"${id}-title\" class=\"text-base font-semibold text-white\">${title}</h3>\n <div class=\"mt-2\">\n <p class=\"text-sm text-gray-400\">${message}</p>\n </div>\n </div>\n </div>\n <div class=\"mt-5 sm:mt-4 sm:flex sm:flex-row-reverse\">\n <button\n type=\"button\"\n onclick=\"${onConfirm}; document.getElementById('${id}').close()\"\n command=\"close\"\n commandfor=\"${id}\"\n class=\"confirm-button inline-flex w-full justify-center rounded-md ${confirmClass} px-3 py-2 text-sm font-semibold text-white sm:ml-3 sm:w-auto\"\n >\n ${confirmText}\n </button>\n <button\n type=\"button\"\n command=\"close\"\n commandfor=\"${id}\"\n class=\"mt-3 inline-flex w-full justify-center rounded-md bg-white/10 px-3 py-2 text-sm font-semibold text-white ring-1 ring-inset ring-white/5 hover:bg-white/20 sm:mt-0 sm:w-auto\"\n >\n ${cancelText}\n </button>\n </div>\n </el-dialog-panel>\n </div>\n </dialog>\n </el-dialog>\n `\n}\n\n/**\n * Helper function to show a confirmation dialog programmatically\n * Usage in templates: Add this script and call showConfirmDialog()\n */\nexport function getConfirmationDialogScript(): string {\n return `\n <script src=\"https://cdn.jsdelivr.net/npm/@tailwindplus/elements@1\" type=\"module\"></script>\n <script>\n function showConfirmDialog(dialogId) {\n const dialog = document.getElementById(dialogId);\n if (dialog) {\n dialog.showModal();\n }\n }\n </script>\n `\n}\n","export interface PaginationData {\n currentPage: number\n totalPages: number\n totalItems: number\n itemsPerPage: number\n startItem: number\n endItem: number\n baseUrl: string\n queryParams?: Record<string, string>\n showPageNumbers?: boolean\n maxPageNumbers?: number\n showPageSizeSelector?: boolean\n pageSizeOptions?: number[]\n}\n\nexport function renderPagination(data: PaginationData): string {\n // Show pagination if there are multiple pages OR if page size selector is enabled\n const shouldShowPagination = data.totalPages > 1 || (data.showPageSizeSelector !== false && data.totalItems > 0)\n\n if (!shouldShowPagination) {\n return ''\n }\n\n const buildUrl = (page: number, limit?: number): string => {\n const params = new URLSearchParams(data.queryParams || {})\n params.set('page', page.toString())\n if (limit) {\n params.set('limit', limit.toString())\n } else if (data.itemsPerPage !== 20) {\n params.set('limit', data.itemsPerPage.toString())\n }\n return `${data.baseUrl}?${params.toString()}`\n }\n\n const buildPageSizeUrl = (limit: number): string => {\n const params = new URLSearchParams(data.queryParams || {})\n params.set('page', '1') // Reset to page 1 when changing page size\n params.set('limit', limit.toString())\n return `${data.baseUrl}?${params.toString()}`\n }\n\n const generatePageNumbers = (): number[] => {\n const maxNumbers = data.maxPageNumbers || 5\n const half = Math.floor(maxNumbers / 2)\n let start = Math.max(1, data.currentPage - half)\n let end = Math.min(data.totalPages, start + maxNumbers - 1)\n\n // Adjust start if we're near the end\n if (end - start + 1 < maxNumbers) {\n start = Math.max(1, end - maxNumbers + 1)\n }\n\n const pages: number[] = []\n for (let i = start; i <= end; i++) {\n pages.push(i)\n }\n return pages\n }\n\n return `\n <div class=\"rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 px-4 py-3 flex items-center justify-between mt-4\">\n ${data.totalPages > 1 ? `\n <!-- Mobile Pagination -->\n <div class=\"flex-1 flex justify-between sm:hidden\">\n ${data.currentPage > 1 ? `\n <a href=\"${buildUrl(data.currentPage - 1)}\" class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Previous\n </a>\n ` : `\n <span class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-400 dark:text-zinc-600 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 opacity-50 cursor-not-allowed\">Previous</span>\n `}\n\n ${data.currentPage < data.totalPages ? `\n <a href=\"${buildUrl(data.currentPage + 1)}\" class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Next\n </a>\n ` : `\n <span class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-400 dark:text-zinc-600 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 opacity-50 cursor-not-allowed\">Next</span>\n `}\n </div>\n ` : ''}\n\n <!-- Desktop Pagination -->\n <div class=\"hidden sm:flex-1 sm:flex sm:items-center sm:justify-between\">\n <div class=\"flex items-center gap-4\">\n <p class=\"text-sm text-zinc-500 dark:text-zinc-400\">\n Showing <span class=\"font-medium text-zinc-950 dark:text-white\">${data.startItem}</span> to\n <span class=\"font-medium text-zinc-950 dark:text-white\">${data.endItem}</span> of\n <span class=\"font-medium text-zinc-950 dark:text-white\">${data.totalItems}</span> results\n </p>\n ${data.showPageSizeSelector !== false ? `\n <div class=\"flex items-center gap-2\">\n <label for=\"page-size\" class=\"text-sm text-zinc-500 dark:text-zinc-400\">Per page:</label>\n <div class=\"grid grid-cols-1\">\n <select\n id=\"page-size\"\n onchange=\"window.location.href = this.value\"\n class=\"col-start-1 row-start-1 w-full appearance-none rounded-md bg-white/5 dark:bg-white/5 py-1.5 pl-3 pr-8 text-sm text-zinc-950 dark:text-white outline outline-1 -outline-offset-1 outline-zinc-500/30 dark:outline-zinc-400/30 *:bg-white dark:*:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-zinc-500 dark:focus-visible:outline-zinc-400\"\n >\n ${(data.pageSizeOptions || [10, 20, 50, 100]).map(size => `\n <option value=\"${buildPageSizeUrl(size)}\" ${size === data.itemsPerPage ? 'selected' : ''}>\n ${size}\n </option>\n `).join('')}\n </select>\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\" class=\"pointer-events-none col-start-1 row-start-1 mr-2 size-4 self-center justify-self-end text-zinc-600 dark:text-zinc-400\">\n <path d=\"M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\" fill-rule=\"evenodd\" />\n </svg>\n </div>\n </div>\n ` : ''}\n </div>\n\n ${data.totalPages > 1 ? `\n <div class=\"flex items-center gap-x-1\">\n <!-- Previous Button -->\n ${data.currentPage > 1 ? `\n <a href=\"${buildUrl(data.currentPage - 1)}\"\n class=\"rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Previous\n </a>\n ` : ''}\n\n <!-- Page Numbers -->\n ${data.showPageNumbers !== false ? `\n <!-- First page if not in range -->\n ${(() => {\n const pageNumbers = generatePageNumbers()\n const firstPage = pageNumbers.length > 0 ? pageNumbers[0] : null\n return firstPage && firstPage > 1 ? `\n <a href=\"${buildUrl(1)}\"\n class=\"rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n 1\n </a>\n ${firstPage > 2 ? `\n <span class=\"px-2 text-sm text-zinc-500 dark:text-zinc-400\">...</span>\n ` : ''}\n ` : ''\n })()}\n\n <!-- Page number buttons -->\n ${generatePageNumbers().map(pageNum => `\n ${pageNum === data.currentPage ? `\n <span class=\"rounded-lg bg-zinc-950 dark:bg-white px-3 py-2 text-sm font-semibold text-white dark:text-zinc-950\">\n ${pageNum}\n </span>\n ` : `\n <a href=\"${buildUrl(pageNum)}\"\n class=\"rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n ${pageNum}\n </a>\n `}\n `).join('')}\n\n <!-- Last page if not in range -->\n ${(() => {\n const pageNumbers = generatePageNumbers()\n const lastPageNum = pageNumbers.length > 0 ? pageNumbers.slice(-1)[0] : null\n return lastPageNum && lastPageNum < data.totalPages ? `\n ${lastPageNum < data.totalPages - 1 ? `\n <span class=\"px-2 text-sm text-zinc-500 dark:text-zinc-400\">...</span>\n ` : ''}\n <a href=\"${buildUrl(data.totalPages)}\"\n class=\"rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n ${data.totalPages}\n </a>\n ` : ''\n })()}\n ` : ''}\n\n <!-- Next Button -->\n ${data.currentPage < data.totalPages ? `\n <a href=\"${buildUrl(data.currentPage + 1)}\"\n class=\"rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Next\n </a>\n ` : ''}\n </div>\n ` : ''}\n </div>\n </div>\n `\n}","export interface TableColumn {\n key: string\n label: string\n sortable?: boolean\n className?: string\n sortType?: 'string' | 'number' | 'date' | 'boolean'\n render?: (value: any, row: any) => string\n}\n\nexport interface TableData<T = any> {\n columns: TableColumn[]\n rows: T[]\n selectable?: boolean\n className?: string\n emptyMessage?: string\n tableId?: string\n title?: string\n rowClickable?: boolean\n rowClickUrl?: (row: T) => string\n}\n\nexport function renderTable<T = any>(data: TableData<T>): string {\n const tableId = data.tableId || `table-${Math.random().toString(36).substr(2, 9)}`\n\n if (data.rows.length === 0) {\n return `\n <div class=\"rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-8 text-center\">\n <div class=\"text-zinc-500 dark:text-zinc-400\">\n <svg class=\"mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n <p class=\"mt-2 text-sm text-zinc-500 dark:text-zinc-400\">${data.emptyMessage || 'No data available'}</p>\n </div>\n </div>\n `\n }\n\n return `\n <div class=\"${data.className || ''}\" id=\"${tableId}\">\n ${data.title ? `\n <div class=\"px-4 sm:px-0 mb-4\">\n <h3 class=\"text-base font-semibold text-zinc-950 dark:text-white\">${data.title}</h3>\n </div>\n ` : ''}\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full sortable-table\">\n <thead>\n <tr>\n ${data.selectable ? `\n <th class=\"px-4 py-3.5 text-center sm:pl-0\">\n <div class=\"flex items-center justify-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input type=\"checkbox\" id=\"select-all-${tableId}\" class=\"col-start-1 row-start-1 appearance-none rounded border border-white/10 bg-white/5 checked:border-cyan-500 checked:bg-cyan-500 indeterminate:border-cyan-500 indeterminate:bg-cyan-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cyan-500 disabled:border-white/5 disabled:bg-white/10 disabled:checked:bg-white/10 forced-colors:appearance-auto row-checkbox\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n </th>\n ` : ''}\n ${data.columns.map((column, index) => {\n const isFirst = index === 0 && !data.selectable\n const isLast = index === data.columns.length - 1\n return `\n <th class=\"px-4 py-3.5 text-left text-sm font-semibold text-zinc-950 dark:text-white ${isFirst ? 'sm:pl-0' : ''} ${isLast ? 'sm:pr-0' : ''} ${column.className || ''}\">\n ${column.sortable ? `\n <button\n class=\"flex items-center gap-x-2 hover:text-zinc-700 dark:hover:text-zinc-300 transition-colors sort-btn text-left\"\n data-column=\"${column.key}\"\n data-sort-type=\"${column.sortType || 'string'}\"\n data-sort-direction=\"none\"\n onclick=\"sortTable('${tableId}', '${column.key}', '${column.sortType || 'string'}')\"\n >\n <span>${column.label}</span>\n <div class=\"sort-icons flex flex-col\">\n <svg class=\"w-3 h-3 sort-up opacity-30\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z\" clip-rule=\"evenodd\" />\n </svg>\n <svg class=\"w-3 h-3 sort-down opacity-30 -mt-1\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </div>\n </button>\n ` : column.label}\n </th>\n `}).join('')}\n </tr>\n </thead>\n <tbody>\n ${data.rows.map((row) => {\n if (!row) return ''\n const clickableClass = data.rowClickable ? 'cursor-pointer' : ''\n const clickHandler = data.rowClickable && data.rowClickUrl ? `onclick=\"window.location.href='${data.rowClickUrl(row)}'\"` : ''\n return `\n <tr class=\"group border-t border-zinc-950/5 dark:border-white/5 hover:bg-gradient-to-r hover:from-cyan-50/50 hover:via-blue-50/30 hover:to-purple-50/50 dark:hover:from-cyan-900/20 dark:hover:via-blue-900/10 dark:hover:to-purple-900/20 hover:shadow-sm hover:shadow-cyan-500/5 dark:hover:shadow-cyan-400/5 transition-all duration-300 ${clickableClass}\" ${clickHandler}>\n ${data.selectable ? `\n <td class=\"px-4 py-4 sm:pl-0\" onclick=\"event.stopPropagation()\">\n <div class=\"flex items-center justify-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input type=\"checkbox\" value=\"${(row as any).id || ''}\" class=\"col-start-1 row-start-1 appearance-none rounded border border-white/10 bg-white/5 checked:border-cyan-500 checked:bg-cyan-500 indeterminate:border-cyan-500 indeterminate:bg-cyan-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cyan-500 disabled:border-white/5 disabled:bg-white/10 disabled:checked:bg-white/10 forced-colors:appearance-auto row-checkbox\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n </td>\n ` : ''}\n ${data.columns.map((column, colIndex) => {\n const value = (row as any)[column.key]\n const displayValue = column.render ? column.render(value, row) : value\n const stopPropagation = column.key === 'actions' ? 'onclick=\"event.stopPropagation()\"' : ''\n const isFirst = colIndex === 0 && !data.selectable\n const isLast = colIndex === data.columns.length - 1\n return `\n <td class=\"px-4 py-4 text-sm text-zinc-500 dark:text-zinc-400 ${isFirst ? 'sm:pl-0 font-medium text-zinc-950 dark:text-white' : ''} ${isLast ? 'sm:pr-0' : ''} ${column.className || ''}\" ${stopPropagation}>\n ${displayValue || ''}\n </td>\n `\n }).join('')}\n </tr>\n `\n }).join('')}\n </tbody>\n </table>\n </div>\n\n <script>\n // Table sorting functionality\n window.sortTable = function(tableId, column, sortType) {\n const tableContainer = document.getElementById(tableId);\n const table = tableContainer.querySelector('.sortable-table');\n const tbody = table.querySelector('tbody');\n const rows = Array.from(tbody.querySelectorAll('tr'));\n const headerBtn = table.querySelector(\\`[data-column=\"\\${column}\"]\\`);\n\n // Get current sort direction\n let direction = headerBtn.getAttribute('data-sort-direction');\n\n // Reset all sort indicators\n table.querySelectorAll('.sort-btn').forEach(btn => {\n btn.setAttribute('data-sort-direction', 'none');\n btn.querySelectorAll('.sort-up, .sort-down').forEach(icon => {\n icon.classList.add('opacity-30');\n icon.classList.remove('opacity-100', 'text-zinc-950', 'dark:text-white');\n });\n });\n\n // Determine new direction\n if (direction === 'none' || direction === 'desc') {\n direction = 'asc';\n } else {\n direction = 'desc';\n }\n\n // Update current header\n headerBtn.setAttribute('data-sort-direction', direction);\n const upIcon = headerBtn.querySelector('.sort-up');\n const downIcon = headerBtn.querySelector('.sort-down');\n\n if (direction === 'asc') {\n upIcon.classList.remove('opacity-30');\n upIcon.classList.add('opacity-100', 'text-zinc-950', 'dark:text-white');\n downIcon.classList.add('opacity-30');\n downIcon.classList.remove('opacity-100', 'text-zinc-950', 'dark:text-white');\n } else {\n downIcon.classList.remove('opacity-30');\n downIcon.classList.add('opacity-100', 'text-zinc-950', 'dark:text-white');\n upIcon.classList.add('opacity-30');\n upIcon.classList.remove('opacity-100', 'text-zinc-950', 'dark:text-white');\n }\n\n // Find column index (accounting for potential select column)\n const headers = Array.from(table.querySelectorAll('th'));\n const selectableOffset = table.querySelector('input[id^=\"select-all\"]') ? 1 : 0;\n const columnIndex = headers.findIndex(th => th.querySelector(\\`[data-column=\"\\${column}\"]\\`)) - selectableOffset;\n\n // Sort rows\n rows.sort((a, b) => {\n const aCell = a.children[columnIndex + selectableOffset];\n const bCell = b.children[columnIndex + selectableOffset];\n\n if (!aCell || !bCell) return 0;\n\n let aValue = aCell.textContent.trim();\n let bValue = bCell.textContent.trim();\n\n // Handle different sort types\n switch (sortType) {\n case 'number':\n aValue = parseFloat(aValue.replace(/[^0-9.-]/g, '')) || 0;\n bValue = parseFloat(bValue.replace(/[^0-9.-]/g, '')) || 0;\n break;\n case 'date':\n aValue = new Date(aValue).getTime() || 0;\n bValue = new Date(bValue).getTime() || 0;\n break;\n case 'boolean':\n aValue = aValue.toLowerCase() === 'true' || aValue.toLowerCase() === 'published' || aValue.toLowerCase() === 'active';\n bValue = bValue.toLowerCase() === 'true' || bValue.toLowerCase() === 'published' || bValue.toLowerCase() === 'active';\n break;\n default: // string\n aValue = aValue.toLowerCase();\n bValue = bValue.toLowerCase();\n }\n\n if (aValue < bValue) return direction === 'asc' ? -1 : 1;\n if (aValue > bValue) return direction === 'asc' ? 1 : -1;\n return 0;\n });\n\n // Re-append sorted rows\n rows.forEach(row => tbody.appendChild(row));\n };\n\n // Select all functionality\n document.addEventListener('DOMContentLoaded', function() {\n document.querySelectorAll('[id^=\"select-all\"]').forEach(selectAll => {\n selectAll.addEventListener('change', function() {\n const tableId = this.id.replace('select-all-', '');\n const table = document.getElementById(tableId);\n if (table) {\n const checkboxes = table.querySelectorAll('.row-checkbox');\n checkboxes.forEach(checkbox => {\n checkbox.checked = this.checked;\n });\n }\n });\n });\n });\n </script>\n </div>\n `\n}","import { HtmlEscapedString } from \"hono/utils/html\";\nimport { renderLogo } from \"../components/logo.template\";\n\nexport interface AdminLayoutData {\n title: string;\n pageTitle?: string;\n currentPath?: string;\n version?: string;\n enableExperimentalFeatures?: boolean;\n user?: {\n name: string;\n email: string;\n role: string;\n };\n scripts?: string[];\n styles?: string[];\n content: string | HtmlEscapedString;\n dynamicMenuItems?: Array<{\n label: string;\n path: string;\n icon: string;\n }>;\n}\n\nexport function renderAdminLayout(data: AdminLayoutData): string {\n // Import and use the new Catalyst layout\n const {\n renderAdminLayoutCatalyst,\n } = require(\"./admin-layout-catalyst.template\");\n return renderAdminLayoutCatalyst(data);\n}\n\nexport function adminLayoutV2(data: AdminLayoutData): string {\n return `<!DOCTYPE html>\n<html lang=\"en\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${data.title} - SonicJS AI Admin</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\">\n \n <!-- Tailwind CSS -->\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n backdropBlur: {\n xs: '2px',\n },\n colors: {\n primary: '#465FFF',\n secondary: '#212A3E',\n dark: '#1C1C24',\n 'dark-2': '#1A1A27',\n 'dark-3': '#2C2C54',\n 'dark-4': '#40407A',\n 'dark-5': '#706FD3',\n 'gray-1': '#F7F9FC',\n 'gray-2': '#E4E6EA',\n 'gray-3': '#D2D4D9',\n 'gray-4': '#9CA3AF',\n 'gray-5': '#6B7280',\n 'gray-6': '#4B5563',\n 'gray-7': '#374151',\n 'gray-8': '#1F2937',\n 'gray-9': '#111827',\n success: '#10B981',\n warning: '#F59E0B',\n error: '#EF4444',\n info: '#3B82F6'\n },\n fontFamily: {\n satoshi: ['Satoshi', 'sans-serif'],\n },\n spacing: {\n '4.5': '1.125rem',\n '5.5': '1.375rem',\n '6.5': '1.625rem',\n '7.5': '1.875rem'\n },\n boxShadow: {\n 'default': '0px 8px 13px -3px rgba(0, 0, 0, 0.07)',\n 'card': '0px 1px 3px rgba(0, 0, 0, 0.12)',\n 'card-2': '0px 1px 2px rgba(0, 0, 0, 0.05)',\n 'switcher': '0px 2px 4px rgba(0, 0, 0, 0.2), inset 0px 2px 2px #FFFFFF, inset 0px -1px 1px rgba(0, 0, 0, 0.1)',\n },\n dropShadow: {\n 1: '0px 1px 0px #E2E8F0',\n 2: '0px 1px 4px rgba(0, 0, 0, 0.12)',\n }\n }\n }\n }\n </script>\n \n <!-- Additional Styles -->\n <style>\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');\n \n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: 'Inter', system-ui, -apple-system, sans-serif;\n }\n \n /* Custom scrollbar */\n ::-webkit-scrollbar {\n width: 6px;\n }\n \n ::-webkit-scrollbar-track {\n background: #1F2937;\n }\n \n ::-webkit-scrollbar-thumb {\n background: #465FFF;\n border-radius: 3px;\n }\n \n ::-webkit-scrollbar-thumb:hover {\n background: #3B4EE8;\n }\n \n /* Sidebar animations */\n .sidebar-item {\n transition: all 0.3s ease;\n }\n \n .sidebar-item:hover {\n transform: translateX(4px);\n }\n \n /* Card animations */\n .card-hover {\n transition: all 0.3s ease;\n }\n \n .card-hover:hover {\n transform: translateY(-2px);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n }\n \n /* Button gradients */\n .btn-gradient {\n background: linear-gradient(135deg, #465FFF 0%, #9333EA 100%);\n }\n \n .btn-gradient:hover {\n background: linear-gradient(135deg, #3B4EE8 0%, #7C2D12 100%);\n }\n \n /* Dark mode form elements */\n .form-input {\n background-color: #1F2937;\n border-color: #374151;\n color: #F9FAFB;\n }\n \n .form-input:focus {\n border-color: #465FFF;\n box-shadow: 0 0 0 3px rgba(70, 95, 255, 0.1);\n }\n \n /* Notification styles */\n .notification {\n -webkit-backdrop-filter: blur(15px);\n backdrop-filter: blur(15px);\n animation: slideInRight 0.3s ease-out;\n }\n \n @keyframes slideInRight {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n }\n \n /* Custom slider styles */\n .slider::-webkit-slider-thumb {\n appearance: none;\n height: 16px;\n width: 16px;\n border-radius: 50%;\n background: #465FFF;\n cursor: pointer;\n border: 2px solid white;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n }\n \n .slider::-moz-range-thumb {\n height: 16px;\n width: 16px;\n border-radius: 50%;\n background: #465FFF;\n cursor: pointer;\n border: 2px solid white;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n }\n \n .slider::-webkit-slider-track {\n height: 8px;\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.2);\n }\n \n .slider::-moz-range-track {\n height: 8px;\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.2);\n border: none;\n }\n \n /* PNG Background Images */\n .svg-pattern-blue-waves {\n background-color: #111827;\n background-image: url('/images/backgrounds/blue-waves.png');\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n }\n \n .svg-pattern-blue-crescent {\n background-color: #111827;\n background-image: url('/images/backgrounds/blue-crescent.png');\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n }\n \n .svg-pattern-blue-stars {\n background-color: #111827;\n background-image: url('/images/backgrounds/blue-stars.png');\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n }\n \n .svg-pattern-blue-waves-3d {\n background-color: #111827;\n background-image: url('/images/backgrounds/blue-waves-3d.png');\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n }\n </style>\n \n <!-- Scripts -->\n <script src=\"https://unpkg.com/htmx.org@2.0.3\"></script>\n <script src=\"https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js\" defer></script>\n <script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n \n ${data.styles ? data.styles.map((style) => `<link rel=\"stylesheet\" href=\"${style}\">`).join(\"\\n \") : \"\"}\n ${data.scripts ? data.scripts.map((script) => `<script src=\"${script}\"></script>`).join(\"\\n \") : \"\"}\n</head>\n<body class=\"bg-gradient-to-br from-slate-900 via-gray-900 to-black min-h-screen text-gray-1\">\n <!-- Background overlay with glass effect -->\n <div id=\"background-overlay\" class=\"fixed inset-0 backdrop-blur-sm\" style=\"background-color: rgba(0, 0, 0, 0.2);\"></div>\n <!-- Main container -->\n <div class=\"relative z-10 min-h-screen\">\n <!-- Header -->\n ${renderTopBar(data.pageTitle || \"Dashboard\", data.user)}\n\n <!-- Main content area -->\n <div class=\"px-4 sm:px-6 lg:px-8 py-8\">\n <div class=\"grid grid-cols-1 lg:grid-cols-5 gap-6\">\n <!-- Sidebar -->\n <div class=\"lg:col-span-1\">\n ${renderSidebar(data.currentPath || \"/\", data.user, data.dynamicMenuItems)}\n </div>\n \n <!-- Main content -->\n <div class=\"lg:col-span-4\">\n ${data.content}\n </div>\n </div>\n </div>\n </div>\n \n <!-- Notification Container -->\n <div id=\"notification-container\" class=\"fixed top-4 right-4 z-50 space-y-2\"></div>\n \n <script>\n // Dark mode toggle functionality\n function toggleDarkMode() {\n document.documentElement.classList.toggle('dark');\n localStorage.setItem('darkMode', document.documentElement.classList.contains('dark'));\n }\n \n // Initialize dark mode from localStorage\n if (localStorage.getItem('darkMode') === 'true' || (!('darkMode' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {\n document.documentElement.classList.add('dark');\n }\n \n // Sidebar toggle for mobile\n function toggleSidebar() {\n const sidebar = document.getElementById('sidebar');\n const overlay = document.getElementById('sidebar-overlay');\n sidebar.classList.toggle('-translate-x-full');\n overlay.classList.toggle('hidden');\n }\n \n // Close sidebar on overlay click\n function closeSidebar() {\n const sidebar = document.getElementById('sidebar');\n const overlay = document.getElementById('sidebar-overlay');\n sidebar.classList.add('-translate-x-full');\n overlay.classList.add('hidden');\n }\n \n // User dropdown toggle\n function toggleUserDropdown() {\n const dropdowns = document.querySelectorAll('.userDropdown');\n dropdowns.forEach(function(dropdown) {\n dropdown.classList.toggle('hidden');\n });\n }\n \n // Close dropdown when clicking outside\n document.addEventListener('click', function(event) {\n const dropdowns = document.querySelectorAll('.userDropdown');\n const button = event.target.closest('button');\n if (!button || !button.getAttribute('onclick')) {\n dropdowns.forEach(function(dropdown) {\n dropdown.classList.add('hidden');\n });\n }\n });\n \n // Show notification\n function showNotification(message, type = 'info') {\n const container = document.getElementById('notification-container');\n const notification = document.createElement('div');\n const colors = {\n success: 'bg-success text-white',\n error: 'bg-error text-white',\n warning: 'bg-warning text-white',\n info: 'bg-info text-white'\n };\n \n notification.className = \\`notification px-6 py-4 rounded-lg shadow-lg \\${colors[type] || colors.info} max-w-sm\\`;\n notification.innerHTML = \\`\n <div class=\"flex items-center justify-between\">\n <span>\\${message}</span>\n <button onclick=\"this.parentElement.parentElement.remove()\" class=\"ml-4 text-white/80 hover:text-white\">\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n </button>\n </div>\n \\`;\n \n container.appendChild(notification);\n \n // Auto remove after 5 seconds\n setTimeout(() => {\n if (notification.parentElement) {\n notification.remove();\n }\n }, 5000);\n }\n \n // Background customizer functionality\n function toggleBackgroundCustomizer() {\n const dropdown = document.getElementById('backgroundCustomizer');\n dropdown.classList.toggle('hidden');\n }\n \n // Background themes\n const backgroundThemes = {\n 'default': 'bg-gradient-to-br from-slate-900 via-gray-900 to-black',\n 'cosmic-blue': 'bg-gradient-to-br from-slate-900 via-blue-900 to-indigo-900',\n 'matrix-green': 'bg-gradient-to-br from-gray-900 via-emerald-900 to-green-900',\n 'cyber-pink': 'bg-gradient-to-br from-gray-900 via-pink-900 to-rose-900',\n 'neon-orange': 'bg-gradient-to-br from-gray-900 via-orange-900 to-amber-900',\n 'purple-space': 'bg-gradient-to-br from-gray-900 via-purple-900 to-violet-800',\n 'blue-waves': 'svg-pattern-blue-waves',\n 'blue-crescent': 'svg-pattern-blue-crescent',\n 'blue-stars': 'svg-pattern-blue-stars',\n 'blue-waves-3d': 'svg-pattern-blue-waves-3d'\n };\n \n // Set background theme\n function setBackground(theme) {\n const body = document.body;\n \n // Remove all existing background classes and SVG patterns\n Object.values(backgroundThemes).forEach(bgClass => {\n if (bgClass.startsWith('svg-pattern-')) {\n body.classList.remove(bgClass);\n } else {\n body.classList.remove(...bgClass.split(' ').slice(1)); // Remove 'bg-gradient-to-br' prefix\n }\n });\n body.classList.remove('bg-gradient-to-br');\n \n // Add new background\n const themeClass = backgroundThemes[theme];\n if (themeClass.startsWith('svg-pattern-')) {\n body.classList.add(themeClass);\n } else {\n const newClasses = themeClass.split(' ').slice(1); // Remove 'bg-gradient-to-br' prefix\n body.classList.add('bg-gradient-to-br', ...newClasses);\n }\n \n // Save preference\n localStorage.setItem('backgroundTheme', theme);\n \n // Close dropdown\n toggleBackgroundCustomizer();\n \n // Show notification\n showNotification('Background changed to ' + theme.replace('-', ' '), 'success');\n }\n \n // Adjust background darkness\n function adjustDarkness(value) {\n const overlay = document.getElementById('background-overlay');\n if (overlay) {\n const opacity = value / 100; // Convert percentage to decimal\n overlay.style.backgroundColor = 'rgba(0, 0, 0, ' + opacity + ')';\n localStorage.setItem('backgroundDarkness', value);\n console.log('Darkness adjusted to:', value + '%', 'Opacity:', opacity);\n } else {\n console.log('Overlay element not found');\n }\n }\n \n // Initialize background on page load\n function initializeBackground() {\n const savedTheme = localStorage.getItem('backgroundTheme') || 'default';\n const savedDarkness = localStorage.getItem('backgroundDarkness') || '20';\n \n // Set background theme\n if (savedTheme !== 'default') {\n const body = document.body;\n const themeClass = backgroundThemes[savedTheme];\n \n // Remove all existing backgrounds first\n Object.values(backgroundThemes).forEach(bgClass => {\n if (bgClass.startsWith('svg-pattern-')) {\n body.classList.remove(bgClass);\n } else {\n body.classList.remove(...bgClass.split(' ').slice(1));\n }\n });\n body.classList.remove('bg-gradient-to-br');\n \n // Apply saved theme\n if (themeClass.startsWith('svg-pattern-')) {\n body.classList.add(themeClass);\n } else {\n const newClasses = themeClass.split(' ').slice(1);\n body.classList.add('bg-gradient-to-br', ...newClasses);\n }\n }\n \n // Set darkness\n const overlay = document.getElementById('background-overlay');\n if (overlay) {\n const opacity = savedDarkness / 100;\n overlay.style.backgroundColor = 'rgba(0, 0, 0, ' + opacity + ')';\n }\n \n // Set slider value\n const slider = document.getElementById('darknessSlider');\n if (slider) {\n slider.value = savedDarkness;\n }\n }\n \n // Close dropdown when clicking outside\n document.addEventListener('click', function(event) {\n const dropdown = document.getElementById('backgroundCustomizer');\n const button = event.target.closest('button');\n const slider = event.target.closest('#darknessSlider');\n const dropdownContainer = event.target.closest('#backgroundCustomizer');\n \n // Don't close if clicking inside the dropdown, on the toggle button, or on the slider\n if (!button?.getAttribute('onclick')?.includes('toggleBackgroundCustomizer') && \n !slider && !dropdownContainer) {\n dropdown?.classList.add('hidden');\n }\n });\n \n // Initialize background when page loads\n document.addEventListener('DOMContentLoaded', initializeBackground);\n </script>\n</body>\n</html>`;\n}\n\nfunction renderSidebar(\n currentPath: string,\n user?: any,\n dynamicMenuItems?: Array<{\n label: string;\n path: string;\n icon: string;\n }>\n): string {\n const baseMenuItems = [\n {\n label: \"Content\",\n path: \"/admin/content\",\n icon: `<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"/>\n </svg>`,\n },\n {\n label: \"Collections\",\n path: \"/admin/collections\",\n icon: `<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3z\"/>\n </svg>`,\n },\n {\n label: \"Media\",\n path: \"/admin/media\",\n icon: `<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 000 2v8a2 2 0 002 2h2.586l-1.293 1.293a1 1 0 101.414 1.414L10 15.414l2.293 2.293a1 1 0 001.414-1.414L12.414 15H15a2 2 0 002-2V5a1 1 0 100-2H3zm11.707 4.707a1 1 0 00-1.414-1.414L10 9.586 8.707 8.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\"/>\n </svg>`,\n },\n {\n label: \"Users\",\n path: \"/admin/users\",\n icon: `<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3z\"/>\n </svg>`,\n },\n {\n label: \"Plugins\",\n path: \"/admin/plugins\",\n icon: `<svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10\"/>\n </svg>`,\n },\n {\n label: \"Cache\",\n path: \"/admin/cache\",\n icon: `<svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 10V3L4 14h7v7l9-11h-7z\"/>\n </svg>`,\n },\n {\n label: \"Logs\",\n path: \"/admin/logs\",\n icon: `<svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"/>\n </svg>`,\n },\n {\n label: \"Settings\",\n path: \"/admin/settings\",\n icon: `<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z\" clip-rule=\"evenodd\"/>\n </svg>`,\n },\n {\n label: \"API Reference\",\n path: \"/admin/api-reference\",\n icon: `<svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4\"/>\n </svg>`,\n },\n {\n label: \"Field Types\",\n path: \"/admin/field-types\",\n icon: `<svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"/>\n </svg>`,\n },\n {\n label: \"API Spec\",\n path: \"/api\",\n target: \"_blank\",\n icon: `<svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"/>\n </svg>`,\n },\n ];\n\n // Combine base menu items with dynamic menu items from active plugins\n const allMenuItems = [...baseMenuItems];\n\n // Insert dynamic menu items after \"Users\"\n if (dynamicMenuItems && dynamicMenuItems.length > 0) {\n const usersIndex = allMenuItems.findIndex(\n (item) => item.path === \"/admin/users\"\n );\n if (usersIndex !== -1) {\n allMenuItems.splice(usersIndex + 1, 0, ...dynamicMenuItems);\n } else {\n // Fallback: add to end if Users not found\n allMenuItems.push(...dynamicMenuItems);\n }\n }\n\n return `\n <nav class=\"backdrop-blur-md bg-black/30 rounded-xl border border-white/10 shadow-xl p-6 h-[calc(100vh-9.5rem)] sticky top-8\">\n <div class=\"space-y-4\">\n ${allMenuItems\n .map((item) => {\n const isActive =\n currentPath === item.path ||\n (item.path !== \"/admin\" && currentPath.startsWith(item.path));\n const targetAttr = (item as any).target\n ? ` target=\"${(item as any).target}\"`\n : \"\";\n return `\n <a href=\"${item.path}\"${targetAttr} class=\"flex items-center space-x-3 ${isActive ? \"text-white bg-white/20\" : \"text-gray-300 hover:text-white\"} rounded-lg px-3 py-2 transition-all hover:bg-white/10\">\n ${item.icon}\n <span>${item.label}</span>\n </a>\n `;\n })\n .join(\"\")}\n </div>\n </nav>\n `;\n}\n\nfunction renderTopBar(pageTitle: string, user?: any): string {\n return `\n <header class=\"backdrop-blur-md bg-white/10 border-b border-white/20 shadow-lg relative z-[9998]\">\n <div class=\"px-4 sm:px-6 lg:px-8\">\n <div class=\"flex justify-between items-center py-4\">\n <div class=\"flex items-center space-x-4\">\n ${renderLogo({ size: \"md\", showText: true, variant: \"white\" })}\n </div>\n \n <div class=\"flex items-center space-x-4\">\n <!-- Notifications -->\n <button class=\"p-2 text-gray-300 hover:text-white transition-colors rounded-lg hover:bg-white/10 relative\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9\"/>\n </svg>\n <span class=\"absolute top-1 right-1 w-2 h-2 bg-red-400 rounded-full\"></span>\n </button>\n\n <!-- Background Customizer -->\n <div class=\"relative z-[9999]\">\n <button class=\"p-2 text-gray-300 hover:text-white transition-colors rounded-lg hover:bg-white/10\" onclick=\"toggleBackgroundCustomizer()\">\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.098 19.902a3.75 3.75 0 0 0 5.304 0l6.401-6.402M6.75 21A3.75 3.75 0 0 1 3 17.25V4.125C3 3.504 3.504 3 4.125 3h5.25c.621 0 1.125.504 1.125 1.125v4.072M6.75 21a3.75 3.75 0 0 0 3.75-3.75V8.197M6.75 21h13.125c.621 0 1.125-.504 1.125-1.125v-5.25c0-.621-.504-1.125-1.125-1.125h-4.072M10.5 8.197l2.88-2.88c.438-.439 1.15-.439 1.59 0l3.712 3.713c.44.44.44 1.152 0 1.59l-2.879 2.88M6.75 17.25h.008v.008H6.75v-.008Z\" />\n </svg>\n </button>\n \n <!-- Background Customizer Dropdown -->\n <div id=\"backgroundCustomizer\" class=\"hidden absolute right-0 mt-2 w-80 backdrop-blur-md bg-black/95 rounded-xl border border-white/10 shadow-xl z-[9999]\">\n <div class=\"p-6\">\n <div class=\"flex items-center justify-between mb-4\">\n <h3 class=\"text-lg font-semibold text-white\">Background Themes</h3>\n <button onclick=\"toggleBackgroundCustomizer()\" class=\"text-gray-400 hover:text-white\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n \n <!-- Background Options -->\n <div class=\"space-y-3 mb-6\">\n <div class=\"grid grid-cols-2 gap-3\">\n <!-- Default (Deep Space) -->\n <button onclick=\"setBackground('default')\" class=\"bg-preview bg-gradient-to-br from-slate-900 via-gray-900 to-black h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group\">\n <div class=\"absolute inset-0 bg-black/20 rounded-lg\"></div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium\">Default</div>\n </button>\n \n <!-- Cosmic Blue -->\n <button onclick=\"setBackground('cosmic-blue')\" class=\"bg-preview bg-gradient-to-br from-slate-900 via-blue-900 to-indigo-900 h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group\">\n <div class=\"absolute inset-0 bg-black/20 rounded-lg\"></div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium\">Cosmic</div>\n </button>\n \n <!-- Matrix Green -->\n <button onclick=\"setBackground('matrix-green')\" class=\"bg-preview bg-gradient-to-br from-gray-900 via-emerald-900 to-green-900 h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group\">\n <div class=\"absolute inset-0 bg-black/20 rounded-lg\"></div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium\">Matrix</div>\n </button>\n \n <!-- Cyber Pink -->\n <button onclick=\"setBackground('cyber-pink')\" class=\"bg-preview bg-gradient-to-br from-gray-900 via-pink-900 to-rose-900 h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group\">\n <div class=\"absolute inset-0 bg-black/20 rounded-lg\"></div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium\">Cyber</div>\n </button>\n \n <!-- Neon Orange -->\n <button onclick=\"setBackground('neon-orange')\" class=\"bg-preview bg-gradient-to-br from-gray-900 via-orange-900 to-amber-900 h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group\">\n <div class=\"absolute inset-0 bg-black/20 rounded-lg\"></div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium\">Neon</div>\n </button>\n \n <!-- Purple Space -->\n <button onclick=\"setBackground('purple-space')\" class=\"bg-preview bg-gradient-to-br from-gray-900 via-purple-900 to-violet-800 h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group\">\n <div class=\"absolute inset-0 bg-black/20 rounded-lg\"></div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium\">Purple</div>\n </button>\n </div>\n \n <!-- Custom Backgrounds -->\n <div class=\"mt-4\">\n <h4 class=\"text-sm font-medium text-gray-300 mb-3\">Custom Backgrounds</h4>\n <div class=\"grid grid-cols-2 gap-3\">\n <!-- Blue Waves -->\n <button onclick=\"setBackground('blue-waves')\" class=\"h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group overflow-hidden\">\n <div class=\"absolute inset-0\">\n <img src=\"/images/backgrounds/blue-waves.png\" alt=\"Blue Waves\" class=\"w-full h-full object-cover opacity-60\">\n </div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium bg-black/50 px-2 py-1 rounded\">Waves</div>\n </button>\n \n <!-- Blue Crescent -->\n <button onclick=\"setBackground('blue-crescent')\" class=\"h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group overflow-hidden\">\n <div class=\"absolute inset-0\">\n <img src=\"/images/backgrounds/blue-crescent.png\" alt=\"Blue Crescent\" class=\"w-full h-full object-cover opacity-60\">\n </div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium bg-black/50 px-2 py-1 rounded\">Crescent</div>\n </button>\n \n <!-- Blue Stars -->\n <button onclick=\"setBackground('blue-stars')\" class=\"h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group overflow-hidden\">\n <div class=\"absolute inset-0\">\n <img src=\"/images/backgrounds/blue-stars.png\" alt=\"Blue Stars\" class=\"w-full h-full object-cover opacity-60\">\n </div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium bg-black/50 px-2 py-1 rounded\">Stars</div>\n </button>\n \n <!-- Blue Waves 3D -->\n <button onclick=\"setBackground('blue-waves-3d')\" class=\"h-16 rounded-lg border-2 border-white/20 hover:border-white/40 transition-all relative group overflow-hidden\">\n <div class=\"absolute inset-0\">\n <img src=\"/images/backgrounds/blue-waves-3d.png\" alt=\"Blue Waves 3D\" class=\"w-full h-full object-cover opacity-60\">\n </div>\n <div class=\"absolute bottom-1 left-2 text-xs text-white font-medium bg-black/50 px-2 py-1 rounded\">3D Waves</div>\n </button>\n </div>\n </div>\n </div>\n \n <!-- Darkness Slider -->\n <div class=\"space-y-3\">\n <label class=\"block text-sm font-medium text-white\">Background Darkness</label>\n <div class=\"flex items-center space-x-3\">\n <svg class=\"w-4 h-4 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707\"/>\n </svg>\n <input \n type=\"range\" \n id=\"darknessSlider\" \n min=\"10\" \n max=\"100\" \n value=\"20\" \n class=\"flex-1 h-2 bg-white/20 rounded-lg appearance-none cursor-pointer slider\"\n oninput=\"adjustDarkness(this.value)\"\n onchange=\"adjustDarkness(this.value)\"\n >\n <svg class=\"w-4 h-4 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z\"/>\n </svg>\n </div>\n <div class=\"text-xs text-gray-400 text-center\">Adjust overlay darkness</div>\n </div>\n </div>\n </div>\n </div>\n \n <!-- User Dropdown -->\n ${\n user\n ? `\n <div class=\"relative z-[9999]\">\n <button class=\"flex items-center space-x-3 p-2 rounded-lg hover:bg-white/10 transition-colors group\" onclick=\"toggleUserDropdown()\">\n <div class=\"w-8 h-8 bg-gradient-to-br from-green-400 to-blue-500 rounded-full flex items-center justify-center\">\n <span class=\"text-white text-sm font-medium\">${(user.name || user.email || \"U\").charAt(0).toUpperCase()}</span>\n </div>\n <div class=\"hidden md:block text-left\">\n <div class=\"text-white text-sm font-medium\">${user.name || user.email || \"User\"}</div>\n <div class=\"text-gray-400 text-xs\">${user.role || \"Administrator\"}</div>\n </div>\n <svg class=\"w-4 h-4 text-gray-400 group-hover:text-white transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"/>\n </svg>\n </button>\n \n <!-- Dropdown Menu -->\n <div class=\"userDropdown hidden absolute right-0 mt-2 w-48 backdrop-blur-md bg-black/95 rounded-xl border border-white/10 shadow-xl z-[9999]\">\n <div class=\"py-2\">\n <div class=\"px-4 py-2 border-b border-white/10\">\n <p class=\"text-sm font-medium text-gray-1\">${user.name || user.email || \"User\"}</p>\n <p class=\"text-xs text-gray-4\">${user.email || \"\"}</p>\n </div>\n <a href=\"/admin/profile\" class=\"flex items-center gap-3 px-4 py-2 text-sm text-gray-300 hover:bg-white/10 hover:text-white transition-colors\">\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"/>\n </svg>\n My Profile\n </a>\n <a href=\"/auth/logout\" class=\"flex items-center gap-3 px-4 py-2 text-sm text-red-300 hover:bg-red-500/10 hover:text-red-200 transition-colors\">\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1\"/>\n </svg>\n Sign Out\n </a>\n </div>\n </div>\n </div>\n `\n : `\n <a href=\"/auth/login\" class=\"backdrop-blur-md bg-white/10 px-4 py-2 rounded-lg text-white font-medium hover:bg-white/20 transition-all\">\n Sign In\n </a>\n `\n }\n </div>\n </div>\n </header>\n `;\n}\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\n\nexport interface CheckboxPageData {\n user?: {\n name: string\n email: string\n role: string\n }\n}\n\nexport function renderCheckboxPage(data: CheckboxPageData): string {\n const pageContent = `\n <div class=\"space-y-8\">\n <!-- Header -->\n <div class=\"sm:flex sm:items-center sm:justify-between\">\n <div>\n <h1 class=\"text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8\">Catalyst Checkboxes</h1>\n <p class=\"mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400\">\n Interactive examples using the official Catalyst checkbox component\n </p>\n </div>\n <div class=\"mt-4 sm:mt-0\">\n <a\n href=\"/admin\"\n class=\"inline-flex items-center gap-x-2 rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-700 ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 transition-colors shadow-sm\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\"/>\n </svg>\n Back to Admin\n </a>\n </div>\n </div>\n\n <!-- Example 1: Discoverability -->\n <div class=\"rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-8\">\n <h3 class=\"text-base/6 font-semibold text-zinc-950 dark:text-white mb-2\">Discoverability</h3>\n <p class=\"text-sm/6 text-zinc-500 dark:text-zinc-400 mb-6\">Decide where your events can be found across the web.</p>\n\n <fieldset>\n <legend class=\"sr-only\">Discoverability</legend>\n <div class=\"space-y-5\">\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"show_on_events_page\" type=\"checkbox\" name=\"discoverability\" checked aria-describedby=\"show-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"show_on_events_page\" class=\"font-medium text-zinc-950 dark:text-white\">Show on events page</label>\n <p id=\"show-description\" class=\"text-zinc-500 dark:text-zinc-400\">Make this event visible on your profile.</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"allow_embedding\" type=\"checkbox\" name=\"discoverability\" aria-describedby=\"embedding-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"allow_embedding\" class=\"font-medium text-zinc-950 dark:text-white\">Allow embedding</label>\n <p id=\"embedding-description\" class=\"text-zinc-500 dark:text-zinc-400\">Allow others to embed your event details on their own site.</p>\n </div>\n </div>\n </div>\n </fieldset>\n </div>\n\n <!-- Example 2: Newsletter Preferences -->\n <div class=\"rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-8\">\n <h3 class=\"text-base/6 font-semibold text-zinc-950 dark:text-white mb-2\">Newsletter Preferences</h3>\n <p class=\"text-sm/6 text-zinc-500 dark:text-zinc-400 mb-6\">Choose which updates you'd like to receive.</p>\n\n <fieldset>\n <legend class=\"sr-only\">Newsletter Preferences</legend>\n <div class=\"space-y-5\">\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"product_updates\" type=\"checkbox\" name=\"newsletter\" checked aria-describedby=\"product-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"product_updates\" class=\"font-medium text-zinc-950 dark:text-white\">Product Updates</label>\n <p id=\"product-description\" class=\"text-zinc-500 dark:text-zinc-400\">Get notified about new features and improvements.</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"weekly_digest\" type=\"checkbox\" name=\"newsletter\" aria-describedby=\"weekly-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"weekly_digest\" class=\"font-medium text-zinc-950 dark:text-white\">Weekly Digest</label>\n <p id=\"weekly-description\" class=\"text-zinc-500 dark:text-zinc-400\">Receive a summary of activity every week.</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"marketing\" type=\"checkbox\" name=\"newsletter\" aria-describedby=\"marketing-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"marketing\" class=\"font-medium text-zinc-950 dark:text-white\">Marketing Emails</label>\n <p id=\"marketing-description\" class=\"text-zinc-500 dark:text-zinc-400\">Special offers and promotional content.</p>\n </div>\n </div>\n </div>\n </fieldset>\n </div>\n\n <!-- Example 3: Privacy Settings -->\n <div class=\"rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-8\">\n <h3 class=\"text-base/6 font-semibold text-zinc-950 dark:text-white mb-2\">Privacy Settings</h3>\n <p class=\"text-sm/6 text-zinc-500 dark:text-zinc-400 mb-6\">Control your privacy and data sharing preferences.</p>\n\n <fieldset>\n <legend class=\"sr-only\">Privacy Settings</legend>\n <div class=\"space-y-5\">\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"profile_public\" type=\"checkbox\" name=\"privacy\" checked aria-describedby=\"profile-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"profile_public\" class=\"font-medium text-zinc-950 dark:text-white\">Public Profile</label>\n <p id=\"profile-description\" class=\"text-zinc-500 dark:text-zinc-400\">Make your profile visible to other users.</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"show_activity\" type=\"checkbox\" name=\"privacy\" checked aria-describedby=\"activity-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"show_activity\" class=\"font-medium text-zinc-950 dark:text-white\">Show Activity</label>\n <p id=\"activity-description\" class=\"text-zinc-500 dark:text-zinc-400\">Display your recent activity on your profile.</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n <div class=\"flex h-6 shrink-0 items-center\">\n <div class=\"group grid size-4 grid-cols-1\">\n <input id=\"analytics\" type=\"checkbox\" name=\"privacy\" aria-describedby=\"analytics-description\" class=\"col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 indeterminate:border-indigo-500 indeterminate:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 disabled:checked:bg-zinc-950/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto\" />\n <svg viewBox=\"0 0 14 14\" fill=\"none\" class=\"pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white dark:stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:checked]:opacity-100\" />\n <path d=\"M3 7H11\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"opacity-0 group-has-[:indeterminate]:opacity-100\" />\n </svg>\n </div>\n </div>\n <div class=\"text-sm/6\">\n <label for=\"analytics\" class=\"font-medium text-zinc-950 dark:text-white\">Analytics</label>\n <p id=\"analytics-description\" class=\"text-zinc-500 dark:text-zinc-400\">Help us improve by sharing anonymous usage data.</p>\n </div>\n </div>\n </div>\n </fieldset>\n </div>\n </div>\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Catalyst Checkboxes',\n pageTitle: 'Catalyst Checkboxes',\n currentPath: '/admin/checkboxes',\n user: data.user,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","export interface FormField {\n name: string\n label: string\n type: 'text' | 'email' | 'textarea' | 'select' | 'checkbox' | 'rich_text' | 'number' | 'date' | 'multi_select' | 'file'\n value?: any\n placeholder?: string\n required?: boolean\n readonly?: boolean\n helpText?: string\n options?: Array<{ value: string; label: string; selected?: boolean }>\n rows?: number\n className?: string\n validation?: {\n min?: number\n max?: number\n pattern?: string\n }\n}\n\nexport interface FormData {\n id?: string\n action?: string\n method?: string\n hxPost?: string\n hxPut?: string\n hxTarget?: string\n fields: FormField[]\n submitButtons: Array<{\n label: string\n type?: 'submit' | 'button'\n value?: string\n name?: string\n className?: string\n onclick?: string\n }>\n title?: string\n description?: string\n className?: string\n csrfToken?: string\n}\n\nexport function renderForm(data: FormData): string {\n return `\n <form \n ${data.id ? `id=\"${data.id}\"` : ''}\n ${data.hxPost ? `hx-post=\"${data.hxPost}\"` : data.hxPut ? `hx-put=\"${data.hxPut}\"` : data.action ? `action=\"${data.action}\"` : ''}\n ${data.hxTarget ? `hx-target=\"${data.hxTarget}\"` : ''}\n method=\"${data.method || 'POST'}\"\n class=\"${data.className || 'space-y-6'}\"\n ${data.fields.some(f => f.type === 'file') ? 'enctype=\"multipart/form-data\"' : ''}\n >\n ${data.csrfToken ? `<input type=\"hidden\" name=\"_csrf\" value=\"${data.csrfToken}\">` : ''}\n ${data.title ? `\n <div class=\"mb-6\">\n <h2 class=\"text-lg font-medium text-gray-1\">${data.title}</h2>\n ${data.description ? `<p class=\"mt-1 text-sm text-gray-4\">${data.description}</p>` : ''}\n </div>\n ` : ''}\n \n <div id=\"form-messages\"></div>\n \n ${data.fields.map(field => renderFormField(field)).join('')}\n \n <div class=\"flex justify-between items-center pt-6 border-t border-gray-7\">\n <div class=\"flex space-x-4\">\n ${data.submitButtons.map(button => `\n <button \n type=\"${button.type || 'submit'}\"\n ${button.name ? `name=\"${button.name}\"` : ''}\n ${button.value ? `value=\"${button.value}\"` : ''}\n ${button.onclick ? `onclick=\"${button.onclick}\"` : ''}\n class=\"btn ${button.className || 'btn-primary'}\"\n >\n ${button.label}\n </button>\n `).join('')}\n </div>\n </div>\n </form>\n `\n}\n\nexport function renderFormField(field: FormField): string {\n const fieldId = `field-${field.name}`\n const required = field.required ? 'required' : ''\n const readonly = field.readonly ? 'readonly' : ''\n const placeholder = field.placeholder ? `placeholder=\"${field.placeholder}\"` : ''\n\n let fieldHTML = ''\n\n switch (field.type) {\n case 'text':\n case 'email':\n case 'number':\n case 'date':\n fieldHTML = `\n <input\n type=\"${field.type === 'date' ? 'datetime-local' : field.type}\"\n id=\"${fieldId}\"\n name=\"${field.name}\"\n value=\"${field.value || ''}\"\n class=\"form-input ${field.className || ''}\"\n ${placeholder}\n ${required}\n ${readonly}\n ${field.validation?.min !== undefined ? `min=\"${field.validation.min}\"` : ''}\n ${field.validation?.max !== undefined ? `max=\"${field.validation.max}\"` : ''}\n ${field.validation?.pattern ? `pattern=\"${field.validation.pattern}\"` : ''}\n >\n `\n break\n \n case 'textarea':\n fieldHTML = `\n <textarea \n id=\"${fieldId}\"\n name=\"${field.name}\" \n class=\"form-textarea ${field.className || ''}\" \n rows=\"${field.rows || 4}\"\n ${placeholder}\n ${required}\n >${field.value || ''}</textarea>\n `\n break\n \n case 'rich_text':\n const uniqueId = `${field.name}-${Date.now()}`\n fieldHTML = `\n <div class=\"markdown-field\">\n <textarea id=\"${uniqueId}\" name=\"${field.name}\" class=\"form-textarea\" rows=\"8\">${field.value || ''}</textarea>\n <script>\n if (typeof EasyMDE !== 'undefined') {\n new EasyMDE({\n element: document.getElementById('${uniqueId}'),\n minHeight: '300px',\n spellChecker: false,\n status: ['autosave', 'lines', 'words', 'cursor'],\n autosave: {\n enabled: true,\n uniqueId: '${uniqueId}',\n delay: 1000\n },\n renderingConfig: {\n singleLineBreaks: false,\n codeSyntaxHighlighting: true\n }\n });\n }\n </script>\n </div>\n `\n break\n \n case 'select':\n fieldHTML = `\n <select \n id=\"${fieldId}\"\n name=\"${field.name}\" \n class=\"form-input ${field.className || ''}\" \n ${required}\n >\n ${field.options ? field.options.map(option => `\n <option value=\"${option.value}\" ${option.selected || field.value === option.value ? 'selected' : ''}>\n ${option.label}\n </option>\n `).join('') : ''}\n </select>\n `\n break\n \n case 'multi_select':\n fieldHTML = `\n <select \n id=\"${fieldId}\"\n name=\"${field.name}\" \n class=\"form-input ${field.className || ''}\" \n multiple \n ${required}\n >\n ${field.options ? field.options.map(option => `\n <option value=\"${option.value}\" ${option.selected ? 'selected' : ''}>\n ${option.label}\n </option>\n `).join('') : ''}\n </select>\n `\n break\n \n case 'checkbox':\n fieldHTML = `\n <input\n type=\"checkbox\"\n id=\"${fieldId}\"\n name=\"${field.name}\"\n value=\"1\"\n class=\"size-4 rounded border border-white/15 bg-white/5 checked:border-transparent checked:bg-white disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-white/20 focus:ring-offset-2 ${field.className || ''}\"\n ${field.value ? 'checked' : ''}\n ${required}\n >\n <label for=\"${fieldId}\" class=\"ml-2 text-sm text-white\">${field.label}</label>\n `\n break\n \n default:\n fieldHTML = `\n <input \n type=\"text\" \n id=\"${fieldId}\"\n name=\"${field.name}\" \n value=\"${field.value || ''}\"\n class=\"form-input ${field.className || ''}\" \n ${placeholder} \n ${required}\n >\n `\n break\n }\n \n // For checkbox, we handle the label differently\n if (field.type === 'checkbox') {\n return `\n <div class=\"form-group\">\n <div class=\"flex items-center\">\n ${fieldHTML}\n </div>\n ${field.helpText ? `<p class=\"text-sm text-zinc-500 dark:text-zinc-400 mt-1 ml-6\">${field.helpText}</p>` : ''}\n </div>\n `\n }\n\n return `\n <div class=\"form-group\">\n <label for=\"${fieldId}\" class=\"form-label\">\n ${field.label}${field.required ? ' *' : ''}\n </label>\n ${fieldHTML}\n ${field.helpText ? `<p class=\"text-sm text-zinc-500 dark:text-zinc-400 mt-1\">${field.helpText}</p>` : ''}\n </div>\n `\n}"]}
@@ -0,0 +1,276 @@
1
+ 'use strict';
2
+
3
+ // src/db/migrations-bundle.ts
4
+ var bundledMigrations = [
5
+ {
6
+ id: "0001",
7
+ name: "Core",
8
+ filename: "0001_core.sql",
9
+ description: "Migration 0001: Core",
10
+ sql: "-- Migration 0001: Auth tables\n-- auth_user, auth_session, auth_account, auth_verification + BA plugin tables + RBAC + auth support.\n-- Only auth_* prefixed tables live here. All content lives in document_* tables (0002_documents.sql).\n\n-- \u2500\u2500 auth_user \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n-- BA user model + SonicJS domain columns as BA additionalFields.\nCREATE TABLE IF NOT EXISTS auth_user (\n id TEXT PRIMARY KEY,\n name TEXT,\n email TEXT NOT NULL UNIQUE,\n email_verified INTEGER NOT NULL DEFAULT 0,\n image TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n -- SonicJS additionalFields\n first_name TEXT NOT NULL,\n last_name TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'viewer',\n -- Platform super-admin: bypasses the multi-tenant membership gate, uses global roles in every\n -- tenant. Opt-in (default 0); intentionally NOT derived from the 'admin' role.\n is_super_admin INTEGER NOT NULL DEFAULT 0,\n avatar TEXT,\n password_hash TEXT,\n is_active INTEGER NOT NULL DEFAULT 1,\n last_login_at INTEGER,\n phone TEXT,\n bio TEXT,\n timezone TEXT DEFAULT 'UTC',\n language TEXT DEFAULT 'en',\n email_notifications INTEGER DEFAULT 1,\n theme TEXT DEFAULT 'dark',\n invitation_token TEXT,\n invited_by TEXT,\n invited_at INTEGER,\n accepted_invitation_at INTEGER,\n failed_login_count INTEGER NOT NULL DEFAULT 0,\n locked_until INTEGER\n);\n\nCREATE INDEX IF NOT EXISTS idx_auth_user_email ON auth_user(email);\nCREATE INDEX IF NOT EXISTS idx_auth_user_role ON auth_user(role);\nCREATE INDEX IF NOT EXISTS idx_auth_user_invitation_token ON auth_user(invitation_token);\nCREATE INDEX IF NOT EXISTS idx_auth_user_locked_until ON auth_user(locked_until) WHERE locked_until IS NOT NULL;\n\n-- \u2500\u2500 auth_session \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nCREATE TABLE IF NOT EXISTS auth_session (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\n token TEXT NOT NULL UNIQUE,\n expires_at INTEGER NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_session_user_id ON auth_session(user_id);\nCREATE INDEX IF NOT EXISTS idx_auth_session_token ON auth_session(token);\nCREATE INDEX IF NOT EXISTS idx_auth_session_expires_at ON auth_session(expires_at);\n\n-- \u2500\u2500 auth_account \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nCREATE TABLE IF NOT EXISTS auth_account (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\n account_id TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n access_token TEXT,\n refresh_token TEXT,\n access_token_expires_at INTEGER,\n refresh_token_expires_at INTEGER,\n scope TEXT,\n id_token TEXT,\n password TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_account_user_id ON auth_account(user_id);\nCREATE INDEX IF NOT EXISTS idx_auth_account_provider ON auth_account(provider_id, account_id);\n\n-- \u2500\u2500 auth_verification \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n-- Covers email verification, password reset, magic-link tokens, OTP codes.\nCREATE TABLE IF NOT EXISTS auth_verification (\n id TEXT PRIMARY KEY,\n identifier TEXT NOT NULL,\n value TEXT NOT NULL,\n expires_at INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_verification_identifier ON auth_verification(identifier);\n\n-- \u2500\u2500 BA plugin tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nCREATE TABLE IF NOT EXISTS auth_two_factor (\n id TEXT PRIMARY KEY,\n secret TEXT NOT NULL,\n backup_codes TEXT NOT NULL,\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\n verified INTEGER NOT NULL DEFAULT 1,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_two_factor_user_id ON auth_two_factor(user_id);\n\nCREATE TABLE IF NOT EXISTS auth_tenant (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n slug TEXT NOT NULL UNIQUE,\n logo TEXT,\n metadata TEXT,\n -- SonicJS tenant-resolution fields (BA organization additionalFields):\n status TEXT NOT NULL DEFAULT 'active',\n domain TEXT,\n notes TEXT NOT NULL DEFAULT '',\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_domain ON auth_tenant(domain);\n\nCREATE TABLE IF NOT EXISTS auth_tenant_member (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL REFERENCES auth_tenant(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\n role TEXT NOT NULL DEFAULT 'member',\n email TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n UNIQUE(tenant_id, user_id)\n);\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_member_tenant ON auth_tenant_member(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_member_user ON auth_tenant_member(user_id);\n\nCREATE TABLE IF NOT EXISTS auth_tenant_invitation (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL REFERENCES auth_tenant(id) ON DELETE CASCADE,\n email TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'member',\n status TEXT NOT NULL DEFAULT 'pending',\n expires_at INTEGER NOT NULL,\n inviter_id TEXT REFERENCES auth_user(id) ON DELETE SET NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_invitation_tenant ON auth_tenant_invitation(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_auth_tenant_invitation_email ON auth_tenant_invitation(email);\n\nCREATE TABLE IF NOT EXISTS auth_tenant_team (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n tenant_id TEXT NOT NULL REFERENCES auth_tenant(id) ON DELETE CASCADE,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- \u2500\u2500 RBAC \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n-- RBAC roles, verbs, and user-role assignments are document-backed (is_auth doc\n-- types rbac_role / rbac_verb / rbac_user_roles \u2014 see services/rbac.ts). The\n-- system roles/verbs/grants are seeded at bootstrap by RbacService.ensureSystemRbacSeed().\n-- No auth_rbac_* tables.\n\n-- \u2500\u2500 Auth support tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nCREATE TABLE IF NOT EXISTS auth_password_history (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,\n password_hash TEXT NOT NULL,\n created_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_password_history_user_id ON auth_password_history(user_id);\n\nCREATE TABLE IF NOT EXISTS auth_api_tokens (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n token TEXT NOT NULL UNIQUE,\n user_id TEXT NOT NULL REFERENCES auth_user(id),\n permissions TEXT NOT NULL,\n expires_at INTEGER,\n last_used_at INTEGER,\n created_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_auth_api_tokens_user ON auth_api_tokens(user_id);\nCREATE INDEX IF NOT EXISTS idx_auth_api_tokens_token ON auth_api_tokens(token);\n\n-- User profiles moved to the document model: a `user_profile` document (is_auth type),\n-- one per user, addressed by slug = userId. See services/document-types-seed.ts and\n-- plugins/core-plugins/user-profiles/user-profile-document.ts. No auth_user_profiles table.\n"
11
+ },
12
+ {
13
+ id: "0002",
14
+ name: "Documents",
15
+ filename: "0002_documents.sql",
16
+ description: "Migration 0002: Documents",
17
+ sql: "-- Migration 0002: Document Schema (v3 greenfield)\n-- Contains only the new document data model tables, generated columns, and indexes.\n\n-- Document type registry\nCREATE TABLE IF NOT EXISTS document_types (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n display_name TEXT NOT NULL,\n description TEXT,\n schema TEXT NOT NULL DEFAULT '{}',\n queryable_fields TEXT NOT NULL DEFAULT '[]',\n settings TEXT NOT NULL DEFAULT '{}',\n plugin_id TEXT,\n source TEXT NOT NULL DEFAULT 'code' CHECK (source IN ('code', 'plugin', 'system')),\n schema_version INTEGER NOT NULL DEFAULT 1,\n is_system INTEGER NOT NULL DEFAULT 0,\n is_active INTEGER NOT NULL DEFAULT 1,\n is_auth INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\n);\n\nCREATE INDEX IF NOT EXISTS idx_document_types_plugin ON document_types(plugin_id);\nCREATE INDEX IF NOT EXISTS idx_document_types_active ON document_types(is_active);\n\n-- Documents: canonical document rows and historical versions.\nCREATE TABLE IF NOT EXISTS documents (\n id TEXT PRIMARY KEY,\n root_id TEXT NOT NULL,\n type_id TEXT NOT NULL REFERENCES document_types(id),\n type_version INTEGER NOT NULL DEFAULT 1,\n\n version_of_id TEXT REFERENCES documents(id),\n version_number INTEGER NOT NULL DEFAULT 1,\n\n is_current_draft INTEGER NOT NULL DEFAULT 1,\n is_published INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'published', 'archived')),\n\n parent_root_id TEXT NOT NULL DEFAULT '',\n slug TEXT,\n path TEXT,\n title TEXT,\n zone TEXT,\n sort_order INTEGER NOT NULL DEFAULT 0,\n visible INTEGER NOT NULL DEFAULT 1,\n\n published_at INTEGER,\n scheduled_at INTEGER,\n expires_at INTEGER,\n deleted_at INTEGER,\n\n tenant_id TEXT NOT NULL DEFAULT 'default',\n locale TEXT NOT NULL DEFAULT 'default',\n translation_group_id TEXT NOT NULL DEFAULT '',\n\n data TEXT NOT NULL DEFAULT '{}',\n metadata TEXT NOT NULL DEFAULT '{}',\n\n owner_id TEXT,\n created_by TEXT,\n updated_by TEXT,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\n);\n\n-- Queryable scalar fields (VIRTUAL generated columns) and their q_* filter indexes\n-- are AUTO-GENERATED at runtime from each document type's queryableFields config \u2014\n-- see DocumentTypeRegistry.register() -> ensureScalarSchema() (document-scalar-schema.ts).\n-- Do not hand-add q_* columns/indexes here; declare the field in the type instead.\n\n-- Revision chain\nCREATE INDEX IF NOT EXISTS idx_documents_root ON documents(root_id, version_number DESC);\n\n-- List / lifecycle\nCREATE INDEX IF NOT EXISTS idx_documents_published ON documents(tenant_id, type_id, locale, is_published)\n WHERE is_published = 1 AND deleted_at IS NULL;\nCREATE INDEX IF NOT EXISTS idx_documents_drafts ON documents(tenant_id, type_id, status, is_current_draft)\n WHERE is_current_draft = 1;\nCREATE INDEX IF NOT EXISTS idx_documents_parent ON documents(tenant_id, parent_root_id, sort_order, is_published);\nCREATE INDEX IF NOT EXISTS idx_documents_path ON documents(tenant_id, path);\nCREATE INDEX IF NOT EXISTS idx_documents_translation ON documents(translation_group_id, locale);\nCREATE INDEX IF NOT EXISTS idx_documents_deleted ON documents(deleted_at);\nCREATE INDEX IF NOT EXISTS idx_documents_scheduled ON documents(scheduled_at) WHERE scheduled_at IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_documents_expires ON documents(expires_at) WHERE expires_at IS NOT NULL;\n\n-- Stable keyset/cursor pagination for published lists\nCREATE INDEX IF NOT EXISTS idx_documents_published_cursor\n ON documents(tenant_id, type_id, updated_at DESC, id DESC)\n WHERE is_published = 1 AND deleted_at IS NULL;\n\n-- (q_* generated-column filter indexes are auto-created at runtime \u2014 see note above.)\n\n-- Partial unique indexes: the hard concurrency guarantees for draft/publish invariants.\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_one_current_draft\n ON documents(root_id) WHERE is_current_draft = 1;\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_one_published\n ON documents(root_id) WHERE is_published = 1;\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_unique_version\n ON documents(root_id, version_number);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_unique_slug\n ON documents(tenant_id, locale, type_id, parent_root_id, slug)\n WHERE is_current_draft = 1 AND deleted_at IS NULL AND slug IS NOT NULL;\nCREATE UNIQUE INDEX IF NOT EXISTS idx_documents_one_translation_per_locale\n ON documents(tenant_id, translation_group_id, locale)\n WHERE is_current_draft = 1 AND translation_group_id <> '';\n\n-- Document references: typed document-to-document edges.\nCREATE TABLE IF NOT EXISTS document_references (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n from_root_id TEXT NOT NULL,\n from_document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,\n field_name TEXT NOT NULL,\n ordinal INTEGER NOT NULL DEFAULT 0,\n to_root_id TEXT NOT NULL,\n ref_strength TEXT NOT NULL DEFAULT 'weak' CHECK (ref_strength IN ('strong', 'weak')),\n created_at INTEGER NOT NULL DEFAULT (unixepoch())\n);\n\nCREATE INDEX IF NOT EXISTS idx_docref_to ON document_references(tenant_id, to_root_id);\nCREATE INDEX IF NOT EXISTS idx_docref_from ON document_references(from_document_id);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_docref_unique\n ON document_references(from_document_id, field_name, ordinal);\n\n-- Document facets: indexed rows for multi-valued scalar fields (e.g. tags arrays).\nCREATE TABLE IF NOT EXISTS document_facets (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n document_id TEXT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,\n root_id TEXT NOT NULL,\n type_id TEXT NOT NULL,\n field_name TEXT NOT NULL,\n ordinal INTEGER NOT NULL DEFAULT 0,\n value_text TEXT,\n value_number REAL,\n created_at INTEGER NOT NULL DEFAULT (unixepoch())\n);\n\nCREATE INDEX IF NOT EXISTS idx_facets_lookup ON document_facets(tenant_id, type_id, field_name, value_text);\nCREATE INDEX IF NOT EXISTS idx_facets_doc ON document_facets(document_id);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_facets_unique\n ON document_facets(document_id, field_name, ordinal);\n\n-- Document permissions: per-document ACL overrides.\nCREATE TABLE IF NOT EXISTS document_permissions (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n root_id TEXT NOT NULL,\n principal_type TEXT NOT NULL CHECK (principal_type IN ('user', 'role', 'group', 'public', 'token')),\n principal_id TEXT NOT NULL,\n permission TEXT NOT NULL CHECK (permission IN ('read', 'create', 'update', 'delete', 'publish', 'manage')),\n effect TEXT NOT NULL DEFAULT 'allow' CHECK (effect IN ('allow', 'deny')),\n inherited INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n created_by TEXT\n);\n\nCREATE INDEX IF NOT EXISTS idx_document_permissions_root ON document_permissions(tenant_id, root_id);\nCREATE INDEX IF NOT EXISTS idx_document_permissions_principal\n ON document_permissions(tenant_id, principal_type, principal_id, permission);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_document_permissions_unique\n ON document_permissions(root_id, principal_type, principal_id, permission);\n"
18
+ }
19
+ ];
20
+ new Map(
21
+ bundledMigrations.map((m) => [m.id, m])
22
+ );
23
+
24
+ // src/services/document-scalar-schema.ts
25
+ var SAFE_IDENTIFIER = /^[a-z_][a-z0-9_]*$/;
26
+ function affinity(type) {
27
+ if (type === "number") return "REAL";
28
+ if (type === "integer" || type === "boolean" || type === "date") return "INTEGER";
29
+ return "TEXT";
30
+ }
31
+ var slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
32
+ function resolveColumn(typeId, f) {
33
+ if (f.column) return f.column;
34
+ const name = `q_${slug(typeId)}_${slug(f.name)}`;
35
+ return name.length <= 60 ? name : `q_${slug(typeId).slice(0, 20)}_${slug(f.name).slice(0, 20)}`;
36
+ }
37
+ async function ensureScalarSchema(db, typeId, fields) {
38
+ const scalars = fields.filter((f) => f.kind === "scalar");
39
+ if (scalars.length === 0) return [];
40
+ let existing = /* @__PURE__ */ new Set();
41
+ try {
42
+ const info = await db.prepare("SELECT name FROM pragma_table_xinfo('documents')").all();
43
+ existing = new Set((info?.results ?? []).map((r) => r.name));
44
+ } catch {
45
+ }
46
+ const added = [];
47
+ for (const f of scalars) {
48
+ const col = resolveColumn(typeId, f);
49
+ if (!SAFE_IDENTIFIER.test(col)) {
50
+ console.error(`[scalar-schema] unsafe column name '${col}' for ${typeId}.${f.name} \u2014 skipped`);
51
+ continue;
52
+ }
53
+ const path = f.path ?? `$.${f.name}`;
54
+ if (path.includes("'")) {
55
+ console.error(`[scalar-schema] unsafe json path for ${col} (${typeId}.${f.name}) \u2014 skipped`);
56
+ continue;
57
+ }
58
+ if (!existing.has(col)) {
59
+ try {
60
+ await db.prepare(`ALTER TABLE documents ADD COLUMN ${col} ${affinity(f.type)} AS (json_extract(data, '${path}')) VIRTUAL`).run();
61
+ added.push(col);
62
+ console.log(`[scalar-schema] added documents.${col} for type '${typeId}'`);
63
+ } catch (error) {
64
+ const msg = error instanceof Error ? error.message : String(error);
65
+ if (!msg.includes("duplicate column name")) {
66
+ console.error(`[scalar-schema] failed to add documents.${col}:`, msg);
67
+ continue;
68
+ }
69
+ }
70
+ }
71
+ try {
72
+ await db.prepare(`CREATE INDEX IF NOT EXISTS idx_${col} ON documents(tenant_id, type_id, ${col}, updated_at DESC, id DESC)`).run();
73
+ } catch (error) {
74
+ console.error(`[scalar-schema] failed to create idx_${col}:`, error instanceof Error ? error.message : String(error));
75
+ }
76
+ }
77
+ return added;
78
+ }
79
+
80
+ // src/services/migrations.ts
81
+ var MigrationService = class {
82
+ constructor(db) {
83
+ this.db = db;
84
+ }
85
+ /**
86
+ * Cloudflare D1 owns migration bookkeeping through `d1_migrations`.
87
+ * SonicJS intentionally does not create its own tracking table.
88
+ */
89
+ async initializeMigrationsTable() {
90
+ }
91
+ /**
92
+ * Get all available migrations from the bundled migrations
93
+ */
94
+ async getAvailableMigrations() {
95
+ const migrations = [];
96
+ const appliedMigrations = await this.getD1AppliedMigrations();
97
+ await this.ensureSchemaCompatibility();
98
+ for (const bundled of bundledMigrations) {
99
+ const applied = appliedMigrations.has(bundled.id);
100
+ const appliedData = appliedMigrations.get(bundled.id);
101
+ migrations.push({
102
+ id: bundled.id,
103
+ name: bundled.name,
104
+ filename: bundled.filename,
105
+ description: bundled.description,
106
+ applied,
107
+ appliedAt: applied ? appliedData?.applied_at : void 0,
108
+ size: bundled.sql.length
109
+ });
110
+ }
111
+ return migrations;
112
+ }
113
+ /**
114
+ * Read Wrangler/D1's canonical migration table. If the table is absent, no
115
+ * migrations have been applied by the supported migration runner yet.
116
+ */
117
+ async getD1AppliedMigrations() {
118
+ try {
119
+ const appliedResult = await this.db.prepare(
120
+ "SELECT name, applied_at FROM d1_migrations ORDER BY applied_at ASC"
121
+ ).all();
122
+ return new Map(
123
+ (appliedResult.results ?? []).map((row) => {
124
+ const filename = String(row.name ?? "");
125
+ const id = filename.match(/^(\d+)/)?.[1];
126
+ if (!id) return null;
127
+ return [id, {
128
+ id,
129
+ name: filename,
130
+ filename,
131
+ applied_at: row.applied_at
132
+ }];
133
+ }).filter((entry) => entry !== null)
134
+ );
135
+ } catch (error) {
136
+ return /* @__PURE__ */ new Map();
137
+ }
138
+ }
139
+ /**
140
+ * Run idempotent compatibility repairs that are safe outside migration state.
141
+ */
142
+ async ensureSchemaCompatibility() {
143
+ if (await this.checkTablesExist(["documents"])) {
144
+ await this.ensureDocumentGeneratedColumns();
145
+ }
146
+ }
147
+ /**
148
+ * Ensure the `documents` table exposes every queryable VIRTUAL generated column + index (D45).
149
+ * Data-driven repair: reconciles from each active type's `queryable_fields` rather than a hardcoded
150
+ * list, so it stays in sync with whatever types are registered. Generation of these columns is owned
151
+ * by DocumentTypeRegistry.register() (via ensureScalarSchema); this pass is a bootstrap safety net for
152
+ * a DB that has document_types rows but lost columns (e.g. table rebuilt). Idempotent.
153
+ */
154
+ async ensureDocumentGeneratedColumns() {
155
+ if (!await this.checkTablesExist(["document_types"])) return;
156
+ const rows = await this.db.prepare("SELECT id, queryable_fields FROM document_types WHERE is_active = 1").all();
157
+ for (const row of rows.results ?? []) {
158
+ let fields;
159
+ try {
160
+ fields = JSON.parse(row.queryable_fields);
161
+ } catch {
162
+ continue;
163
+ }
164
+ await ensureScalarSchema(this.db, row.id, fields);
165
+ }
166
+ }
167
+ /**
168
+ * Check if specific tables exist in the database
169
+ */
170
+ async checkTablesExist(tableNames) {
171
+ try {
172
+ for (const tableName of tableNames) {
173
+ const result = await this.db.prepare(
174
+ `SELECT name FROM sqlite_master WHERE type='table' AND name=?`
175
+ ).bind(tableName).first();
176
+ if (!result) {
177
+ return false;
178
+ }
179
+ }
180
+ return true;
181
+ } catch (error) {
182
+ return false;
183
+ }
184
+ }
185
+ /**
186
+ * Check if a specific column exists in a table
187
+ */
188
+ async checkColumnExists(tableName, columnName) {
189
+ try {
190
+ const result = await this.db.prepare(
191
+ `SELECT * FROM pragma_table_info(?) WHERE name = ?`
192
+ ).bind(tableName, columnName).first();
193
+ return !!result;
194
+ } catch (error) {
195
+ return false;
196
+ }
197
+ }
198
+ /**
199
+ * Get migration status summary
200
+ */
201
+ async getMigrationStatus() {
202
+ const migrations = await this.getAvailableMigrations();
203
+ const appliedMigrations = migrations.filter((m) => m.applied);
204
+ const pendingMigrations = migrations.filter((m) => !m.applied);
205
+ const lastApplied = appliedMigrations.length > 0 ? appliedMigrations[appliedMigrations.length - 1]?.appliedAt : void 0;
206
+ return {
207
+ totalMigrations: migrations.length,
208
+ appliedMigrations: appliedMigrations.length,
209
+ pendingMigrations: pendingMigrations.length,
210
+ lastApplied,
211
+ migrations
212
+ };
213
+ }
214
+ /**
215
+ * D1 migration state is managed by Wrangler.
216
+ */
217
+ async markMigrationApplied(migrationId, name, filename) {
218
+ }
219
+ /**
220
+ * D1 migration state is managed by Wrangler.
221
+ */
222
+ async removeMigrationApplied(migrationId) {
223
+ }
224
+ /**
225
+ * Check if a specific migration has been applied
226
+ */
227
+ async isMigrationApplied(migrationId) {
228
+ const appliedMigrations = await this.getD1AppliedMigrations();
229
+ return appliedMigrations.has(migrationId);
230
+ }
231
+ /**
232
+ * Get the last applied migration
233
+ */
234
+ async getLastAppliedMigration() {
235
+ const migrations = await this.getAvailableMigrations();
236
+ return migrations.filter((m) => m.applied).at(-1) ?? null;
237
+ }
238
+ /**
239
+ * Run pending migrations
240
+ */
241
+ async runPendingMigrations() {
242
+ return {
243
+ success: false,
244
+ message: "Migrations are managed by Cloudflare D1. Run `wrangler d1 migrations apply DB --local` or `wrangler d1 migrations apply DB --remote`.",
245
+ applied: [],
246
+ errors: []
247
+ };
248
+ }
249
+ /**
250
+ * Validate database schema
251
+ */
252
+ async validateSchema() {
253
+ const issues = [];
254
+ const requiredTables = [
255
+ "users",
256
+ "documents",
257
+ "document_types"
258
+ ];
259
+ for (const table of requiredTables) {
260
+ try {
261
+ await this.db.prepare(`SELECT COUNT(*) FROM ${table} LIMIT 1`).first();
262
+ } catch (error) {
263
+ issues.push(`Missing table: ${table}`);
264
+ }
265
+ }
266
+ return {
267
+ valid: issues.length === 0,
268
+ issues
269
+ };
270
+ }
271
+ };
272
+
273
+ exports.MigrationService = MigrationService;
274
+ exports.ensureScalarSchema = ensureScalarSchema;
275
+ //# sourceMappingURL=chunk-ORF4CT74.cjs.map
276
+ //# sourceMappingURL=chunk-ORF4CT74.cjs.map