most-box 0.1.0 → 0.1.2

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 (390) hide show
  1. package/README.md +24 -16
  2. package/electron/main.js +72 -8
  3. package/electron/preload.js +6 -0
  4. package/out/404/index.html +2 -2
  5. package/out/404.html +2 -2
  6. package/out/__next.__PAGE__.txt +6 -6
  7. package/out/__next._full.txt +23 -20
  8. package/out/__next._head.txt +3 -3
  9. package/out/__next._index.txt +8 -6
  10. package/out/__next._tree.txt +6 -4
  11. package/out/_next/static/chunks/0-n3pg7th.zza.js +1 -0
  12. package/out/_next/static/chunks/0.4j.0k5a64vg.js +1 -0
  13. package/out/_next/static/chunks/0.e2avjgna_b2.js +1 -0
  14. package/out/_next/static/chunks/0.ozi1_x2.m.~.js +1 -0
  15. package/out/_next/static/chunks/0.t5wlt51zou5.js +1 -0
  16. package/out/_next/static/chunks/0.w4hkvap~bva.js +1 -0
  17. package/out/_next/static/chunks/00d9h1tddnnnd.js +1 -0
  18. package/out/_next/static/chunks/00tkdqwxch-3s.js +1 -0
  19. package/out/_next/static/chunks/01l3o90g~1z42.js +1 -0
  20. package/out/_next/static/chunks/01mfky9camw6i.js +1 -0
  21. package/out/_next/static/chunks/01r.v-pqs1vrm.js +1 -0
  22. package/out/_next/static/chunks/03edqrb4zdj~g.js +31 -0
  23. package/out/_next/static/chunks/03h_6oo-gqkhz.js +1 -0
  24. package/out/_next/static/chunks/{0ho~log~~-jwp.css → 03h~nhgj0hv3p.css} +1 -1
  25. package/out/_next/static/chunks/04hcgsanv1hhu.js +1 -0
  26. package/out/_next/static/chunks/05g2q0w5b34.g.js +1 -0
  27. package/out/_next/static/chunks/05of77xycbt8~.js +1 -0
  28. package/out/_next/static/chunks/05zwemzfjx3sh.js +1 -0
  29. package/out/_next/static/chunks/06dpc5df94.v1.js +1 -0
  30. package/out/_next/static/chunks/06e1~1-z_ic9a.js +1 -0
  31. package/out/_next/static/chunks/075s7sn.ns~u5.js +1 -0
  32. package/out/_next/static/chunks/07dynrbvd3.f4.js +1 -0
  33. package/out/_next/static/chunks/07p~uva5pwgwe.js +1 -0
  34. package/out/_next/static/chunks/07r9nn-pzlgg1.js +1 -0
  35. package/out/_next/static/chunks/07td.jq7xff84.css +1 -0
  36. package/out/_next/static/chunks/08.72abkgwy9g.js +1 -0
  37. package/out/_next/static/chunks/08576xhv~~jck.js +1 -0
  38. package/out/_next/static/chunks/08u211~k~qu52.js +1 -0
  39. package/out/_next/static/chunks/098.p.2-zm4p7.js +1 -0
  40. package/out/_next/static/chunks/09ngvtajm7e5y.js +1 -0
  41. package/out/_next/static/chunks/09ps~-43n5qyo.js +1 -0
  42. package/out/_next/static/chunks/09v7_0gclxr46.js +1 -0
  43. package/out/_next/static/chunks/09yql86dir9c4.js +1 -0
  44. package/out/_next/static/chunks/09zmlfljowj1~.js +1 -0
  45. package/out/_next/static/chunks/0_s~ebb-7b2hr.js +1 -0
  46. package/out/_next/static/chunks/0_w-0-2z5oqd_.js +1 -0
  47. package/out/_next/static/chunks/0adx~d-j05c9d.css +24 -0
  48. package/out/_next/static/chunks/0ao1lbi4b.sfa.js +1 -0
  49. package/out/_next/static/chunks/0aq.rc9woa2nz.js +1 -0
  50. package/out/_next/static/chunks/0bld2u_ld~va2.js +1 -0
  51. package/out/_next/static/chunks/0bliugh5lxw55.js +1 -0
  52. package/out/_next/static/chunks/0cn9a7aimbdzq.js +1 -0
  53. package/out/_next/static/chunks/0d3f-nk3c.2re.js +1 -0
  54. package/out/_next/static/chunks/0dtohpf7~3d12.js +1 -0
  55. package/out/_next/static/chunks/0e-3e8h7g99yf.js +1 -0
  56. package/out/_next/static/chunks/0e531nije_ln2.js +1 -0
  57. package/out/_next/static/chunks/0e5zvj_rh0z3m.js +1 -0
  58. package/out/_next/static/chunks/0etes81d_cihn.js +1 -0
  59. package/out/_next/static/chunks/0f4y~rkk-n81e.js +1 -0
  60. package/out/_next/static/chunks/0fk~0~p7ivfn1.js +1 -0
  61. package/out/_next/static/chunks/0fw6juc~lsj3z.js +1 -0
  62. package/out/_next/static/chunks/0g0u7785a73vo.js +1 -0
  63. package/out/_next/static/chunks/0g_a~e050bgzg.css +1 -0
  64. package/out/_next/static/chunks/0g_fpgh7drfda.js +1 -0
  65. package/out/_next/static/chunks/{0n~dq4kpx9xxx.js → 0gcsdf57gcm6h.js} +1 -1
  66. package/out/_next/static/chunks/0gwian.hp3-92.js +1 -0
  67. package/out/_next/static/chunks/0gze5uso1mbe9.js +1 -0
  68. package/out/_next/static/chunks/0h4r.qtmpa6eh.js +1 -0
  69. package/out/_next/static/chunks/0hf.aosc-7172.js +1 -0
  70. package/out/_next/static/chunks/0hgz35c1ejbs9.js +1 -0
  71. package/out/_next/static/chunks/0hpev4am9jpmu.css +1 -0
  72. package/out/_next/static/chunks/0hrw-r.xmvmsq.js +1 -0
  73. package/out/_next/static/chunks/0hzg4al.v~8~m.js +1 -0
  74. package/out/_next/static/chunks/0ip9xrols_83o.js +1 -0
  75. package/out/_next/static/chunks/0j4-d0qf.v~kn.js +1 -0
  76. package/out/_next/static/chunks/0jhdeq.j9_02m.js +1 -0
  77. package/out/_next/static/chunks/0jy63h3i-y69i.js +1 -0
  78. package/out/_next/static/chunks/0kdnx_u-60k9s.js +1 -0
  79. package/out/_next/static/chunks/0kq~edq42o1-c.js +1 -0
  80. package/out/_next/static/chunks/0l5_.uqb-uqb8.js +1 -0
  81. package/out/_next/static/chunks/0l682p362d-5w.js +1 -0
  82. package/out/_next/static/chunks/0m68p9txef5rs.js +1 -0
  83. package/out/_next/static/chunks/0mex8svsiv-2l.js +1 -0
  84. package/out/_next/static/chunks/0mme-fm5d2oz2.js +1 -0
  85. package/out/_next/static/chunks/0myp4sjagr~h0.js +1 -0
  86. package/out/_next/static/chunks/0myq9gs8szydh.js +1 -0
  87. package/out/_next/static/chunks/0n.qlfk~z7o.6.js +1 -0
  88. package/out/_next/static/chunks/0n4t80gjc3q5h.js +1 -0
  89. package/out/_next/static/chunks/0o9ce4cyf76by.js +736 -0
  90. package/out/_next/static/chunks/0oz3yl6_-716p.js +1 -0
  91. package/out/_next/static/chunks/0p0sv~fuddvgr.js +1 -0
  92. package/out/_next/static/chunks/0pt.5cg1t09qs.js +1 -0
  93. package/out/_next/static/chunks/0q0ksgxg98xgd.js +1 -0
  94. package/out/_next/static/chunks/0qgx9t4jx16ua.css +1 -0
  95. package/out/_next/static/chunks/0qqupeexg83u7.js +1 -0
  96. package/out/_next/static/chunks/0rb-ri481.kc9.js +1 -0
  97. package/out/_next/static/chunks/0rsnmahfd.59p.js +1 -0
  98. package/out/_next/static/chunks/0rt6rgnvr-s_p.js +1 -0
  99. package/out/_next/static/chunks/0runh28p_gg6..js +1 -0
  100. package/out/_next/static/chunks/0shy.t1fwqcev.js +1 -0
  101. package/out/_next/static/chunks/{0d3shmwh5_nmn.js → 0t2xr05rlu96l.js} +1 -1
  102. package/out/_next/static/chunks/0t6h56rhg1y5i.js +1 -0
  103. package/out/_next/static/chunks/0tdqd1zunusgk.js +1 -0
  104. package/out/_next/static/chunks/0ujbnp38x63ek.js +1 -0
  105. package/out/_next/static/chunks/0ukyg~tkm~h2m.css +1 -0
  106. package/out/_next/static/chunks/0v68pdrp54lb-.js +1 -0
  107. package/out/_next/static/chunks/0vsm0m5sxrb.3.js +1 -0
  108. package/out/_next/static/chunks/0vzlz.iboqo3c.js +1 -0
  109. package/out/_next/static/chunks/0w87vbpkf-ogd.js +1 -0
  110. package/out/_next/static/chunks/0wtf0xsiicxx6.js +1 -0
  111. package/out/_next/static/chunks/0xdwau5k2augv.css +4 -0
  112. package/out/_next/static/chunks/0xgg0~kmf3gd-.js +1 -0
  113. package/out/_next/static/chunks/0xj24-70ptdzp.js +1 -0
  114. package/out/_next/static/chunks/0xxlx772fr3x4.js +1 -0
  115. package/out/_next/static/chunks/0y.li-~3oybew.js +1 -0
  116. package/out/_next/static/chunks/0yl2t7cs-n_ng.js +1 -0
  117. package/out/_next/static/chunks/0yq3kh.hchtm_.js +1 -0
  118. package/out/_next/static/chunks/0ys0l5au.9c2c.js +1 -0
  119. package/out/_next/static/chunks/0z48pmi6buytt.js +1 -0
  120. package/out/_next/static/chunks/0zapnvgy89mg..js +1 -0
  121. package/out/_next/static/chunks/0~.-vxi5oc.r0.js +1 -0
  122. package/out/_next/static/chunks/0~3ik-hfp9s-7.js +1 -0
  123. package/out/_next/static/chunks/0~4f5p6tvn1lq.js +1 -0
  124. package/out/_next/static/chunks/0~_0ys.2whxbw.js +1 -0
  125. package/out/_next/static/chunks/0~_ui9l7.2sxf.js +1 -0
  126. package/out/_next/static/chunks/1037jlyw5~7ht.js +1 -0
  127. package/out/_next/static/chunks/1045hfzu533z0.js +1 -0
  128. package/out/_next/static/chunks/104e5nmc.c-pl.js +1 -0
  129. package/out/_next/static/chunks/109taw1pbh-0b.js +1 -0
  130. package/out/_next/static/chunks/10x7~onqwp338.js +1 -0
  131. package/out/_next/static/chunks/10ynz1dy483wf.js +1 -0
  132. package/out/_next/static/chunks/11hds.mg~4_r-.js +1 -0
  133. package/out/_next/static/chunks/11ibzaklcauw~.js +1 -0
  134. package/out/_next/static/chunks/11z.0s6.42b.p.js +1 -0
  135. package/out/_next/static/chunks/12-9n56l0y3yr.js +1 -0
  136. package/out/_next/static/chunks/126enaq~f7scl.js +1 -0
  137. package/out/_next/static/chunks/12nr19.nnn6s3.js +5 -0
  138. package/out/_next/static/chunks/{0qub_r0x_r-e9.css → 12pep-2t-qg4n.css} +1 -1
  139. package/out/_next/static/chunks/1380op_pfk.qo.js +1 -0
  140. package/out/_next/static/chunks/146oiw1bggtn4.js +1 -0
  141. package/out/_next/static/chunks/14_inksek_rth.js +2 -0
  142. package/out/_next/static/chunks/14_po2rb_arn4.js +1 -0
  143. package/out/_next/static/chunks/14a4fwbiq.l3z.js +1 -0
  144. package/out/_next/static/chunks/14cowsqn95m1k.js +1 -0
  145. package/out/_next/static/chunks/14dtd3l03v.kx.js +1 -0
  146. package/out/_next/static/chunks/14tm3qa-v9o-4.js +1 -0
  147. package/out/_next/static/chunks/15-o4kb-evqd7.js +1 -0
  148. package/out/_next/static/chunks/153-sz7s.qml2.js +1 -0
  149. package/out/_next/static/chunks/157z7bowux3xj.js +1 -0
  150. package/out/_next/static/chunks/15m1_677az2cm.js +1 -0
  151. package/out/_next/static/chunks/15v.~.ne6ogkk.js +1 -0
  152. package/out/_next/static/chunks/16i.qbk8t8gf_.js +1 -0
  153. package/out/_next/static/chunks/16u9f35gylw8l.js +1 -0
  154. package/out/_next/static/chunks/16xls5tt_68lx.js +1 -0
  155. package/out/_next/static/chunks/17ajyb5ogk5yj.js +1 -0
  156. package/out/_next/static/chunks/17dyfxbq8yz8n.js +1 -0
  157. package/out/_next/static/chunks/180zln9pcq9ih.js +1 -0
  158. package/out/_next/static/chunks/1814izi5gh.kp.js +1 -0
  159. package/out/_next/static/chunks/turbopack-0xta0kqwzkf28.js +1 -0
  160. package/out/_next/static/media/KaTeX_AMS-Regular.0b~8ki5y928w2.woff +0 -0
  161. package/out/_next/static/media/KaTeX_AMS-Regular.0p1vbqd84i2~o.woff2 +0 -0
  162. package/out/_next/static/media/KaTeX_AMS-Regular.173t6ktr7uf-w.ttf +0 -0
  163. package/out/_next/static/media/KaTeX_Caligraphic-Bold.01-pzluls4zgb.woff2 +0 -0
  164. package/out/_next/static/media/KaTeX_Caligraphic-Bold.0x2v1lwn~880f.woff +0 -0
  165. package/out/_next/static/media/KaTeX_Caligraphic-Bold.16zv5fax0h0ka.ttf +0 -0
  166. package/out/_next/static/media/KaTeX_Caligraphic-Regular.02i3z7wig438t.ttf +0 -0
  167. package/out/_next/static/media/KaTeX_Caligraphic-Regular.0rysu1t-ncjq8.woff2 +0 -0
  168. package/out/_next/static/media/KaTeX_Caligraphic-Regular.10927swgekwun.woff +0 -0
  169. package/out/_next/static/media/KaTeX_Fraktur-Bold.0e-16u10iuyyf.woff +0 -0
  170. package/out/_next/static/media/KaTeX_Fraktur-Bold.0et27v~3~4uhe.ttf +0 -0
  171. package/out/_next/static/media/KaTeX_Fraktur-Bold.0w23i72~hprpq.woff2 +0 -0
  172. package/out/_next/static/media/KaTeX_Fraktur-Regular.0b.riegzdfue2.woff +0 -0
  173. package/out/_next/static/media/KaTeX_Fraktur-Regular.0rekyoa-52fj_.woff2 +0 -0
  174. package/out/_next/static/media/KaTeX_Fraktur-Regular.0vjwa15znhk~4.ttf +0 -0
  175. package/out/_next/static/media/KaTeX_Main-Bold.09i7~607shf-h.ttf +0 -0
  176. package/out/_next/static/media/KaTeX_Main-Bold.09lmynrorhcbw.woff +0 -0
  177. package/out/_next/static/media/KaTeX_Main-Bold.16pfc63_du6mx.woff2 +0 -0
  178. package/out/_next/static/media/KaTeX_Main-BoldItalic.0cp37g7x1q8h6.woff +0 -0
  179. package/out/_next/static/media/KaTeX_Main-BoldItalic.0d54rk08rx11s.woff2 +0 -0
  180. package/out/_next/static/media/KaTeX_Main-BoldItalic.15j6k~hix2t_0.ttf +0 -0
  181. package/out/_next/static/media/KaTeX_Main-Italic.0382gqciexmbu.woff +0 -0
  182. package/out/_next/static/media/KaTeX_Main-Italic.06o5nq0_91v60.woff2 +0 -0
  183. package/out/_next/static/media/KaTeX_Main-Italic.0su4i6mm18-wo.ttf +0 -0
  184. package/out/_next/static/media/KaTeX_Main-Regular.08zh8z.7shijf.ttf +0 -0
  185. package/out/_next/static/media/KaTeX_Main-Regular.0diheg01zyoph.woff +0 -0
  186. package/out/_next/static/media/KaTeX_Main-Regular.0kaf-ag2_wkm-.woff2 +0 -0
  187. package/out/_next/static/media/KaTeX_Math-BoldItalic.0ajzxypnbx1h1.ttf +0 -0
  188. package/out/_next/static/media/KaTeX_Math-BoldItalic.0ck1myuerwyqw.woff +0 -0
  189. package/out/_next/static/media/KaTeX_Math-BoldItalic.0ja97dn.cpc87.woff2 +0 -0
  190. package/out/_next/static/media/KaTeX_Math-Italic.09xkhecjcn5r9.woff +0 -0
  191. package/out/_next/static/media/KaTeX_Math-Italic.0x23a-bmp-5tg.ttf +0 -0
  192. package/out/_next/static/media/KaTeX_Math-Italic.0zrha2c4sl2je.woff2 +0 -0
  193. package/out/_next/static/media/KaTeX_SansSerif-Bold.05a9.pc1j_zx9.woff2 +0 -0
  194. package/out/_next/static/media/KaTeX_SansSerif-Bold.0jcl-ayi1uun0.woff +0 -0
  195. package/out/_next/static/media/KaTeX_SansSerif-Bold.0re8y.dm7.mt5.ttf +0 -0
  196. package/out/_next/static/media/KaTeX_SansSerif-Italic.0a0234dc3s62j.woff2 +0 -0
  197. package/out/_next/static/media/KaTeX_SansSerif-Italic.0judofdln9731.woff +0 -0
  198. package/out/_next/static/media/KaTeX_SansSerif-Italic.10z1iap9pfus8.ttf +0 -0
  199. package/out/_next/static/media/KaTeX_SansSerif-Regular.0h9yjlugq4q_e.woff +0 -0
  200. package/out/_next/static/media/KaTeX_SansSerif-Regular.0v6gcj32-czft.woff2 +0 -0
  201. package/out/_next/static/media/KaTeX_SansSerif-Regular.0zm18kga42ebc.ttf +0 -0
  202. package/out/_next/static/media/KaTeX_Script-Regular.0c4.h-mer83d_.woff2 +0 -0
  203. package/out/_next/static/media/KaTeX_Script-Regular.0q14y6zkzlpob.ttf +0 -0
  204. package/out/_next/static/media/KaTeX_Script-Regular.0ze6v4r_-99oy.woff +0 -0
  205. package/out/_next/static/media/KaTeX_Size1-Regular.013x6a4ierotp.woff2 +0 -0
  206. package/out/_next/static/media/KaTeX_Size1-Regular.0kidw0oi.m68o.woff +0 -0
  207. package/out/_next/static/media/KaTeX_Size1-Regular.0m6y-i6wfokni.ttf +0 -0
  208. package/out/_next/static/media/KaTeX_Size2-Regular.0blpmluwilgbg.woff +0 -0
  209. package/out/_next/static/media/KaTeX_Size2-Regular.0d5inmyp-tyv3.woff2 +0 -0
  210. package/out/_next/static/media/KaTeX_Size2-Regular.0wnhnvj-.k9d5.ttf +0 -0
  211. package/out/_next/static/media/KaTeX_Size3-Regular.01h0xm_sfctj3.woff +0 -0
  212. package/out/_next/static/media/KaTeX_Size3-Regular.0iukctyhw5j56.woff2 +0 -0
  213. package/out/_next/static/media/KaTeX_Size3-Regular.0jl8mqyf4gzpn.ttf +0 -0
  214. package/out/_next/static/media/KaTeX_Size4-Regular.0w3.rb_c4stzk.woff2 +0 -0
  215. package/out/_next/static/media/KaTeX_Size4-Regular.0wr_9l81-mu06.ttf +0 -0
  216. package/out/_next/static/media/KaTeX_Size4-Regular.12tvaesf3.zl3.woff +0 -0
  217. package/out/_next/static/media/KaTeX_Typewriter-Regular.0c4zdxz~8frhm.woff2 +0 -0
  218. package/out/_next/static/media/KaTeX_Typewriter-Regular.0cgrzn5l3kao5.woff +0 -0
  219. package/out/_next/static/media/KaTeX_Typewriter-Regular.128~qc3858otl.ttf +0 -0
  220. package/out/_not-found/__next._full.txt +21 -19
  221. package/out/_not-found/__next._head.txt +3 -3
  222. package/out/_not-found/__next._index.txt +8 -6
  223. package/out/_not-found/__next._not-found.__PAGE__.txt +4 -4
  224. package/out/_not-found/__next._not-found.txt +3 -3
  225. package/out/_not-found/__next._tree.txt +3 -2
  226. package/out/_not-found/index.html +2 -2
  227. package/out/_not-found/index.txt +21 -19
  228. package/out/admin/__next._full.txt +23 -0
  229. package/out/admin/__next._head.txt +5 -0
  230. package/out/admin/__next._index.txt +9 -0
  231. package/out/admin/__next._tree.txt +5 -0
  232. package/out/admin/__next.admin.__PAGE__.txt +9 -0
  233. package/out/admin/__next.admin.txt +5 -0
  234. package/out/admin/index.html +15 -0
  235. package/out/admin/index.txt +23 -0
  236. package/out/app/__next._full.txt +15 -13
  237. package/out/app/__next._head.txt +3 -3
  238. package/out/app/__next._index.txt +8 -6
  239. package/out/app/__next._tree.txt +4 -2
  240. package/out/app/__next.app.__PAGE__.txt +4 -4
  241. package/out/app/__next.app.txt +3 -4
  242. package/out/app/index.html +2 -2
  243. package/out/app/index.txt +15 -13
  244. package/out/chat/__next._full.txt +16 -14
  245. package/out/chat/__next._head.txt +3 -3
  246. package/out/chat/__next._index.txt +8 -6
  247. package/out/chat/__next._tree.txt +5 -3
  248. package/out/chat/__next.chat.__PAGE__.txt +4 -4
  249. package/out/chat/__next.chat.txt +4 -5
  250. package/out/chat/index.html +2 -2
  251. package/out/chat/index.txt +16 -14
  252. package/out/chat/join/__next._full.txt +25 -0
  253. package/out/chat/join/__next._head.txt +5 -0
  254. package/out/chat/join/__next._index.txt +9 -0
  255. package/out/chat/join/__next._tree.txt +5 -0
  256. package/out/chat/join/__next.chat.join.__PAGE__.txt +9 -0
  257. package/out/chat/join/__next.chat.join.txt +5 -0
  258. package/out/chat/join/__next.chat.txt +5 -0
  259. package/out/chat/join/index.html +15 -0
  260. package/out/chat/join/index.txt +25 -0
  261. package/out/download/__next._full.txt +34 -33
  262. package/out/download/__next._head.txt +3 -3
  263. package/out/download/__next._index.txt +8 -6
  264. package/out/download/__next._tree.txt +6 -4
  265. package/out/download/__next.download.__PAGE__.txt +13 -14
  266. package/out/download/__next.download.txt +3 -3
  267. package/out/download/index.html +2 -2
  268. package/out/download/index.txt +34 -33
  269. package/out/index.html +2 -2
  270. package/out/index.txt +23 -20
  271. package/out/note/__next._full.txt +24 -0
  272. package/out/{changelog → note}/__next._head.txt +3 -3
  273. package/out/note/__next._index.txt +9 -0
  274. package/out/note/__next._tree.txt +4 -0
  275. package/out/note/__next.note.__PAGE__.txt +9 -0
  276. package/out/note/__next.note.txt +5 -0
  277. package/out/note/index.html +15 -0
  278. package/out/note/index.txt +24 -0
  279. package/out/ping/__next._full.txt +23 -20
  280. package/out/ping/__next._head.txt +3 -3
  281. package/out/ping/__next._index.txt +8 -6
  282. package/out/ping/__next._tree.txt +6 -4
  283. package/out/ping/__next.ping.__PAGE__.txt +5 -5
  284. package/out/ping/__next.ping.txt +4 -4
  285. package/out/ping/index.html +2 -2
  286. package/out/ping/index.txt +23 -20
  287. package/out/web3/__next._full.txt +16 -14
  288. package/out/web3/__next._head.txt +3 -3
  289. package/out/web3/__next._index.txt +8 -6
  290. package/out/web3/__next._tree.txt +5 -3
  291. package/out/web3/__next.web3.__PAGE__.txt +4 -4
  292. package/out/web3/__next.web3.txt +4 -5
  293. package/out/web3/ed25519/__next._full.txt +14 -12
  294. package/out/web3/ed25519/__next._head.txt +3 -3
  295. package/out/web3/ed25519/__next._index.txt +8 -6
  296. package/out/web3/ed25519/__next._tree.txt +5 -3
  297. package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +2 -2
  298. package/out/web3/ed25519/__next.web3.ed25519.txt +3 -3
  299. package/out/web3/ed25519/__next.web3.txt +4 -5
  300. package/out/web3/ed25519/index.html +1 -1
  301. package/out/web3/ed25519/index.txt +14 -12
  302. package/out/web3/index.html +2 -2
  303. package/out/web3/index.txt +16 -14
  304. package/out/web3/tools/__next._full.txt +14 -12
  305. package/out/web3/tools/__next._head.txt +3 -3
  306. package/out/web3/tools/__next._index.txt +8 -6
  307. package/out/web3/tools/__next._tree.txt +5 -3
  308. package/out/web3/tools/__next.web3.tools.__PAGE__.txt +2 -2
  309. package/out/web3/tools/__next.web3.tools.txt +3 -3
  310. package/out/web3/tools/__next.web3.txt +4 -5
  311. package/out/web3/tools/index.html +1 -1
  312. package/out/web3/tools/index.txt +14 -12
  313. package/package.json +30 -13
  314. package/server/index.js +188 -901
  315. package/server/src/config.js +5 -1
  316. package/server/src/core/channelAttachment.js +68 -0
  317. package/server/src/core/cid.js +6 -71
  318. package/server/src/core/cidTopic.js +29 -0
  319. package/server/src/core/mostLink.js +88 -0
  320. package/server/src/http/access.js +123 -0
  321. package/server/src/http/app.js +1095 -0
  322. package/server/src/http/errors.js +35 -0
  323. package/server/src/http/nodeLogs.js +53 -0
  324. package/server/src/http/nodeStatus.js +146 -0
  325. package/server/src/http/staticFiles.js +84 -0
  326. package/server/src/http/uploads.js +114 -0
  327. package/server/src/index.js +1539 -301
  328. package/server/src/node/config.js +191 -0
  329. package/server/src/node/logs.js +94 -0
  330. package/server/src/utils/api.js +359 -8
  331. package/server/src/utils/auth.js +63 -0
  332. package/server/src/utils/dateTime.js +30 -0
  333. package/server/src/utils/downloadMessages.js +89 -0
  334. package/server/src/utils/errors.js +14 -0
  335. package/server/src/utils/mostWallet.js +185 -1
  336. package/server/src/utils/mp.js +2 -26
  337. package/server/src/utils/noteBackup.js +116 -0
  338. package/server/src/utils/noteUtils.js +128 -0
  339. package/server/src/utils/userIdentity.js +8 -61
  340. package/out/_next/static/chunks/003jnm.v5tzw5.js +0 -1
  341. package/out/_next/static/chunks/00re8v.gbcywn.js +0 -1
  342. package/out/_next/static/chunks/00s106sbq8t9v.js +0 -1
  343. package/out/_next/static/chunks/012hi627qrdnn.js +0 -1
  344. package/out/_next/static/chunks/0174xh3wfsjm1.js +0 -2
  345. package/out/_next/static/chunks/02~o2nmo5pmy1.js +0 -1
  346. package/out/_next/static/chunks/07t.dhhokszz5.css +0 -1
  347. package/out/_next/static/chunks/0_wia9ofmsi1c.css +0 -2
  348. package/out/_next/static/chunks/0ah8fihozo2_u.js +0 -5
  349. package/out/_next/static/chunks/0bzupvr5gt3k9.js +0 -31
  350. package/out/_next/static/chunks/0e_h0d3ekzks8.css +0 -1
  351. package/out/_next/static/chunks/0gdluj423gso1.js +0 -1
  352. package/out/_next/static/chunks/0gmoiq06srjay.css +0 -1
  353. package/out/_next/static/chunks/0imkasy7kb67u.js +0 -1
  354. package/out/_next/static/chunks/0jjc_b9q_ldi2.js +0 -1
  355. package/out/_next/static/chunks/0jl~j62iz2uvr.js +0 -1
  356. package/out/_next/static/chunks/0lqslm813wk_h.js +0 -1
  357. package/out/_next/static/chunks/0q782fxxd0lx~.js +0 -1
  358. package/out/_next/static/chunks/0slwj0c46k5cu.js +0 -1
  359. package/out/_next/static/chunks/0sorqk.oc6b7j.css +0 -1
  360. package/out/_next/static/chunks/0tapzqc6hgvx-.js +0 -1
  361. package/out/_next/static/chunks/0xsc7z5x8n7wg.js +0 -1
  362. package/out/_next/static/chunks/0zm~gys2jwl0g.js +0 -1
  363. package/out/_next/static/chunks/turbopack-0a_g3u0ud~jb8.js +0 -1
  364. package/out/changelog/__next._full.txt +0 -22
  365. package/out/changelog/__next._index.txt +0 -7
  366. package/out/changelog/__next._tree.txt +0 -3
  367. package/out/changelog/__next.changelog.__PAGE__.txt +0 -10
  368. package/out/changelog/__next.changelog.txt +0 -5
  369. package/out/changelog/index.html +0 -15
  370. package/out/changelog/index.txt +0 -22
  371. package/out/docs/__next._full.txt +0 -22
  372. package/out/docs/__next._head.txt +0 -5
  373. package/out/docs/__next._index.txt +0 -7
  374. package/out/docs/__next._tree.txt +0 -3
  375. package/out/docs/__next.docs.__PAGE__.txt +0 -10
  376. package/out/docs/__next.docs.txt +0 -5
  377. package/out/docs/getting-started/__next._full.txt +0 -22
  378. package/out/docs/getting-started/__next._head.txt +0 -5
  379. package/out/docs/getting-started/__next._index.txt +0 -7
  380. package/out/docs/getting-started/__next._tree.txt +0 -3
  381. package/out/docs/getting-started/__next.docs.getting-started.__PAGE__.txt +0 -10
  382. package/out/docs/getting-started/__next.docs.getting-started.txt +0 -5
  383. package/out/docs/getting-started/__next.docs.txt +0 -5
  384. package/out/docs/getting-started/index.html +0 -15
  385. package/out/docs/getting-started/index.txt +0 -22
  386. package/out/docs/index.html +0 -15
  387. package/out/docs/index.txt +0 -22
  388. /package/out/_next/static/{iOB2EBwOGZ0iYW7Lbg9u_ → t7ZIeQpVvjz4a7-5Tt-VK}/_buildManifest.js +0 -0
  389. /package/out/_next/static/{iOB2EBwOGZ0iYW7Lbg9u_ → t7ZIeQpVvjz4a7-5Tt-VK}/_clientMiddlewareManifest.js +0 -0
  390. /package/out/_next/static/{iOB2EBwOGZ0iYW7Lbg9u_ → t7ZIeQpVvjz4a7-5Tt-VK}/_ssgManifest.js +0 -0
