alepha 0.15.2 → 0.15.4

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 (180) hide show
  1. package/README.md +68 -80
  2. package/dist/api/audits/index.d.ts.map +1 -1
  3. package/dist/api/audits/index.js +8 -0
  4. package/dist/api/audits/index.js.map +1 -1
  5. package/dist/api/files/index.d.ts +170 -170
  6. package/dist/api/files/index.d.ts.map +1 -1
  7. package/dist/api/files/index.js +1 -0
  8. package/dist/api/files/index.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/jobs/index.js +3 -0
  11. package/dist/api/jobs/index.js.map +1 -1
  12. package/dist/api/notifications/index.browser.js +1 -0
  13. package/dist/api/notifications/index.browser.js.map +1 -1
  14. package/dist/api/notifications/index.js +1 -0
  15. package/dist/api/notifications/index.js.map +1 -1
  16. package/dist/api/parameters/index.d.ts +260 -260
  17. package/dist/api/parameters/index.d.ts.map +1 -1
  18. package/dist/api/parameters/index.js +10 -0
  19. package/dist/api/parameters/index.js.map +1 -1
  20. package/dist/api/users/index.d.ts +12 -1
  21. package/dist/api/users/index.d.ts.map +1 -1
  22. package/dist/api/users/index.js +18 -2
  23. package/dist/api/users/index.js.map +1 -1
  24. package/dist/batch/index.d.ts +4 -4
  25. package/dist/bucket/index.d.ts +8 -0
  26. package/dist/bucket/index.d.ts.map +1 -1
  27. package/dist/bucket/index.js +7 -2
  28. package/dist/bucket/index.js.map +1 -1
  29. package/dist/cli/index.d.ts +196 -74
  30. package/dist/cli/index.d.ts.map +1 -1
  31. package/dist/cli/index.js +234 -50
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/command/index.d.ts +10 -0
  34. package/dist/command/index.d.ts.map +1 -1
  35. package/dist/command/index.js +67 -13
  36. package/dist/command/index.js.map +1 -1
  37. package/dist/core/index.browser.js +28 -21
  38. package/dist/core/index.browser.js.map +1 -1
  39. package/dist/core/index.d.ts.map +1 -1
  40. package/dist/core/index.js +28 -21
  41. package/dist/core/index.js.map +1 -1
  42. package/dist/core/index.native.js +28 -21
  43. package/dist/core/index.native.js.map +1 -1
  44. package/dist/email/index.d.ts +21 -13
  45. package/dist/email/index.d.ts.map +1 -1
  46. package/dist/email/index.js +10561 -4
  47. package/dist/email/index.js.map +1 -1
  48. package/dist/lock/core/index.d.ts +6 -1
  49. package/dist/lock/core/index.d.ts.map +1 -1
  50. package/dist/lock/core/index.js +9 -1
  51. package/dist/lock/core/index.js.map +1 -1
  52. package/dist/mcp/index.d.ts +5 -5
  53. package/dist/orm/index.bun.js +32 -16
  54. package/dist/orm/index.bun.js.map +1 -1
  55. package/dist/orm/index.d.ts +4 -1
  56. package/dist/orm/index.d.ts.map +1 -1
  57. package/dist/orm/index.js +34 -22
  58. package/dist/orm/index.js.map +1 -1
  59. package/dist/react/auth/index.browser.js +2 -1
  60. package/dist/react/auth/index.browser.js.map +1 -1
  61. package/dist/react/auth/index.js +2 -1
  62. package/dist/react/auth/index.js.map +1 -1
  63. package/dist/react/core/index.d.ts +3 -3
  64. package/dist/react/router/index.browser.js +9 -15
  65. package/dist/react/router/index.browser.js.map +1 -1
  66. package/dist/react/router/index.d.ts +305 -407
  67. package/dist/react/router/index.d.ts.map +1 -1
  68. package/dist/react/router/index.js +581 -781
  69. package/dist/react/router/index.js.map +1 -1
  70. package/dist/scheduler/index.d.ts +13 -1
  71. package/dist/scheduler/index.d.ts.map +1 -1
  72. package/dist/scheduler/index.js +42 -4
  73. package/dist/scheduler/index.js.map +1 -1
  74. package/dist/security/index.d.ts +42 -42
  75. package/dist/security/index.d.ts.map +1 -1
  76. package/dist/security/index.js +8 -7
  77. package/dist/security/index.js.map +1 -1
  78. package/dist/server/auth/index.d.ts +167 -167
  79. package/dist/server/compress/index.d.ts.map +1 -1
  80. package/dist/server/compress/index.js +1 -0
  81. package/dist/server/compress/index.js.map +1 -1
  82. package/dist/server/health/index.d.ts +17 -17
  83. package/dist/server/links/index.d.ts +39 -39
  84. package/dist/server/links/index.js +1 -1
  85. package/dist/server/links/index.js.map +1 -1
  86. package/dist/server/static/index.js +7 -2
  87. package/dist/server/static/index.js.map +1 -1
  88. package/dist/server/swagger/index.d.ts +8 -0
  89. package/dist/server/swagger/index.d.ts.map +1 -1
  90. package/dist/server/swagger/index.js +7 -2
  91. package/dist/server/swagger/index.js.map +1 -1
  92. package/dist/sms/index.d.ts +8 -0
  93. package/dist/sms/index.d.ts.map +1 -1
  94. package/dist/sms/index.js +7 -2
  95. package/dist/sms/index.js.map +1 -1
  96. package/dist/system/index.browser.js +734 -12
  97. package/dist/system/index.browser.js.map +1 -1
  98. package/dist/system/index.d.ts +8 -0
  99. package/dist/system/index.d.ts.map +1 -1
  100. package/dist/system/index.js +7 -2
  101. package/dist/system/index.js.map +1 -1
  102. package/dist/vite/index.d.ts +3 -2
  103. package/dist/vite/index.d.ts.map +1 -1
  104. package/dist/vite/index.js +42 -8
  105. package/dist/vite/index.js.map +1 -1
  106. package/dist/websocket/index.d.ts +34 -34
  107. package/dist/websocket/index.d.ts.map +1 -1
  108. package/package.json +9 -4
  109. package/src/api/audits/controllers/AdminAuditController.ts +8 -0
  110. package/src/api/files/controllers/AdminFileStatsController.ts +1 -0
  111. package/src/api/jobs/controllers/AdminJobController.ts +3 -0
  112. package/src/api/logs/TODO.md +13 -10
  113. package/src/api/notifications/controllers/AdminNotificationController.ts +1 -0
  114. package/src/api/parameters/controllers/AdminConfigController.ts +10 -0
  115. package/src/api/users/controllers/AdminIdentityController.ts +3 -0
  116. package/src/api/users/controllers/AdminSessionController.ts +3 -0
  117. package/src/api/users/controllers/AdminUserController.ts +5 -0
  118. package/src/cli/apps/AlephaPackageBuilderCli.ts +9 -0
  119. package/src/cli/atoms/buildOptions.ts +99 -9
  120. package/src/cli/commands/build.ts +150 -32
  121. package/src/cli/commands/db.ts +5 -7
  122. package/src/cli/commands/init.spec.ts +50 -6
  123. package/src/cli/commands/init.ts +28 -5
  124. package/src/cli/providers/ViteDevServerProvider.ts +31 -9
  125. package/src/cli/services/AlephaCliUtils.ts +16 -0
  126. package/src/cli/services/PackageManagerUtils.ts +2 -0
  127. package/src/cli/services/ProjectScaffolder.spec.ts +97 -0
  128. package/src/cli/services/ProjectScaffolder.ts +28 -6
  129. package/src/cli/templates/agentMd.ts +6 -1
  130. package/src/cli/templates/apiAppSecurityTs.ts +11 -0
  131. package/src/cli/templates/apiIndexTs.ts +18 -4
  132. package/src/cli/templates/webAppRouterTs.ts +25 -1
  133. package/src/cli/templates/webHelloComponentTsx.ts +15 -5
  134. package/src/command/helpers/Runner.spec.ts +135 -0
  135. package/src/command/helpers/Runner.ts +4 -1
  136. package/src/command/providers/CliProvider.spec.ts +325 -0
  137. package/src/command/providers/CliProvider.ts +117 -7
  138. package/src/core/Alepha.ts +32 -25
  139. package/src/email/index.workerd.ts +36 -0
  140. package/src/email/providers/WorkermailerEmailProvider.ts +221 -0
  141. package/src/lock/core/primitives/$lock.ts +13 -1
  142. package/src/orm/index.bun.ts +1 -1
  143. package/src/orm/index.ts +2 -6
  144. package/src/orm/providers/drivers/BunSqliteProvider.ts +4 -1
  145. package/src/orm/providers/drivers/CloudflareD1Provider.ts +57 -30
  146. package/src/orm/providers/drivers/DatabaseProvider.ts +9 -1
  147. package/src/orm/providers/drivers/NodeSqliteProvider.ts +4 -1
  148. package/src/react/auth/services/ReactAuth.ts +3 -1
  149. package/src/react/router/atoms/ssrManifestAtom.ts +7 -0
  150. package/src/react/router/hooks/useActive.ts +1 -1
  151. package/src/react/router/hooks/useRouter.ts +1 -1
  152. package/src/react/router/index.ts +4 -0
  153. package/src/react/router/primitives/$page.browser.spec.tsx +24 -24
  154. package/src/react/router/primitives/$page.spec.tsx +0 -32
  155. package/src/react/router/primitives/$page.ts +6 -14
  156. package/src/react/router/providers/ReactBrowserProvider.ts +6 -3
  157. package/src/react/router/providers/ReactPageProvider.ts +1 -1
  158. package/src/react/router/providers/ReactPreloadProvider.spec.ts +142 -0
  159. package/src/react/router/providers/ReactPreloadProvider.ts +85 -0
  160. package/src/react/router/providers/ReactServerProvider.ts +21 -82
  161. package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
  162. package/src/react/router/providers/ReactServerTemplateProvider.ts +228 -665
  163. package/src/react/router/providers/SSRManifestProvider.ts +7 -0
  164. package/src/react/router/services/ReactRouter.ts +13 -13
  165. package/src/scheduler/index.workerd.ts +43 -0
  166. package/src/scheduler/providers/CronProvider.ts +53 -6
  167. package/src/scheduler/providers/WorkerdCronProvider.ts +102 -0
  168. package/src/security/__tests__/ServerSecurityProvider.spec.ts +77 -0
  169. package/src/security/providers/ServerSecurityProvider.ts +30 -22
  170. package/src/server/compress/providers/ServerCompressProvider.ts +6 -0
  171. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +9 -3
  172. package/src/server/links/providers/ServerLinksProvider.spec.ts +332 -0
  173. package/src/server/links/providers/ServerLinksProvider.ts +1 -1
  174. package/src/system/index.browser.ts +25 -0
  175. package/src/system/index.workerd.ts +1 -0
  176. package/src/system/providers/FileSystemProvider.ts +8 -0
  177. package/src/system/providers/NodeFileSystemProvider.ts +11 -2
  178. package/src/vite/tasks/buildServer.ts +2 -12
  179. package/src/vite/tasks/generateCloudflare.ts +47 -8
  180. package/src/vite/tasks/generateDocker.ts +4 -0
