most-box 0.0.8 → 0.1.1

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 (375) hide show
  1. package/README.md +3 -2
  2. package/out/404/index.html +2 -2
  3. package/out/404.html +2 -2
  4. package/out/__next.__PAGE__.txt +6 -6
  5. package/out/__next._full.txt +23 -20
  6. package/out/__next._head.txt +3 -3
  7. package/out/__next._index.txt +8 -6
  8. package/out/__next._tree.txt +6 -4
  9. package/out/_next/static/chunks/0-n3pg7th.zza.js +1 -0
  10. package/out/_next/static/chunks/0.4j.0k5a64vg.js +1 -0
  11. package/out/_next/static/chunks/0.ozi1_x2.m.~.js +1 -0
  12. package/out/_next/static/chunks/0.t5wlt51zou5.js +1 -0
  13. package/out/_next/static/chunks/0.w4hkvap~bva.js +1 -0
  14. package/out/_next/static/chunks/00-u5nq76f0.j.js +1 -0
  15. package/out/_next/static/chunks/00d9h1tddnnnd.js +1 -0
  16. package/out/_next/static/chunks/00fm8lijienf1.js +1 -0
  17. package/out/_next/static/chunks/00o9ht.f2qm00.css +4 -0
  18. package/out/_next/static/chunks/00tkdqwxch-3s.js +1 -0
  19. package/out/_next/static/chunks/00zi-erhjrny2.js +2 -0
  20. package/out/_next/static/chunks/01l3o90g~1z42.js +1 -0
  21. package/out/_next/static/chunks/01mfky9camw6i.js +1 -0
  22. package/out/_next/static/chunks/01r.v-pqs1vrm.js +1 -0
  23. package/out/_next/static/chunks/03edqrb4zdj~g.js +31 -0
  24. package/out/_next/static/chunks/03h_6oo-gqkhz.js +1 -0
  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/08.72abkgwy9g.js +1 -0
  36. package/out/_next/static/chunks/084xf0edl9sfo.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/09f1gfke9m5wg.css +1 -0
  41. package/out/_next/static/chunks/09ngvtajm7e5y.js +1 -0
  42. package/out/_next/static/chunks/09ps~-43n5qyo.js +1 -0
  43. package/out/_next/static/chunks/09v7_0gclxr46.js +1 -0
  44. package/out/_next/static/chunks/09xyi6fpro_d-.css +1 -0
  45. package/out/_next/static/chunks/09yql86dir9c4.js +1 -0
  46. package/out/_next/static/chunks/09zmlfljowj1~.js +1 -0
  47. package/out/_next/static/chunks/0_npg_pcoywti.js +5 -0
  48. package/out/_next/static/chunks/0_r_mk1~6bosc.js +1 -0
  49. package/out/_next/static/chunks/0_s~ebb-7b2hr.js +1 -0
  50. package/out/_next/static/chunks/0_w-0-2z5oqd_.js +1 -0
  51. package/out/_next/static/chunks/0ao1lbi4b.sfa.js +1 -0
  52. package/out/_next/static/chunks/0arm0a6adt7cc.css +1 -0
  53. package/out/_next/static/chunks/0bld2u_ld~va2.js +1 -0
  54. package/out/_next/static/chunks/0bliugh5lxw55.js +1 -0
  55. package/out/_next/static/chunks/{0e_h0d3ekzks8.css → 0c9j3eq_14vv2.css} +1 -1
  56. package/out/_next/static/chunks/0cn9a7aimbdzq.js +1 -0
  57. package/out/_next/static/chunks/0d3f-nk3c.2re.js +1 -0
  58. package/out/_next/static/chunks/0d4bueddmcnca.js +1 -0
  59. package/out/_next/static/chunks/0dtohpf7~3d12.js +1 -0
  60. package/out/_next/static/chunks/0e-3e8h7g99yf.js +1 -0
  61. package/out/_next/static/chunks/0e531nije_ln2.js +1 -0
  62. package/out/_next/static/chunks/0e5zvj_rh0z3m.js +1 -0
  63. package/out/_next/static/chunks/0f4y~rkk-n81e.js +1 -0
  64. package/out/_next/static/chunks/0fk~0~p7ivfn1.js +1 -0
  65. package/out/_next/static/chunks/0fw6juc~lsj3z.js +1 -0
  66. package/out/_next/static/chunks/0g0u7785a73vo.js +1 -0
  67. package/out/_next/static/chunks/0g_fpgh7drfda.js +1 -0
  68. package/out/_next/static/chunks/0gtwvy1z9ksa7.css +1 -0
  69. package/out/_next/static/chunks/0gze5uso1mbe9.js +1 -0
  70. package/out/_next/static/chunks/0h4r.qtmpa6eh.js +1 -0
  71. package/out/_next/static/chunks/0hf.aosc-7172.js +1 -0
  72. package/out/_next/static/chunks/0hgz35c1ejbs9.js +1 -0
  73. package/out/_next/static/chunks/0hrw-r.xmvmsq.js +1 -0
  74. package/out/_next/static/chunks/0hzg4al.v~8~m.js +1 -0
  75. package/out/_next/static/chunks/0ip9xrols_83o.js +1 -0
  76. package/out/_next/static/chunks/0j27tcmtt4ly7.js +1 -0
  77. package/out/_next/static/chunks/0j3v4mq67wtnh.js +1 -0
  78. package/out/_next/static/chunks/0j4-d0qf.v~kn.js +1 -0
  79. package/out/_next/static/chunks/0jhdeq.j9_02m.js +1 -0
  80. package/out/_next/static/chunks/0jy63h3i-y69i.js +1 -0
  81. package/out/_next/static/chunks/0kdnx_u-60k9s.js +1 -0
  82. package/out/_next/static/chunks/0kq~edq42o1-c.js +1 -0
  83. package/out/_next/static/chunks/0l682p362d-5w.js +1 -0
  84. package/out/_next/static/chunks/0lkmf5ry.s_7w.js +1 -0
  85. package/out/_next/static/chunks/0m68p9txef5rs.js +1 -0
  86. package/out/_next/static/chunks/0mme-fm5d2oz2.js +1 -0
  87. package/out/_next/static/chunks/0myp4sjagr~h0.js +1 -0
  88. package/out/_next/static/chunks/0n.qlfk~z7o.6.js +1 -0
  89. package/out/_next/static/chunks/0n4t80gjc3q5h.js +1 -0
  90. package/out/_next/static/chunks/{0n~dq4kpx9xxx.js → 0o6lrkxy4jwag.js} +1 -1
  91. package/out/_next/static/chunks/0o98f1yq..o.8.js +1 -0
  92. package/out/_next/static/chunks/0oz3yl6_-716p.js +1 -0
  93. package/out/_next/static/chunks/0p486m03-zfoi.js +1 -0
  94. package/out/_next/static/chunks/0qou.u2e2dy48.css +24 -0
  95. package/out/_next/static/chunks/0qqupeexg83u7.js +1 -0
  96. package/out/_next/static/chunks/0r1~k82nji8sf.js +1 -0
  97. package/out/_next/static/chunks/0rb-ri481.kc9.js +1 -0
  98. package/out/_next/static/chunks/0rsnmahfd.59p.js +1 -0
  99. package/out/_next/static/chunks/0rt6rgnvr-s_p.js +1 -0
  100. package/out/_next/static/chunks/0runh28p_gg6..js +1 -0
  101. package/out/_next/static/chunks/0shy.t1fwqcev.js +1 -0
  102. package/out/_next/static/chunks/{0d3shmwh5_nmn.js → 0t2xr05rlu96l.js} +1 -1
  103. package/out/_next/static/chunks/0t6h56rhg1y5i.js +1 -0
  104. package/out/_next/static/chunks/0tdqd1zunusgk.js +1 -0
  105. package/out/_next/static/chunks/0ujbnp38x63ek.js +1 -0
  106. package/out/_next/static/chunks/0usvo~vu7r8np.js +736 -0
  107. package/out/_next/static/chunks/0v68pdrp54lb-.js +1 -0
  108. package/out/_next/static/chunks/0v7qp4hv-_._r.js +1 -0
  109. package/out/_next/static/chunks/0vsm0m5sxrb.3.js +1 -0
  110. package/out/_next/static/chunks/0vzlz.iboqo3c.js +1 -0
  111. package/out/_next/static/chunks/0w87vbpkf-ogd.js +1 -0
  112. package/out/_next/static/chunks/0wuwlgcn6gxqt.js +1 -0
  113. package/out/_next/static/chunks/0xgg0~kmf3gd-.js +1 -0
  114. package/out/_next/static/chunks/0xj24-70ptdzp.js +1 -0
  115. package/out/_next/static/chunks/0xl5_avhu._i8.js +1 -0
  116. package/out/_next/static/chunks/0xxlx772fr3x4.js +1 -0
  117. package/out/_next/static/chunks/0y.li-~3oybew.js +1 -0
  118. package/out/_next/static/chunks/0yl2t7cs-n_ng.js +1 -0
  119. package/out/_next/static/chunks/0yq3kh.hchtm_.js +1 -0
  120. package/out/_next/static/chunks/0ys0l5au.9c2c.js +1 -0
  121. package/out/_next/static/chunks/0z48pmi6buytt.js +1 -0
  122. package/out/_next/static/chunks/0zapnvgy89mg..js +1 -0
  123. package/out/_next/static/chunks/0~.-vxi5oc.r0.js +1 -0
  124. package/out/_next/static/chunks/0~3ik-hfp9s-7.js +1 -0
  125. package/out/_next/static/chunks/0~4f5p6tvn1lq.js +1 -0
  126. package/out/_next/static/chunks/0~_0ys.2whxbw.js +1 -0
  127. package/out/_next/static/chunks/0~_ui9l7.2sxf.js +1 -0
  128. package/out/_next/static/chunks/1037jlyw5~7ht.js +1 -0
  129. package/out/_next/static/chunks/1045hfzu533z0.js +1 -0
  130. package/out/_next/static/chunks/104e5nmc.c-pl.js +1 -0
  131. package/out/_next/static/chunks/109taw1pbh-0b.js +1 -0
  132. package/out/_next/static/chunks/10kvl8vj_plm-.js +1 -0
  133. package/out/_next/static/chunks/10x7~onqwp338.js +1 -0
  134. package/out/_next/static/chunks/10ynz1dy483wf.js +1 -0
  135. package/out/_next/static/chunks/11hds.mg~4_r-.js +1 -0
  136. package/out/_next/static/chunks/11ibzaklcauw~.js +1 -0
  137. package/out/_next/static/chunks/11z.0s6.42b.p.js +1 -0
  138. package/out/_next/static/chunks/12-9n56l0y3yr.js +1 -0
  139. package/out/_next/static/chunks/126enaq~f7scl.js +1 -0
  140. package/out/_next/static/chunks/1380op_pfk.qo.js +1 -0
  141. package/out/_next/static/chunks/146oiw1bggtn4.js +1 -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/157z7bowux3xj.js +1 -0
  149. package/out/_next/static/chunks/15m1_677az2cm.js +1 -0
  150. package/out/_next/static/chunks/15v.~.ne6ogkk.js +1 -0
  151. package/out/_next/static/chunks/16i.qbk8t8gf_.js +1 -0
  152. package/out/_next/static/chunks/16m27azcs4k6w.js +1 -0
  153. package/out/_next/static/chunks/16u9f35gylw8l.js +1 -0
  154. package/out/_next/static/chunks/17ajyb5ogk5yj.js +1 -0
  155. package/out/_next/static/chunks/17dyfxbq8yz8n.js +1 -0
  156. package/out/_next/static/chunks/180zln9pcq9ih.js +1 -0
  157. package/out/_next/static/chunks/1814izi5gh.kp.js +1 -0
  158. package/out/_next/static/chunks/turbopack-0xs6mybc~5t_3.js +1 -0
  159. package/out/_next/static/media/KaTeX_AMS-Regular.0b~8ki5y928w2.woff +0 -0
  160. package/out/_next/static/media/KaTeX_AMS-Regular.0p1vbqd84i2~o.woff2 +0 -0
  161. package/out/_next/static/media/KaTeX_AMS-Regular.173t6ktr7uf-w.ttf +0 -0
  162. package/out/_next/static/media/KaTeX_Caligraphic-Bold.01-pzluls4zgb.woff2 +0 -0
  163. package/out/_next/static/media/KaTeX_Caligraphic-Bold.0x2v1lwn~880f.woff +0 -0
  164. package/out/_next/static/media/KaTeX_Caligraphic-Bold.16zv5fax0h0ka.ttf +0 -0
  165. package/out/_next/static/media/KaTeX_Caligraphic-Regular.02i3z7wig438t.ttf +0 -0
  166. package/out/_next/static/media/KaTeX_Caligraphic-Regular.0rysu1t-ncjq8.woff2 +0 -0
  167. package/out/_next/static/media/KaTeX_Caligraphic-Regular.10927swgekwun.woff +0 -0
  168. package/out/_next/static/media/KaTeX_Fraktur-Bold.0e-16u10iuyyf.woff +0 -0
  169. package/out/_next/static/media/KaTeX_Fraktur-Bold.0et27v~3~4uhe.ttf +0 -0
  170. package/out/_next/static/media/KaTeX_Fraktur-Bold.0w23i72~hprpq.woff2 +0 -0
  171. package/out/_next/static/media/KaTeX_Fraktur-Regular.0b.riegzdfue2.woff +0 -0
  172. package/out/_next/static/media/KaTeX_Fraktur-Regular.0rekyoa-52fj_.woff2 +0 -0
  173. package/out/_next/static/media/KaTeX_Fraktur-Regular.0vjwa15znhk~4.ttf +0 -0
  174. package/out/_next/static/media/KaTeX_Main-Bold.09i7~607shf-h.ttf +0 -0
  175. package/out/_next/static/media/KaTeX_Main-Bold.09lmynrorhcbw.woff +0 -0
  176. package/out/_next/static/media/KaTeX_Main-Bold.16pfc63_du6mx.woff2 +0 -0
  177. package/out/_next/static/media/KaTeX_Main-BoldItalic.0cp37g7x1q8h6.woff +0 -0
  178. package/out/_next/static/media/KaTeX_Main-BoldItalic.0d54rk08rx11s.woff2 +0 -0
  179. package/out/_next/static/media/KaTeX_Main-BoldItalic.15j6k~hix2t_0.ttf +0 -0
  180. package/out/_next/static/media/KaTeX_Main-Italic.0382gqciexmbu.woff +0 -0
  181. package/out/_next/static/media/KaTeX_Main-Italic.06o5nq0_91v60.woff2 +0 -0
  182. package/out/_next/static/media/KaTeX_Main-Italic.0su4i6mm18-wo.ttf +0 -0
  183. package/out/_next/static/media/KaTeX_Main-Regular.08zh8z.7shijf.ttf +0 -0
  184. package/out/_next/static/media/KaTeX_Main-Regular.0diheg01zyoph.woff +0 -0
  185. package/out/_next/static/media/KaTeX_Main-Regular.0kaf-ag2_wkm-.woff2 +0 -0
  186. package/out/_next/static/media/KaTeX_Math-BoldItalic.0ajzxypnbx1h1.ttf +0 -0
  187. package/out/_next/static/media/KaTeX_Math-BoldItalic.0ck1myuerwyqw.woff +0 -0
  188. package/out/_next/static/media/KaTeX_Math-BoldItalic.0ja97dn.cpc87.woff2 +0 -0
  189. package/out/_next/static/media/KaTeX_Math-Italic.09xkhecjcn5r9.woff +0 -0
  190. package/out/_next/static/media/KaTeX_Math-Italic.0x23a-bmp-5tg.ttf +0 -0
  191. package/out/_next/static/media/KaTeX_Math-Italic.0zrha2c4sl2je.woff2 +0 -0
  192. package/out/_next/static/media/KaTeX_SansSerif-Bold.05a9.pc1j_zx9.woff2 +0 -0
  193. package/out/_next/static/media/KaTeX_SansSerif-Bold.0jcl-ayi1uun0.woff +0 -0
  194. package/out/_next/static/media/KaTeX_SansSerif-Bold.0re8y.dm7.mt5.ttf +0 -0
  195. package/out/_next/static/media/KaTeX_SansSerif-Italic.0a0234dc3s62j.woff2 +0 -0
  196. package/out/_next/static/media/KaTeX_SansSerif-Italic.0judofdln9731.woff +0 -0
  197. package/out/_next/static/media/KaTeX_SansSerif-Italic.10z1iap9pfus8.ttf +0 -0
  198. package/out/_next/static/media/KaTeX_SansSerif-Regular.0h9yjlugq4q_e.woff +0 -0
  199. package/out/_next/static/media/KaTeX_SansSerif-Regular.0v6gcj32-czft.woff2 +0 -0
  200. package/out/_next/static/media/KaTeX_SansSerif-Regular.0zm18kga42ebc.ttf +0 -0
  201. package/out/_next/static/media/KaTeX_Script-Regular.0c4.h-mer83d_.woff2 +0 -0
  202. package/out/_next/static/media/KaTeX_Script-Regular.0q14y6zkzlpob.ttf +0 -0
  203. package/out/_next/static/media/KaTeX_Script-Regular.0ze6v4r_-99oy.woff +0 -0
  204. package/out/_next/static/media/KaTeX_Size1-Regular.013x6a4ierotp.woff2 +0 -0
  205. package/out/_next/static/media/KaTeX_Size1-Regular.0kidw0oi.m68o.woff +0 -0
  206. package/out/_next/static/media/KaTeX_Size1-Regular.0m6y-i6wfokni.ttf +0 -0
  207. package/out/_next/static/media/KaTeX_Size2-Regular.0blpmluwilgbg.woff +0 -0
  208. package/out/_next/static/media/KaTeX_Size2-Regular.0d5inmyp-tyv3.woff2 +0 -0
  209. package/out/_next/static/media/KaTeX_Size2-Regular.0wnhnvj-.k9d5.ttf +0 -0
  210. package/out/_next/static/media/KaTeX_Size3-Regular.01h0xm_sfctj3.woff +0 -0
  211. package/out/_next/static/media/KaTeX_Size3-Regular.0iukctyhw5j56.woff2 +0 -0
  212. package/out/_next/static/media/KaTeX_Size3-Regular.0jl8mqyf4gzpn.ttf +0 -0
  213. package/out/_next/static/media/KaTeX_Size4-Regular.0w3.rb_c4stzk.woff2 +0 -0
  214. package/out/_next/static/media/KaTeX_Size4-Regular.0wr_9l81-mu06.ttf +0 -0
  215. package/out/_next/static/media/KaTeX_Size4-Regular.12tvaesf3.zl3.woff +0 -0
  216. package/out/_next/static/media/KaTeX_Typewriter-Regular.0c4zdxz~8frhm.woff2 +0 -0
  217. package/out/_next/static/media/KaTeX_Typewriter-Regular.0cgrzn5l3kao5.woff +0 -0
  218. package/out/_next/static/media/KaTeX_Typewriter-Regular.128~qc3858otl.ttf +0 -0
  219. package/out/_not-found/__next._full.txt +21 -19
  220. package/out/_not-found/__next._head.txt +3 -3
  221. package/out/_not-found/__next._index.txt +8 -6
  222. package/out/_not-found/__next._not-found.__PAGE__.txt +4 -4
  223. package/out/_not-found/__next._not-found.txt +3 -3
  224. package/out/_not-found/__next._tree.txt +3 -2
  225. package/out/_not-found/index.html +2 -2
  226. package/out/_not-found/index.txt +21 -19
  227. package/out/admin/__next._full.txt +23 -0
  228. package/out/admin/__next._head.txt +5 -0
  229. package/out/admin/__next._index.txt +9 -0
  230. package/out/admin/__next._tree.txt +5 -0
  231. package/out/admin/__next.admin.__PAGE__.txt +9 -0
  232. package/out/admin/__next.admin.txt +5 -0
  233. package/out/admin/index.html +15 -0
  234. package/out/admin/index.txt +23 -0
  235. package/out/app/__next._full.txt +15 -13
  236. package/out/app/__next._head.txt +3 -3
  237. package/out/app/__next._index.txt +8 -6
  238. package/out/app/__next._tree.txt +4 -2
  239. package/out/app/__next.app.__PAGE__.txt +4 -4
  240. package/out/app/__next.app.txt +3 -4
  241. package/out/app/index.html +2 -2
  242. package/out/app/index.txt +15 -13
  243. package/out/changelog/__next._full.txt +24 -21
  244. package/out/changelog/__next._head.txt +3 -3
  245. package/out/changelog/__next._index.txt +8 -6
  246. package/out/changelog/__next._tree.txt +5 -3
  247. package/out/changelog/__next.changelog.__PAGE__.txt +5 -5
  248. package/out/changelog/__next.changelog.txt +3 -3
  249. package/out/changelog/index.html +2 -2
  250. package/out/changelog/index.txt +24 -21
  251. package/out/chat/__next._full.txt +16 -14
  252. package/out/chat/__next._head.txt +3 -3
  253. package/out/chat/__next._index.txt +8 -6
  254. package/out/chat/__next._tree.txt +5 -3
  255. package/out/chat/__next.chat.__PAGE__.txt +4 -4
  256. package/out/chat/__next.chat.txt +4 -5
  257. package/out/chat/index.html +2 -2
  258. package/out/chat/index.txt +16 -14
  259. package/out/docs/__next._full.txt +24 -21
  260. package/out/docs/__next._head.txt +3 -3
  261. package/out/docs/__next._index.txt +8 -6
  262. package/out/docs/__next._tree.txt +5 -3
  263. package/out/docs/__next.docs.__PAGE__.txt +5 -5
  264. package/out/docs/__next.docs.txt +3 -3
  265. package/out/docs/getting-started/__next._full.txt +24 -21
  266. package/out/docs/getting-started/__next._head.txt +3 -3
  267. package/out/docs/getting-started/__next._index.txt +8 -6
  268. package/out/docs/getting-started/__next._tree.txt +5 -3
  269. package/out/docs/getting-started/__next.docs.getting-started.__PAGE__.txt +5 -5
  270. package/out/docs/getting-started/__next.docs.getting-started.txt +3 -3
  271. package/out/docs/getting-started/__next.docs.txt +3 -3
  272. package/out/docs/getting-started/index.html +2 -2
  273. package/out/docs/getting-started/index.txt +24 -21
  274. package/out/docs/index.html +2 -2
  275. package/out/docs/index.txt +24 -21
  276. package/out/download/__next._full.txt +33 -32
  277. package/out/download/__next._head.txt +3 -3
  278. package/out/download/__next._index.txt +8 -6
  279. package/out/download/__next._tree.txt +5 -3
  280. package/out/download/__next.download.__PAGE__.txt +10 -11
  281. package/out/download/__next.download.txt +3 -3
  282. package/out/download/index.html +2 -2
  283. package/out/download/index.txt +33 -32
  284. package/out/index.html +2 -2
  285. package/out/index.txt +23 -20
  286. package/out/note/__next._full.txt +24 -0
  287. package/out/note/__next._head.txt +5 -0
  288. package/out/note/__next._index.txt +9 -0
  289. package/out/note/__next._tree.txt +4 -0
  290. package/out/note/__next.note.__PAGE__.txt +9 -0
  291. package/out/note/__next.note.txt +5 -0
  292. package/out/note/edit/__next._full.txt +24 -0
  293. package/out/note/edit/__next._head.txt +5 -0
  294. package/out/note/edit/__next._index.txt +9 -0
  295. package/out/note/edit/__next._tree.txt +4 -0
  296. package/out/note/edit/__next.note.edit.__PAGE__.txt +9 -0
  297. package/out/note/edit/__next.note.edit.txt +5 -0
  298. package/out/note/edit/__next.note.txt +5 -0
  299. package/out/note/edit/index.html +15 -0
  300. package/out/note/edit/index.txt +24 -0
  301. package/out/note/index.html +15 -0
  302. package/out/note/index.txt +24 -0
  303. package/out/ping/__next._full.txt +22 -19
  304. package/out/ping/__next._head.txt +3 -3
  305. package/out/ping/__next._index.txt +8 -6
  306. package/out/ping/__next._tree.txt +5 -3
  307. package/out/ping/__next.ping.__PAGE__.txt +5 -5
  308. package/out/ping/__next.ping.txt +3 -3
  309. package/out/ping/index.html +2 -2
  310. package/out/ping/index.txt +22 -19
  311. package/out/web3/__next._full.txt +16 -14
  312. package/out/web3/__next._head.txt +3 -3
  313. package/out/web3/__next._index.txt +8 -6
  314. package/out/web3/__next._tree.txt +5 -3
  315. package/out/web3/__next.web3.__PAGE__.txt +4 -4
  316. package/out/web3/__next.web3.txt +4 -5
  317. package/out/web3/ed25519/__next._full.txt +14 -12
  318. package/out/web3/ed25519/__next._head.txt +3 -3
  319. package/out/web3/ed25519/__next._index.txt +8 -6
  320. package/out/web3/ed25519/__next._tree.txt +5 -3
  321. package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +2 -2
  322. package/out/web3/ed25519/__next.web3.ed25519.txt +3 -3
  323. package/out/web3/ed25519/__next.web3.txt +4 -5
  324. package/out/web3/ed25519/index.html +1 -1
  325. package/out/web3/ed25519/index.txt +14 -12
  326. package/out/web3/index.html +2 -2
  327. package/out/web3/index.txt +16 -14
  328. package/out/web3/tools/__next._full.txt +14 -12
  329. package/out/web3/tools/__next._head.txt +3 -3
  330. package/out/web3/tools/__next._index.txt +8 -6
  331. package/out/web3/tools/__next._tree.txt +5 -3
  332. package/out/web3/tools/__next.web3.tools.__PAGE__.txt +2 -2
  333. package/out/web3/tools/__next.web3.tools.txt +3 -3
  334. package/out/web3/tools/__next.web3.txt +4 -5
  335. package/out/web3/tools/index.html +1 -1
  336. package/out/web3/tools/index.txt +14 -12
  337. package/package.json +12 -2
  338. package/server/index.js +558 -101
  339. package/server/src/config.js +4 -0
  340. package/server/src/core/cid.js +53 -32
  341. package/server/src/index.js +772 -122
  342. package/server/src/node/config.js +159 -0
  343. package/server/src/node/logs.js +94 -0
  344. package/server/src/utils/api.js +80 -2
  345. package/server/src/utils/errors.js +7 -0
  346. package/server/src/utils/mostWallet.js +34 -1
  347. package/server/src/utils/noteBackup.js +119 -0
  348. package/server/src/utils/noteUtils.js +120 -0
  349. package/server/src/utils/userIdentity.js +8 -60
  350. package/out/_next/static/chunks/003jnm.v5tzw5.js +0 -1
  351. package/out/_next/static/chunks/00re8v.gbcywn.js +0 -1
  352. package/out/_next/static/chunks/00s106sbq8t9v.js +0 -1
  353. package/out/_next/static/chunks/012hi627qrdnn.js +0 -1
  354. package/out/_next/static/chunks/0174xh3wfsjm1.js +0 -2
  355. package/out/_next/static/chunks/02~o2nmo5pmy1.js +0 -1
  356. package/out/_next/static/chunks/07t.dhhokszz5.css +0 -1
  357. package/out/_next/static/chunks/0_wia9ofmsi1c.css +0 -2
  358. package/out/_next/static/chunks/0ah8fihozo2_u.js +0 -5
  359. package/out/_next/static/chunks/0bzupvr5gt3k9.js +0 -31
  360. package/out/_next/static/chunks/0gdluj423gso1.js +0 -1
  361. package/out/_next/static/chunks/0gmoiq06srjay.css +0 -1
  362. package/out/_next/static/chunks/0imkasy7kb67u.js +0 -1
  363. package/out/_next/static/chunks/0jjc_b9q_ldi2.js +0 -1
  364. package/out/_next/static/chunks/0jl~j62iz2uvr.js +0 -1
  365. package/out/_next/static/chunks/0lqslm813wk_h.js +0 -1
  366. package/out/_next/static/chunks/0q782fxxd0lx~.js +0 -1
  367. package/out/_next/static/chunks/0slwj0c46k5cu.js +0 -1
  368. package/out/_next/static/chunks/0sorqk.oc6b7j.css +0 -1
  369. package/out/_next/static/chunks/0tapzqc6hgvx-.js +0 -1
  370. package/out/_next/static/chunks/0xsc7z5x8n7wg.js +0 -1
  371. package/out/_next/static/chunks/0zm~gys2jwl0g.js +0 -1
  372. package/out/_next/static/chunks/turbopack-0a_g3u0ud~jb8.js +0 -1
  373. /package/out/_next/static/{MKMAM_PgkfJypNTQAws_M → sIuUKxnnGU7K9Tu9UDKE8}/_buildManifest.js +0 -0
  374. /package/out/_next/static/{MKMAM_PgkfJypNTQAws_M → sIuUKxnnGU7K9Tu9UDKE8}/_clientMiddlewareManifest.js +0 -0
  375. /package/out/_next/static/{MKMAM_PgkfJypNTQAws_M → sIuUKxnnGU7K9Tu9UDKE8}/_ssgManifest.js +0 -0
