@beechcms/api 0.4.0-preview.1 → 0.4.0-preview.10

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 (76) hide show
  1. package/assets/dashboard/BeechLogo.svg +18 -0
  2. package/assets/dashboard/BeechLogoLIght.svg +48 -0
  3. package/assets/dashboard/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  4. package/assets/dashboard/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  5. package/assets/dashboard/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  6. package/assets/dashboard/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  7. package/assets/dashboard/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  8. package/assets/dashboard/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  9. package/assets/dashboard/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  10. package/assets/dashboard/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  11. package/assets/dashboard/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  12. package/assets/dashboard/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  13. package/assets/dashboard/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  14. package/assets/dashboard/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  15. package/assets/dashboard/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  16. package/assets/dashboard/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  17. package/assets/dashboard/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  18. package/assets/dashboard/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  19. package/assets/dashboard/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  20. package/assets/dashboard/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  21. package/assets/dashboard/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  22. package/assets/dashboard/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  23. package/assets/dashboard/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  24. package/assets/dashboard/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  25. package/assets/dashboard/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  26. package/assets/dashboard/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  27. package/assets/dashboard/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  28. package/assets/dashboard/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  29. package/assets/dashboard/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  30. package/assets/dashboard/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  31. package/assets/dashboard/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  32. package/assets/dashboard/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  33. package/assets/dashboard/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  34. package/assets/dashboard/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  35. package/assets/dashboard/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  36. package/assets/dashboard/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  37. package/assets/dashboard/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  38. package/assets/dashboard/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  39. package/assets/dashboard/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  40. package/assets/dashboard/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  41. package/assets/dashboard/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  42. package/assets/dashboard/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  43. package/assets/dashboard/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  44. package/assets/dashboard/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  45. package/assets/dashboard/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  46. package/assets/dashboard/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  47. package/assets/dashboard/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  48. package/assets/dashboard/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  49. package/assets/dashboard/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  50. package/assets/dashboard/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  51. package/assets/dashboard/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  52. package/assets/dashboard/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  53. package/assets/dashboard/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  54. package/assets/dashboard/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  55. package/assets/dashboard/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  56. package/assets/dashboard/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  57. package/assets/dashboard/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  58. package/assets/dashboard/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  59. package/assets/dashboard/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  60. package/assets/dashboard/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  61. package/assets/dashboard/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  62. package/assets/dashboard/assets/index-CFTJe1vb.js +554 -0
  63. package/assets/dashboard/assets/index-CQODXprH.css +1 -0
  64. package/assets/dashboard/beechLogoDark.svg +48 -0
  65. package/assets/dashboard/index.html +18 -0
  66. package/assets/dashboard/sol.svg +3 -0
  67. package/assets/dashboard/undraw_clouds_bmtk.svg +1 -0
  68. package/assets/dashboard/undraw_enter_nwx3.svg +36 -0
  69. package/assets/dashboard/vite.svg +1 -0
  70. package/package.json +4 -3
  71. package/src/factory.ts +266 -8
  72. package/src/features/password-reset/request.ts +1 -1
  73. package/src/features/schema/schema.handler.ts +16 -0
  74. package/src/index.ts +6 -339
  75. package/src/search-utils.ts +5 -1
  76. package/src/types.ts +1 -0
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="811.453" height="311.372" viewBox="0 0 811.453 311.372" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" artist="Katerina Limpitsouni" source="https://undraw.co/"><g transform="translate(-411.975 -357.501)"><path d="M831.938,243.782a48.214,48.214,0,0,1,48.147-45.694c1.465,0,2.912.076,4.344.2a64.058,64.058,0,0,1,110.733-.052c1.208-.091,2.424-.152,3.656-.152a48.214,48.214,0,0,1,48.147,45.693" transform="translate(-419.962 207.558)" fill="#f2f2f2"/><path d="M844.569,239.117a48.214,48.214,0,0,1,48.147-45.694c1.465,0,2.912.076,4.344.2a64.058,64.058,0,0,1,110.733-.052c1.208-.091,2.424-.152,3.656-.152a48.214,48.214,0,0,1,48.147,45.693" transform="translate(-422.552 208.515)" fill="none" stroke="#3f3d56" stroke-miterlimit="10" stroke-width="1"/><path d="M155.988,539.473A159.577,159.577,0,0,1,315.344,388.236c4.85,0,9.639.253,14.379.677a212.017,212.017,0,0,1,366.5-.173c4-.3,8.024-.5,12.1-.5A159.577,159.577,0,0,1,867.679,539.473" transform="translate(322.013 86.835)" fill="#f2f2f2"/><path d="M197.794,524.033A159.577,159.577,0,0,1,357.15,372.8c4.85,0,9.639.253,14.379.677a212.017,212.017,0,0,1,366.5-.173c4-.3,8.024-.5,12.1-.5A159.577,159.577,0,0,1,909.485,524.033" transform="translate(313.444 90)" fill="none" stroke="#3f3d56" stroke-miterlimit="10" stroke-width="1"/><path d="M84.962,212.741a65.236,65.236,0,0,1,65.146-61.827c1.983,0,3.94.1,5.878.277a86.674,86.674,0,0,1,149.827-.071c1.635-.123,3.28-.206,4.946-.206a65.236,65.236,0,0,1,65.146,61.825" transform="translate(493.985 456.133)" fill="#d5a889"/><path d="M102.053,206.428A65.236,65.236,0,0,1,167.2,144.6c1.983,0,3.94.1,5.878.277a86.674,86.674,0,0,1,149.828-.071c1.635-.123,3.28-.206,4.946-.206A65.236,65.236,0,0,1,393,206.427" transform="translate(490.482 457.427)" fill="none" stroke="#3f3d56" stroke-miterlimit="10" stroke-width="1"/></g></svg>
@@ -0,0 +1,36 @@
1
+ <svg width="784" height="869" viewBox="0 0 784 869" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_1_2)">
3
+ <path d="M533.24 538.196C960.679 824.193 821.76 930.762 266.62 833.7C121.57 808.34 0 701.399 0 538.196C0 374.994 119.37 242.692 266.62 242.692C413.87 242.692 397.6 447.44 533.24 538.196Z" fill="#3F3D56"/>
4
+ <path opacity="0.1" d="M571.456 816.814C664.715 816.814 740.315 810.05 740.315 801.706C740.315 793.362 664.715 786.597 571.456 786.597C478.197 786.597 402.597 793.362 402.597 801.706C402.597 810.05 478.197 816.814 571.456 816.814Z" fill="black"/>
5
+ <path opacity="0.1" d="M238.428 318.814C287.857 318.814 327.928 312.05 327.928 303.706C327.928 295.362 287.857 288.598 238.428 288.598C188.998 288.598 148.928 295.362 148.928 303.706C148.928 312.05 188.998 318.814 238.428 318.814Z" fill="black"/>
6
+ <path opacity="0.1" d="M233.737 340.899C195.335 340.891 157.715 351.748 125.221 372.214C92.7278 392.68 66.687 421.921 50.1069 456.559C69.1658 435.504 92.43 418.681 118.396 407.178C144.363 395.675 172.454 389.748 200.854 389.779C313.252 389.779 404.374 480.901 404.374 593.3C404.42 623.708 397.622 653.736 384.484 681.16C418.509 643.754 437.33 594.985 437.257 544.419C437.257 432.021 346.135 340.899 233.737 340.899Z" fill="black"/>
7
+ <path opacity="0.3" d="M404.374 592.411C404.42 622.819 397.622 652.848 384.484 680.271C365.425 701.326 342.161 718.149 316.195 729.652C290.228 741.155 262.137 747.082 233.737 747.051C121.339 747.051 30.217 655.929 30.217 543.53C30.1711 513.122 36.969 483.094 50.1069 455.67C69.1658 434.615 92.43 417.792 118.396 406.289C144.363 394.786 172.454 388.859 200.854 388.891C313.252 388.891 404.374 480.013 404.374 592.411Z" fill="#D5A889"/>
8
+ <path d="M233.737 748.05C120.964 748.05 29.2168 656.303 29.2168 543.531C29.1348 512.969 35.9682 482.784 49.2051 455.238C65.8668 420.43 92.0355 391.045 124.689 370.479C157.342 349.912 195.147 339.003 233.737 339.01C346.51 339.01 438.257 430.758 438.257 543.531C438.259 570.389 432.97 596.985 422.693 621.799C412.415 646.613 397.35 669.16 378.359 688.152C359.367 707.144 336.82 722.208 312.006 732.486C287.191 742.763 260.596 748.052 233.737 748.05ZM233.737 341.01C156.248 341.01 84.5224 386.187 51.0088 456.103C37.9014 483.38 31.1352 513.268 31.2168 543.531C31.2168 655.201 122.067 746.05 233.737 746.05C260.333 746.052 286.669 740.815 311.24 730.638C335.812 720.461 358.139 705.544 376.945 686.738C395.751 667.932 410.668 645.606 420.845 621.034C431.022 596.462 436.259 570.127 436.257 543.531C436.257 431.86 345.407 341.01 233.737 341.01Z" fill="white"/>
9
+ <path d="M699.356 750.635C684.574 769.966 686.264 796.093 686.264 796.093C686.264 796.093 711.92 790.876 726.702 771.544C741.484 752.213 739.793 726.086 739.793 726.086C739.793 726.086 714.137 731.303 699.356 750.635Z" fill="#D0CDE1"/>
10
+ <path d="M709.042 754.976C706.174 779.142 686.756 796.703 686.756 796.703C686.756 796.703 671.99 775.084 674.858 750.919C677.727 726.753 697.144 709.191 697.144 709.191C697.144 709.191 711.911 730.811 709.042 754.976Z" fill="#D5A889"/>
11
+ <path d="M354.901 190.533C354.942 274.417 305.088 303.727 243.578 303.756C242.149 303.757 240.727 303.742 239.312 303.711C236.461 303.651 233.64 303.522 230.849 303.325C175.332 299.421 132.182 268.653 132.144 190.641C132.105 109.908 235.238 7.97471 242.972 0.4377C242.979 0.4377 242.979 0.437699 242.986 0.430849C243.28 0.143599 243.43 0 243.43 0C243.43 0 354.861 106.655 354.901 190.533Z" fill="#D5A889"/>
12
+ <path d="M239.518 290.927L280.226 233.991L239.418 297.175L239.312 303.711C236.461 303.651 233.64 303.522 230.849 303.325L235.197 219.405L235.162 218.755L235.237 218.632L235.651 210.702L194.679 147.4L235.771 204.762L235.874 206.443L239.159 143.038L204.079 77.6211L239.584 131.895L242.972 0.437694L242.986 0.000213623L242.986 0.430842L242.462 104.099L277.326 62.9838L242.316 113.027L241.421 169.8L273.981 115.301L241.295 178.147L240.798 209.715L288.052 133.854L240.618 220.728L239.518 290.927Z" fill="#3F3D56"/>
13
+ <path d="M572.956 238.594C562.281 220.557 541.162 219.716 541.162 219.716C541.162 219.716 520.583 217.085 507.382 244.555C495.077 270.159 478.095 294.881 504.648 300.875L509.444 285.947L512.414 301.986C516.195 302.258 519.988 302.323 523.775 302.181C552.211 301.263 579.292 302.449 578.42 292.245C577.261 278.68 583.227 255.949 572.956 238.594Z" fill="#2F2E41"/>
14
+ <path d="M525.862 407.843L528.608 435.301L592.22 428.437L593.593 407.843H525.862Z" fill="#A0616A"/>
15
+ <path d="M518.998 422.945L517.167 438.962C517.167 438.962 496.116 468.251 497.946 518.592C499.777 568.933 469.115 792.72 491.081 794.55C513.048 796.381 552.405 799.127 554.236 792.262C556.067 785.398 559.728 524.999 559.728 524.999C559.728 524.999 569.338 792.587 585.813 793.502C602.289 794.418 657.663 796.248 657.663 789.384C657.663 782.519 609.153 476.031 609.153 476.031L601.373 450.403L593.593 418.826C593.593 418.826 545.083 427.064 531.812 423.86C518.54 420.657 518.998 422.945 518.998 422.945Z" fill="#2F2E41"/>
16
+ <path d="M540.964 296.178C557.14 296.178 570.254 283.065 570.254 266.889C570.254 250.713 557.14 237.6 540.964 237.6C524.789 237.6 511.675 250.713 511.675 266.889C511.675 283.065 524.789 296.178 540.964 296.178Z" fill="#A0616A"/>
17
+ <path d="M592.22 315.399L586.66 323.49L583.1 328.666L577.118 337.366L547.371 339.654C547.371 339.654 540.145 337.32 531.807 333.911C528.727 332.648 525.492 331.238 522.416 329.742C510.485 323.948 500.912 316.877 511.675 312.195C513.587 311.375 515.423 310.389 517.162 309.248C518.745 308.214 520.219 307.021 521.56 305.688C524.318 302.925 526.359 299.531 527.508 295.8C528.656 292.069 528.877 288.115 528.15 284.279L556.982 280.161C556.144 287.474 563.416 295.45 571.567 301.963C574.244 304.109 577.022 306.091 579.635 307.839C586.486 312.424 592.22 315.399 592.22 315.399Z" fill="#A0616A"/>
18
+ <path d="M552.863 324.094C552.863 324.094 524.718 319.289 518.311 309.221C518.311 309.221 490.624 312.653 492.912 327.298C495.2 341.942 518.082 422.03 518.082 422.03C518.082 422.03 575.288 411.046 596.339 419.284L609.153 317.23C609.153 317.23 604.577 307.161 595.882 309.907C587.186 312.653 583.754 310.136 583.754 310.136C583.754 310.136 573.915 324.094 552.863 324.094Z" fill="#D0CDE1"/>
19
+ <path d="M578.491 484.727C578.491 484.727 598.17 506.693 587.186 510.355C576.203 514.016 562.931 495.71 562.931 495.71L578.491 484.727Z" fill="#A0616A"/>
20
+ <path d="M584.898 486.557C584.898 486.557 568.881 497.541 574.83 504.863C580.779 512.185 601.373 498.456 601.373 495.71C601.373 492.964 584.898 486.557 584.898 486.557Z" fill="#A0616A"/>
21
+ <path d="M545.541 427.064L532.269 429.352L523.574 364.824C524.076 353.118 523.689 341.39 522.416 329.742C521.446 321.962 519.826 314.484 517.162 309.248C518.745 308.214 520.219 307.021 521.56 305.688C524.746 310.736 530.558 321.426 531.807 333.911C532.134 337.037 532.135 340.189 531.812 343.315C529.523 364.824 529.981 368.943 529.981 368.943L545.541 427.064Z" fill="#2F2E41"/>
22
+ <path d="M514.879 313.111C514.879 313.111 493.37 307.161 491.539 319.975C489.709 332.789 491.997 365.74 497.031 378.096C502.065 390.452 519.455 430.725 519.455 430.725C519.455 430.725 551.033 470.997 552.406 480.608C553.778 490.218 560.643 500.286 560.643 500.286L582.61 486.1L539.591 413.334L520.828 362.994C520.828 362.994 528.608 317.23 514.879 313.111Z" fill="#D0CDE1"/>
23
+ <path d="M599.085 314.941L609.153 317.23C609.153 317.23 618.306 356.587 614.645 377.638C610.984 398.69 610.526 406.012 610.526 406.012L607.323 465.963C607.323 465.963 608.238 504.405 601.831 498.456C595.424 492.507 582.61 489.761 582.61 489.761C582.61 489.761 583.983 472.828 589.017 468.709C589.017 468.709 594.966 437.132 591.305 423.403C587.644 409.673 599.085 314.941 599.085 314.941Z" fill="#D0CDE1"/>
24
+ <path d="M602.746 359.333L591.076 426.835L583.983 423.86L596.339 359.333L583.1 328.666L571.567 301.963C574.244 304.109 577.022 306.091 579.635 307.839L586.66 323.49L602.746 359.333Z" fill="#2F2E41"/>
25
+ <path d="M568.236 236.855L547.372 225.926L518.559 230.397L512.598 256.726L527.437 256.155L531.583 246.482V255.996L538.43 255.732L542.404 240.332L544.888 256.726L569.23 256.229L568.236 236.855Z" fill="#2F2E41"/>
26
+ <path d="M527.019 801.706C534.873 801.706 541.239 799.319 541.239 796.374C541.239 793.429 534.873 791.041 527.019 791.041C519.166 791.041 512.8 793.429 512.8 796.374C512.8 799.319 519.166 801.706 527.019 801.706Z" fill="#2F2E41"/>
27
+ <path d="M623.003 801.706C630.856 801.706 637.222 799.319 637.222 796.374C637.222 793.429 630.856 791.041 623.003 791.041C615.149 791.041 608.783 793.429 608.783 796.374C608.783 799.319 615.149 801.706 623.003 801.706Z" fill="#2F2E41"/>
28
+ <path d="M263.546 648.795C249 658.26 232.238 663.769 214.913 664.778C197.589 665.788 180.3 662.262 164.754 654.549L166.955 650.059C185.694 659.265 206.933 662.076 227.422 658.063C247.91 654.049 266.519 643.433 280.399 627.838C294.28 612.242 302.668 592.528 304.279 571.713C305.89 550.897 300.635 530.127 289.319 512.582C278.003 495.037 261.249 481.683 241.623 474.566C221.996 467.448 200.577 466.958 180.645 473.17C160.713 479.383 143.366 491.956 131.259 508.966C119.153 525.975 112.954 546.483 113.611 567.35L108.613 567.503C108.059 549.946 112.117 532.549 120.382 517.048C128.648 501.548 140.831 488.484 155.719 479.159C170.606 469.835 187.678 464.575 205.231 463.905C222.785 463.234 240.208 467.176 255.764 475.338C271.319 483.5 284.464 495.596 293.887 510.421C303.311 525.246 308.684 542.282 309.471 559.831C310.258 577.38 306.432 594.829 298.374 610.439C290.316 626.048 278.308 639.273 263.546 648.795Z" fill="white"/>
29
+ <path d="M218.318 558.375C203.532 561.648 183.855 563.642 169.517 561.56L187.516 575.266L137.128 607.765L139.838 611.967L190.226 579.468L195.292 601.522C199.308 587.602 209.241 570.499 218.318 558.375Z" fill="white"/>
30
+ </g>
31
+ <defs>
32
+ <clipPath id="clip0_1_2">
33
+ <rect width="783.928" height="868.734" fill="white"/>
34
+ </clipPath>
35
+ </defs>
36
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@beechcms/api",
3
- "version": "0.4.0-preview.1",
3
+ "version": "0.4.0-preview.10",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/factory.ts"
7
7
  },