@@ -1,16 +1,7 @@
1
1
  import { $inject, $module, Json } from "alepha";
2
2
  import { join } from "node:path";
3
+ import { Readable } from "node:stream";
3
4
 
4
- //#region ../../src/system/errors/FileError.ts
5
- var FileError = class extends Error {
6
- constructor(message, cause) {
7
- super(message);
8
- this.name = "FileError";
9
- this.cause = cause;
10
- }
11
- };
12
-
13
- //#endregion
14
5
  //#region ../../src/system/providers/FileSystemProvider.ts
15
6
  /**
16
7
  * FileSystem interface providing utilities for working with files.
@@ -487,10 +478,741 @@ var MemoryShellProvider = class {
487
478
  */
488
479
  var ShellProvider = class {};
489
480
 
481
+ //#endregion
482
+ //#region ../../src/system/services/FileDetector.ts
483
+ /**
484
+ * Service for detecting file types and getting content types.
485
+ *
486
+ * @example
487
+ * ```typescript
488
+ * const detector = alepha.inject(FileDetector);
489
+ *
490
+ * // Get content type from filename
491
+ * const mimeType = detector.getContentType("image.png"); // "image/png"
492
+ *
493
+ * // Detect file type by magic bytes
494
+ * const stream = createReadStream('image.png');
495
+ * const result = await detector.detectFileType(stream, 'image.png');
496
+ * console.log(result.mimeType); // 'image/png'
497
+ * console.log(result.verified); // true if magic bytes match
498
+ * ```
499
+ */
500
+ var FileDetector = class FileDetector {
501
+ /**
502
+ * Magic byte signatures for common file formats.
503
+ * Each signature is represented as an array of bytes or null (wildcard).
504
+ */
505
+ static MAGIC_BYTES = {
506
+ png: [{
507
+ signature: [
508
+ 137,
509
+ 80,
510
+ 78,
511
+ 71,
512
+ 13,
513
+ 10,
514
+ 26,
515
+ 10
516
+ ],
517
+ mimeType: "image/png"
518
+ }],
519
+ jpg: [
520
+ {
521
+ signature: [
522
+ 255,
523
+ 216,
524
+ 255,
525
+ 224
526
+ ],
527
+ mimeType: "image/jpeg"
528
+ },
529
+ {
530
+ signature: [
531
+ 255,
532
+ 216,
533
+ 255,
534
+ 225
535
+ ],
536
+ mimeType: "image/jpeg"
537
+ },
538
+ {
539
+ signature: [
540
+ 255,
541
+ 216,
542
+ 255,
543
+ 226
544
+ ],
545
+ mimeType: "image/jpeg"
546
+ },
547
+ {
548
+ signature: [
549
+ 255,
550
+ 216,
551
+ 255,
552
+ 227
553
+ ],
554
+ mimeType: "image/jpeg"
555
+ },
556
+ {
557
+ signature: [
558
+ 255,
559
+ 216,
560
+ 255,
561
+ 232
562
+ ],
563
+ mimeType: "image/jpeg"
564
+ }
565
+ ],
566
+ jpeg: [
567
+ {
568
+ signature: [
569
+ 255,
570
+ 216,
571
+ 255,
572
+ 224
573
+ ],
574
+ mimeType: "image/jpeg"
575
+ },
576
+ {
577
+ signature: [
578
+ 255,
579
+ 216,
580
+ 255,
581
+ 225
582
+ ],
583
+ mimeType: "image/jpeg"
584
+ },
585
+ {
586
+ signature: [
587
+ 255,
588
+ 216,
589
+ 255,
590
+ 226
591
+ ],
592
+ mimeType: "image/jpeg"
593
+ },
594
+ {
595
+ signature: [
596
+ 255,
597
+ 216,
598
+ 255,
599
+ 227
600
+ ],
601
+ mimeType: "image/jpeg"
602
+ },
603
+ {
604
+ signature: [
605
+ 255,
606
+ 216,
607
+ 255,
608
+ 232
609
+ ],
610
+ mimeType: "image/jpeg"
611
+ }
612
+ ],
613
+ gif: [{
614
+ signature: [
615
+ 71,
616
+ 73,
617
+ 70,
618
+ 56,
619
+ 55,
620
+ 97
621
+ ],
622
+ mimeType: "image/gif"
623
+ }, {
624
+ signature: [
625
+ 71,
626
+ 73,
627
+ 70,
628
+ 56,
629
+ 57,
630
+ 97
631
+ ],
632
+ mimeType: "image/gif"
633
+ }],
634
+ webp: [{
635
+ signature: [
636
+ 82,
637
+ 73,
638
+ 70,
639
+ 70,
640
+ null,
641
+ null,
642
+ null,
643
+ null,
644
+ 87,
645
+ 69,
646
+ 66,
647
+ 80
648
+ ],
649
+ mimeType: "image/webp"
650
+ }],
651
+ bmp: [{
652
+ signature: [66, 77],
653
+ mimeType: "image/bmp"
654
+ }],
655
+ ico: [{
656
+ signature: [
657
+ 0,
658
+ 0,
659
+ 1,
660
+ 0
661
+ ],
662
+ mimeType: "image/x-icon"
663
+ }],
664
+ tiff: [{
665
+ signature: [
666
+ 73,
667
+ 73,
668
+ 42,
669
+ 0
670
+ ],
671
+ mimeType: "image/tiff"
672
+ }, {
673
+ signature: [
674
+ 77,
675
+ 77,
676
+ 0,
677
+ 42
678
+ ],
679
+ mimeType: "image/tiff"
680
+ }],
681
+ tif: [{
682
+ signature: [
683
+ 73,
684
+ 73,
685
+ 42,
686
+ 0
687
+ ],
688
+ mimeType: "image/tiff"
689
+ }, {
690
+ signature: [
691
+ 77,
692
+ 77,
693
+ 0,
694
+ 42
695
+ ],
696
+ mimeType: "image/tiff"
697
+ }],
698
+ pdf: [{
699
+ signature: [
700
+ 37,
701
+ 80,
702
+ 68,
703
+ 70,
704
+ 45
705
+ ],
706
+ mimeType: "application/pdf"
707
+ }],
708
+ zip: [
709
+ {
710
+ signature: [
711
+ 80,
712
+ 75,
713
+ 3,
714
+ 4
715
+ ],
716
+ mimeType: "application/zip"
717
+ },
718
+ {
719
+ signature: [
720
+ 80,
721
+ 75,
722
+ 5,
723
+ 6
724
+ ],
725
+ mimeType: "application/zip"
726
+ },
727
+ {
728
+ signature: [
729
+ 80,
730
+ 75,
731
+ 7,
732
+ 8
733
+ ],
734
+ mimeType: "application/zip"
735
+ }
736
+ ],
737
+ rar: [{
738
+ signature: [
739
+ 82,
740
+ 97,
741
+ 114,
742
+ 33,
743
+ 26,
744
+ 7
745
+ ],
746
+ mimeType: "application/vnd.rar"
747
+ }],
748
+ "7z": [{
749
+ signature: [
750
+ 55,
751
+ 122,
752
+ 188,
753
+ 175,
754
+ 39,
755
+ 28
756
+ ],
757
+ mimeType: "application/x-7z-compressed"
758
+ }],
759
+ tar: [{
760
+ signature: [
761
+ 117,
762
+ 115,
763
+ 116,
764
+ 97,
765
+ 114
766
+ ],
767
+ mimeType: "application/x-tar"
768
+ }],
769
+ gz: [{
770
+ signature: [31, 139],
771
+ mimeType: "application/gzip"
772
+ }],
773
+ tgz: [{
774
+ signature: [31, 139],
775
+ mimeType: "application/gzip"
776
+ }],
777
+ mp3: [
778
+ {
779
+ signature: [255, 251],
780
+ mimeType: "audio/mpeg"
781
+ },
782
+ {
783
+ signature: [255, 243],
784
+ mimeType: "audio/mpeg"
785
+ },
786
+ {
787
+ signature: [255, 242],
788
+ mimeType: "audio/mpeg"
789
+ },
790
+ {
791
+ signature: [
792
+ 73,
793
+ 68,
794
+ 51
795
+ ],
796
+ mimeType: "audio/mpeg"
797
+ }
798
+ ],
799
+ wav: [{
800
+ signature: [
801
+ 82,
802
+ 73,
803
+ 70,
804
+ 70,
805
+ null,
806
+ null,
807
+ null,
808
+ null,
809
+ 87,
810
+ 65,
811
+ 86,
812
+ 69
813
+ ],
814
+ mimeType: "audio/wav"
815
+ }],
816
+ ogg: [{
817
+ signature: [
818
+ 79,
819
+ 103,
820
+ 103,
821
+ 83
822
+ ],
823
+ mimeType: "audio/ogg"
824
+ }],
825
+ flac: [{
826
+ signature: [
827
+ 102,
828
+ 76,
829
+ 97,
830
+ 67
831
+ ],
832
+ mimeType: "audio/flac"
833
+ }],
834
+ mp4: [
835
+ {
836
+ signature: [
837
+ null,
838
+ null,
839
+ null,
840
+ null,
841
+ 102,
842
+ 116,
843
+ 121,
844
+ 112
845
+ ],
846
+ mimeType: "video/mp4"
847
+ },
848
+ {
849
+ signature: [
850
+ null,
851
+ null,
852
+ null,
853
+ null,
854
+ 102,
855
+ 116,
856
+ 121,
857
+ 112,
858
+ 105,
859
+ 115,
860
+ 111,
861
+ 109
862
+ ],
863
+ mimeType: "video/mp4"
864
+ },
865
+ {
866
+ signature: [
867
+ null,
868
+ null,
869
+ null,
870
+ null,
871
+ 102,
872
+ 116,
873
+ 121,
874
+ 112,
875
+ 109,
876
+ 112,
877
+ 52,
878
+ 50
879
+ ],
880
+ mimeType: "video/mp4"
881
+ }
882
+ ],
883
+ webm: [{
884
+ signature: [
885
+ 26,
886
+ 69,
887
+ 223,
888
+ 163
889
+ ],
890
+ mimeType: "video/webm"
891
+ }],
892
+ avi: [{
893
+ signature: [
894
+ 82,
895
+ 73,
896
+ 70,
897
+ 70,
898
+ null,
899
+ null,
900
+ null,
901
+ null,
902
+ 65,
903
+ 86,
904
+ 73,
905
+ 32
906
+ ],
907
+ mimeType: "video/x-msvideo"
908
+ }],
909
+ mov: [{
910
+ signature: [
911
+ null,
912
+ null,
913
+ null,
914
+ null,
915
+ 102,
916
+ 116,
917
+ 121,
918
+ 112,
919
+ 113,
920
+ 116,
921
+ 32,
922
+ 32
923
+ ],
924
+ mimeType: "video/quicktime"
925
+ }],
926
+ mkv: [{
927
+ signature: [
928
+ 26,
929
+ 69,
930
+ 223,
931
+ 163
932
+ ],
933
+ mimeType: "video/x-matroska"
934
+ }],
935
+ docx: [{
936
+ signature: [
937
+ 80,
938
+ 75,
939
+ 3,
940
+ 4
941
+ ],
942
+ mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
943
+ }],
944
+ xlsx: [{
945
+ signature: [
946
+ 80,
947
+ 75,
948
+ 3,
949
+ 4
950
+ ],
951
+ mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
952
+ }],
953
+ pptx: [{
954
+ signature: [
955
+ 80,
956
+ 75,
957
+ 3,
958
+ 4
959
+ ],
960
+ mimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
961
+ }],
962
+ doc: [{
963
+ signature: [
964
+ 208,
965
+ 207,
966
+ 17,
967
+ 224,
968
+ 161,
969
+ 177,
970
+ 26,
971
+ 225
972
+ ],
973
+ mimeType: "application/msword"
974
+ }],
975
+ xls: [{
976
+ signature: [
977
+ 208,
978
+ 207,
979
+ 17,
980
+ 224,
981
+ 161,
982
+ 177,
983
+ 26,
984
+ 225
985
+ ],
986
+ mimeType: "application/vnd.ms-excel"
987
+ }],
988
+ ppt: [{
989
+ signature: [
990
+ 208,
991
+ 207,
992
+ 17,
993
+ 224,
994
+ 161,
995
+ 177,
996
+ 26,
997
+ 225
998
+ ],
999
+ mimeType: "application/vnd.ms-powerpoint"
1000
+ }]
1001
+ };
1002
+ /**
1003
+ * All possible format signatures for checking against actual file content
1004
+ */
1005
+ static ALL_SIGNATURES = Object.entries(FileDetector.MAGIC_BYTES).flatMap(([ext, signatures]) => signatures.map((sig) => ({
1006
+ ext,
1007
+ ...sig
1008
+ })));
1009
+ /**
1010
+ * MIME type map for file extensions.
1011
+ *
1012
+ * Can be used to get the content type of file based on its extension.
1013
+ * Feel free to add more mime types in your project!
1014
+ */
1015
+ static mimeMap = {
1016
+ json: "application/json",
1017
+ txt: "text/plain",
1018
+ html: "text/html",
1019
+ htm: "text/html",
1020
+ xml: "application/xml",
1021
+ csv: "text/csv",
1022
+ pdf: "application/pdf",
1023
+ md: "text/markdown",
1024
+ markdown: "text/markdown",
1025
+ rtf: "application/rtf",
1026
+ css: "text/css",
1027
+ js: "application/javascript",
1028
+ mjs: "application/javascript",
1029
+ ts: "application/typescript",
1030
+ jsx: "text/jsx",
1031
+ tsx: "text/tsx",
1032
+ zip: "application/zip",
1033
+ rar: "application/vnd.rar",
1034
+ "7z": "application/x-7z-compressed",
1035
+ tar: "application/x-tar",
1036
+ gz: "application/gzip",
1037
+ tgz: "application/gzip",
1038
+ png: "image/png",
1039
+ jpg: "image/jpeg",
1040
+ jpeg: "image/jpeg",
1041
+ gif: "image/gif",
1042
+ webp: "image/webp",
1043
+ svg: "image/svg+xml",
1044
+ bmp: "image/bmp",
1045
+ ico: "image/x-icon",
1046
+ tiff: "image/tiff",
1047
+ tif: "image/tiff",
1048
+ mp3: "audio/mpeg",
1049
+ wav: "audio/wav",
1050
+ ogg: "audio/ogg",
1051
+ m4a: "audio/mp4",
1052
+ aac: "audio/aac",
1053
+ flac: "audio/flac",
1054
+ mp4: "video/mp4",
1055
+ webm: "video/webm",
1056
+ avi: "video/x-msvideo",
1057
+ mov: "video/quicktime",
1058
+ wmv: "video/x-ms-wmv",
1059
+ flv: "video/x-flv",
1060
+ mkv: "video/x-matroska",
1061
+ doc: "application/msword",
1062
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1063
+ xls: "application/vnd.ms-excel",
1064
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1065
+ ppt: "application/vnd.ms-powerpoint",
1066
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1067
+ woff: "font/woff",
1068
+ woff2: "font/woff2",
1069
+ ttf: "font/ttf",
1070
+ otf: "font/otf",
1071
+ eot: "application/vnd.ms-fontobject"
1072
+ };
1073
+ /**
1074
+ * Reverse MIME type map for looking up extensions from MIME types.
1075
+ * Prefers shorter, more common extensions when multiple exist.
1076
+ */
1077
+ static reverseMimeMap = (() => {
1078
+ const reverse = {};
1079
+ for (const [ext, mimeType] of Object.entries(FileDetector.mimeMap)) if (!reverse[mimeType]) reverse[mimeType] = ext;
1080
+ return reverse;
1081
+ })();
1082
+ /**
1083
+ * Returns the file extension for a given MIME type.
1084
+ *
1085
+ * @param mimeType - The MIME type to look up
1086
+ * @returns The file extension (without dot), or "bin" if not found
1087
+ *
1088
+ * @example
1089
+ * ```typescript
1090
+ * const detector = alepha.inject(FileDetector);
1091
+ * const ext = detector.getExtensionFromMimeType("image/png"); // "png"
1092
+ * const ext2 = detector.getExtensionFromMimeType("application/octet-stream"); // "bin"
1093
+ * ```
1094
+ */
1095
+ getExtensionFromMimeType(mimeType) {
1096
+ return FileDetector.reverseMimeMap[mimeType] || "bin";
1097
+ }
1098
+ /**
1099
+ * Returns the content type of file based on its filename.
1100
+ *
1101
+ * @param filename - The filename to check
1102
+ * @returns The MIME type
1103
+ *
1104
+ * @example
1105
+ * ```typescript
1106
+ * const detector = alepha.inject(FileDetector);
1107
+ * const mimeType = detector.getContentType("image.png"); // "image/png"
1108
+ * ```
1109
+ */
1110
+ getContentType(filename) {
1111
+ const ext = filename.toLowerCase().split(".").pop() || "";
1112
+ return FileDetector.mimeMap[ext] || "application/octet-stream";
1113
+ }
1114
+ /**
1115
+ * Detects the file type by checking magic bytes against the stream content.
1116
+ *
1117
+ * @param stream - The readable stream to check
1118
+ * @param filename - The filename (used to get the extension)
1119
+ * @returns File type information including MIME type, extension, and verification status
1120
+ *
1121
+ * @example
1122
+ * ```typescript
1123
+ * const detector = alepha.inject(FileDetector);
1124
+ * const stream = createReadStream('image.png');
1125
+ * const result = await detector.detectFileType(stream, 'image.png');
1126
+ * console.log(result.mimeType); // 'image/png'
1127
+ * console.log(result.verified); // true if magic bytes match
1128
+ * ```
1129
+ */
1130
+ async detectFileType(stream, filename) {
1131
+ const expectedMimeType = this.getContentType(filename);
1132
+ const lastDotIndex = filename.lastIndexOf(".");
1133
+ const ext = lastDotIndex > 0 ? filename.substring(lastDotIndex + 1).toLowerCase() : "";
1134
+ const { buffer, stream: newStream } = await this.peekBytes(stream, 16);
1135
+ const expectedSignatures = FileDetector.MAGIC_BYTES[ext];
1136
+ if (expectedSignatures) {
1137
+ for (const { signature, mimeType } of expectedSignatures) if (this.matchesSignature(buffer, signature)) return {
1138
+ mimeType,
1139
+ extension: ext,
1140
+ verified: true,
1141
+ stream: newStream
1142
+ };
1143
+ }
1144
+ for (const { ext: detectedExt, signature, mimeType } of FileDetector.ALL_SIGNATURES) if (detectedExt !== ext && this.matchesSignature(buffer, signature)) return {
1145
+ mimeType,
1146
+ extension: detectedExt,
1147
+ verified: true,
1148
+ stream: newStream
1149
+ };
1150
+ return {
1151
+ mimeType: expectedMimeType,
1152
+ extension: ext,
1153
+ verified: false,
1154
+ stream: newStream
1155
+ };
1156
+ }
1157
+ /**
1158
+ * Reads all bytes from a stream and returns the first N bytes along with a new stream containing all data.
1159
+ * This approach reads the entire stream upfront to avoid complex async handling issues.
1160
+ *
1161
+ * @protected
1162
+ */
1163
+ async peekBytes(stream, numBytes) {
1164
+ const chunks = [];
1165
+ for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1166
+ const allData = Buffer.concat(chunks);
1167
+ return {
1168
+ buffer: allData.subarray(0, numBytes),
1169
+ stream: Readable.from(allData)
1170
+ };
1171
+ }
1172
+ /**
1173
+ * Checks if a buffer matches a magic byte signature.
1174
+ *
1175
+ * @protected
1176
+ */
1177
+ matchesSignature(buffer, signature) {
1178
+ if (buffer.length < signature.length) return false;
1179
+ for (let i = 0; i < signature.length; i++) if (signature[i] !== null && buffer[i] !== signature[i]) return false;
1180
+ return true;
1181
+ }
1182
+ };
1183
+
1184
+ //#endregion
1185
+ //#region ../../src/system/errors/FileError.ts
1186
+ var FileError = class extends Error {
1187
+ constructor(message, cause) {
1188
+ super(message);
1189
+ this.name = "FileError";
1190
+ this.cause = cause;
1191
+ }
1192
+ };
1193
+
490
1194
  //#endregion
491
1195
  //#region ../../src/system/index.browser.ts
492
- const AlephaSystem = $module({ name: "alepha.system" });
1196
+ const AlephaSystem = $module({
1197
+ name: "alepha.system",
1198
+ services: [
1199
+ FileDetector,
1200
+ FileSystemProvider,
1201
+ MemoryFileSystemProvider,
1202
+ ShellProvider,
1203
+ MemoryShellProvider
1204
+ ],
1205
+ register: (alepha) => alepha.with({
1206
+ optional: true,
1207
+ provide: FileSystemProvider,
1208
+ use: MemoryFileSystemProvider
1209
+ }).with({
1210
+ optional: true,
1211
+ provide: ShellProvider,
1212
+ use: MemoryShellProvider
1213
+ })
1214
+ });
493
1215
 
494
1216
  //#endregion
495
- export { AlephaSystem, FileError, FileSystemProvider, MemoryFileSystemProvider, MemoryShellProvider, ShellProvider };
1217
+ export { AlephaSystem, FileDetector, FileError, FileSystemProvider, MemoryFileSystemProvider, MemoryShellProvider, ShellProvider };
496
1218
  //# sourceMappingURL=index.browser.js.map