package/server/index.js CHANGED
@@ -13,53 +13,238 @@ import { MostBoxEngine } from './src/index.js'
13
13
  import { parseMostLink, validateCidString } from './src/core/cid.js'
14
14
  import { sanitizeFilename } from './src/utils/security.js'
15
15
  import { MAX_FILE_SIZE } from './src/config.js'
16
+ import {
17
+ createNodeConfigStore,
18
+ evaluateStorageLimits,
19
+ } from './src/node/config.js'
20
+ import { createNodeLogger } from './src/node/logs.js'
16
21
 
17
22
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
18
23
  const PORT = Number(process.env.MOSTBOX_PORT || process.env.PORT) || 1976
19
24
  const HOST = process.env.MOSTBOX_HOST || '0.0.0.0'
20
25
 
21
- const MAX_UPLOAD_SIZE = MAX_FILE_SIZE
22
26
  const UPLOAD_TMP_DIR = path.join(os.tmpdir(), 'most-box-uploads')
23
27
 
24
28
  const RATE_LIMIT_WINDOW = 60 * 1000
25
29
  const RATE_LIMIT_MAX_REQUESTS = 120
26
30
 
27
31
  // --- 配置 ---
28
- const CONFIG_DIR = path.join(os.homedir(), '.most-box')
29
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
32
+ const defaultConfigStore = createNodeConfigStore()
33
+ const defaultNodeLogger = createNodeLogger(defaultConfigStore.configDir)
34
+ const CONFIG_DIR = defaultConfigStore.configDir
35
+ const PACKAGE_JSON = readPackageJson()
36
+
37
+ function getApiErrorStatus(err) {
38
+ switch (err.code) {
39
+ case 'VALIDATION_ERROR':
40
+ case 'PATH_SECURITY_ERROR':
41
+ case 'FILE_SIZE_ERROR':
42
+ return 400
43
+ case 'PEER_NOT_FOUND':
44
+ return 503
45
+ case 'INTEGRITY_ERROR':
46
+ return 422
47
+ case 'CONFLICT':
48
+ return 409
49
+ case 'PERMISSION_ERROR':
50
+ return 403
51
+ case 'ENGINE_NOT_INITIALIZED':
52
+ return 503
53
+ default:
54
+ return 500
55
+ }
56
+ }
57
+
58
+ function errorJson(c, err) {
59
+ return c.json(
60
+ {
61
+ error: err.message,
62
+ code: err.code || 'UNKNOWN',
63
+ },
64
+ getApiErrorStatus(err)
65
+ )
66
+ }
30
67
 