8
8
  "files": [
9
9
  "src/",
10
- "migrations/0000_v040_base.sql"
10
+ "migrations/0000_v040_base.sql",
11
+ "assets/"
11
12
  ],
12
13
  "scripts": {
13
14
  "dev": "wrangler dev --port 8789",
@@ -21,7 +22,7 @@
21
22
  },
22
23
  "dependencies": {
23
24
  "@aws-sdk/client-s3": "^3.995.0",
24
- "@beechcms/core": "^0.4.0-preview.1",
25
+ "@beechcms/core": "^0.4.0-preview.10",
25
26
  "bcryptjs": "^2.4.3",
26
27
  "hono": "^4.11.9",
27
28
  "jose": "^6.1.3"
package/src/factory.ts CHANGED
@@ -1,31 +1,106 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
  import { Hono } from 'hono'
3
3
  import { cors } from 'hono/cors'
4
+ import { getCookie, setCookie, deleteCookie } from 'hono/cookie'
4
5
  import type { Seed } from '@beechcms/core'
5
6
  import type { Env, Variables } from './types'
6
7
 
8
+ // Imports delle rotte e middleware
9
+ import { AUTH_ERRORS } from './auth/constants'
10
+ import {
11
+ parseLoginBody,
12
+ validateLoginInput,
13
+ findUserByEmail,
14
+ verifyPassword,
15
+ DUMMY_PASSWORD_HASH,
16
+ } from './auth/login'
17
+ import {
18
+ generateRefreshToken,
19
+ saveRefreshToken,
20
+ generateAccessToken,
21
+ validateRefreshToken,
22
+ revokeRefreshToken,
23
+ } from './auth/refresh'
24
+ import { authMiddleware } from './middleware'
25
+ import { contentRoutes } from './content'
26
+ import { widgetApp } from './widget'
27
+ import { rotateFieldApp } from './features/rotate-field'
28
+ import { passwordResetApp } from './features/password-reset'
29
+ import { setupApp } from './features/setup'
30
+ import { draftApp } from './features/draft'
31
+ import { settingsApp } from './features/settings/settings.handler'
32
+ import { schemaApp } from './features/schema/schema.handler'
33
+ import { notificationsApp } from './features/notifications'
34
+ import { statsApp } from './features/stats'
35
+ import { uploadRoutes, serveMediaHandler } from './upload'
36
+ import { publicRoutes, apiKeyMiddleware, publicRateLimitMiddleware } from './public'
37
+ import { searchRouter } from "./search"
38
+
7
39
  export interface BeechConfig {
8
- seeds: Seed[]
40
+ seeds: Seed[] | Record<string, Seed>
41
+ }
42
+
43
+ // --- Costanti e helper ---
44
+ const REFRESH_TOKEN_EXPIRY_DAYS = 7
45
+ const SECONDS_PER_DAY = 24 * 60 * 60
46
+
47
+ function isRequestSecure(url: string): boolean {
48
+ return new URL(url).protocol === 'https:'
49
+ }
50
+
51
+ function getClientIp(headers: Headers): string {
52
+ return headers.get('cf-connecting-ip') ?? 'unknown'
53
+ }
54
+
55
+ function getRefreshTokenCookieOptions(secure: boolean) {
56
+ return {
57
+ httpOnly: true,
58
+ secure,
59
+ sameSite: 'Strict' as const,
60
+ maxAge: REFRESH_TOKEN_EXPIRY_DAYS * SECONDS_PER_DAY,
61
+ path: '/auth',
62
+ }
63
+ }
64
+
65
+ function getRefreshTokenDeleteCookieOptions(secure: boolean) {
66
+ return {
67
+ httpOnly: true,
68
+ secure,
69
+ sameSite: 'Strict' as const,
70
+ path: '/auth',
71
+ }
72
+ }
73
+
74
+ function handleAuthError(c: any, err: unknown, operationName: string): Response {
75
+ if (c.env.ENV !== 'production') {
76
+ console.error(`${operationName} error:`, err)
77
+ }
78
+ return c.json({ error: AUTH_ERRORS.GENERIC_ERROR }, 500)
79
+ }
80
+
81
+ function extractPublicSeed(path: string): string {
82
+ const match = path.match(/^\/api\/v1\/public\/([^/?]+)/)
83
+ return match ? match[1] : ''
9
84
  }
10
85
 
11
86
  /**
12
87
  * Builds a fully configured Hono app with the given seeds injected into context.
13
- * Seeds are available in every handler via c.get('getSeed') and c.get('seedRegistry').
88
+ * This is the main entry point for a BeechCMS project.
14
89
  */
15
90
  export function createBeechApp(config: BeechConfig): Hono<{ Bindings: Env; Variables: Variables }> {
16
- const registry: Record<string, Seed> = Object.fromEntries(config.seeds.map(s => [s.slug, s]))
91
+ const seedsArray = Array.isArray(config.seeds) ? config.seeds : Object.values(config.seeds)
92
+ const registry: Record<string, Seed> = Object.fromEntries(seedsArray.map(s => [s.slug, s]))
17
93
  const getSeedFn = (slug: string): Seed | null => registry[slug] ?? null
18
94
 
19
95
  const app = new Hono<{ Bindings: Env; Variables: Variables }>()
20
96
 
21
- // Inject seed registry into every request context
97
+ // 1. Core Middleware (Seeds, CORS, Security)
22
98
  app.use('*', async (c, next) => {
23
99
  c.set('getSeed', getSeedFn)
24
100
  c.set('seedRegistry', registry)
25
101
  await next()
26
102
  })
27
103
 
28
- // CORS
29
104
  app.use('*', async (c, next) => {
30
105
  const origins = (c.env.CORS_ORIGINS ?? 'http://localhost:5173')
31
106
  .split(',')
@@ -33,8 +108,19 @@ export function createBeechApp(config: BeechConfig): Hono<{ Bindings: Env; Varia
33
108
  .filter(Boolean)
34
109
  return cors({
35
110
  origin: (origin) => {
36
- if (!origin) return origins[0] ?? null
37
- return origins.includes(origin) ? origin : null
111
+ // If same-origin (no Origin header) or matched in CORS_ORIGINS
112
+ if (!origin || origins.includes(origin)) return origin || origins[0]
113
+
114
+ // Allow same-origin if the host matches
115
+ try {
116
+ const originUrl = new URL(origin)
117
+ const requestUrl = new URL(c.req.url)
118
+ if (originUrl.hostname === requestUrl.hostname && originUrl.port === requestUrl.port) {
119
+ return origin
120
+ }
121
+ } catch {}
122
+
123
+ return null
38
124
  },
39
125
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
40
126
  allowHeaders: ['Content-Type', 'Authorization', 'X-API-Key'],
@@ -42,9 +128,9 @@ export function createBeechApp(config: BeechConfig): Hono<{ Bindings: Env; Varia
42
128
  })(c, next)
43
129
  })
44
130
 
45
- // Security headers
46
131
  app.use('*', async (c, next) => {
47
132
  await next()
133
+ if (c.req.path.startsWith('/admin')) return
48
134
  c.header('X-Frame-Options', 'DENY')
49
135
  c.header('X-Content-Type-Options', 'nosniff')
50
136
  c.header('Referrer-Policy', 'strict-origin-when-cross-origin')
@@ -52,5 +138,177 @@ export function createBeechApp(config: BeechConfig): Hono<{ Bindings: Env; Varia
52
138
  c.header('Content-Security-Policy', "default-src 'self'; frame-ancestors 'none'")
53
139
  })
54
140
 
141
+ // 2. Analytics Middleware
142
+ app.use('/api/*', async (c, next) => {
143
+ await next()
144
+ if (c.req.method !== 'OPTIONS' && c.res.status >= 200 && c.res.status < 300) {
145
+ const db = c.env.DB
146
+ let executionCtx: any
147
+ try { executionCtx = c.executionCtx } catch {}
148
+
149
+ if (db && executionCtx) {
150
+ const seed = extractPublicSeed(c.req.path)
151
+ executionCtx.waitUntil((async () => {
152
+ try {
153
+ const today = Math.floor(new Date().setHours(0, 0, 0, 0) / 1000)
154
+ await db.prepare(
155
+ `INSERT INTO analytics (day_ts, metric, seed, value)
156
+ VALUES (?, 'requests', ?, 1)
157
+ ON CONFLICT(day_ts, metric, seed) DO UPDATE SET value = value + 1`
158
+ ).bind(today, seed).run()
159
+ } catch (err) {
160
+ console.error('Analytics middleware error:', err)
161
+ }
162
+ })())
163
+ }
164
+ }
165
+ })
166
+
167
+ // 3. Auth Routes
168
+ app.post('/auth/login', async (c) => {
169
+ try {
170
+ let body: any
171
+ try { body = await c.req.json() } catch { return c.json({ error: AUTH_ERRORS.INVALID_REQUEST }, 400) }
172
+ const credentials = parseLoginBody(body)
173
+ if (!credentials) return c.json({ error: AUTH_ERRORS.INVALID_REQUEST }, 400)
174
+ const { email, password } = credentials
175
+ if (!validateLoginInput(email, password)) return c.json({ error: AUTH_ERRORS.INVALID_REQUEST }, 400)
176
+
177
+ const loginLimiter = c.env.LOGIN_RATE_LIMITER
178
+ if (loginLimiter) {
179
+ const clientIp = getClientIp(c.req.raw.headers)
180
+ const { success } = await loginLimiter.limit({ key: `${clientIp}:${email}` })
181
+ if (!success) return c.json({ error: AUTH_ERRORS.RATE_LIMIT_EXCEEDED }, 429)
182
+ }
183
+
184
+ const { DB, JWT_SECRET } = c.env
185
+ const user = await findUserByEmail(DB, email)
186
+ const hashToCompare = user?.password_hash ?? DUMMY_PASSWORD_HASH
187
+ const isValid = await verifyPassword(password, hashToCompare)
188
+
189
+ if (!user || !isValid) return c.json({ error: AUTH_ERRORS.INVALID_CREDENTIALS }, 401)
190
+
191
+ const userProfile = await DB.prepare('SELECT name FROM users WHERE id = ? LIMIT 1').bind(user.id).first<{ name: string | null }>()
192
+ const accessToken = await generateAccessToken(user.id, user.email, JWT_SECRET, {
193
+ issuer: c.env.JWT_ISSUER,
194
+ audience: c.env.JWT_AUDIENCE,
195
+ }, userProfile?.name ?? undefined)
196
+ const refreshToken = generateRefreshToken()
197
+
198
+ await saveRefreshToken(DB, user.id, refreshToken, REFRESH_TOKEN_EXPIRY_DAYS)
199
+ setCookie(c, 'refresh_token', refreshToken, getRefreshTokenCookieOptions(isRequestSecure(c.req.url)))
200
+ return c.json({ token: accessToken, expiresIn: '15m' }, 200)
201
+ } catch (err) {
202
+ return handleAuthError(c, err, 'Login')
203
+ }
204
+ })
205
+
206
+ app.post('/auth/refresh', async (c) => {
207
+ try {
208
+ const refreshLimiter = c.env.REFRESH_RATE_LIMITER
209
+ if (refreshLimiter) {
210
+ const clientIp = getClientIp(c.req.raw.headers)
211
+ const { success } = await refreshLimiter.limit({ key: clientIp })
212
+ if (!success) return c.json({ error: AUTH_ERRORS.RATE_LIMIT_EXCEEDED }, 429)
213
+ }
214
+
215
+ const refreshToken = getCookie(c, 'refresh_token')
216
+ if (!refreshToken) return c.json({ error: 'Refresh token missing' }, 401)
217
+
218
+ const { DB, JWT_SECRET } = c.env
219
+ const validation = await validateRefreshToken(DB, refreshToken)
220
+ if (!validation.valid || !validation.userId) return c.json({ error: 'Invalid refresh token' }, 401)
221
+
222
+ const user = await DB.prepare('SELECT id, email, name FROM users WHERE id = ? LIMIT 1').bind(validation.userId).first<{ id: string; email: string; name: string | null }>()
223
+ if (!user) return c.json({ error: 'User not found' }, 401)
224
+
225
+ const revoked = await revokeRefreshToken(DB, refreshToken)
226
+ if (!revoked) return c.json({ error: 'Invalid refresh token' }, 401)
227
+
228
+ const newAccessToken = await generateAccessToken(user.id, user.email, JWT_SECRET, {
229
+ issuer: c.env.JWT_ISSUER,
230
+ audience: c.env.JWT_AUDIENCE,
231
+ }, user.name ?? undefined)
232
+ const newRefreshToken = generateRefreshToken()
233
+
234
+ await saveRefreshToken(DB, user.id, newRefreshToken, REFRESH_TOKEN_EXPIRY_DAYS)
235
+ setCookie(c, 'refresh_token', newRefreshToken, getRefreshTokenCookieOptions(isRequestSecure(c.req.url)))
236
+ return c.json({ token: newAccessToken, expiresIn: '15m' }, 200)
237
+ } catch (err) {
238
+ return handleAuthError(c, err, 'Refresh')
239
+ }
240
+ })
241
+
242
+ app.post('/auth/logout', async (c) => {
243
+ try {
244
+ const refreshToken = getCookie(c, 'refresh_token')
245
+ if (refreshToken) await revokeRefreshToken(c.env.DB, refreshToken)
246
+ deleteCookie(c, 'refresh_token', getRefreshTokenDeleteCookieOptions(isRequestSecure(c.req.url)))
247
+ return c.json({ message: 'Logged out' }, 200)
248
+ } catch (err) {
249
+ return handleAuthError(c, err, 'Logout')
250
+ }
251
+ })
252
+
253
+ // 4. Setup & Password Reset
254
+ app.route('/', setupApp)
255
+ app.route('/', passwordResetApp)
256
+
257
+ // 5. Protected CMS API
258
+ const apiProtected = new Hono<{ Bindings: Env; Variables: Variables }>()
259
+ apiProtected.use('*', async (c, next) => {
260
+ await authMiddleware(c.env.JWT_SECRET, {
261
+ issuer: c.env.JWT_ISSUER,
262
+ audience: c.env.JWT_AUDIENCE,
263
+ })(c, next)
264
+ })
265
+
266
+ apiProtected.route('/settings', settingsApp)
267
+ apiProtected.route('/schema', schemaApp)
268
+ apiProtected.route('/content', notificationsApp)
269
+ apiProtected.route('/content', statsApp)
270
+ apiProtected.route('/content', rotateFieldApp)
271
+ apiProtected.route('/content', draftApp)
272
+ apiProtected.route('/content', contentRoutes)
273
+ apiProtected.route('/widget', widgetApp)
274
+
275
+ app.route('/api', apiProtected)
276
+ app.route('/api/search', searchRouter)
277
+ app.route('/api', uploadRoutes)
278
+ app.get('/api/media/:key', (c) => serveMediaHandler(c))
279
+
280
+ // 6. Public API
281
+ const apiPublic = new Hono<{ Bindings: Env; Variables: Variables }>()
282
+ apiPublic.use('*', publicRateLimitMiddleware())
283
+ apiPublic.use('*', apiKeyMiddleware())
284
+ apiPublic.route('/', publicRoutes)
285
+ app.route('/api/v1/public', apiPublic)
286
+
287
+ // 7. Dashboard SPA — serve static assets from Workers Assets binding
288
+ app.get('/admin', (c) => c.redirect('/admin/', 301))
289
+ app.get('/admin/*', async (c) => {
290
+ if (!c.env.ASSETS) {
291
+ return c.text('Dashboard not configured. Set up the ASSETS binding in wrangler.toml pointing to node_modules/@beechcms/api/assets/dashboard', 503)
292
+ }
293
+ const url = new URL(c.req.url)
294
+ const originalPath = url.pathname
295
+ url.pathname = originalPath.replace(/^\/admin/, '') || '/'
296
+
297
+ let assetResponse = await c.env.ASSETS.fetch(new Request(url.toString(), c.req.raw))
298
+ if (assetResponse.status === 404) {
299
+ // SPA fallback: any unmatched /admin/* route serves index.html
300
+ assetResponse = await c.env.ASSETS.fetch(new Request(new URL('/index.html', c.req.url)))
301
+ }
302
+ // ASSETS returns an immutable Response — wrap it to inject security headers
303
+ const headers = new Headers(assetResponse.headers)
304
+ headers.set('Content-Security-Policy',
305
+ "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self'; frame-ancestors 'none'"
306
+ )
307
+ headers.set('X-Frame-Options', 'DENY')
308
+ headers.set('X-Content-Type-Options', 'nosniff')
309
+ headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
310
+ return new Response(assetResponse.body, { status: assetResponse.status, headers })
311
+ })
312
+
55
313
  return app
56
314
  }
@@ -67,7 +67,7 @@ export async function requestPasswordReset(
67
67
  .run()
68
68
 
69
69
  const appUrl = (c.env.APP_URL ?? new URL(c.req.url).origin).replace(/\/$/, '')
70
- const resetUrl = `${appUrl}/reset-password?token=${token}`
70
+ const resetUrl = `${appUrl}/admin/reset-password?token=${token}`
71
71
 
72
72
  try {
73
73
  await sendPasswordResetEmail({
@@ -0,0 +1,16 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { Hono } from 'hono'
3
+ import type { Env, Variables } from '../../types'
4
+
5
+ const schemaApp = new Hono<{ Bindings: Env; Variables: Variables }>()
6
+
7
+ /**
8
+ * Ritorna l'intero schema del CMS (la lista dei Seed configurati).
9
+ * Usato dalla Dashboard per generare dinamicamente il menu e le form.
10
+ */
11
+ schemaApp.get('/', async (c) => {
12
+ const registry = c.get('seedRegistry')
13
+ return c.json(Object.values(registry))
14
+ })
15
+
16
+ export { schemaApp }