package/server/index.js CHANGED
@@ -1,888 +1,109 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import os from 'node:os'
4
3
  import { fileURLToPath } from 'node:url'
5
- import { spawn } from 'node:child_process'
6
- import Busboy from 'busboy'
7
4
  import { WebSocketServer } from 'ws'
8
- import { Hono } from 'hono'
9
- import { cors } from 'hono/cors'
10
- import { serveStatic } from '@hono/node-server/serve-static'
11
5
  import { serve } from '@hono/node-server'
12
6
  import { MostBoxEngine } from './src/index.js'
13
- import { parseMostLink, validateCidString } from './src/core/cid.js'
14
- import { sanitizeFilename } from './src/utils/security.js'
15
- import { MAX_FILE_SIZE } from './src/config.js'
16
-
17
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
18
- const PORT = Number(process.env.MOSTBOX_PORT || process.env.PORT) || 1976
19
- const HOST = process.env.MOSTBOX_HOST || '0.0.0.0'
20
-
21
- const MAX_UPLOAD_SIZE = MAX_FILE_SIZE
22
- const UPLOAD_TMP_DIR = path.join(os.tmpdir(), 'most-box-uploads')
23
-
24
- const RATE_LIMIT_WINDOW = 60 * 1000
25
- const RATE_LIMIT_MAX_REQUESTS = 120
26
-
27
- // --- 配置 ---
28
- const CONFIG_DIR = path.join(os.homedir(), '.most-box')
29
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
30
-
31
- function loadConfig() {
32
- try {
33
- if (fs.existsSync(CONFIG_FILE)) {
34
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'))
35
- }
36
- } catch (err) {
37
- console.error('[Config] Load error:', err.message)
38
- }
39
- return {}
40
- }
41
-
42
- function saveConfig(config) {
43
- try {
44
- if (!fs.existsSync(CONFIG_DIR)) {
45
- fs.mkdirSync(CONFIG_DIR, { recursive: true })
46
- }
47
- const tmpPath = CONFIG_FILE + '.tmp'
48
- fs.writeFileSync(tmpPath, JSON.stringify(config, null, 2), 'utf-8')
49
- fs.renameSync(tmpPath, CONFIG_FILE)
50
- return true
51
- } catch (err) {
52
- console.error('[Config] Save error:', err.message)
53
- return false
54
- }
55
- }
56
-
57
- function getDataPath() {
58
- if (process.env.MOSTBOX_DATA_PATH) {
59
- return process.env.MOSTBOX_DATA_PATH
60
- }
61
- const config = loadConfig()
62
- return config.dataPath || path.join(os.homedir(), 'most-data')
63
- }
64
-
65
- // --- 静态文件服务 ---
66
- const MIME_TYPES = {
67
- '.html': 'text/html; charset=utf-8',
68
- '.js': 'application/javascript; charset=utf-8',
69
- '.css': 'text/css; charset=utf-8',
70
- '.json': 'application/json',
71
- '.png': 'image/png',
72
- '.jpg': 'image/jpeg',
73
- '.jpeg': 'image/jpeg',
74
- '.gif': 'image/gif',
75
- '.webp': 'image/webp',
76
- '.svg': 'image/svg+xml',
77
- '.ico': 'image/x-icon',
78
- '.mp4': 'video/mp4',
79
- '.webm': 'video/webm',
80
- '.ogg': 'video/ogg',
81
- '.mp3': 'audio/mpeg',
82
- '.wav': 'audio/wav',
83
- '.flac': 'audio/flac',
84
- '.aac': 'audio/aac',
85
- '.m4a': 'audio/mp4',
86
- '.opus': 'audio/opus',
87
- '.woff2': 'font/woff2',
88
- '.woff': 'font/woff',
89
- }
90
-
91
- function getMimeType(fileName) {
92
- const ext = path.extname(fileName).toLowerCase()
93
- return MIME_TYPES[ext] || 'application/octet-stream'
94
- }
95
-
96
- function decodeFilenameFromHeader(headerStr) {
97
- if (!headerStr) return null
98
-
99
- const filenameStarMatch = headerStr.match(
100
- /filename\*=(?:UTF-8''|utf-8'')([^;\r\n]+)/i
101
- )
102
- if (filenameStarMatch) {
103
- return decodeURIComponent(filenameStarMatch[1])
104
- }
105
-
106
- const filenameMatch = headerStr.match(/filename="([^"]+)"/)
107
- if (filenameMatch) {
108
- const rawFilename = filenameMatch[1]
7
+ import {
8
+ DEFAULT_NODE_HOST,
9
+ DEFAULT_NODE_PORT,
10
+ createNodeConfigStore,
11
+ } from './src/node/config.js'
12
+ import { createNodeLogger } from './src/node/logs.js'
13
+ import {
14
+ UPLOAD_TMP_DIR,
15
+ createApp,
16
+ getDataPath,
17
+ } from './src/http/app.js'
18
+
19
+ export { createApp } from './src/http/app.js'
20
+
21
+ const PORT = DEFAULT_NODE_PORT
22
+ const HOST = DEFAULT_NODE_HOST
23
+
24
+ function cleanUploadTempDir() {
25
+ if (!fs.existsSync(UPLOAD_TMP_DIR)) return
26
+
27
+ const staleFiles = fs.readdirSync(UPLOAD_TMP_DIR)
28
+ for (const file of staleFiles) {
109
29
  try {
110
- const buf = Buffer.from(rawFilename, 'latin1')
111
- const decoded = buf.toString('utf8')
112
- if (decoded.includes('\ufffd')) {
113
- return rawFilename
114
- }
115
- return decoded
116
- } catch {
117
- return rawFilename
118
- }
119
- }
120
-
121
- const filenamePlainMatch = headerStr.match(/filename=([^;\r\n]+)/)
122
- if (filenamePlainMatch) {
123
- return filenamePlainMatch[1].trim()
124
- }
125
- return null
126
- }
127
-
128
- async function parseMultipartBusboy(req) {
129
- return new Promise((resolve, reject) => {
130
- if (!fs.existsSync(UPLOAD_TMP_DIR)) {
131
- fs.mkdirSync(UPLOAD_TMP_DIR, { recursive: true })
132
- }
133
-
134
- const busboy = Busboy({
135
- headers: req.headers,
136
- limits: {
137
- fileSize: MAX_UPLOAD_SIZE,
138
- files: 1,
139
- fields: 0,
140
- },
141
- })
142
-
143
- const result = { filePath: null, filename: null }
144
- let fileSize = 0
145
- let writeStream = null
146
- let tempPath = null
147
-
148
- busboy.on('file', (name, stream, info) => {
149
- result.filename = decodeFilenameFromHeader(`filename="${info.filename}"`)
150
- tempPath = path.join(
151
- UPLOAD_TMP_DIR,
152
- `upload_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
153
- )
154
- writeStream = fs.createWriteStream(tempPath)
155
-
156
- stream.on('data', chunk => {
157
- fileSize += chunk.length
158
- if (fileSize > MAX_UPLOAD_SIZE) {
159
- stream.destroy()
160
- writeStream.destroy()
161
- fs.unlink(tempPath, () => {})
162
- reject(new Error('File too large'))
163
- return
164
- }
165
- })
166
-
167
- stream.on('error', () => {
168
- if (tempPath) fs.unlink(tempPath, () => {})
169
- })
170
-
171
- stream.pipe(writeStream)
172
-
173
- writeStream.on('finish', () => {
174
- result.filePath = tempPath
175
- resolve(result)
176
- })
177
-
178
- writeStream.on('error', err => {
179
- if (tempPath) fs.unlink(tempPath, () => {})
180
- reject(err)
181
- })
182
- })
183
-
184
- busboy.on('error', err => {
185
- if (tempPath) fs.unlink(tempPath, () => {})
186
- reject(err)
187
- })
188
-
189
- busboy.on('close', () => {
190
- if (!result.filename) {
191
- resolve(null)
192
- }
193
- })
194
-
195
- req.on('error', err => {
196
- if (tempPath) fs.unlink(tempPath, () => {})
197
- reject(err)
198
- })
199
- req.pipe(busboy)
200
- })
201
- }
202
-
203
- // --- Hono 应用工厂 ---
204
- export function createApp(engine, options = {}) {
205
- const appPort = options.port || PORT
206
- const wssRef = options.wssRef || { current: null }
207
- const serverInstanceRef = options.serverInstanceRef || { current: null }
208
-
209
- // 速率限制(每个 app 实例独立)
210
- const rateLimitMap = new Map()
211
- function checkRateLimit(clientIp) {
212
- const now = Date.now()
213
- if (!rateLimitMap.has(clientIp)) {
214
- rateLimitMap.set(clientIp, [])
215
- }
216
- const requests = rateLimitMap.get(clientIp)
217
- while (requests.length > 0 && requests[0] < now - RATE_LIMIT_WINDOW) {
218
- requests.shift()
219
- }
220
- if (requests.length === 0) {
221
- rateLimitMap.delete(clientIp)
222
- }
223
- if (requests.length >= RATE_LIMIT_MAX_REQUESTS) {
224
- return false
225
- }
226
- requests.push(now)
227
- return true
228
- }
229
-
230
- function rateLimitMiddleware() {
231
- return async (c, next) => {
232
- const clientIp =
233
- c.req.header('x-forwarded-for') ||
234
- c.env.incoming?.socket?.remoteAddress ||
235
- 'unknown'
236
- if (!checkRateLimit(clientIp)) {
237
- return c.json({ error: 'Too many requests' }, 429)
238
- }
239
- await next()
240
- }
241
- }
242
-
243
- // WebSocket 广播
244
- const channelSubscriptions = new Map()
245
-
246
- function wsBroadcast(event, data) {
247
- const payload = JSON.stringify({ event, data })
248
- const wss = wssRef.current
249
- if (wss) {
250
- wss.clients.forEach(client => {
251
- if (client.readyState === 1) {
252
- try {
253
- client.send(payload)
254
- } catch (err) {
255
- console.warn('[WS] Failed to send to client:', err.message)
256
- }
257
- }
258
- })
259
- }
260
- }
261
-
262
- function wsSendToChannel(channelName, event, data) {
263
- const payload = JSON.stringify({ event, data })
264
- const subscribers = channelSubscriptions.get(channelName)
265
- if (subscribers) {
266
- subscribers.forEach(ws => {
267
- if (ws.readyState === 1) {
268
- try {
269
- ws.send(payload)
270
- } catch (err) {
271
- console.warn('[WS] Failed to send to channel subscriber:', err.message)
272
- }
273
- }
274
- })
275
- }
276
- }
277
-
278
- function subscribeToChannel(ws, channelName) {
279
- if (!channelSubscriptions.has(channelName)) {
280
- channelSubscriptions.set(channelName, new Set())
281
- }
282
- channelSubscriptions.get(channelName).add(ws)
283
- }
284
-
285
- function unsubscribeFromChannel(ws, channelName) {
286
- const subscribers = channelSubscriptions.get(channelName)
287
- if (subscribers) {
288
- subscribers.delete(ws)
289
- if (subscribers.size === 0) {
290
- channelSubscriptions.delete(channelName)
291
- }
292
- }
293
- }
294
-
295
- function cleanupWsSubscriptions(ws) {
296
- for (const [channel, subscribers] of channelSubscriptions) {
297
- subscribers.delete(ws)
298
- if (subscribers.size === 0) {
299
- channelSubscriptions.delete(channel)
300
- }
301
- }
302
- }
303
-
304
- // 将广播函数挂载到 engine 上供外部测试使用
305
- engine.wsBroadcast = wsBroadcast
306
- engine.wsSendToChannel = wsSendToChannel
307
-
308
- const app = new Hono()
309
-
310
- // CORS 中间件
311
- app.use(
312
- '/api/*',
313
- cors({
314
- origin: [
315
- 'http://localhost:3000',
316
- 'https://most.box',
317
- `http://localhost:${appPort}`,
318
- ],
319
- credentials: true,
320
- })
321
- )
322
-
323
- // 速率限制中间件
324
- app.use('/api/*', rateLimitMiddleware())
325
-
326
- // 全局错误处理
327
- app.onError((err, c) => {
328
- console.error('[API Error]', err)
329
- try {
330
- const errorLogPath = path.join(CONFIG_DIR, 'server-error.log')
331
- if (!fs.existsSync(CONFIG_DIR)) {
332
- fs.mkdirSync(CONFIG_DIR, { recursive: true })
333
- }
334
- fs.appendFileSync(
335
- errorLogPath,
336
- `[${new Date().toISOString()}] ${err.stack}\n`
337
- )
338
- } catch {}
339
- return c.json({ error: err.message, code: err.code }, 500)
340
- })
341
-
342
- // --- 配置路由 ---
343
- app.get('/api/node-id', c => {
344
- return c.json({ id: engine.getNodeId() })
345
- })
346
-
347
- app.get('/api/config', c => {
348
- const config = loadConfig()
349
- return c.json({ dataPath: config.dataPath || '' })
350
- })
351
-
352
- app.post('/api/config', async c => {
353
- const body = await c.req.json()
354
- const config = loadConfig()
355
-
356
- if (body.resetStorage) {
357
- config.dataPath = ''
358
- } else if (body.dataPath !== undefined) {
359
- let dataPath = body.dataPath.trim()
360
- let basePath = dataPath
361
-
362
- if (dataPath.match(/^[A-Za-z]:\\$/)) {
363
- basePath = dataPath
364
- dataPath = path.join(dataPath, 'most-data')
365
- }
366
-
367
- if (!fs.existsSync(basePath)) {
368
- return c.json({ error: '目录不存在' }, 400)
369
- }
370
-
371
- if (!fs.existsSync(dataPath)) {
372
- fs.mkdirSync(dataPath, { recursive: true })
373
- }
374
-
375
- config.dataPath = dataPath
376
- }
377
-
378
- const success = saveConfig(config)
379
- return c.json({ success, dataPath: getDataPath() })
380
- })
381
-
382
- app.get('/api/config/data-path', c => {
383
- const config = loadConfig()
384
- const isDefault = !config.dataPath
385
- const dataPath = getDataPath()
386
- return c.json({ dataPath, isDefault })
387
- })
388
-
389
- // --- 网络路由 ---
390
- app.get('/api/network-status', c => {
391
- return c.json(engine.getNetworkStatus())
392
- })
393
-
394
- app.get('/api/network', c => {
395
- const interfaces = os.networkInterfaces()
396
- const addresses = []
397
- const seen = new Set()
398
-
399
- for (const [name, nets] of Object.entries(interfaces)) {
400
- for (const net of nets) {
401
- if (net.family !== 'IPv4' || net.internal) continue
402
- if (seen.has(net.address)) continue
403
- seen.add(net.address)
404
-
405
- let type = 'lan'
406
- let label = '局域网'
407
- if (net.address.startsWith('100.')) {
408
- type = 'tailscale'
409
- label = 'Tailscale'
410
- } else if (
411
- name.toLowerCase().includes('zt') ||
412
- name.toLowerCase().includes('zerotier')
413
- ) {
414
- type = 'zerotier'
415
- label = 'ZeroTier'
416
- }
417
-
418
- addresses.push({ type, ip: net.address, label, iface: name })
419
- }
420
- }
421
-
422
- const localEntry = {
423
- type: 'local',
424
- ip: 'localhost',
425
- label: '本机',
426
- iface: 'loopback',
427
- }
428
- return c.json({ port: appPort, addresses: [localEntry, ...addresses] })
429
- })
430
-
431
- // --- 文件路由 ---
432
- app.get('/api/files', c => {
433
- return c.json(engine.listPublishedFiles())
434
- })
435
-
436
- app.post('/api/publish', async c => {
437
- const req = c.env.incoming
438
- const result = await parseMultipartBusboy(req)
439
-
440
- if (!result || !result.filename) {
441
- return c.json({ error: 'No file provided' }, 400)
442
- }
443
-
444
- try {
445
- const publishResult = await engine.publishFile(
446
- result.filePath,
447
- result.filename
448
- )
449
- return c.json({ success: true, ...publishResult })
450
- } finally {
451
- fs.unlink(result.filePath, () => {})
452
- }
453
- })
454
-
455
- app.post('/api/download', async c => {
456
- const body = await c.req.json()
457
- if (!body.link) {
458
- return c.json({ error: 'link is required' }, 400)
459
- }
460
-
461
- const taskId = `dl_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
462
-
463
- const parsed = parseMostLink(body.link)
464
- if (parsed.error) {
465
- return c.json({ error: parsed.error }, 400)
466
- }
467
-
468
- const existingFile = engine
469
- .getPublishedFiles()
470
- .find(f => f.cid === parsed.cid)
471
- if (existingFile) {
472
- console.log(`[MostBox] File already exists: ${existingFile.fileName}`)
473
- return c.json({
474
- success: true,
475
- taskId,
476
- alreadyExists: true,
477
- fileName: existingFile.fileName,
478
- })
479
- }
480
-
481
- engine.downloadFile(body.link, taskId).catch(err => {
482
- if (err.message === 'Download cancelled') {
483
- wsBroadcast('download:cancelled', { taskId })
484
- } else {
485
- wsBroadcast('download:error', { taskId, error: err.message })
486
- }
487
- })
488
-
489
- return c.json({ success: true, taskId })
490
- })
491
-
492
- app.post('/api/download/cancel', async c => {
493
- const body = await c.req.json()
494
- if (!body.taskId) {
495
- return c.json({ error: 'taskId is required' }, 400)
496
- }
497
- engine.cancelDownload(body.taskId)
498
- return c.json({ success: true })
499
- })
500
-
501
- app.delete('/api/files/:cid', async c => {
502
- const cid = c.req.param('cid')
503
- const cidValidation = validateCidString(cid)
504
- if (!cidValidation.valid) {
505
- return c.json({ error: cidValidation.error }, 400)
506
- }
507
- const result = await engine.deletePublishedFile(cid)
508
- return c.json(result)
509
- })
510
-
511
- app.post('/api/move', async c => {
512
- const body = await c.req.json()
513
- if (!body.cid || !body.newFileName) {
514
- return c.json({ error: 'cid and newFileName are required' }, 400)
515
- }
516
- const cidValidation = validateCidString(body.cid)
517
- if (!cidValidation.valid) {
518
- return c.json({ error: cidValidation.error }, 400)
519
- }
520
- const cleanFileName = sanitizeFilename(body.newFileName)
521
- if (
522
- !cleanFileName ||
523
- cleanFileName === 'unnamed' ||
524
- body.newFileName.length > 255
525
- ) {
526
- return c.json({ error: 'Invalid filename' }, 400)
527
- }
528
- try {
529
- const result = engine.moveFile(body.cid, cleanFileName)
530
- return c.json({ success: true, ...result })
30
+ fs.unlinkSync(path.join(UPLOAD_TMP_DIR, file))
531
31
  } catch (err) {
532
- return c.json({ error: err.message }, 400)
533
- }
534
- })
535
-
536
- app.get('/api/files/:cid/download', async c => {
537
- const cid = c.req.param('cid')
538
- const cidValidation = validateCidString(cid)
539
- if (!cidValidation.valid) {
540
- return c.json({ error: cidValidation.error }, 400)
32
+ console.warn('[MostBox] Failed to clean upload temp file:', err.message)
541
33
  }
542
-
543
- const rangeHeader = c.req.header('range')
544
-
545
- try {
546
- if (rangeHeader) {
547
- const rangeMatch = rangeHeader.match(/bytes=(\d+)-(\d*)/)
548
- if (rangeMatch) {
549
- const start = parseInt(rangeMatch[1], 10)
550
- const end = rangeMatch[2] ? parseInt(rangeMatch[2], 10) : undefined
551
- const offset = start
552
- const limit = end !== undefined ? end - start + 1 : undefined
553
-
554
- const result = await engine.readFileRaw(cid, { offset, limit })
555
- const contentType = getMimeType(result.fileName)
556
-
557
- c.header('Content-Type', contentType)
558
- c.header('Content-Length', String(result.buffer.length))
559
- c.header(
560
- 'Content-Range',
561
- `bytes ${offset}-${offset + result.buffer.length - 1}/${result.totalSize}`
562
- )
563
- c.header('Accept-Ranges', 'bytes')
564
- c.status(206)
565
- return c.body(result.buffer)
566
- }
567
- }
568
-
569
- const result = await engine.readFileRaw(cid)
570
- const contentType = getMimeType(result.fileName)
571
- c.header('Content-Type', contentType)
572
- c.header('Content-Length', String(result.totalSize))
573
- c.header('Accept-Ranges', 'bytes')
574
- c.header(
575
- 'Content-Disposition',
576
- `inline; filename="${encodeURIComponent(result.fileName)}"`
577
- )
578
- return c.body(result.buffer)
579
- } catch (err) {
580
- if (err.message === 'File not found') {
581
- return c.json({ error: err.message }, 404)
582
- }
583
- return c.json({ error: err.message }, 400)
584
- }
585
- })
586
-
587
- // --- 回收站路由 ---
588
- app.get('/api/trash', c => {
589
- return c.json(engine.listTrashFiles())
590
- })
591
-
592
- app.post('/api/trash/:cid/restore', async c => {
593
- const cid = c.req.param('cid')
594
- const cidValidation = validateCidString(cid)
595
- if (!cidValidation.valid) {
596
- return c.json({ error: cidValidation.error }, 400)
597
- }
598
- try {
599
- const result = engine.restoreTrashFile(cid)
600
- return c.json({ success: true, files: result })
601
- } catch (err) {
602
- return c.json({ error: err.message }, 400)
603
- }
604
- })
605
-
606
- app.delete('/api/trash/:cid', async c => {
607
- const cid = c.req.param('cid')
608
- const cidValidation = validateCidString(cid)
609
- if (!cidValidation.valid) {
610
- return c.json({ error: cidValidation.error }, 400)
611
- }
612
- const result = await engine.permanentDeleteTrashFile(cid)
613
- return c.json({ success: true, trashFiles: result })
614
- })
615
-
616
- app.delete('/api/trash', async c => {
617
- const result = await engine.emptyTrash()
618
- return c.json({ success: true, trashFiles: result })
619
- })
620
-
621
- // --- 收藏路由 ---
622
- app.post('/api/files/:cid/star', async c => {
623
- const cid = c.req.param('cid')
624
- const cidValidation = validateCidString(cid)
625
- if (!cidValidation.valid) {
626
- return c.json({ error: cidValidation.error }, 400)
627
- }
628
- try {
629
- const result = engine.toggleStarred(cid)
630
- return c.json({ success: true, ...result })
631
- } catch (err) {
632
- return c.json({ error: err.message }, 400)
633
- }
634
- })
635
-
636
- // --- 存储路由 ---
637
- app.get('/api/storage', async c => {
638
- const result = await engine.getStorageStats()
639
- return c.json(result)
640
- })
641
-
642
- // --- 显示名路由 ---
643
- app.get('/api/display-name', c => {
644
- return c.json({ displayName: engine.getDisplayName() })
645
- })
646
-
647
- app.post('/api/display-name', async c => {
648
- const body = await c.req.json()
649
- if (!body.name || !body.name.trim()) {
650
- return c.json({ error: 'name is required' }, 400)
651
- }
652
- const trimmed = body.name.trim()
653
- if (trimmed.length > 100) {
654
- return c.json({ error: 'Name too long (max 100 chars)' }, 400)
655
- }
656
- if (/[<>]/.test(trimmed)) {
657
- return c.json({ error: 'Name contains invalid characters' }, 400)
658
- }
659
- const success = engine.setDisplayName(trimmed)
660
- return c.json({ success, displayName: engine.getDisplayName() })
661
- })
662
-
663
- // --- 频道路由 ---
664
- app.post('/api/channels', async c => {
665
- const body = await c.req.json()
666
- if (!body.name || !body.name.trim()) {
667
- return c.json({ error: 'name is required' }, 400)
668
- }
669
- try {
670
- const result = await engine.createChannel(
671
- body.name.trim(),
672
- body.type || 'personal'
673
- )
674
- return c.json({ success: true, ...result })
675
- } catch (err) {
676
- return c.json({ error: err.message }, 400)
677
- }
678
- })
679
-
680
- app.get('/api/channels', c => {
681
- return c.json(engine.listChannels())
682
- })
683
-
684
- app.delete('/api/channels/:name', async c => {
685
- const name = c.req.param('name')
686
- try {
687
- const result = await engine.leaveChannel(name)
688
- return c.json({ success: true, channels: result })
689
- } catch (err) {
690
- return c.json({ error: err.message }, 400)
691
- }
692
- })
693
-
694
- app.get('/api/channels/:name/messages', async c => {
695
- const name = c.req.param('name')
696
- const limit = parseInt(c.req.query('limit') || '100', 10)
697
- const offset = parseInt(c.req.query('offset') || '0', 10)
698
- try {
699
- const messages = await engine.getChannelMessages(name, { limit, offset })
700
- return c.json(messages)
701
- } catch (err) {
702
- return c.json({ error: err.message }, 400)
703
- }
704
- })
705
-
706
- app.post('/api/channels/:name/messages', async c => {
707
- const name = c.req.param('name')
708
- const body = await c.req.json()
709
- if (!body.content || !body.content.trim()) {
710
- return c.json({ error: 'content is required' }, 400)
711
- }
712
- if (!body.author || !body.authorName) {
713
- return c.json({ error: 'author and authorName are required' }, 400)
714
- }
715
- if (!/^0x[a-fA-F0-9]{40}$/.test(body.author)) {
716
- return c.json({ error: 'Invalid author format' }, 400)
717
- }
718
- if (body.authorName.length > 50) {
719
- return c.json({ error: 'authorName too long' }, 400)
720
- }
721
- try {
722
- const message = await engine.sendMessage(
723
- name,
724
- body.content,
725
- body.author,
726
- body.authorName
727
- )
728
- return c.json({ success: true, message })
729
- } catch (err) {
730
- return c.json({ error: err.message }, 400)
731
- }
732
- })
733
-
734
- app.get('/api/channels/:name/peers', c => {
735
- return c.json(engine.getChannelPeers(c.req.param('name')))
736
- })
737
-
738
- // --- 文件夹重命名 ---
739
- app.post('/api/folder/rename', async c => {
740
- const body = await c.req.json()
741
- if (!body.oldPath || !body.newPath) {
742
- return c.json({ error: 'oldPath and newPath are required' }, 400)
743
- }
744
- if (body.oldPath.length > 500 || body.newPath.length > 500) {
745
- return c.json({ error: 'Path too long' }, 400)
746
- }
747
- if (body.oldPath.includes('..') || body.newPath.includes('..')) {
748
- return c.json({ error: 'Path traversal not allowed' }, 400)
749
- }
750
- try {
751
- const result = engine.renameFolder(body.oldPath, body.newPath)
752
- return c.json({ success: true, ...result })
753
- } catch (err) {
754
- return c.json({ error: err.message }, 400)
755
- }
756
- })
757
-
758
- // --- 关机路由 ---
759
- app.post('/api/shutdown', c => {
760
- const clientIp = c.env.incoming?.socket?.remoteAddress || 'unknown'
761
- const isLocalhost =
762
- clientIp === 'localhost' ||
763
- clientIp === '::1' ||
764
- clientIp === '::ffff:localhost' ||
765
- clientIp === '127.0.0.1' ||
766
- clientIp === '::ffff:127.0.0.1' ||
767
- clientIp.startsWith('::ffff:127.')
768
- if (!isLocalhost) {
769
- return c.json({ error: 'Forbidden' }, 403)
770
- }
771
- c.json({ success: true })
772
- console.log('[MostBox] Shutdown requested via API...')
773
- setTimeout(async () => {
774
- await engine.stop()
775
- if (serverInstanceRef.current) serverInstanceRef.current.close()
776
- console.log('[MostBox] Server stopped.')
777
- process.exit(0)
778
- }, 100)
779
- return c.body(null)
780
- })
781
-
782
- // --- 静态文件服务(SPA fallback) ---
783
- const publicDir = path.join(__dirname, '..', 'out')
784
-
785
- app.get('/static/*', serveStatic({ root: './out' }))
786
- app.get('/_next/*', serveStatic({ root: './out' }))
787
-
788
- app.all('/api/*', c => {
789
- return c.json({ error: 'Not found' }, 404)
790
- })
791
-
792
- app.get('*', async c => {
793
- const pathname = c.req.path
794
- const filePath = path.join(publicDir, pathname)
795
- const resolved = path.resolve(filePath)
796
- const resolvedPublic = path.resolve(publicDir)
797
-
798
- if (!resolved.startsWith(resolvedPublic + path.sep) && resolved !== resolvedPublic) {
799
- return c.json({ error: 'Not found' }, 404)
800
- }
801
-
802
- if (fs.existsSync(filePath)) {
803
- const stat = fs.statSync(filePath)
804
- if (stat.isFile()) {
805
- const ext = path.extname(filePath)
806
- c.header('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')
807
- return c.body(fs.readFileSync(filePath))
808
- }
809
- if (stat.isDirectory()) {
810
- const dirIndex = path.join(filePath, 'index.html')
811
- if (fs.existsSync(dirIndex)) {
812
- c.header('Content-Type', 'text/html; charset=utf-8')
813
- return c.body(fs.readFileSync(dirIndex, 'utf-8'))
814
- }
815
- }
816
- }
817
-
818
- const indexPath = path.join(publicDir, 'index.html')
819
- if (fs.existsSync(indexPath)) {
820
- c.header('Content-Type', 'text/html; charset=utf-8')
821
- return c.body(fs.readFileSync(indexPath, 'utf-8'))
822
- }
823
-
824
- return c.json({ error: 'Not found' }, 404)
825
- })
826
-
827
- return {
828
- app,
829
- wsBroadcast,
830
- wsSendToChannel,
831
- subscribeToChannel,
832
- unsubscribeFromChannel,
833
- cleanupWsSubscriptions,
834
34
  }
35
+ console.log(`[MostBox] Cleaned ${staleFiles.length} stale upload temp files`)
835
36
  }
836
37
 
837
- // --- 主函数 ---
838
- export async function main() {
839
- console.log('[MostBox] Starting core daemon...')
840
-
841
- if (fs.existsSync(UPLOAD_TMP_DIR)) {
842
- const staleFiles = fs.readdirSync(UPLOAD_TMP_DIR)
843
- for (const file of staleFiles) {
844
- try {
845
- fs.unlinkSync(path.join(UPLOAD_TMP_DIR, file))
846
- } catch (err) {
847
- console.warn('[MostBox] Failed to clean upload temp file:', err.message)
848
- }
38
+ function bindEngineEvents({
39
+ engine,
40
+ wsBroadcast,
41
+ wsSendToChannel,
42
+ appendNodeLog,
43
+ broadcastNodeStatus,
44
+ }) {
45
+ let engineReadyForStatus = false
46
+ const safeBroadcastNodeStatus = () => {
47
+ if (engineReadyForStatus) {
48
+ broadcastNodeStatus()
849
49
  }
850
- console.log(
851
- `[MostBox] Cleaned ${staleFiles.length} stale upload temp files`
852
- )
853
50
  }
854
51
 
855
- const dataPath = getDataPath()
856
- console.log(`[MostBox] Storage: ${dataPath}`)
857
-
858
- const engine = new MostBoxEngine({ dataPath })
859
-
860
- const wssRef = { current: null }
861
- const serverInstanceRef = { current: null }
862
-
863
- const {
864
- app,
865
- wsBroadcast,
866
- wsSendToChannel,
867
- subscribeToChannel,
868
- unsubscribeFromChannel,
869
- cleanupWsSubscriptions,
870
- } = createApp(engine, {
871
- port: PORT,
872
- wssRef,
873
- serverInstanceRef,
874
- })
875
-
876
52
  engine.on('download:progress', data => wsBroadcast('download:progress', data))
877
53
  engine.on('download:status', data => wsBroadcast('download:status', data))
878
- engine.on('download:success', data => wsBroadcast('download:success', data))
54
+ engine.on('download:success', data => {
55
+ wsBroadcast('download:success', data)
56
+ appendNodeLog({
57
+ event: 'node:download:success',
58
+ message: 'Download verified and stored',
59
+ data,
60
+ })
61
+ safeBroadcastNodeStatus()
62
+ })
879
63
  engine.on('download:cancelled', data =>
880
64
  wsBroadcast('download:cancelled', data)
881
65
  )
882
66
  engine.on('publish:progress', data => wsBroadcast('publish:progress', data))
883
- engine.on('publish:success', data => wsBroadcast('publish:success', data))
67
+ engine.on('publish:success', data => {
68
+ wsBroadcast('publish:success', data)
69
+ appendNodeLog({
70
+ event: 'node:publish:success',
71
+ message: 'File published and seeding',
72
+ data: { cid: data.cid, fileName: data.fileName },
73
+ })
74
+ safeBroadcastNodeStatus()
75
+ })
884
76
  engine.on('connection', () => {
885
77
  wsBroadcast('network:status', engine.getNetworkStatus())
78
+ safeBroadcastNodeStatus()
79
+ })
80
+ engine.on('holding:updated', data => {
81
+ appendNodeLog({
82
+ event: 'node:holding:updated',
83
+ message: 'Holding metadata updated',
84
+ data: { cid: data.cid, size: data.size },
85
+ })
86
+ safeBroadcastNodeStatus()
87
+ })
88
+ engine.on('holding:removed', data => {
89
+ appendNodeLog({
90
+ event: 'node:holding:removed',
91
+ message: 'Holding metadata removed',
92
+ data,
93
+ })
94
+ safeBroadcastNodeStatus()
95
+ })
96
+ engine.on('file:topic:joined', data => {
97
+ appendNodeLog({
98
+ event: 'node:topic:joined',
99
+ message: 'CID topic joined',
100
+ data,
101
+ })
102
+ safeBroadcastNodeStatus()
103
+ })
104
+ engine.on('seed:metrics', data => {
105
+ wsBroadcast('seed:metrics', data)
106
+ safeBroadcastNodeStatus()
886
107
  })
887
108
  engine.on('channel:message', data =>
888
109
  wsSendToChannel(data.channel, 'channel:message', data)
@@ -896,34 +117,23 @@ export async function main() {
896
117
  engine.on('channel:joined', data => wsBroadcast('channel:joined', data))
897
118
  engine.on('channel:left', data => wsBroadcast('channel:left', data))
898
119
 
899
- await engine.start()
900
- console.log('[MostBox] Engine ready')
901
-
902
- serverInstanceRef.current = serve(
903
- { fetch: app.fetch, port: PORT, hostname: HOST },
904
- () => {
905
- const displayUrl = `http://localhost:${PORT}`
906
- console.log(`[MostBox] Server running at ${displayUrl}`)
907
-
908
- if (process.env.ELECTRON_APP) return
120
+ return {
121
+ markReady() {
122
+ engineReadyForStatus = true
123
+ },
124
+ }
125
+ }
909
126
 
910
- if (process.platform === 'win32') {
911
- spawn('cmd.exe', ['/c', 'start', '', displayUrl], {
912
- detached: true,
913
- stdio: 'ignore',
914
- }).unref()
915
- } else {
916
- const cmd = process.platform === 'darwin' ? 'open' : 'xdg-open'
917
- spawn(cmd, [displayUrl], {
918
- detached: true,
919
- stdio: 'ignore',
920
- }).unref()
921
- }
922
- }
923
- )
127
+ function createWebSocketServer({
128
+ serverInstance,
129
+ validateWebSocketRequest,
130
+ subscribeToChannel,
131
+ unsubscribeFromChannel,
132
+ cleanupWsSubscriptions,
133
+ }) {
134
+ const wss = new WebSocketServer({ noServer: true })
924
135
 
925
- wssRef.current = new WebSocketServer({ noServer: true })
926
- wssRef.current.on('connection', ws => {
136
+ wss.on('connection', ws => {
927
137
  ws.on('error', () => {})
928
138
  ws.on('close', () => {
929
139
  cleanupWsSubscriptions(ws)
@@ -954,31 +164,108 @@ export async function main() {
954
164
  })
955
165
  })
956
166
 
957
- serverInstanceRef.current.on('upgrade', (req, socket, head) => {
958
- if (req.url.startsWith('/ws')) {
959
- wssRef.current.handleUpgrade(req, socket, head, ws => {
960
- wssRef.current.emit('connection', ws, req)
961
- })
962
- } else {
167
+ serverInstance.on('upgrade', (req, socket, head) => {
168
+ if (!req.url.startsWith('/ws')) {
169
+ socket.destroy()
170
+ return
171
+ }
172
+
173
+ if (!validateWebSocketRequest(req)) {
963
174
  socket.destroy()
175
+ return
964
176
  }
177
+
178
+ wss.handleUpgrade(req, socket, head, ws => {
179
+ wss.emit('connection', ws, req)
180
+ })
965
181
  })
966
182
 
967
- process.on('SIGINT', async () => {
968
- console.log('\n[MostBox] Shutting down...')
183
+ return wss
184
+ }
185
+
186
+ function bindShutdownSignals({ engine, wssRef, serverInstanceRef }) {
187
+ async function shutdown(message) {
188
+ if (message) console.log(message)
969
189
  await engine.stop()
970
190
  if (wssRef.current) wssRef.current.close()
971
191
  serverInstanceRef.current.close()
972
192
  process.exit(0)
193
+ }
194
+
195
+ process.on('SIGINT', () => {
196
+ shutdown('\n[MostBox] Shutting down...')
973
197
  })
974
198
 
975
- process.on('SIGTERM', async () => {
976
- await engine.stop()
977
- if (wssRef.current) wssRef.current.close()
978
- serverInstanceRef.current.close()
979
- process.exit(0)
199
+ process.on('SIGTERM', () => {
200
+ shutdown()
201
+ })
202
+ }
203
+
204
+ // --- 主函数 ---
205
+ export async function main() {
206
+ console.log('[MostBox] Starting core daemon...')
207
+ cleanUploadTempDir()
208
+
209
+ const configStore = createNodeConfigStore()
210
+ const nodeLogger = createNodeLogger(configStore.configDir)
211
+ const dataPath = getDataPath(configStore)
212
+ console.log(`[MostBox] Storage: ${dataPath}`)
213
+
214
+ const nodeConfig = configStore.getNodeConfig()
215
+ const engine = new MostBoxEngine({
216
+ dataPath,
217
+ maxFileSize: nodeConfig.maxFileSizeBytes,
218
+ capacityBytes: nodeConfig.capacityBytes,
980
219
  })
981
220
 
221
+ const wssRef = { current: null }
222
+ const serverInstanceRef = { current: null }
223
+
224
+ const appRuntime = createApp(engine, {
225
+ port: PORT,
226
+ host: HOST,
227
+ configStore,
228
+ nodeLogger,
229
+ wssRef,
230
+ serverInstanceRef,
231
+ })
232
+
233
+ const engineEvents = bindEngineEvents({
234
+ engine,
235
+ wsBroadcast: appRuntime.wsBroadcast,
236
+ wsSendToChannel: appRuntime.wsSendToChannel,
237
+ appendNodeLog: appRuntime.appendNodeLog,
238
+ broadcastNodeStatus: appRuntime.broadcastNodeStatus,
239
+ })
240
+
241
+ await engine.start()
242
+ engineEvents.markReady()
243
+ console.log('[MostBox] Engine ready')
244
+ appRuntime.appendNodeLog({
245
+ event: 'node:ready',
246
+ message: 'Node daemon ready',
247
+ data: { dataPath, port: PORT },
248
+ })
249
+ appRuntime.broadcastNodeStatus()
250
+
251
+ serverInstanceRef.current = serve(
252
+ { fetch: appRuntime.app.fetch, port: PORT, hostname: HOST },
253
+ () => {
254
+ const displayUrl = `http://localhost:${PORT}`
255
+ console.log(`[MostBox] Server running at ${displayUrl}`)
256
+ }
257
+ )
258
+
259
+ wssRef.current = createWebSocketServer({
260
+ serverInstance: serverInstanceRef.current,
261
+ validateWebSocketRequest: appRuntime.validateWebSocketRequest,
262
+ subscribeToChannel: appRuntime.subscribeToChannel,
263
+ unsubscribeFromChannel: appRuntime.unsubscribeFromChannel,
264
+ cleanupWsSubscriptions: appRuntime.cleanupWsSubscriptions,
265
+ })
266
+
267
+ bindShutdownSignals({ engine, wssRef, serverInstanceRef })
268
+
982
269
  return engine
983
270
  }
984
271