31
- function loadConfig() {
68
+ function readPackageJson() {
32
69
  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)
70
+ return JSON.parse(
71
+ fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8')
72
+ )
73
+ } catch {
74
+ return { version: '0.0.0' }
38
75
  }
39
- return {}
40
76
  }
41
77
 
42
- function saveConfig(config) {
43
- try {
44
- if (!fs.existsSync(CONFIG_DIR)) {
45
- fs.mkdirSync(CONFIG_DIR, { recursive: true })
78
+ function getDataPath(configStore = defaultConfigStore) {
79
+ return configStore.getDataPath()
80
+ }
81
+
82
+ function resolveDataPathForSave(inputPath) {
83
+ let dataPath = String(inputPath || '').trim()
84
+ let basePath = dataPath
85
+
86
+ if (!dataPath) {
87
+ return { dataPath: '' }
88
+ }
89
+
90
+ if (dataPath.match(/^[A-Za-z]:\\$/)) {
91
+ basePath = dataPath
92
+ dataPath = path.join(dataPath, 'most-data')
93
+ }
94
+
95
+ if (!fs.existsSync(basePath)) {
96
+ return { error: '目录不存在' }
97
+ }
98
+
99
+ if (!fs.existsSync(dataPath)) {
100
+ fs.mkdirSync(dataPath, { recursive: true })
101
+ }
102
+
103
+ return { dataPath }
104
+ }
105
+
106
+ function getNetworkAddresses(appPort) {
107
+ const interfaces = os.networkInterfaces()
108
+ const addresses = []
109
+ const seen = new Set()
110
+
111
+ for (const [name, nets] of Object.entries(interfaces)) {
112
+ for (const net of nets) {
113
+ if (net.family !== 'IPv4' || net.internal) continue
114
+ if (seen.has(net.address)) continue
115
+ seen.add(net.address)
116
+
117
+ let type = 'lan'
118
+ let label = '局域网'
119
+ if (net.address.startsWith('100.')) {
120
+ type = 'tailscale'
121
+ label = 'Tailscale'
122
+ } else if (
123
+ name.toLowerCase().includes('zt') ||
124
+ name.toLowerCase().includes('zerotier')
125
+ ) {
126
+ type = 'zerotier'
127
+ label = 'ZeroTier'
128
+ }
129
+
130
+ addresses.push({ type, ip: net.address, label, iface: name })
46
131
  }
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
132
  }
133
+
134
+ const localEntry = {
135
+ type: 'local',
136
+ ip: 'localhost',
137
+ label: '本机',
138
+ iface: 'loopback',
139
+ }
140
+ return { port: appPort, addresses: [localEntry, ...addresses] }
55
141
  }
56
142
 
57
- function getDataPath() {
58
- if (process.env.MOSTBOX_DATA_PATH) {
59
- return process.env.MOSTBOX_DATA_PATH
143
+ async function buildNodeStatus(engine, configStore, appPort, host) {
144
+ const config = configStore.getNodeConfig()
145
+ const storage = await engine.getStorageStats()
146
+ const network = engine.getNetworkStatus()
147
+ const holdings = engine.listHoldings()
148
+
149
+ return {
150
+ status: 'online',
151
+ version: PACKAGE_JSON.version,
152
+ uptimeSeconds: Math.floor(process.uptime()),
153
+ nodeId: engine.getNodeId(),
154
+ host,
155
+ port: appPort,
156
+ listen: getNetworkAddresses(appPort),
157
+ dataPath: getDataPath(configStore),
158
+ config,
159
+ policy: {
160
+ maxFileSizeBytes: config.maxFileSizeBytes,
161
+ },
162
+ capacity: {
163
+ configuredBytes: config.capacityBytes,
164
+ usedBytes: storage.used,
165
+ freeBytes: Math.max(0, config.capacityBytes - storage.used),
166
+ },
167
+ storage,
168
+ network,
169
+ holdings,
170
+ }
171
+ }
172
+
173
+ function buildOpenApiSpec(appPort) {
174
+ return {
175
+ openapi: '3.1.0',
176
+ info: {
177
+ title: 'MostBox Node Daemon API',
178
+ version: PACKAGE_JSON.version,
179
+ },
180
+ servers: [{ url: `http://localhost:${appPort}` }],
181
+ paths: {
182
+ '/api/node/status': {
183
+ get: {
184
+ summary: 'Get node daemon status',
185
+ responses: { 200: { description: 'Node status' } },
186
+ },
187
+ },
188
+ '/api/node/config': {
189
+ get: {
190
+ summary: 'Get node daemon config',
191
+ responses: { 200: { description: 'Node config' } },
192
+ },
193
+ post: {
194
+ summary: 'Update node daemon config',
195
+ responses: { 200: { description: 'Updated config' } },
196
+ },
197
+ },
198
+ '/api/node/policy': {
199
+ get: {
200
+ summary: 'Get local storage limits',
201
+ responses: { 200: { description: 'Storage limits' } },
202
+ },
203
+ post: {
204
+ summary: 'Update local storage limits',
205
+ responses: { 200: { description: 'Updated storage limits' } },
206
+ },
207
+ },
208
+ '/api/node/policy/evaluate': {
209
+ post: {
210
+ summary: 'Evaluate a local file against storage limits',
211
+ responses: { 200: { description: 'Storage limit decision' } },
212
+ },
213
+ },
214
+ '/api/node/holdings': {
215
+ get: {
216
+ summary: 'List CID replicas held by this node',
217
+ responses: { 200: { description: 'Node holdings' } },
218
+ },
219
+ post: {
220
+ summary: 'Add a held CID replica record and join its topic',
221
+ responses: { 200: { description: 'Created holding' } },
222
+ },
223
+ },
224
+ '/api/node/logs': {
225
+ get: {
226
+ summary: 'Read recent node daemon logs',
227
+ responses: { 200: { description: 'Node logs' } },
228
+ },
229
+ delete: {
230
+ summary: 'Clear node daemon logs',
231
+ responses: { 200: { description: 'Logs cleared' } },
232
+ },
233
+ },
234
+ '/api/storage': {
235
+ get: {
236
+ summary: 'Get storage statistics',
237
+ responses: { 200: { description: 'Storage statistics' } },
238
+ },
239
+ },
240
+ '/api/p2p/pull': {
241
+ post: {
242
+ summary: 'Pull a full file replica by CID',
243
+ responses: { 200: { description: 'Pull task result' } },
244
+ },
245
+ },
246
+ },
60
247
  }
61
- const config = loadConfig()
62
- return config.dataPath || path.join(os.homedir(), 'most-data')
63
248
  }
64
249
 
65
250
  // --- 静态文件服务 ---
@@ -125,7 +310,7 @@ function decodeFilenameFromHeader(headerStr) {
125
310
  return null
126
311
  }
127
312
 
128
- async function parseMultipartBusboy(req) {
313
+ async function parseMultipartBusboy(req, maxUploadSize = MAX_FILE_SIZE) {
129
314
  return new Promise((resolve, reject) => {
130
315
  if (!fs.existsSync(UPLOAD_TMP_DIR)) {
131
316
  fs.mkdirSync(UPLOAD_TMP_DIR, { recursive: true })
@@ -134,7 +319,7 @@ async function parseMultipartBusboy(req) {
134
319
  const busboy = Busboy({
135
320
  headers: req.headers,
136
321
  limits: {
137
- fileSize: MAX_UPLOAD_SIZE,
322
+ fileSize: maxUploadSize,
138
323
  files: 1,
139
324
  fields: 0,
140
325
  },
@@ -155,7 +340,7 @@ async function parseMultipartBusboy(req) {
155
340
 
156
341
  stream.on('data', chunk => {
157
342
  fileSize += chunk.length
158
- if (fileSize > MAX_UPLOAD_SIZE) {
343
+ if (fileSize > maxUploadSize) {
159
344
  stream.destroy()
160
345
  writeStream.destroy()
161
346
  fs.unlink(tempPath, () => {})
@@ -203,6 +388,10 @@ async function parseMultipartBusboy(req) {
203
388
  // --- Hono 应用工厂 ---
204
389
  export function createApp(engine, options = {}) {
205
390
  const appPort = options.port || PORT
391
+ const appHost = options.host || HOST
392
+ const configStore = options.configStore || defaultConfigStore
393
+ const nodeLogger =
394
+ options.nodeLogger || createNodeLogger(configStore.configDir || CONFIG_DIR)
206
395
  const wssRef = options.wssRef || { current: null }
207
396
  const serverInstanceRef = options.serverInstanceRef || { current: null }
208
397
 
@@ -231,7 +420,7 @@ export function createApp(engine, options = {}) {
231
420
  return async (c, next) => {
232
421
  const clientIp =
233
422
  c.req.header('x-forwarded-for') ||
234
- c.env.incoming?.socket?.remoteAddress ||
423
+ c.env?.incoming?.socket?.remoteAddress ||
235
424
  'unknown'
236
425
  if (!checkRateLimit(clientIp)) {
237
426
  return c.json({ error: 'Too many requests' }, 429)
@@ -259,6 +448,33 @@ export function createApp(engine, options = {}) {
259
448
  }
260
449
  }
261
450
 
451
+ async function broadcastNodeStatus() {
452
+ try {
453
+ const status = await buildNodeStatus(
454
+ engine,
455
+ configStore,
456
+ appPort,
457
+ appHost
458
+ )
459
+ wsBroadcast('node:status', status)
460
+ return status
461
+ } catch (err) {
462
+ const entry = nodeLogger.append({
463
+ level: 'error',
464
+ event: 'node:status:error',
465
+ message: err.message,
466
+ })
467
+ wsBroadcast('node:log', entry)
468
+ return null
469
+ }
470
+ }
471
+
472
+ function appendNodeLog(input) {
473
+ const entry = nodeLogger.append(input)
474
+ wsBroadcast('node:log', entry)
475
+ return entry
476
+ }
477
+
262
478
  function wsSendToChannel(channelName, event, data) {
263
479
  const payload = JSON.stringify({ event, data })
264
480
  const subscribers = channelSubscriptions.get(channelName)
@@ -268,7 +484,10 @@ export function createApp(engine, options = {}) {
268
484
  try {
269
485
  ws.send(payload)
270
486
  } catch (err) {
271
- console.warn('[WS] Failed to send to channel subscriber:', err.message)
487
+ console.warn(
488
+ '[WS] Failed to send to channel subscriber:',
489
+ err.message
490
+ )
272
491
  }
273
492
  }
274
493
  })
@@ -313,8 +532,10 @@ export function createApp(engine, options = {}) {
313
532
  cors({
314
533
  origin: [
315
534
  'http://localhost:3000',
535
+ 'http://127.0.0.1:3000',
316
536
  'https://most.box',
317
537
  `http://localhost:${appPort}`,
538
+ `http://127.0.0.1:${appPort}`,
318
539
  ],
319
540
  credentials: true,
320
541
  })
@@ -327,9 +548,10 @@ export function createApp(engine, options = {}) {
327
548
  app.onError((err, c) => {
328
549
  console.error('[API Error]', err)
329
550
  try {
330
- const errorLogPath = path.join(CONFIG_DIR, 'server-error.log')
331
- if (!fs.existsSync(CONFIG_DIR)) {
332
- fs.mkdirSync(CONFIG_DIR, { recursive: true })
551
+ const errorLogDir = configStore.configDir || CONFIG_DIR
552
+ const errorLogPath = path.join(errorLogDir, 'server-error.log')
553
+ if (!fs.existsSync(errorLogDir)) {
554
+ fs.mkdirSync(errorLogDir, { recursive: true })
333
555
  }
334
556
  fs.appendFileSync(
335
557
  errorLogPath,
@@ -345,45 +567,134 @@ export function createApp(engine, options = {}) {
345
567
  })
346
568
 
347
569
  app.get('/api/config', c => {
348
- const config = loadConfig()
570
+ const config = configStore.loadRawConfig()
349
571
  return c.json({ dataPath: config.dataPath || '' })
350
572
  })
351
573
 
352
574
  app.post('/api/config', async c => {
353
575
  const body = await c.req.json()
354
- const config = loadConfig()
576
+ const patch = {}
355
577
 
356
578
  if (body.resetStorage) {
357
- config.dataPath = ''
579
+ patch.dataPath = ''
358
580
  } else if (body.dataPath !== undefined) {
359
- let dataPath = body.dataPath.trim()
360
- let basePath = dataPath
581
+ const resolved = resolveDataPathForSave(body.dataPath)
582
+ if (resolved.error) return c.json({ error: resolved.error }, 400)
583
+ patch.dataPath = resolved.dataPath
584
+ }
361
585
 
362
- if (dataPath.match(/^[A-Za-z]:\\$/)) {
363
- basePath = dataPath
364
- dataPath = path.join(dataPath, 'most-data')
365
- }
586
+ const { success } = configStore.saveNodeConfigPatch(patch)
587
+ appendNodeLog({
588
+ event: 'node:config:updated',
589
+ message: 'Node config updated',
590
+ data: { dataPath: getDataPath(configStore) },
591
+ })
592
+ await broadcastNodeStatus()
593
+ return c.json({ success, dataPath: getDataPath(configStore) })
594
+ })
366
595
 
367
- if (!fs.existsSync(basePath)) {
368
- return c.json({ error: '目录不存在' }, 400)
369
- }
596
+ app.get('/api/config/data-path', c => {
597
+ const config = configStore.getNodeConfig()
598
+ const isDefault = !config.dataPath
599
+ const dataPath = getDataPath(configStore)
600
+ return c.json({ dataPath, isDefault })
601
+ })
370
602
 
371
- if (!fs.existsSync(dataPath)) {
372
- fs.mkdirSync(dataPath, { recursive: true })
373
- }
603
+ app.get('/api/node/status', async c => {
604
+ try {
605
+ return c.json(
606
+ await buildNodeStatus(engine, configStore, appPort, appHost)
607
+ )
608
+ } catch (err) {
609
+ return errorJson(c, err)
610
+ }
611
+ })
374
612
 
375
- config.dataPath = dataPath
613
+ app.get('/api/node/config', c => {
614
+ const config = configStore.getNodeConfig()
615
+ return c.json({
616
+ ...config,
617
+ dataPath: getDataPath(configStore),
618
+ configuredDataPath: config.dataPath,
619
+ isDefaultDataPath: !config.dataPath && !process.env.MOSTBOX_DATA_PATH,
620
+ envDataPath: process.env.MOSTBOX_DATA_PATH || null,
621
+ })
622
+ })
623
+
624
+ app.post('/api/node/config', async c => {
625
+ const body = await c.req.json()
626
+ const patch = { ...body }
627
+
628
+ if (body.resetStorage) {
629
+ patch.dataPath = ''
630
+ } else if (body.dataPath !== undefined) {
631
+ const resolved = resolveDataPathForSave(body.dataPath)
632
+ if (resolved.error) return c.json({ error: resolved.error }, 400)
633
+ patch.dataPath = resolved.dataPath
376
634
  }
377
635
 
378
- const success = saveConfig(config)
379
- return c.json({ success, dataPath: getDataPath() })
636
+ const { success, config } = configStore.saveNodeConfigPatch(patch)
637
+ engine.setMaxFileSize(config.maxFileSizeBytes)
638
+ appendNodeLog({
639
+ event: 'node:config:updated',
640
+ message: 'Node daemon config updated',
641
+ data: {
642
+ dataPath: getDataPath(configStore),
643
+ capacityBytes: config.capacityBytes,
644
+ },
645
+ })
646
+ await broadcastNodeStatus()
647
+ return c.json({ success, ...config, dataPath: getDataPath(configStore) })
380
648
  })
381
649
 
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 })
650
+ app.get('/api/node/policy', c => {
651
+ const config = configStore.getNodeConfig()
652
+ return c.json({
653
+ maxFileSizeBytes: config.maxFileSizeBytes,
654
+ })
655
+ })
656
+
657
+ app.post('/api/node/policy', async c => {
658
+ const body = await c.req.json()
659
+ const { success, config } = configStore.saveNodeConfigPatch({
660
+ maxFileSizeBytes: body.maxFileSizeBytes,
661
+ })
662
+ engine.setMaxFileSize(config.maxFileSizeBytes)
663
+ const policy = {
664
+ maxFileSizeBytes: config.maxFileSizeBytes,
665
+ }
666
+ appendNodeLog({
667
+ event: 'node:policy:updated',
668
+ message: 'Node storage limits updated',
669
+ data: policy,
670
+ })
671
+ await broadcastNodeStatus()
672
+ return c.json({ success, ...policy })
673
+ })
674
+
675
+ app.post('/api/node/policy/evaluate', async c => {
676
+ const body = await c.req.json()
677
+ const decision = evaluateStorageLimits(configStore.getNodeConfig(), body)
678
+ return c.json(decision)
679
+ })
680
+
681
+ app.get('/api/node/logs', c => {
682
+ const limit = Number(c.req.query('limit') || 100)
683
+ return c.json({
684
+ logFile: nodeLogger.logFile,
685
+ logs: nodeLogger.list(limit),
686
+ })
687
+ })
688
+
689
+ app.delete('/api/node/logs', c => {
690
+ const success = nodeLogger.clear()
691
+ const clearedAt = new Date().toISOString()
692
+ wsBroadcast('node:logs:cleared', { clearedAt })
693
+ return c.json({ success, clearedAt })
694
+ })
695
+
696
+ app.get('/api/openapi.json', c => {
697
+ return c.json(buildOpenApiSpec(appPort))
387
698
  })
388
699
 
389
700
  // --- 网络路由 ---
@@ -392,40 +703,59 @@ export function createApp(engine, options = {}) {
392
703
  })
393
704
 
394
705
  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
- }
706
+ return c.json(getNetworkAddresses(appPort))
707
+ })
417
708
 
418
- addresses.push({ type, ip: net.address, label, iface: name })
419
- }
709
+ // --- 节点保种路由 ---
710
+ app.get('/api/node/holdings', c => {
711
+ try {
712
+ return c.json(engine.listHoldings())
713
+ } catch (err) {
714
+ return errorJson(c, err)
420
715
  }
716
+ })
421
717
 
422
- const localEntry = {
423
- type: 'local',
424
- ip: 'localhost',
425
- label: '本机',
426
- iface: 'loopback',
718
+ app.post('/api/node/holdings', async c => {
719
+ try {
720
+ const body = await c.req.json()
721
+ const holding = await engine.addHolding(body)
722
+ appendNodeLog({
723
+ event: 'node:holding:added',
724
+ message: 'Node holding added',
725
+ data: { cid: holding.cid, size: holding.size },
726
+ })
727
+ await broadcastNodeStatus()
728
+ return c.json({ success: true, holding })
729
+ } catch (err) {
730
+ return errorJson(c, err)
731
+ }
732
+ })
733
+
734
+ app.post('/api/p2p/pull', async c => {
735
+ try {
736
+ const body = await c.req.json()
737
+ const timeout =
738
+ body.timeout === undefined ? undefined : Number(body.timeout)
739
+ const result = await engine.pullByCid({
740
+ ...body,
741
+ timeout: Number.isFinite(timeout) && timeout > 0 ? timeout : undefined,
742
+ })
743
+ appendNodeLog({
744
+ event: 'node:pull:success',
745
+ message: 'P2P pull completed',
746
+ data: { cid: result.cid, taskId: result.taskId },
747
+ })
748
+ await broadcastNodeStatus()
749
+ return c.json({ success: true, ...result })
750
+ } catch (err) {
751
+ appendNodeLog({
752
+ level: 'error',
753
+ event: 'node:pull:error',
754
+ message: err.message,
755
+ data: { code: err.code || 'UNKNOWN' },
756
+ })
757
+ return errorJson(c, err)
427
758
  }
428
- return c.json({ port: appPort, addresses: [localEntry, ...addresses] })
429
759
  })
430
760
 
431
761
  // --- 文件路由 ---
@@ -435,7 +765,10 @@ export function createApp(engine, options = {}) {
435
765
 
436
766
  app.post('/api/publish', async c => {
437
767
  const req = c.env.incoming
438
- const result = await parseMultipartBusboy(req)
768
+ const result = await parseMultipartBusboy(
769
+ req,
770
+ configStore.getNodeConfig().maxFileSizeBytes
771
+ )
439
772
 
440
773
  if (!result || !result.filename) {
441
774
  return c.json({ error: 'No file provided' }, 400)
@@ -444,7 +777,8 @@ export function createApp(engine, options = {}) {
444
777
  try {
445
778
  const publishResult = await engine.publishFile(
446
779
  result.filePath,
447
- result.filename
780
+ result.filename,
781
+ { localPath: null }
448
782
  )
449
783
  return c.json({ success: true, ...publishResult })
450
784
  } finally {
@@ -452,14 +786,12 @@ export function createApp(engine, options = {}) {
452
786
  }
453
787
  })
454
788
 
455
- app.post('/api/download', async c => {
789
+ app.post('/api/download/check', async c => {
456
790
  const body = await c.req.json()
457
791
  if (!body.link) {
458
792
  return c.json({ error: 'link is required' }, 400)
459
793
  }
460
794
 
461
- const taskId = `dl_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
462
-
463
795
  const parsed = parseMostLink(body.link)
464
796
  if (parsed.error) {
465
797
  return c.json({ error: parsed.error }, 400)
@@ -469,15 +801,70 @@ export function createApp(engine, options = {}) {
469
801
  .getPublishedFiles()
470
802
  .find(f => f.cid === parsed.cid)
471
803
  if (existingFile) {
472
- console.log(`[MostBox] File already exists: ${existingFile.fileName}`)
473
804
  return c.json({
474
805
  success: true,
475
- taskId,
476
- alreadyExists: true,
806
+ available: true,
807
+ cid: parsed.cid,
477
808
  fileName: existingFile.fileName,
809
+ size: Number(existingFile.size) || null,
810
+ alreadyExists: true,
478
811
  })
479
812
  }
480
813
 
814
+ if (engine.hasDownloadNameConflict(parsed.fileName)) {
815
+ return c.json(
816
+ {
817
+ error: `已有同名文件: ${parsed.fileName}`,
818
+ code: 'CONFLICT',
819
+ },
820
+ 409
821
+ )
822
+ }
823
+
824
+ try {
825
+ const result = await engine.checkDownloadAvailability(body.link)
826
+ return c.json({ success: true, ...result })
827
+ } catch (err) {
828
+ return errorJson(c, err)
829
+ }
830
+ })
831
+
832
+ app.post('/api/download', async c => {
833
+ const body = await c.req.json()
834
+ if (!body.link) {
835
+ return c.json({ error: 'link is required' }, 400)
836
+ }
837
+
838
+ const taskId = `dl_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
839
+
840
+ const parsed = parseMostLink(body.link)
841
+ if (parsed.error) {
842
+ return c.json({ error: parsed.error }, 400)
843
+ }
844
+
845
+ const existingFile = engine
846
+ .getPublishedFiles()
847
+ .find(f => f.cid === parsed.cid)
848
+ if (existingFile) {
849
+ console.log(`[MostBox] File already exists: ${existingFile.fileName}`)
850
+ try {
851
+ const result = await engine.downloadFile(body.link, taskId)
852
+ return c.json({ success: true, ...result })
853
+ } catch (err) {
854
+ return errorJson(c, err)
855
+ }
856
+ }
857
+
858
+ if (engine.hasDownloadNameConflict(parsed.fileName)) {
859
+ return c.json(
860
+ {
861
+ error: `已有同名文件: ${parsed.fileName}`,
862
+ code: 'CONFLICT',
863
+ },
864
+ 409
865
+ )
866
+ }
867
+
481
868
  engine.downloadFile(body.link, taskId).catch(err => {
482
869
  if (err.message === 'Download cancelled') {
483
870
  wsBroadcast('download:cancelled', { taskId })
@@ -596,7 +983,7 @@ export function createApp(engine, options = {}) {
596
983
  return c.json({ error: cidValidation.error }, 400)
597
984
  }
598
985
  try {
599
- const result = engine.restoreTrashFile(cid)
986
+ const result = await engine.restoreTrashFile(cid)
600
987
  return c.json({ success: true, files: result })
601
988
  } catch (err) {
602
989
  return c.json({ error: err.message }, 400)
@@ -795,7 +1182,10 @@ export function createApp(engine, options = {}) {
795
1182
  const resolved = path.resolve(filePath)
796
1183
  const resolvedPublic = path.resolve(publicDir)
797
1184
 
798
- if (!resolved.startsWith(resolvedPublic + path.sep) && resolved !== resolvedPublic) {
1185
+ if (
1186
+ !resolved.startsWith(resolvedPublic + path.sep) &&
1187
+ resolved !== resolvedPublic
1188
+ ) {
799
1189
  return c.json({ error: 'Not found' }, 404)
800
1190
  }
801
1191
 
@@ -828,6 +1218,8 @@ export function createApp(engine, options = {}) {
828
1218
  app,
829
1219
  wsBroadcast,
830
1220
  wsSendToChannel,
1221
+ broadcastNodeStatus,
1222
+ appendNodeLog,
831
1223
  subscribeToChannel,
832
1224
  unsubscribeFromChannel,
833
1225
  cleanupWsSubscriptions,
@@ -852,10 +1244,15 @@ export async function main() {
852
1244
  )
853
1245
  }
854
1246
 
855
- const dataPath = getDataPath()
1247
+ const configStore = defaultConfigStore
1248
+ const nodeLogger = defaultNodeLogger
1249
+ const dataPath = getDataPath(configStore)
856
1250
  console.log(`[MostBox] Storage: ${dataPath}`)
857
1251
 
858
- const engine = new MostBoxEngine({ dataPath })
1252
+ const engine = new MostBoxEngine({
1253
+ dataPath,
1254
+ maxFileSize: configStore.getNodeConfig().maxFileSizeBytes,
1255
+ })
859
1256
 
860
1257
  const wssRef = { current: null }
861
1258
  const serverInstanceRef = { current: null }
@@ -864,25 +1261,78 @@ export async function main() {
864
1261
  app,
865
1262
  wsBroadcast,
866
1263
  wsSendToChannel,
1264
+ broadcastNodeStatus,
1265
+ appendNodeLog,
867
1266
  subscribeToChannel,
868
1267
  unsubscribeFromChannel,
869
1268
  cleanupWsSubscriptions,
870
1269
  } = createApp(engine, {
871
1270
  port: PORT,
1271
+ host: HOST,
1272
+ configStore,
1273
+ nodeLogger,
872
1274
  wssRef,
873
1275
  serverInstanceRef,
874
1276
  })
875
1277
 
1278
+ let engineReadyForStatus = false
1279
+ const safeBroadcastNodeStatus = () => {
1280
+ if (engineReadyForStatus) {
1281
+ broadcastNodeStatus()
1282
+ }
1283
+ }
1284
+
876
1285
  engine.on('download:progress', data => wsBroadcast('download:progress', data))
877
1286
  engine.on('download:status', data => wsBroadcast('download:status', data))
878
- engine.on('download:success', data => wsBroadcast('download:success', data))
1287
+ engine.on('download:success', data => {
1288
+ wsBroadcast('download:success', data)
1289
+ appendNodeLog({
1290
+ event: 'node:download:success',
1291
+ message: 'Download verified and stored',
1292
+ data,
1293
+ })
1294
+ safeBroadcastNodeStatus()
1295
+ })
879
1296
  engine.on('download:cancelled', data =>
880
1297
  wsBroadcast('download:cancelled', data)
881
1298
  )
882
1299
  engine.on('publish:progress', data => wsBroadcast('publish:progress', data))
883
- engine.on('publish:success', data => wsBroadcast('publish:success', data))
1300
+ engine.on('publish:success', data => {
1301
+ wsBroadcast('publish:success', data)
1302
+ appendNodeLog({
1303
+ event: 'node:publish:success',
1304
+ message: 'File published and seeding',
1305
+ data: { cid: data.cid, fileName: data.fileName },
1306
+ })
1307
+ safeBroadcastNodeStatus()
1308
+ })
884
1309
  engine.on('connection', () => {
885
1310
  wsBroadcast('network:status', engine.getNetworkStatus())
1311
+ safeBroadcastNodeStatus()
1312
+ })
1313
+ engine.on('holding:updated', data => {
1314
+ appendNodeLog({
1315
+ event: 'node:holding:updated',
1316
+ message: 'Holding metadata updated',
1317
+ data: { cid: data.cid, size: data.size },
1318
+ })
1319
+ safeBroadcastNodeStatus()
1320
+ })
1321
+ engine.on('holding:removed', data => {
1322
+ appendNodeLog({
1323
+ event: 'node:holding:removed',
1324
+ message: 'Holding metadata removed',
1325
+ data,
1326
+ })
1327
+ safeBroadcastNodeStatus()
1328
+ })
1329
+ engine.on('file:topic:joined', data => {
1330
+ appendNodeLog({
1331
+ event: 'node:topic:joined',
1332
+ message: 'CID topic joined',
1333
+ data,
1334
+ })
1335
+ safeBroadcastNodeStatus()
886
1336
  })
887
1337
  engine.on('channel:message', data =>
888
1338
  wsSendToChannel(data.channel, 'channel:message', data)
@@ -897,7 +1347,14 @@ export async function main() {
897
1347
  engine.on('channel:left', data => wsBroadcast('channel:left', data))
898
1348
 
899
1349
  await engine.start()
1350
+ engineReadyForStatus = true
900
1351
  console.log('[MostBox] Engine ready')
1352
+ appendNodeLog({
1353
+ event: 'node:ready',
1354
+ message: 'Node daemon ready',
1355
+ data: { dataPath, port: PORT },
1356
+ })
1357
+ broadcastNodeStatus()
901
1358
 
902
1359
  serverInstanceRef.current = serve(
903
1360
  { fetch: app.fetch, port: PORT, hostname: HOST },