most-box 0.1.0 → 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.
- package/README.md +3 -2
- package/out/404/index.html +2 -2
- package/out/404.html +2 -2
- package/out/__next.__PAGE__.txt +6 -6
- package/out/__next._full.txt +23 -20
- package/out/__next._head.txt +3 -3
- package/out/__next._index.txt +8 -6
- package/out/__next._tree.txt +6 -4
- package/out/_next/static/chunks/0-n3pg7th.zza.js +1 -0
- package/out/_next/static/chunks/0.4j.0k5a64vg.js +1 -0
- package/out/_next/static/chunks/0.ozi1_x2.m.~.js +1 -0
- package/out/_next/static/chunks/0.t5wlt51zou5.js +1 -0
- package/out/_next/static/chunks/0.w4hkvap~bva.js +1 -0
- package/out/_next/static/chunks/00-u5nq76f0.j.js +1 -0
- package/out/_next/static/chunks/00d9h1tddnnnd.js +1 -0
- package/out/_next/static/chunks/00fm8lijienf1.js +1 -0
- package/out/_next/static/chunks/00o9ht.f2qm00.css +4 -0
- package/out/_next/static/chunks/00tkdqwxch-3s.js +1 -0
- package/out/_next/static/chunks/00zi-erhjrny2.js +2 -0
- package/out/_next/static/chunks/01l3o90g~1z42.js +1 -0
- package/out/_next/static/chunks/01mfky9camw6i.js +1 -0
- package/out/_next/static/chunks/01r.v-pqs1vrm.js +1 -0
- package/out/_next/static/chunks/03edqrb4zdj~g.js +31 -0
- package/out/_next/static/chunks/03h_6oo-gqkhz.js +1 -0
- package/out/_next/static/chunks/04hcgsanv1hhu.js +1 -0
- package/out/_next/static/chunks/05g2q0w5b34.g.js +1 -0
- package/out/_next/static/chunks/05of77xycbt8~.js +1 -0
- package/out/_next/static/chunks/05zwemzfjx3sh.js +1 -0
- package/out/_next/static/chunks/06dpc5df94.v1.js +1 -0
- package/out/_next/static/chunks/06e1~1-z_ic9a.js +1 -0
- package/out/_next/static/chunks/075s7sn.ns~u5.js +1 -0
- package/out/_next/static/chunks/07dynrbvd3.f4.js +1 -0
- package/out/_next/static/chunks/07p~uva5pwgwe.js +1 -0
- package/out/_next/static/chunks/07r9nn-pzlgg1.js +1 -0
- package/out/_next/static/chunks/08.72abkgwy9g.js +1 -0
- package/out/_next/static/chunks/084xf0edl9sfo.js +1 -0
- package/out/_next/static/chunks/08576xhv~~jck.js +1 -0
- package/out/_next/static/chunks/08u211~k~qu52.js +1 -0
- package/out/_next/static/chunks/098.p.2-zm4p7.js +1 -0
- package/out/_next/static/chunks/09f1gfke9m5wg.css +1 -0
- package/out/_next/static/chunks/09ngvtajm7e5y.js +1 -0
- package/out/_next/static/chunks/09ps~-43n5qyo.js +1 -0
- package/out/_next/static/chunks/09v7_0gclxr46.js +1 -0
- package/out/_next/static/chunks/09xyi6fpro_d-.css +1 -0
- package/out/_next/static/chunks/09yql86dir9c4.js +1 -0
- package/out/_next/static/chunks/09zmlfljowj1~.js +1 -0
- package/out/_next/static/chunks/0_npg_pcoywti.js +5 -0
- package/out/_next/static/chunks/0_r_mk1~6bosc.js +1 -0
- package/out/_next/static/chunks/0_s~ebb-7b2hr.js +1 -0
- package/out/_next/static/chunks/0_w-0-2z5oqd_.js +1 -0
- package/out/_next/static/chunks/0ao1lbi4b.sfa.js +1 -0
- package/out/_next/static/chunks/0arm0a6adt7cc.css +1 -0
- package/out/_next/static/chunks/0bld2u_ld~va2.js +1 -0
- package/out/_next/static/chunks/0bliugh5lxw55.js +1 -0
- package/out/_next/static/chunks/{0e_h0d3ekzks8.css → 0c9j3eq_14vv2.css} +1 -1
- package/out/_next/static/chunks/0cn9a7aimbdzq.js +1 -0
- package/out/_next/static/chunks/0d3f-nk3c.2re.js +1 -0
- package/out/_next/static/chunks/0d4bueddmcnca.js +1 -0
- package/out/_next/static/chunks/0dtohpf7~3d12.js +1 -0
- package/out/_next/static/chunks/0e-3e8h7g99yf.js +1 -0
- package/out/_next/static/chunks/0e531nije_ln2.js +1 -0
- package/out/_next/static/chunks/0e5zvj_rh0z3m.js +1 -0
- package/out/_next/static/chunks/0f4y~rkk-n81e.js +1 -0
- package/out/_next/static/chunks/0fk~0~p7ivfn1.js +1 -0
- package/out/_next/static/chunks/0fw6juc~lsj3z.js +1 -0
- package/out/_next/static/chunks/0g0u7785a73vo.js +1 -0
- package/out/_next/static/chunks/0g_fpgh7drfda.js +1 -0
- package/out/_next/static/chunks/0gtwvy1z9ksa7.css +1 -0
- package/out/_next/static/chunks/0gze5uso1mbe9.js +1 -0
- package/out/_next/static/chunks/0h4r.qtmpa6eh.js +1 -0
- package/out/_next/static/chunks/0hf.aosc-7172.js +1 -0
- package/out/_next/static/chunks/0hgz35c1ejbs9.js +1 -0
- package/out/_next/static/chunks/0hrw-r.xmvmsq.js +1 -0
- package/out/_next/static/chunks/0hzg4al.v~8~m.js +1 -0
- package/out/_next/static/chunks/0ip9xrols_83o.js +1 -0
- package/out/_next/static/chunks/0j27tcmtt4ly7.js +1 -0
- package/out/_next/static/chunks/0j3v4mq67wtnh.js +1 -0
- package/out/_next/static/chunks/0j4-d0qf.v~kn.js +1 -0
- package/out/_next/static/chunks/0jhdeq.j9_02m.js +1 -0
- package/out/_next/static/chunks/0jy63h3i-y69i.js +1 -0
- package/out/_next/static/chunks/0kdnx_u-60k9s.js +1 -0
- package/out/_next/static/chunks/0kq~edq42o1-c.js +1 -0
- package/out/_next/static/chunks/0l682p362d-5w.js +1 -0
- package/out/_next/static/chunks/0lkmf5ry.s_7w.js +1 -0
- package/out/_next/static/chunks/0m68p9txef5rs.js +1 -0
- package/out/_next/static/chunks/0mme-fm5d2oz2.js +1 -0
- package/out/_next/static/chunks/0myp4sjagr~h0.js +1 -0
- package/out/_next/static/chunks/0n.qlfk~z7o.6.js +1 -0
- package/out/_next/static/chunks/0n4t80gjc3q5h.js +1 -0
- package/out/_next/static/chunks/{0n~dq4kpx9xxx.js → 0o6lrkxy4jwag.js} +1 -1
- package/out/_next/static/chunks/0o98f1yq..o.8.js +1 -0
- package/out/_next/static/chunks/0oz3yl6_-716p.js +1 -0
- package/out/_next/static/chunks/0p486m03-zfoi.js +1 -0
- package/out/_next/static/chunks/0qou.u2e2dy48.css +24 -0
- package/out/_next/static/chunks/0qqupeexg83u7.js +1 -0
- package/out/_next/static/chunks/0r1~k82nji8sf.js +1 -0
- package/out/_next/static/chunks/0rb-ri481.kc9.js +1 -0
- package/out/_next/static/chunks/0rsnmahfd.59p.js +1 -0
- package/out/_next/static/chunks/0rt6rgnvr-s_p.js +1 -0
- package/out/_next/static/chunks/0runh28p_gg6..js +1 -0
- package/out/_next/static/chunks/0shy.t1fwqcev.js +1 -0
- package/out/_next/static/chunks/{0d3shmwh5_nmn.js → 0t2xr05rlu96l.js} +1 -1
- package/out/_next/static/chunks/0t6h56rhg1y5i.js +1 -0
- package/out/_next/static/chunks/0tdqd1zunusgk.js +1 -0
- package/out/_next/static/chunks/0ujbnp38x63ek.js +1 -0
- package/out/_next/static/chunks/0usvo~vu7r8np.js +736 -0
- package/out/_next/static/chunks/0v68pdrp54lb-.js +1 -0
- package/out/_next/static/chunks/0v7qp4hv-_._r.js +1 -0
- package/out/_next/static/chunks/0vsm0m5sxrb.3.js +1 -0
- package/out/_next/static/chunks/0vzlz.iboqo3c.js +1 -0
- package/out/_next/static/chunks/0w87vbpkf-ogd.js +1 -0
- package/out/_next/static/chunks/0wuwlgcn6gxqt.js +1 -0
- package/out/_next/static/chunks/0xgg0~kmf3gd-.js +1 -0
- package/out/_next/static/chunks/0xj24-70ptdzp.js +1 -0
- package/out/_next/static/chunks/0xl5_avhu._i8.js +1 -0
- package/out/_next/static/chunks/0xxlx772fr3x4.js +1 -0
- package/out/_next/static/chunks/0y.li-~3oybew.js +1 -0
- package/out/_next/static/chunks/0yl2t7cs-n_ng.js +1 -0
- package/out/_next/static/chunks/0yq3kh.hchtm_.js +1 -0
- package/out/_next/static/chunks/0ys0l5au.9c2c.js +1 -0
- package/out/_next/static/chunks/0z48pmi6buytt.js +1 -0
- package/out/_next/static/chunks/0zapnvgy89mg..js +1 -0
- package/out/_next/static/chunks/0~.-vxi5oc.r0.js +1 -0
- package/out/_next/static/chunks/0~3ik-hfp9s-7.js +1 -0
- package/out/_next/static/chunks/0~4f5p6tvn1lq.js +1 -0
- package/out/_next/static/chunks/0~_0ys.2whxbw.js +1 -0
- package/out/_next/static/chunks/0~_ui9l7.2sxf.js +1 -0
- package/out/_next/static/chunks/1037jlyw5~7ht.js +1 -0
- package/out/_next/static/chunks/1045hfzu533z0.js +1 -0
- package/out/_next/static/chunks/104e5nmc.c-pl.js +1 -0
- package/out/_next/static/chunks/109taw1pbh-0b.js +1 -0
- package/out/_next/static/chunks/10kvl8vj_plm-.js +1 -0
- package/out/_next/static/chunks/10x7~onqwp338.js +1 -0
- package/out/_next/static/chunks/10ynz1dy483wf.js +1 -0
- package/out/_next/static/chunks/11hds.mg~4_r-.js +1 -0
- package/out/_next/static/chunks/11ibzaklcauw~.js +1 -0
- package/out/_next/static/chunks/11z.0s6.42b.p.js +1 -0
- package/out/_next/static/chunks/12-9n56l0y3yr.js +1 -0
- package/out/_next/static/chunks/126enaq~f7scl.js +1 -0
- package/out/_next/static/chunks/1380op_pfk.qo.js +1 -0
- package/out/_next/static/chunks/146oiw1bggtn4.js +1 -0
- package/out/_next/static/chunks/14_po2rb_arn4.js +1 -0
- package/out/_next/static/chunks/14a4fwbiq.l3z.js +1 -0
- package/out/_next/static/chunks/14cowsqn95m1k.js +1 -0
- package/out/_next/static/chunks/14dtd3l03v.kx.js +1 -0
- package/out/_next/static/chunks/14tm3qa-v9o-4.js +1 -0
- package/out/_next/static/chunks/15-o4kb-evqd7.js +1 -0
- package/out/_next/static/chunks/157z7bowux3xj.js +1 -0
- package/out/_next/static/chunks/15m1_677az2cm.js +1 -0
- package/out/_next/static/chunks/15v.~.ne6ogkk.js +1 -0
- package/out/_next/static/chunks/16i.qbk8t8gf_.js +1 -0
- package/out/_next/static/chunks/16m27azcs4k6w.js +1 -0
- package/out/_next/static/chunks/16u9f35gylw8l.js +1 -0
- package/out/_next/static/chunks/17ajyb5ogk5yj.js +1 -0
- package/out/_next/static/chunks/17dyfxbq8yz8n.js +1 -0
- package/out/_next/static/chunks/180zln9pcq9ih.js +1 -0
- package/out/_next/static/chunks/1814izi5gh.kp.js +1 -0
- package/out/_next/static/chunks/turbopack-0xs6mybc~5t_3.js +1 -0
- package/out/_next/static/media/KaTeX_AMS-Regular.0b~8ki5y928w2.woff +0 -0
- package/out/_next/static/media/KaTeX_AMS-Regular.0p1vbqd84i2~o.woff2 +0 -0
- package/out/_next/static/media/KaTeX_AMS-Regular.173t6ktr7uf-w.ttf +0 -0
- package/out/_next/static/media/KaTeX_Caligraphic-Bold.01-pzluls4zgb.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Caligraphic-Bold.0x2v1lwn~880f.woff +0 -0
- package/out/_next/static/media/KaTeX_Caligraphic-Bold.16zv5fax0h0ka.ttf +0 -0
- package/out/_next/static/media/KaTeX_Caligraphic-Regular.02i3z7wig438t.ttf +0 -0
- package/out/_next/static/media/KaTeX_Caligraphic-Regular.0rysu1t-ncjq8.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Caligraphic-Regular.10927swgekwun.woff +0 -0
- package/out/_next/static/media/KaTeX_Fraktur-Bold.0e-16u10iuyyf.woff +0 -0
- package/out/_next/static/media/KaTeX_Fraktur-Bold.0et27v~3~4uhe.ttf +0 -0
- package/out/_next/static/media/KaTeX_Fraktur-Bold.0w23i72~hprpq.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Fraktur-Regular.0b.riegzdfue2.woff +0 -0
- package/out/_next/static/media/KaTeX_Fraktur-Regular.0rekyoa-52fj_.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Fraktur-Regular.0vjwa15znhk~4.ttf +0 -0
- package/out/_next/static/media/KaTeX_Main-Bold.09i7~607shf-h.ttf +0 -0
- package/out/_next/static/media/KaTeX_Main-Bold.09lmynrorhcbw.woff +0 -0
- package/out/_next/static/media/KaTeX_Main-Bold.16pfc63_du6mx.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Main-BoldItalic.0cp37g7x1q8h6.woff +0 -0
- package/out/_next/static/media/KaTeX_Main-BoldItalic.0d54rk08rx11s.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Main-BoldItalic.15j6k~hix2t_0.ttf +0 -0
- package/out/_next/static/media/KaTeX_Main-Italic.0382gqciexmbu.woff +0 -0
- package/out/_next/static/media/KaTeX_Main-Italic.06o5nq0_91v60.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Main-Italic.0su4i6mm18-wo.ttf +0 -0
- package/out/_next/static/media/KaTeX_Main-Regular.08zh8z.7shijf.ttf +0 -0
- package/out/_next/static/media/KaTeX_Main-Regular.0diheg01zyoph.woff +0 -0
- package/out/_next/static/media/KaTeX_Main-Regular.0kaf-ag2_wkm-.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Math-BoldItalic.0ajzxypnbx1h1.ttf +0 -0
- package/out/_next/static/media/KaTeX_Math-BoldItalic.0ck1myuerwyqw.woff +0 -0
- package/out/_next/static/media/KaTeX_Math-BoldItalic.0ja97dn.cpc87.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Math-Italic.09xkhecjcn5r9.woff +0 -0
- package/out/_next/static/media/KaTeX_Math-Italic.0x23a-bmp-5tg.ttf +0 -0
- package/out/_next/static/media/KaTeX_Math-Italic.0zrha2c4sl2je.woff2 +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Bold.05a9.pc1j_zx9.woff2 +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Bold.0jcl-ayi1uun0.woff +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Bold.0re8y.dm7.mt5.ttf +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Italic.0a0234dc3s62j.woff2 +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Italic.0judofdln9731.woff +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Italic.10z1iap9pfus8.ttf +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Regular.0h9yjlugq4q_e.woff +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Regular.0v6gcj32-czft.woff2 +0 -0
- package/out/_next/static/media/KaTeX_SansSerif-Regular.0zm18kga42ebc.ttf +0 -0
- package/out/_next/static/media/KaTeX_Script-Regular.0c4.h-mer83d_.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Script-Regular.0q14y6zkzlpob.ttf +0 -0
- package/out/_next/static/media/KaTeX_Script-Regular.0ze6v4r_-99oy.woff +0 -0
- package/out/_next/static/media/KaTeX_Size1-Regular.013x6a4ierotp.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Size1-Regular.0kidw0oi.m68o.woff +0 -0
- package/out/_next/static/media/KaTeX_Size1-Regular.0m6y-i6wfokni.ttf +0 -0
- package/out/_next/static/media/KaTeX_Size2-Regular.0blpmluwilgbg.woff +0 -0
- package/out/_next/static/media/KaTeX_Size2-Regular.0d5inmyp-tyv3.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Size2-Regular.0wnhnvj-.k9d5.ttf +0 -0
- package/out/_next/static/media/KaTeX_Size3-Regular.01h0xm_sfctj3.woff +0 -0
- package/out/_next/static/media/KaTeX_Size3-Regular.0iukctyhw5j56.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Size3-Regular.0jl8mqyf4gzpn.ttf +0 -0
- package/out/_next/static/media/KaTeX_Size4-Regular.0w3.rb_c4stzk.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Size4-Regular.0wr_9l81-mu06.ttf +0 -0
- package/out/_next/static/media/KaTeX_Size4-Regular.12tvaesf3.zl3.woff +0 -0
- package/out/_next/static/media/KaTeX_Typewriter-Regular.0c4zdxz~8frhm.woff2 +0 -0
- package/out/_next/static/media/KaTeX_Typewriter-Regular.0cgrzn5l3kao5.woff +0 -0
- package/out/_next/static/media/KaTeX_Typewriter-Regular.128~qc3858otl.ttf +0 -0
- package/out/_not-found/__next._full.txt +21 -19
- package/out/_not-found/__next._head.txt +3 -3
- package/out/_not-found/__next._index.txt +8 -6
- package/out/_not-found/__next._not-found.__PAGE__.txt +4 -4
- package/out/_not-found/__next._not-found.txt +3 -3
- package/out/_not-found/__next._tree.txt +3 -2
- package/out/_not-found/index.html +2 -2
- package/out/_not-found/index.txt +21 -19
- package/out/admin/__next._full.txt +23 -0
- package/out/admin/__next._head.txt +5 -0
- package/out/admin/__next._index.txt +9 -0
- package/out/admin/__next._tree.txt +5 -0
- package/out/admin/__next.admin.__PAGE__.txt +9 -0
- package/out/admin/__next.admin.txt +5 -0
- package/out/admin/index.html +15 -0
- package/out/admin/index.txt +23 -0
- package/out/app/__next._full.txt +15 -13
- package/out/app/__next._head.txt +3 -3
- package/out/app/__next._index.txt +8 -6
- package/out/app/__next._tree.txt +4 -2
- package/out/app/__next.app.__PAGE__.txt +4 -4
- package/out/app/__next.app.txt +3 -4
- package/out/app/index.html +2 -2
- package/out/app/index.txt +15 -13
- package/out/changelog/__next._full.txt +24 -21
- package/out/changelog/__next._head.txt +3 -3
- package/out/changelog/__next._index.txt +8 -6
- package/out/changelog/__next._tree.txt +5 -3
- package/out/changelog/__next.changelog.__PAGE__.txt +5 -5
- package/out/changelog/__next.changelog.txt +3 -3
- package/out/changelog/index.html +2 -2
- package/out/changelog/index.txt +24 -21
- package/out/chat/__next._full.txt +16 -14
- package/out/chat/__next._head.txt +3 -3
- package/out/chat/__next._index.txt +8 -6
- package/out/chat/__next._tree.txt +5 -3
- package/out/chat/__next.chat.__PAGE__.txt +4 -4
- package/out/chat/__next.chat.txt +4 -5
- package/out/chat/index.html +2 -2
- package/out/chat/index.txt +16 -14
- package/out/docs/__next._full.txt +24 -21
- package/out/docs/__next._head.txt +3 -3
- package/out/docs/__next._index.txt +8 -6
- package/out/docs/__next._tree.txt +5 -3
- package/out/docs/__next.docs.__PAGE__.txt +5 -5
- package/out/docs/__next.docs.txt +3 -3
- package/out/docs/getting-started/__next._full.txt +24 -21
- package/out/docs/getting-started/__next._head.txt +3 -3
- package/out/docs/getting-started/__next._index.txt +8 -6
- package/out/docs/getting-started/__next._tree.txt +5 -3
- package/out/docs/getting-started/__next.docs.getting-started.__PAGE__.txt +5 -5
- package/out/docs/getting-started/__next.docs.getting-started.txt +3 -3
- package/out/docs/getting-started/__next.docs.txt +3 -3
- package/out/docs/getting-started/index.html +2 -2
- package/out/docs/getting-started/index.txt +24 -21
- package/out/docs/index.html +2 -2
- package/out/docs/index.txt +24 -21
- package/out/download/__next._full.txt +33 -32
- package/out/download/__next._head.txt +3 -3
- package/out/download/__next._index.txt +8 -6
- package/out/download/__next._tree.txt +5 -3
- package/out/download/__next.download.__PAGE__.txt +10 -11
- package/out/download/__next.download.txt +3 -3
- package/out/download/index.html +2 -2
- package/out/download/index.txt +33 -32
- package/out/index.html +2 -2
- package/out/index.txt +23 -20
- package/out/note/__next._full.txt +24 -0
- package/out/note/__next._head.txt +5 -0
- package/out/note/__next._index.txt +9 -0
- package/out/note/__next._tree.txt +4 -0
- package/out/note/__next.note.__PAGE__.txt +9 -0
- package/out/note/__next.note.txt +5 -0
- package/out/note/edit/__next._full.txt +24 -0
- package/out/note/edit/__next._head.txt +5 -0
- package/out/note/edit/__next._index.txt +9 -0
- package/out/note/edit/__next._tree.txt +4 -0
- package/out/note/edit/__next.note.edit.__PAGE__.txt +9 -0
- package/out/note/edit/__next.note.edit.txt +5 -0
- package/out/note/edit/__next.note.txt +5 -0
- package/out/note/edit/index.html +15 -0
- package/out/note/edit/index.txt +24 -0
- package/out/note/index.html +15 -0
- package/out/note/index.txt +24 -0
- package/out/ping/__next._full.txt +22 -19
- package/out/ping/__next._head.txt +3 -3
- package/out/ping/__next._index.txt +8 -6
- package/out/ping/__next._tree.txt +5 -3
- package/out/ping/__next.ping.__PAGE__.txt +5 -5
- package/out/ping/__next.ping.txt +3 -3
- package/out/ping/index.html +2 -2
- package/out/ping/index.txt +22 -19
- package/out/web3/__next._full.txt +16 -14
- package/out/web3/__next._head.txt +3 -3
- package/out/web3/__next._index.txt +8 -6
- package/out/web3/__next._tree.txt +5 -3
- package/out/web3/__next.web3.__PAGE__.txt +4 -4
- package/out/web3/__next.web3.txt +4 -5
- package/out/web3/ed25519/__next._full.txt +14 -12
- package/out/web3/ed25519/__next._head.txt +3 -3
- package/out/web3/ed25519/__next._index.txt +8 -6
- package/out/web3/ed25519/__next._tree.txt +5 -3
- package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +2 -2
- package/out/web3/ed25519/__next.web3.ed25519.txt +3 -3
- package/out/web3/ed25519/__next.web3.txt +4 -5
- package/out/web3/ed25519/index.html +1 -1
- package/out/web3/ed25519/index.txt +14 -12
- package/out/web3/index.html +2 -2
- package/out/web3/index.txt +16 -14
- package/out/web3/tools/__next._full.txt +14 -12
- package/out/web3/tools/__next._head.txt +3 -3
- package/out/web3/tools/__next._index.txt +8 -6
- package/out/web3/tools/__next._tree.txt +5 -3
- package/out/web3/tools/__next.web3.tools.__PAGE__.txt +2 -2
- package/out/web3/tools/__next.web3.tools.txt +3 -3
- package/out/web3/tools/__next.web3.txt +4 -5
- package/out/web3/tools/index.html +1 -1
- package/out/web3/tools/index.txt +14 -12
- package/package.json +12 -5
- package/server/index.js +558 -101
- package/server/src/config.js +4 -0
- package/server/src/core/cid.js +53 -32
- package/server/src/index.js +772 -122
- package/server/src/node/config.js +159 -0
- package/server/src/node/logs.js +94 -0
- package/server/src/utils/api.js +80 -2
- package/server/src/utils/errors.js +7 -0
- package/server/src/utils/mostWallet.js +34 -1
- package/server/src/utils/noteBackup.js +119 -0
- package/server/src/utils/noteUtils.js +120 -0
- package/server/src/utils/userIdentity.js +8 -60
- package/out/_next/static/chunks/003jnm.v5tzw5.js +0 -1
- package/out/_next/static/chunks/00re8v.gbcywn.js +0 -1
- package/out/_next/static/chunks/00s106sbq8t9v.js +0 -1
- package/out/_next/static/chunks/012hi627qrdnn.js +0 -1
- package/out/_next/static/chunks/0174xh3wfsjm1.js +0 -2
- package/out/_next/static/chunks/02~o2nmo5pmy1.js +0 -1
- package/out/_next/static/chunks/07t.dhhokszz5.css +0 -1
- package/out/_next/static/chunks/0_wia9ofmsi1c.css +0 -2
- package/out/_next/static/chunks/0ah8fihozo2_u.js +0 -5
- package/out/_next/static/chunks/0bzupvr5gt3k9.js +0 -31
- package/out/_next/static/chunks/0gdluj423gso1.js +0 -1
- package/out/_next/static/chunks/0gmoiq06srjay.css +0 -1
- package/out/_next/static/chunks/0imkasy7kb67u.js +0 -1
- package/out/_next/static/chunks/0jjc_b9q_ldi2.js +0 -1
- package/out/_next/static/chunks/0jl~j62iz2uvr.js +0 -1
- package/out/_next/static/chunks/0lqslm813wk_h.js +0 -1
- package/out/_next/static/chunks/0q782fxxd0lx~.js +0 -1
- package/out/_next/static/chunks/0slwj0c46k5cu.js +0 -1
- package/out/_next/static/chunks/0sorqk.oc6b7j.css +0 -1
- package/out/_next/static/chunks/0tapzqc6hgvx-.js +0 -1
- package/out/_next/static/chunks/0xsc7z5x8n7wg.js +0 -1
- package/out/_next/static/chunks/0zm~gys2jwl0g.js +0 -1
- package/out/_next/static/chunks/turbopack-0a_g3u0ud~jb8.js +0 -1
- /package/out/_next/static/{iOB2EBwOGZ0iYW7Lbg9u_ → sIuUKxnnGU7K9Tu9UDKE8}/_buildManifest.js +0 -0
- /package/out/_next/static/{iOB2EBwOGZ0iYW7Lbg9u_ → sIuUKxnnGU7K9Tu9UDKE8}/_clientMiddlewareManifest.js +0 -0
- /package/out/_next/static/{iOB2EBwOGZ0iYW7Lbg9u_ → 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
|
|
29
|
-
const
|
|
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
|
|
68
|
+
function readPackageJson() {
|
|
32
69
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} catch
|
|
37
|
-
|
|
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
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
58
|
-
|
|
59
|
-
|
|
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:
|
|
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 >
|
|
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
|
|
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(
|
|
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
|
|
331
|
-
|
|
332
|
-
|
|
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 =
|
|
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
|
|
576
|
+
const patch = {}
|
|
355
577
|
|
|
356
578
|
if (body.resetStorage) {
|
|
357
|
-
|
|
579
|
+
patch.dataPath = ''
|
|
358
580
|
} else if (body.dataPath !== undefined) {
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
368
|
-
|
|
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
|
-
|
|
372
|
-
|
|
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
|
-
|
|
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 =
|
|
379
|
-
|
|
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/
|
|
383
|
-
const config =
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
396
|
-
|
|
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
|
-
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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(
|
|
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
|
-
|
|
476
|
-
|
|
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 (
|
|
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
|
|
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({
|
|
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 =>
|
|
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 =>
|
|
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 },
|