most-box 0.1.4 → 0.1.6

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 (400) hide show
  1. package/README.md +22 -12
  2. package/electron/main.js +31 -10
  3. package/out/404/index.html +3 -3
  4. package/out/404.html +3 -3
  5. package/out/__next.__PAGE__.txt +6 -6
  6. package/out/__next._full.txt +16 -16
  7. package/out/__next._head.txt +3 -3
  8. package/out/__next._index.txt +8 -8
  9. package/out/__next._tree.txt +5 -5
  10. package/out/_next/static/chunks/{06lttvu7563zo.css → 0-ryc9icn6dql.css} +1 -1
  11. package/out/_next/static/chunks/088-v8tzobg5g.js +1 -0
  12. package/out/_next/static/chunks/0g9303i8psy6z.js +1 -0
  13. package/out/_next/static/chunks/0nwdp-n94owg0.css +1 -0
  14. package/out/_next/static/chunks/{0pt.5cg1t09qs.js → 0s7i7nfr9j3b1.js} +1 -1
  15. package/out/_next/static/chunks/0vmjat-s4a3yj.css +1 -0
  16. package/out/_next/static/chunks/10p6-qnuk3p9x.js +1 -0
  17. package/out/_next/static/chunks/1ei8b9nw-ea8p.css +1 -0
  18. package/out/_next/static/chunks/1lxjpnw925-0p.css +1 -0
  19. package/out/_next/static/chunks/1v-molv0hbcjl.js +1 -0
  20. package/out/_next/static/chunks/23kls47vn_rpg.css +23 -0
  21. package/out/_next/static/chunks/2524ggtr3e4fp.js +1 -0
  22. package/out/_next/static/chunks/2fmkcw8ui5xp3.js +5 -0
  23. package/out/_next/static/chunks/2mcmt4yla_xle.js +1 -0
  24. package/out/_next/static/chunks/2uget3ephe4e3.js +736 -0
  25. package/out/_next/static/chunks/2v7_4ps1l4a8o.css +1 -0
  26. package/out/_next/static/chunks/2va-v1iiap4zv.js +1 -0
  27. package/out/_next/static/chunks/2vk2ln79gpvm4.js +1 -0
  28. package/out/_next/static/chunks/2vm9uslik2wfi.css +5 -0
  29. package/out/_next/static/chunks/37msy2-4ucgts.js +1 -0
  30. package/out/_next/static/chunks/384w3w4qvhw61.js +1 -0
  31. package/out/_next/static/chunks/3aa-weedhv4e0.js +1 -0
  32. package/out/_next/static/chunks/3erbaukgkw8f2.js +1 -0
  33. package/out/_next/static/chunks/3fea100s764m-.js +1 -0
  34. package/out/_next/static/chunks/3g0c367tk4esf.js +1 -0
  35. package/out/_next/static/chunks/{0gcsdf57gcm6h.js → 3oe03qxgd_rid.js} +1 -1
  36. package/out/_next/static/chunks/3qj5xz_d4cbk6.js +1 -0
  37. package/out/_next/static/chunks/3r5wf57k0gys9.js +1 -0
  38. package/out/_next/static/chunks/3yc_zd5vxq0j7.css +1 -0
  39. package/out/_next/static/chunks/{turbopack-0xta0kqwzkf28.js → turbopack-026p0g9v9_pva.js} +1 -1
  40. package/out/_not-found/__next._full.txt +13 -13
  41. package/out/_not-found/__next._head.txt +3 -3
  42. package/out/_not-found/__next._index.txt +8 -8
  43. package/out/_not-found/__next._not-found.__PAGE__.txt +4 -4
  44. package/out/_not-found/__next._not-found.txt +3 -3
  45. package/out/_not-found/__next._tree.txt +3 -3
  46. package/out/_not-found/index.html +3 -3
  47. package/out/_not-found/index.txt +13 -13
  48. package/out/admin/__next._full.txt +15 -15
  49. package/out/admin/__next._head.txt +3 -3
  50. package/out/admin/__next._index.txt +8 -8
  51. package/out/admin/__next._tree.txt +4 -4
  52. package/out/admin/__next.admin.__PAGE__.txt +4 -4
  53. package/out/admin/__next.admin.txt +4 -4
  54. package/out/admin/index.html +3 -3
  55. package/out/admin/index.txt +15 -15
  56. package/out/app/__next._full.txt +14 -14
  57. package/out/app/__next._head.txt +3 -3
  58. package/out/app/__next._index.txt +8 -8
  59. package/out/app/__next._tree.txt +3 -3
  60. package/out/app/__next.app.__PAGE__.txt +4 -4
  61. package/out/app/__next.app.txt +3 -3
  62. package/out/app/index.html +3 -3
  63. package/out/app/index.txt +14 -14
  64. package/out/chat/__next._full.txt +15 -15
  65. package/out/chat/__next._head.txt +3 -3
  66. package/out/chat/__next._index.txt +8 -8
  67. package/out/chat/__next._tree.txt +4 -4
  68. package/out/chat/__next.chat.__PAGE__.txt +4 -4
  69. package/out/chat/__next.chat.txt +4 -4
  70. package/out/chat/index.html +3 -3
  71. package/out/chat/index.txt +15 -15
  72. package/out/chat/join/__next._full.txt +15 -15
  73. package/out/chat/join/__next._head.txt +3 -3
  74. package/out/chat/join/__next._index.txt +8 -8
  75. package/out/chat/join/__next._tree.txt +4 -4
  76. package/out/chat/join/__next.chat.join.__PAGE__.txt +4 -4
  77. package/out/chat/join/__next.chat.join.txt +3 -3
  78. package/out/chat/join/__next.chat.txt +4 -4
  79. package/out/chat/join/index.html +3 -3
  80. package/out/chat/join/index.txt +15 -15
  81. package/out/demo/__next._full.txt +27 -0
  82. package/out/demo/__next._head.txt +5 -0
  83. package/out/demo/__next._index.txt +9 -0
  84. package/out/demo/__next._tree.txt +7 -0
  85. package/out/demo/__next.demo.__PAGE__.txt +12 -0
  86. package/out/demo/__next.demo.txt +5 -0
  87. package/out/demo/index.html +17 -0
  88. package/out/demo/index.txt +27 -0
  89. package/out/download/__next._full.txt +35 -37
  90. package/out/download/__next._head.txt +3 -3
  91. package/out/download/__next._index.txt +8 -8
  92. package/out/download/__next._tree.txt +5 -5
  93. package/out/download/__next.download.__PAGE__.txt +7 -7
  94. package/out/download/__next.download.txt +3 -3
  95. package/out/download/index.html +3 -3
  96. package/out/download/index.txt +35 -37
  97. package/out/favicon.ico +0 -0
  98. package/out/game/__next._full.txt +13 -13
  99. package/out/game/__next._head.txt +3 -3
  100. package/out/game/__next._index.txt +8 -8
  101. package/out/game/__next._tree.txt +4 -4
  102. package/out/game/__next.game.__PAGE__.txt +2 -2
  103. package/out/game/__next.game.txt +4 -4
  104. package/out/game/gandengyan/__next._full.txt +16 -16
  105. package/out/game/gandengyan/__next._head.txt +3 -3
  106. package/out/game/gandengyan/__next._index.txt +8 -8
  107. package/out/game/gandengyan/__next._tree.txt +5 -5
  108. package/out/game/gandengyan/__next.game.gandengyan.__PAGE__.txt +5 -5
  109. package/out/game/gandengyan/__next.game.gandengyan.txt +3 -3
  110. package/out/game/gandengyan/__next.game.txt +4 -4
  111. package/out/game/gandengyan/index.html +3 -3
  112. package/out/game/gandengyan/index.txt +16 -16
  113. package/out/game/index.html +1 -1
  114. package/out/game/index.txt +13 -13
  115. package/out/game/zhajinhua/__next._full.txt +15 -15
  116. package/out/game/zhajinhua/__next._head.txt +3 -3
  117. package/out/game/zhajinhua/__next._index.txt +8 -8
  118. package/out/game/zhajinhua/__next._tree.txt +4 -4
  119. package/out/game/zhajinhua/__next.game.txt +4 -4
  120. package/out/game/zhajinhua/__next.game.zhajinhua.__PAGE__.txt +4 -4
  121. package/out/game/zhajinhua/__next.game.zhajinhua.txt +3 -3
  122. package/out/game/zhajinhua/index.html +3 -3
  123. package/out/game/zhajinhua/index.txt +15 -15
  124. package/out/index.html +3 -3
  125. package/out/index.txt +16 -16
  126. package/out/logo-512.png +0 -0
  127. package/out/logo.ico +0 -0
  128. package/out/logo.svg +12 -0
  129. package/out/note/__next._full.txt +14 -14
  130. package/out/note/__next._head.txt +3 -3
  131. package/out/note/__next._index.txt +8 -8
  132. package/out/note/__next._tree.txt +3 -3
  133. package/out/note/__next.note.__PAGE__.txt +4 -4
  134. package/out/note/__next.note.txt +3 -3
  135. package/out/note/index.html +3 -3
  136. package/out/note/index.txt +14 -14
  137. package/out/ping/__next._full.txt +16 -16
  138. package/out/ping/__next._head.txt +3 -3
  139. package/out/ping/__next._index.txt +8 -8
  140. package/out/ping/__next._tree.txt +5 -5
  141. package/out/ping/__next.ping.__PAGE__.txt +5 -5
  142. package/out/ping/__next.ping.txt +4 -4
  143. package/out/ping/index.html +3 -3
  144. package/out/ping/index.txt +16 -16
  145. package/out/web3/__next._full.txt +15 -15
  146. package/out/web3/__next._head.txt +3 -3
  147. package/out/web3/__next._index.txt +8 -8
  148. package/out/web3/__next._tree.txt +4 -4
  149. package/out/web3/__next.web3.__PAGE__.txt +4 -4
  150. package/out/web3/__next.web3.txt +4 -4
  151. package/out/web3/ed25519/__next._full.txt +13 -13
  152. package/out/web3/ed25519/__next._head.txt +3 -3
  153. package/out/web3/ed25519/__next._index.txt +8 -8
  154. package/out/web3/ed25519/__next._tree.txt +4 -4
  155. package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +2 -2
  156. package/out/web3/ed25519/__next.web3.ed25519.txt +3 -3
  157. package/out/web3/ed25519/__next.web3.txt +4 -4
  158. package/out/web3/ed25519/index.html +1 -1
  159. package/out/web3/ed25519/index.txt +13 -13
  160. package/out/web3/index.html +3 -3
  161. package/out/web3/index.txt +15 -15
  162. package/out/web3/tools/__next._full.txt +13 -13
  163. package/out/web3/tools/__next._head.txt +3 -3
  164. package/out/web3/tools/__next._index.txt +8 -8
  165. package/out/web3/tools/__next._tree.txt +4 -4
  166. package/out/web3/tools/__next.web3.tools.__PAGE__.txt +2 -2
  167. package/out/web3/tools/__next.web3.tools.txt +3 -3
  168. package/out/web3/tools/__next.web3.txt +4 -4
  169. package/out/web3/tools/index.html +1 -1
  170. package/out/web3/tools/index.txt +13 -13
  171. package/package.json +27 -27
  172. package/public/favicon.ico +0 -0
  173. package/public/logo-512.png +0 -0
  174. package/public/logo.ico +0 -0
  175. package/public/logo.svg +12 -0
  176. package/server/src/core/mostLink.js +1 -1
  177. package/server/src/games/gandengyan.js +49 -19
  178. package/server/src/http/app.js +40 -15
  179. package/server/src/http/nodeStatus.js +37 -0
  180. package/server/src/http/uploads.js +1 -0
  181. package/server/src/index.js +417 -112
  182. package/server/src/utils/avatar.js +3 -2
  183. package/out/_next/static/chunks/03gsbg0fr00ey.js +0 -1
  184. package/out/_next/static/chunks/0adx~d-j05c9d.css +0 -24
  185. package/out/_next/static/chunks/0ao1lbi4b.sfa.js +0 -1
  186. package/out/_next/static/chunks/0fo9-h4knidcz.js +0 -1
  187. package/out/_next/static/chunks/0g_a~e050bgzg.css +0 -1
  188. package/out/_next/static/chunks/0h4r.qtmpa6eh.js +0 -1
  189. package/out/_next/static/chunks/0hpev4am9jpmu.css +0 -1
  190. package/out/_next/static/chunks/0hyds~bp.auvh.js +0 -1
  191. package/out/_next/static/chunks/0i9sfdypwuw8~.js +0 -1
  192. package/out/_next/static/chunks/0o9ce4cyf76by.js +0 -736
  193. package/out/_next/static/chunks/0olqjomda37-e.js +0 -1
  194. package/out/_next/static/chunks/0puk.7e.tr2zy.js +0 -1
  195. package/out/_next/static/chunks/0qgx9t4jx16ua.css +0 -1
  196. package/out/_next/static/chunks/0s1k6rlwy02c2.js +0 -1
  197. package/out/_next/static/chunks/0sgltmtk_9s8p.css +0 -1
  198. package/out/_next/static/chunks/0snehvtvu1n4q.js +0 -1
  199. package/out/_next/static/chunks/0s~g.l~x049o2.js +0 -1
  200. package/out/_next/static/chunks/0t_3xxx4zkerp.js +0 -5
  201. package/out/_next/static/chunks/0u38kke9vhobe.js +0 -1
  202. package/out/_next/static/chunks/0vd4_a5x-wpdh.js +0 -1
  203. package/out/_next/static/chunks/0xdwau5k2augv.css +0 -4
  204. package/out/_next/static/chunks/0xx_10jns1.s7.css +0 -1
  205. package/out/_next/static/chunks/10f-t2n4y1zx8.js +0 -1
  206. package/out/_next/static/chunks/13jdyag9a-~kk.js +0 -1
  207. package/out/_next/static/chunks/153-sz7s.qml2.js +0 -1
  208. package/out/_next/static/chunks/17cwkb2yn_akx.js +0 -1
  209. /package/out/_next/static/{sSvbBrwXZY-4lBmcHshga → NPIlpdzQWkiVZpgfhlypH}/_buildManifest.js +0 -0
  210. /package/out/_next/static/{sSvbBrwXZY-4lBmcHshga → NPIlpdzQWkiVZpgfhlypH}/_clientMiddlewareManifest.js +0 -0
  211. /package/out/_next/static/{sSvbBrwXZY-4lBmcHshga → NPIlpdzQWkiVZpgfhlypH}/_ssgManifest.js +0 -0
  212. /package/out/_next/static/chunks/{0bld2u_ld~va2.js → 0-jy8rfo075fy.js} +0 -0
  213. /package/out/_next/static/chunks/{0bliugh5lxw55.js → 0-kczrcxjk7lc.js} +0 -0
  214. /package/out/_next/static/chunks/{00d9h1tddnnnd.js → 012yllpioyi-k.js} +0 -0
  215. /package/out/_next/static/chunks/{00tkdqwxch-3s.js → 02f7w-ybfnvpd.js} +0 -0
  216. /package/out/_next/static/chunks/{01l3o90g~1z42.js → 04_v8i3c2y4ni.js} +0 -0
  217. /package/out/_next/static/chunks/{01xlw8hd842-c.js → 05-c3ty_6dwfk.js} +0 -0
  218. /package/out/_next/static/chunks/{01mfky9camw6i.js → 052vp9tk7oqx6.js} +0 -0
  219. /package/out/_next/static/chunks/{01r.v-pqs1vrm.js → 05k6874y7n0cw.js} +0 -0
  220. /package/out/_next/static/chunks/{02zzxfop_k6tl.css → 09g8c9-u_uh1z.css} +0 -0
  221. /package/out/_next/static/chunks/{03edqrb4zdj~g.js → 0az8vxg2gfuhm.js} +0 -0
  222. /package/out/_next/static/chunks/{03h_6oo-gqkhz.js → 0b899y85ei3i_.js} +0 -0
  223. /package/out/_next/static/chunks/{03~yq9q893hmn.js → 0cz1d0mv5g_q7.js} +0 -0
  224. /package/out/_next/static/chunks/{04hcgsanv1hhu.js → 0eg1osglq6nq7.js} +0 -0
  225. /package/out/_next/static/chunks/{05g2q0w5b34.g.js → 0hlvocunlbrjs.js} +0 -0
  226. /package/out/_next/static/chunks/{05of77xycbt8~.js → 0i9k23rx749fx.js} +0 -0
  227. /package/out/_next/static/chunks/{05zwemzfjx3sh.js → 0j6wiyqf1637r.js} +0 -0
  228. /package/out/_next/static/chunks/{06dpc5df94.v1.js → 0knzyzd1jvley.js} +0 -0
  229. /package/out/_next/static/chunks/{06e1~1-z_ic9a.js → 0kp8ujaqwut11.js} +0 -0
  230. /package/out/_next/static/chunks/{075s7sn.ns~u5.js → 0n92y9hb-ta0u.js} +0 -0
  231. /package/out/_next/static/chunks/{07dynrbvd3.f4.js → 0nybb-z3ufrbx.js} +0 -0
  232. /package/out/_next/static/chunks/{07r9nn-pzlgg1.js → 0o-o9af-grvj8.js} +0 -0
  233. /package/out/_next/static/chunks/{07p~uva5pwgwe.js → 0oxr0r0aewn99.js} +0 -0
  234. /package/out/_next/static/chunks/{08576xhv~~jck.js → 0qh3b90ouc9bd.js} +0 -0
  235. /package/out/_next/static/chunks/{08u211~k~qu52.js → 0sh_jm8siqvek.js} +0 -0
  236. /package/out/_next/static/chunks/{08.72abkgwy9g.js → 0t86ducxkqweb.js} +0 -0
  237. /package/out/_next/static/chunks/{098.p.2-zm4p7.js → 0u0j5i6-n4oqd.js} +0 -0
  238. /package/out/_next/static/chunks/{09ngvtajm7e5y.js → 0v73vfxjds7sj.js} +0 -0
  239. /package/out/_next/static/chunks/{09ps~-43n5qyo.js → 0ve8ixremhwy0.js} +0 -0
  240. /package/out/_next/static/chunks/{09v7_0gclxr46.js → 0vv5cwj6kr506.js} +0 -0
  241. /package/out/_next/static/chunks/{09yql86dir9c4.js → 0w3wf8o-ewec9.js} +0 -0
  242. /package/out/_next/static/chunks/{09zmlfljowj1~.js → 0w6o4o76scrb2.js} +0 -0
  243. /package/out/_next/static/chunks/{0n4t80gjc3q5h.js → 1-88dio6azz54.js} +0 -0
  244. /package/out/_next/static/chunks/{0cn9a7aimbdzq.js → 12zg24u7mbv4z.js} +0 -0
  245. /package/out/_next/static/chunks/{0d3f-nk3c.2re.js → 14lsse587-ccf.js} +0 -0
  246. /package/out/_next/static/chunks/{0dtohpf7~3d12.js → 16qtikqm_sate.js} +0 -0
  247. /package/out/_next/static/chunks/{0e531nije_ln2.js → 17_ly1mk2z3q8.js} +0 -0
  248. /package/out/_next/static/chunks/{0e5zvj_rh0z3m.js → 181421-y2xzj7.js} +0 -0
  249. /package/out/_next/static/chunks/{0myp4sjagr~h0.js → 1_e-vuvfsntao.js} +0 -0
  250. /package/out/_next/static/chunks/{0e-3e8h7g99yf.js → 1aljc62wfhqhr.js} +0 -0
  251. /package/out/_next/static/chunks/{0f4y~rkk-n81e.js → 1b7mbzsylsn-m.js} +0 -0
  252. /package/out/_next/static/chunks/{0fk~0~p7ivfn1.js → 1cjakikh0o1tm.js} +0 -0
  253. /package/out/_next/static/chunks/{0fw6juc~lsj3z.js → 1dfzez629llzh.js} +0 -0
  254. /package/out/_next/static/chunks/{0g0u7785a73vo.js → 1e4ilit3ave6c.js} +0 -0
  255. /package/out/_next/static/chunks/{0gze5uso1mbe9.js → 1gzgcv355ziff.js} +0 -0
  256. /package/out/_next/static/chunks/{0g_fpgh7drfda.js → 1h0o6fj73le9_.js} +0 -0
  257. /package/out/_next/static/chunks/{0hf.aosc-7172.js → 1in766ibz5l-p.js} +0 -0
  258. /package/out/_next/static/chunks/{0hgz35c1ejbs9.js → 1ip_c70si4tj2.js} +0 -0
  259. /package/out/_next/static/chunks/{0hrw-r.xmvmsq.js → 1jlu197-yog_n.js} +0 -0
  260. /package/out/_next/static/chunks/{0hzg4al.v~8~m.js → 1k788fny29y_j.js} +0 -0
  261. /package/out/_next/static/chunks/{0ip9xrols_83o.js → 1mnhfyfn52md5.js} +0 -0
  262. /package/out/_next/static/chunks/{0j4-d0qf.v~kn.js → 1o8brm8yipzn4.js} +0 -0
  263. /package/out/_next/static/chunks/{0jhdeq.j9_02m.js → 1p8oa39bqu6ed.js} +0 -0
  264. /package/out/_next/static/chunks/{0jy63h3i-y69i.js → 1qmnmb_dutuw8.js} +0 -0
  265. /package/out/_next/static/chunks/{0kdnx_u-60k9s.js → 1s6rdcw0q185p.js} +0 -0
  266. /package/out/_next/static/chunks/{0kq~edq42o1-c.js → 1ta0w8zc7tae7.js} +0 -0
  267. /package/out/_next/static/chunks/{0l682p362d-5w.js → 1uvi_hie0s3z5.js} +0 -0
  268. /package/out/_next/static/chunks/{0m68p9txef5rs.js → 1y36s6sv2z7r4.js} +0 -0
  269. /package/out/_next/static/chunks/{0mme-fm5d2oz2.js → 1zf4i-oj7n-ll.js} +0 -0
  270. /package/out/_next/static/chunks/{0y.li-~3oybew.js → 2-vtwv8h_uokj.js} +0 -0
  271. /package/out/_next/static/chunks/{0n.qlfk~z7o.6.js → 2227enga_0c-6.js} +0 -0
  272. /package/out/_next/static/chunks/{0oz3yl6_-716p.js → 24zr4q96g-eii.js} +0 -0
  273. /package/out/_next/static/chunks/{0pqt~8bl3ukh4.js → 27jktro2p5rq9.js} +0 -0
  274. /package/out/_next/static/chunks/{0yl2t7cs-n_ng.js → 2_cqphhur0a6t.js} +0 -0
  275. /package/out/_next/static/chunks/{0yq3kh.hchtm_.js → 2_s88st3j0tql.js} +0 -0
  276. /package/out/_next/static/chunks/{0ys0l5au.9c2c.js → 2_y6edbaubqrt.js} +0 -0
  277. /package/out/_next/static/chunks/{0qqupeexg83u7.js → 2at8y3pbt5cue.js} +0 -0
  278. /package/out/_next/static/chunks/{0rb-ri481.kc9.js → 2cv1zex4has67.js} +0 -0
  279. /package/out/_next/static/chunks/{0rsnmahfd.59p.js → 2e6j5h4ftd4jd.js} +0 -0
  280. /package/out/_next/static/chunks/{0rt6rgnvr-s_p.js → 2e8b26r0td7ou.js} +0 -0
  281. /package/out/_next/static/chunks/{0runh28p_gg6..js → 2ecppdrjm9cs4.js} +0 -0
  282. /package/out/_next/static/chunks/{0shy.t1fwqcev.js → 2gl0wusc9zf3d.js} +0 -0
  283. /package/out/_next/static/chunks/{0t2xr05rlu96l.js → 2im7c515bo69p.js} +0 -0
  284. /package/out/_next/static/chunks/{0t6h56rhg1y5i.js → 2ixaku9ie8hym.js} +0 -0
  285. /package/out/_next/static/chunks/{0tdqd1zunusgk.js → 2jhnrjgj_k2-z.js} +0 -0
  286. /package/out/_next/static/chunks/{0ujbnp38x63ek.js → 2n6pb94vmohgf.js} +0 -0
  287. /package/out/_next/static/chunks/{0ukyg~tkm~h2m.css → 2nbju8t9-ux58.css} +0 -0
  288. /package/out/_next/static/chunks/{0v68pdrp54lb-.js → 2pdxw43rsbho0.js} +0 -0
  289. /package/out/_next/static/chunks/{0vsm0m5sxrb.3.js → 2r6z3vlfw0ppd.js} +0 -0
  290. /package/out/_next/static/chunks/{0vzlz.iboqo3c.js → 2rskzmv3skmq3.js} +0 -0
  291. /package/out/_next/static/chunks/{0w87vbpkf-ogd.js → 2stoe6xiau1b3.js} +0 -0
  292. /package/out/_next/static/chunks/{0xgg0~kmf3gd-.js → 2wqoc60afpg_5.js} +0 -0
  293. /package/out/_next/static/chunks/{0xj24-70ptdzp.js → 2wyvwsayrr98o.js} +0 -0
  294. /package/out/_next/static/chunks/{0xxlx772fr3x4.js → 2y3o2mnyfnx68.js} +0 -0
  295. /package/out/_next/static/chunks/{16i.qbk8t8gf_.js → 3-7y7sjol3yto.js} +0 -0
  296. /package/out/_next/static/chunks/{0z48pmi6buytt.js → 3089gugfv3ov9.js} +0 -0
  297. /package/out/_next/static/chunks/{0zapnvgy89mg..js → 30s3_0brd77ky.js} +0 -0
  298. /package/out/_next/static/chunks/{0_s~ebb-7b2hr.js → 35idql3ziq0wz.js} +0 -0
  299. /package/out/_next/static/chunks/{0_w-0-2z5oqd_.js → 35unmm4isvqg5.js} +0 -0
  300. /package/out/_next/static/chunks/{0-n3pg7th.zza.js → 389wmv2b6x2nn.js} +0 -0
  301. /package/out/_next/static/chunks/{0~4f5p6tvn1lq.js → 39-oy5n969lo6.js} +0 -0
  302. /package/out/_next/static/chunks/{0~3ik-hfp9s-7.js → 39yvee40syj70.js} +0 -0
  303. /package/out/_next/static/chunks/{0~_0ys.2whxbw.js → 3clhij8e1eul0.js} +0 -0
  304. /package/out/_next/static/chunks/{0~_ui9l7.2sxf.js → 3cnsdzbvm3q7p.js} +0 -0
  305. /package/out/_next/static/chunks/{0~.-vxi5oc.r0.js → 3cxmalqqghdac.js} +0 -0
  306. /package/out/_next/static/chunks/{0.4j.0k5a64vg.js → 3d9p88evh2scq.js} +0 -0
  307. /package/out/_next/static/chunks/{0.ozi1_x2.m.~.js → 3eyprczj7yrg6.js} +0 -0
  308. /package/out/_next/static/chunks/{0.t5wlt51zou5.js → 3f9v_gtppe4hs.js} +0 -0
  309. /package/out/_next/static/chunks/{0.w4hkvap~bva.js → 3fj0amtzqae6f.js} +0 -0
  310. /package/out/_next/static/chunks/{1037jlyw5~7ht.js → 3gf98e08a-l_e.js} +0 -0
  311. /package/out/_next/static/chunks/{1045hfzu533z0.js → 3gi6og9m_yaak.js} +0 -0
  312. /package/out/_next/static/chunks/{104e5nmc.c-pl.js → 3giw7r1lii84y.js} +0 -0
  313. /package/out/_next/static/chunks/{109taw1pbh-0b.js → 3gzhy1cs_f2oi.js} +0 -0
  314. /package/out/_next/static/chunks/{10ynz1dy483wf.js → 3i_ceknny1oqt.js} +0 -0
  315. /package/out/_next/static/chunks/{10x7~onqwp338.js → 3iw0815ssih3b.js} +0 -0
  316. /package/out/_next/static/chunks/{11hds.mg~4_r-.js → 3kun-vwr7nzd4.js} +0 -0
  317. /package/out/_next/static/chunks/{11ibzaklcauw~.js → 3kxm1e-b1er3_.js} +0 -0
  318. /package/out/_next/static/chunks/{11z.0s6.42b.p.js → 3mc8fynmv71yg.js} +0 -0
  319. /package/out/_next/static/chunks/{126enaq~f7scl.js → 3n6cor2n9zyn7.js} +0 -0
  320. /package/out/_next/static/chunks/{12pep-2t-qg4n.css → 3or2h8swxfxyj.css} +0 -0
  321. /package/out/_next/static/chunks/{12-9n56l0y3yr.js → 3ppt04b6xqz29.js} +0 -0
  322. /package/out/_next/static/chunks/{1380op_pfk.qo.js → 3ql2pi_m5_5p_.js} +0 -0
  323. /package/out/_next/static/chunks/{14a4fwbiq.l3z.js → 3t-6u8caafiu9.js} +0 -0
  324. /package/out/_next/static/chunks/{146oiw1bggtn4.js → 3tqdzb_n12tdm.js} +0 -0
  325. /package/out/_next/static/chunks/{14cowsqn95m1k.js → 3u6zpg943kpst.js} +0 -0
  326. /package/out/_next/static/chunks/{14dtd3l03v.kx.js → 3uaedu2hf291z.js} +0 -0
  327. /package/out/_next/static/chunks/{14tm3qa-v9o-4.js → 3vladx3wh0d4k.js} +0 -0
  328. /package/out/_next/static/chunks/{14_inksek_rth.js → 3w4o9hklow6fg.js} +0 -0
  329. /package/out/_next/static/chunks/{14_po2rb_arn4.js → 3w56w25z6u89b.js} +0 -0
  330. /package/out/_next/static/chunks/{157z7bowux3xj.js → 3x1y_gkazt6kx.js} +0 -0
  331. /package/out/_next/static/chunks/{15m1_677az2cm.js → 3y7r1h96dtcov.js} +0 -0
  332. /package/out/_next/static/chunks/{15v.~.ne6ogkk.js → 3z0hydntmwg19.js} +0 -0
  333. /package/out/_next/static/chunks/{15-o4kb-evqd7.js → 3zhu1svjr0bc5.js} +0 -0
  334. /package/out/_next/static/chunks/{16u9f35gylw8l.js → 404orp1erq__7.js} +0 -0
  335. /package/out/_next/static/chunks/{17ajyb5ogk5yj.js → 41talcs-dc2tc.js} +0 -0
  336. /package/out/_next/static/chunks/{17dyfxbq8yz8n.js → 421pn8weymo-b.js} +0 -0
  337. /package/out/_next/static/chunks/{180zln9pcq9ih.js → 44987pmr20now.js} +0 -0
  338. /package/out/_next/static/chunks/{1814izi5gh.kp.js → 449ygeh62gitc.js} +0 -0
  339. /package/out/_next/static/media/{KaTeX_AMS-Regular.0b~8ki5y928w2.woff → KaTeX_AMS-Regular.10y3kupq4t663.woff} +0 -0
  340. /package/out/_next/static/media/{KaTeX_AMS-Regular.0p1vbqd84i2~o.woff2 → KaTeX_AMS-Regular.25ieegmnh38ts.woff2} +0 -0
  341. /package/out/_next/static/media/{KaTeX_AMS-Regular.173t6ktr7uf-w.ttf → KaTeX_AMS-Regular.418dr7cz3fo2x.ttf} +0 -0
  342. /package/out/_next/static/media/{KaTeX_Caligraphic-Bold.01-pzluls4zgb.woff2 → KaTeX_Caligraphic-Bold.06b-ya9t43ioz.woff2} +0 -0
  343. /package/out/_next/static/media/{KaTeX_Caligraphic-Bold.0x2v1lwn~880f.woff → KaTeX_Caligraphic-Bold.2vmk2hva4ctha.woff} +0 -0
  344. /package/out/_next/static/media/{KaTeX_Caligraphic-Bold.16zv5fax0h0ka.ttf → KaTeX_Caligraphic-Bold.40ltxhe834pns.ttf} +0 -0
  345. /package/out/_next/static/media/{KaTeX_Caligraphic-Regular.02i3z7wig438t.ttf → KaTeX_Caligraphic-Regular.07-7u27-nhn_r.ttf} +0 -0
  346. /package/out/_next/static/media/{KaTeX_Caligraphic-Regular.0rysu1t-ncjq8.woff2 → KaTeX_Caligraphic-Regular.2eph4dlhid_m9.woff2} +0 -0
  347. /package/out/_next/static/media/{KaTeX_Caligraphic-Regular.10927swgekwun.woff → KaTeX_Caligraphic-Regular.3gxeetazf831f.woff} +0 -0
  348. /package/out/_next/static/media/{KaTeX_Fraktur-Bold.0et27v~3~4uhe.ttf → KaTeX_Fraktur-Bold.19yqa_tc9d_gx.ttf} +0 -0
  349. /package/out/_next/static/media/{KaTeX_Fraktur-Bold.0e-16u10iuyyf.woff → KaTeX_Fraktur-Bold.1alcy76__wdj2.woff} +0 -0
  350. /package/out/_next/static/media/{KaTeX_Fraktur-Bold.0w23i72~hprpq.woff2 → KaTeX_Fraktur-Bold.2sasz-d-jtw8y.woff2} +0 -0
  351. /package/out/_next/static/media/{KaTeX_Fraktur-Regular.0b.riegzdfue2.woff → KaTeX_Fraktur-Regular.110oo81prr9n5.woff} +0 -0
  352. /package/out/_next/static/media/{KaTeX_Fraktur-Regular.0rekyoa-52fj_.woff2 → KaTeX_Fraktur-Regular.2d10y4xmjvzlf.woff2} +0 -0
  353. /package/out/_next/static/media/{KaTeX_Fraktur-Regular.0vjwa15znhk~4.ttf → KaTeX_Fraktur-Regular.2qhy34r6a05dn.ttf} +0 -0
  354. /package/out/_next/static/media/{KaTeX_Main-Bold.09i7~607shf-h.ttf → KaTeX_Main-Bold.0us_n0tnxlxu7.ttf} +0 -0
  355. /package/out/_next/static/media/{KaTeX_Main-Bold.09lmynrorhcbw.woff → KaTeX_Main-Bold.0v1esh257kqpe.woff} +0 -0
  356. /package/out/_next/static/media/{KaTeX_Main-Bold.16pfc63_du6mx.woff2 → KaTeX_Main-Bold.3-rowy8o6_4ky.woff2} +0 -0
  357. /package/out/_next/static/media/{KaTeX_Main-BoldItalic.0cp37g7x1q8h6.woff → KaTeX_Main-BoldItalic.13355ck5zr48q.woff} +0 -0
  358. /package/out/_next/static/media/{KaTeX_Main-BoldItalic.0d54rk08rx11s.woff2 → KaTeX_Main-BoldItalic.14r2naom8mrec.woff2} +0 -0
  359. /package/out/_next/static/media/{KaTeX_Main-BoldItalic.15j6k~hix2t_0.ttf → KaTeX_Main-BoldItalic.3x_u9cepaced0.ttf} +0 -0
  360. /package/out/_next/static/media/{KaTeX_Main-Italic.0382gqciexmbu.woff → KaTeX_Main-Italic.0afv392dj4w59.woff} +0 -0
  361. /package/out/_next/static/media/{KaTeX_Main-Italic.06o5nq0_91v60.woff2 → KaTeX_Main-Italic.0lig0v9j0700p.woff2} +0 -0
  362. /package/out/_next/static/media/{KaTeX_Main-Italic.0su4i6mm18-wo.ttf → KaTeX_Main-Italic.2hkw3230mfwcv.ttf} +0 -0
  363. /package/out/_next/static/media/{KaTeX_Main-Regular.08zh8z.7shijf.ttf → KaTeX_Main-Regular.0symfa7dqj6jd.ttf} +0 -0
  364. /package/out/_next/static/media/{KaTeX_Main-Regular.0diheg01zyoph.woff → KaTeX_Main-Regular.15u8r3b2y7fv4.woff} +0 -0
  365. /package/out/_next/static/media/{KaTeX_Main-Regular.0kaf-ag2_wkm-.woff2 → KaTeX_Main-Regular.1ryvsdzh2w1_e.woff2} +0 -0
  366. /package/out/_next/static/media/{KaTeX_Math-BoldItalic.0ajzxypnbx1h1.ttf → KaTeX_Math-BoldItalic.0y5w36a5aq__2.ttf} +0 -0
  367. /package/out/_next/static/media/{KaTeX_Math-BoldItalic.0ck1myuerwyqw.woff → KaTeX_Math-BoldItalic.12pl58orkw9rg.woff} +0 -0
  368. /package/out/_next/static/media/{KaTeX_Math-BoldItalic.0ja97dn.cpc87.woff2 → KaTeX_Math-BoldItalic.1oopuu636h4il.woff2} +0 -0
  369. /package/out/_next/static/media/{KaTeX_Math-Italic.09xkhecjcn5r9.woff → KaTeX_Math-Italic.0w0b1ugh62cfr.woff} +0 -0
  370. /package/out/_next/static/media/{KaTeX_Math-Italic.0x23a-bmp-5tg.ttf → KaTeX_Math-Italic.2vkekfblmz5nb.ttf} +0 -0
  371. /package/out/_next/static/media/{KaTeX_Math-Italic.0zrha2c4sl2je.woff2 → KaTeX_Math-Italic.32405s1aq8vas.woff2} +0 -0
  372. /package/out/_next/static/media/{KaTeX_SansSerif-Bold.05a9.pc1j_zx9.woff2 → KaTeX_SansSerif-Bold.0h3wi2z_eouyg.woff2} +0 -0
  373. /package/out/_next/static/media/{KaTeX_SansSerif-Bold.0jcl-ayi1uun0.woff → KaTeX_SansSerif-Bold.1ovw5p-yjp56g.woff} +0 -0
  374. /package/out/_next/static/media/{KaTeX_SansSerif-Bold.0re8y.dm7.mt5.ttf → KaTeX_SansSerif-Bold.2d03q85pwxpti.ttf} +0 -0
  375. /package/out/_next/static/media/{KaTeX_SansSerif-Italic.0a0234dc3s62j.woff2 → KaTeX_SansSerif-Italic.0wkjc4dm2kcit.woff2} +0 -0
  376. /package/out/_next/static/media/{KaTeX_SansSerif-Italic.0judofdln9731.woff → KaTeX_SansSerif-Italic.1qavw__2zz8gk.woff} +0 -0
  377. /package/out/_next/static/media/{KaTeX_SansSerif-Italic.10z1iap9pfus8.ttf → KaTeX_SansSerif-Italic.3i-q087b23-m8.ttf} +0 -0
  378. /package/out/_next/static/media/{KaTeX_SansSerif-Regular.0h9yjlugq4q_e.woff → KaTeX_SansSerif-Regular.1i4afx8nk8n4r.woff} +0 -0
  379. /package/out/_next/static/media/{KaTeX_SansSerif-Regular.0v6gcj32-czft.woff2 → KaTeX_SansSerif-Regular.2peiewu59z3d-.woff2} +0 -0
  380. /package/out/_next/static/media/{KaTeX_SansSerif-Regular.0zm18kga42ebc.ttf → KaTeX_SansSerif-Regular.31pbu25feko_c.ttf} +0 -0
  381. /package/out/_next/static/media/{KaTeX_Script-Regular.0c4.h-mer83d_.woff2 → KaTeX_Script-Regular.11h14300o9pd0.woff2} +0 -0
  382. /package/out/_next/static/media/{KaTeX_Script-Regular.0q14y6zkzlpob.ttf → KaTeX_Script-Regular.28p_x7iz71ofe.ttf} +0 -0
  383. /package/out/_next/static/media/{KaTeX_Script-Regular.0ze6v4r_-99oy.woff → KaTeX_Script-Regular.3110jb9c-bxna.woff} +0 -0
  384. /package/out/_next/static/media/{KaTeX_Size1-Regular.013x6a4ierotp.woff2 → KaTeX_Size1-Regular.03lhvx36ekcou.woff2} +0 -0
  385. /package/out/_next/static/media/{KaTeX_Size1-Regular.0kidw0oi.m68o.woff → KaTeX_Size1-Regular.1slf4bh0hc6vm.woff} +0 -0
  386. /package/out/_next/static/media/{KaTeX_Size1-Regular.0m6y-i6wfokni.ttf → KaTeX_Size1-Regular.1y57-ck23ey8c.ttf} +0 -0
  387. /package/out/_next/static/media/{KaTeX_Size2-Regular.0blpmluwilgbg.woff → KaTeX_Size2-Regular.0-kwyvx03omo8.woff} +0 -0
  388. /package/out/_next/static/media/{KaTeX_Size2-Regular.0d5inmyp-tyv3.woff2 → KaTeX_Size2-Regular.14s5gg-puz6h-.woff2} +0 -0
  389. /package/out/_next/static/media/{KaTeX_Size2-Regular.0wnhnvj-.k9d5.ttf → KaTeX_Size2-Regular.2u0s-b07k2o9m.ttf} +0 -0
  390. /package/out/_next/static/media/{KaTeX_Size3-Regular.01h0xm_sfctj3.woff → KaTeX_Size3-Regular.04o9a_02gu_e8.woff} +0 -0
  391. /package/out/_next/static/media/{KaTeX_Size3-Regular.0iukctyhw5j56.woff2 → KaTeX_Size3-Regular.1n1rgzz84z8r9.woff2} +0 -0
  392. /package/out/_next/static/media/{KaTeX_Size3-Regular.0jl8mqyf4gzpn.ttf → KaTeX_Size3-Regular.1pkn-dge4q0fv.ttf} +0 -0
  393. /package/out/_next/static/media/{KaTeX_Size4-Regular.0w3.rb_c4stzk.woff2 → KaTeX_Size4-Regular.2sgotkdv3dcyv.woff2} +0 -0
  394. /package/out/_next/static/media/{KaTeX_Size4-Regular.0wr_9l81-mu06.ttf → KaTeX_Size4-Regular.2uelkfk2yna5e.ttf} +0 -0
  395. /package/out/_next/static/media/{KaTeX_Size4-Regular.12tvaesf3.zl3.woff → KaTeX_Size4-Regular.3p2r1l7xmebxv.woff} +0 -0
  396. /package/out/_next/static/media/{KaTeX_Typewriter-Regular.0c4zdxz~8frhm.woff2 → KaTeX_Typewriter-Regular.11gr2d2wuwz77.woff2} +0 -0
  397. /package/out/_next/static/media/{KaTeX_Typewriter-Regular.0cgrzn5l3kao5.woff → KaTeX_Typewriter-Regular.12f8myjij3617.woff} +0 -0
  398. /package/out/_next/static/media/{KaTeX_Typewriter-Regular.128~qc3858otl.ttf → KaTeX_Typewriter-Regular.3nee9kjfy6nm8.ttf} +0 -0
  399. /package/out/{pwa-512x512.png → avatar.png} +0 -0
  400. /package/public/{pwa-512x512.png → avatar.png} +0 -0
@@ -48,7 +48,6 @@ import {
48
48
  SWARM_KEEP_ALIVE_INTERVAL,
49
49
  SWARM_RANDOM_PUNCH_INTERVAL,
50
50
  DRIVE_ENTRY_TIMEOUT,
51
- DRIVE_SYNC_TIMEOUT,
52
51
  STREAM_READ_TIMEOUT,
53
52
  FILE_WRITE_CHUNK_SIZE,
54
53
  DOWNLOAD_POLL_INTERVAL_MIN,
@@ -67,12 +66,39 @@ import {
67
66
  } from './config.js'
68
67
 
69
68
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
69
+ const CHAT_FILE_ROOT = 'chat-file'
70
70
 
71
71
  function normalizeOwnerAddress(address) {
72
72
  const value = String(address || '').trim()
73
73
  return /^0x[a-fA-F0-9]{40}$/.test(value) ? value.toLowerCase() : ''
74
74
  }
75
75
 
76
+ function getPathBaseName(fileName) {
77
+ const parts = String(fileName || '').split('/').filter(Boolean)
78
+ return parts[parts.length - 1] || 'unnamed_file'
79
+ }
80
+
81
+ function getDisplayPathFolder(fileName) {
82
+ const parts = String(fileName || '').split('/').filter(Boolean)
83
+ parts.pop()
84
+ return parts.join('/')
85
+ }
86
+
87
+ function buildMostLink(cid, fileName) {
88
+ return `most://${cid}?filename=${encodeURIComponent(fileName)}`
89
+ }
90
+
91
+ function normalizeChannelDisplayName(input, fallbackAddress = '') {
92
+ const value = String(input || '').trim()
93
+ if (value) return value.slice(0, 50)
94
+ return fallbackAddress ? fallbackAddress.slice(0, 10) : ''
95
+ }
96
+
97
+ function normalizeChannelAvatar(input) {
98
+ const value = String(input || '').trim()
99
+ return value ? value.slice(0, 4096) : ''
100
+ }
101
+
76
102
  function createOfflineSwarm() {
77
103
  return {
78
104
  connections: new Set(),
@@ -528,6 +554,10 @@ export class MostBoxEngine extends EventEmitter {
528
554
  }
529
555
  }
530
556
 
557
+ this.#assertDisplayNameAvailable(safeFileName, {
558
+ ownerAddress,
559
+ })
560
+
531
561
  // 获取或创建该 CID 对应的 drive
532
562
  let drive = this.#drives.get(name)
533
563
 
@@ -644,39 +674,48 @@ export class MostBoxEngine extends EventEmitter {
644
674
  const cidString = parsed.cid
645
675
  console.log(`[MostBox] Parsed CID: ${cidString}`)
646
676
  const { driveName: name } = this.#getCidInfo(cidString)
677
+ const linkFileName = sanitizeFilename(parsed.fileName)
647
678
 
648
- const existingFile = this.#publishedFiles.find(
649
- f => f.cid === cidString && this.#recordMatchesOwner(f, ownerAddress)
650
- )
651
- if (existingFile) {
652
- console.log(`[MostBox] File already exists: ${existingFile.fileName}`)
679
+ const localContent = await this.#getLocalCidContent(cidString, {
680
+ ownerAddress,
681
+ public: true,
682
+ allowHoldingFallback: true,
683
+ })
684
+ if (localContent) {
685
+ const existingFile = localContent.fileRecord
686
+ console.log(
687
+ `[MostBox] CID content already exists locally: ${cidString}`
688
+ )
653
689
  const existingHolding = this.#holdings.find(
654
690
  item => item.cid === cidString
655
691
  )
656
- const existingSize = Number(existingFile.size)
657
692
  await this.#joinCidTopicInternal(cidString, {
658
693
  server: true,
659
694
  client: false,
660
695
  })
661
696
  this.#upsertHolding({
662
697
  cid: cidString,
663
- fileName: existingFile.fileName,
698
+ fileName:
699
+ existingHolding?.fileName || existingFile?.fileName || linkFileName,
664
700
  size:
665
701
  existingHolding?.size ??
666
- (Number.isFinite(existingSize) ? existingSize : 0),
702
+ (Number.isFinite(localContent.size) ? localContent.size : 0),
667
703
  localPath:
668
- existingHolding?.localPath || existingFile.localPath || null,
669
- driveName: existingFile.driveName || name,
704
+ existingHolding?.localPath || existingFile?.localPath || null,
705
+ driveName: existingFile?.driveName || name,
670
706
  source: existingHolding?.source || 'published',
671
707
  })
672
708
  return {
673
709
  taskId,
674
- fileName: existingFile.fileName,
710
+ fileName: linkFileName,
675
711
  alreadyExists: true,
676
712
  }
677
713
  }
678
714
 
679
- const linkFileName = parsed.fileName
715
+ this.#assertDisplayNameAvailable(linkFileName, {
716
+ ownerAddress,
717
+ excludeCid: cidString,
718
+ })
680
719
 
681
720
  if (taskState.aborted) throw new Error('Download cancelled')
682
721
 
@@ -924,11 +963,14 @@ export class MostBoxEngine extends EventEmitter {
924
963
  const existingIndex = this.#publishedFiles.findIndex(
925
964
  f => f.cid === cidString && this.#recordMatchesOwner(f, ownerAddress)
926
965
  )
966
+ this.#assertDisplayNameAvailable(sanitizedFileName, {
967
+ ownerAddress,
968
+ excludeCid: cidString,
969
+ })
927
970
  if (existingIndex !== -1) {
928
971
  const existing = this.#publishedFiles[existingIndex]
929
- if (existing.fileName !== sanitizedFileName) {
930
- throw new Error(`文件已存在: ${existing.fileName}`)
931
- }
972
+ existing.fileName = sanitizedFileName
973
+ existing.driveName = name
932
974
  existing.publishedAt = new Date().toISOString()
933
975
  } else {
934
976
  this.#publishedFiles.push({
@@ -959,6 +1001,35 @@ export class MostBoxEngine extends EventEmitter {
959
1001
  }
960
1002
  }
961
1003
 
1004
+ /**
1005
+ * 快速检查 most:// 链接对应的 CID 内容是否已在本机可读。
1006
+ */
1007
+ async getLocalCidAvailability(link, options = {}) {
1008
+ this.#ensureInitialized()
1009
+ const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1010
+ const parsed = parseMostLink(link)
1011
+ if (parsed.error) {
1012
+ throw new ValidationError(parsed.error)
1013
+ }
1014
+
1015
+ const localContent = await this.#getLocalCidContent(parsed.cid, {
1016
+ ownerAddress,
1017
+ public: true,
1018
+ allowHoldingFallback: true,
1019
+ })
1020
+ if (!localContent) {
1021
+ return null
1022
+ }
1023
+
1024
+ return {
1025
+ available: true,
1026
+ cid: parsed.cid,
1027
+ fileName: sanitizeFilename(parsed.fileName),
1028
+ size: localContent.size,
1029
+ alreadyExists: true,
1030
+ }
1031
+ }
1032
+
962
1033
  /**
963
1034
  * 检测 most:// 链接当前是否能找到可下载内容,但不读取文件内容。
964
1035
  * @param {string} link - most:// 链接
@@ -978,15 +1049,17 @@ export class MostBoxEngine extends EventEmitter {
978
1049
 
979
1050
  const cidString = parsed.cid
980
1051
  const { driveName: name } = this.#getCidInfo(cidString)
981
- const existingFile = this.#publishedFiles.find(
982
- f => f.cid === cidString && this.#recordMatchesOwner(f, ownerAddress)
983
- )
984
- if (existingFile) {
1052
+ const localContent = await this.#getLocalCidContent(cidString, {
1053
+ ownerAddress,
1054
+ public: true,
1055
+ allowHoldingFallback: true,
1056
+ })
1057
+ if (localContent) {
985
1058
  return {
986
1059
  available: true,
987
1060
  cid: cidString,
988
- fileName: existingFile.fileName,
989
- size: Number(existingFile.size) || null,
1061
+ fileName: sanitizeFilename(parsed.fileName),
1062
+ size: localContent.size,
990
1063
  alreadyExists: true,
991
1064
  }
992
1065
  }
@@ -1172,6 +1245,20 @@ export class MostBoxEngine extends EventEmitter {
1172
1245
 
1173
1246
  const { driveName } = this.#getCidInfo(fileRecord.cid)
1174
1247
 
1248
+ const existingIndex = this.#publishedFiles.findIndex(
1249
+ f => f.cid === fileRecord.cid && this.#recordMatchesOwner(f, ownerAddress)
1250
+ )
1251
+ if (existingIndex !== -1) {
1252
+ this.#trashFiles.splice(index, 1)
1253
+ this.#saveTrashMetadata()
1254
+ return this.listPublishedFiles({ ownerAddress })
1255
+ }
1256
+
1257
+ this.#assertDisplayNameAvailable(fileRecord.fileName, {
1258
+ ownerAddress,
1259
+ excludeCid: fileRecord.cid,
1260
+ })
1261
+
1175
1262
  this.#publishedFiles.push({
1176
1263
  fileName: fileRecord.fileName,
1177
1264
  cid: fileRecord.cid,
@@ -1361,6 +1448,10 @@ export class MostBoxEngine extends EventEmitter {
1361
1448
  throw new Error('File not found')
1362
1449
  }
1363
1450
  const safeFileName = sanitizeFilename(newFileName)
1451
+ this.#assertDisplayNameAvailable(safeFileName, {
1452
+ ownerAddress,
1453
+ excludeCid: cid,
1454
+ })
1364
1455
  this.#publishedFiles[index].fileName = safeFileName
1365
1456
  this.#publishedFiles[index].publishedAt = new Date().toISOString()
1366
1457
  this.#savePublishedMetadata()
@@ -1382,7 +1473,7 @@ export class MostBoxEngine extends EventEmitter {
1382
1473
  this.#ensureInitialized()
1383
1474
  const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1384
1475
  const prefix = oldPath + '/'
1385
- const updatedFiles = []
1476
+ const updates = []
1386
1477
 
1387
1478
  for (const file of this.#publishedFiles) {
1388
1479
  if (
@@ -1393,16 +1484,27 @@ export class MostBoxEngine extends EventEmitter {
1393
1484
  const newFileName = sanitizeFilename(
1394
1485
  remainder ? newPath + '/' + remainder : newPath
1395
1486
  )
1396
- file.fileName = newFileName
1397
- file.publishedAt = new Date().toISOString()
1398
- updatedFiles.push({
1399
- cid: file.cid,
1400
- fileName: file.fileName,
1401
- link: `most://${file.cid}?filename=${encodeURIComponent(file.fileName)}`,
1402
- })
1487
+ updates.push({ file, newFileName })
1403
1488
  }
1404
1489
  }
1405
1490
 
1491
+ for (const { file, newFileName } of updates) {
1492
+ this.#assertDisplayNameAvailable(newFileName, {
1493
+ ownerAddress,
1494
+ excludeCid: file.cid,
1495
+ })
1496
+ }
1497
+
1498
+ const updatedFiles = updates.map(({ file, newFileName }) => {
1499
+ file.fileName = newFileName
1500
+ file.publishedAt = new Date().toISOString()
1501
+ return {
1502
+ cid: file.cid,
1503
+ fileName: file.fileName,
1504
+ link: `most://${file.cid}?filename=${encodeURIComponent(file.fileName)}`,
1505
+ }
1506
+ })
1507
+
1406
1508
  if (updatedFiles.length > 0) {
1407
1509
  this.#savePublishedMetadata()
1408
1510
  }
@@ -1517,7 +1619,7 @@ export class MostBoxEngine extends EventEmitter {
1517
1619
  ...channel,
1518
1620
  members: Array.isArray(channel.members)
1519
1621
  ? channel.members.filter(
1520
- member => normalizeOwnerAddress(member) !== ownerAddress
1622
+ member => normalizeOwnerAddress(member?.address) !== ownerAddress
1521
1623
  )
1522
1624
  : [],
1523
1625
  }))
@@ -1678,28 +1780,23 @@ export class MostBoxEngine extends EventEmitter {
1678
1780
  options = {}
1679
1781
  ) {
1680
1782
  this.#ensureInitialized()
1783
+ if (typeof offset === 'object' && offset !== null) {
1784
+ options = offset
1785
+ offset = 0
1786
+ limit = DEFAULT_READ_LIMIT
1787
+ }
1681
1788
  const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1682
1789
 
1683
- const fileRecord = this.#publishedFiles.find(
1684
- f =>
1685
- f.cid === cid &&
1686
- (options.public || this.#recordMatchesOwner(f, ownerAddress))
1687
- )
1688
- if (!fileRecord) {
1790
+ const localContent = await this.#getLocalCidContent(cid, {
1791
+ ownerAddress,
1792
+ public: options.public,
1793
+ })
1794
+ if (!localContent) {
1689
1795
  throw new Error('File not found')
1690
1796
  }
1691
1797
 
1692
- const drive = await this.#getDriveForFile(fileRecord)
1693
-
1694
- // Hyperdrive 中 key 为 '/' + cid
1695
1798
  const driveKey = '/' + cid
1696
- const entry = await drive.entry(driveKey, {
1697
- wait: true,
1698
- timeout: DRIVE_ENTRY_TIMEOUT,
1699
- })
1700
- if (!entry || !entry.value) {
1701
- throw new Error('File content not available')
1702
- }
1799
+ const { drive } = localContent
1703
1800
 
1704
1801
  const chunks = []
1705
1802
  const stream = drive.createReadStream(driveKey, {
@@ -1743,25 +1840,16 @@ export class MostBoxEngine extends EventEmitter {
1743
1840
  this.#ensureInitialized()
1744
1841
  const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1745
1842
 
1746
- const fileRecord = this.#publishedFiles.find(
1747
- f =>
1748
- f.cid === cid &&
1749
- (options.public || this.#recordMatchesOwner(f, ownerAddress))
1750
- )
1751
- if (!fileRecord) {
1843
+ const localContent = await this.#getLocalCidContent(cid, {
1844
+ ownerAddress,
1845
+ public: options.public,
1846
+ })
1847
+ if (!localContent) {
1752
1848
  throw new Error('File not found')
1753
1849
  }
1754
1850
 
1755
- const drive = await this.#getDriveForFile(fileRecord)
1756
-
1757
1851
  const driveKey = '/' + cid
1758
- const entry = await drive.entry(driveKey, {
1759
- wait: true,
1760
- timeout: DRIVE_ENTRY_TIMEOUT,
1761
- })
1762
- if (!entry || !entry.value || !entry.value.blob) {
1763
- throw new Error('File content not available')
1764
- }
1852
+ const { drive, entry, fileRecord } = localContent
1765
1853
 
1766
1854
  const totalSize = entry.value.blob.byteLength || 0
1767
1855
 
@@ -1808,19 +1896,63 @@ export class MostBoxEngine extends EventEmitter {
1808
1896
  return { buffer, fileName: fileRecord.fileName, totalSize }
1809
1897
  }
1810
1898
 
1811
- /**
1812
- * 获取文件对应的 drive,如果不存在则创建并同步
1813
- */
1814
- async #getDriveForFile(fileRecord) {
1815
- let drive = this.#drives.get(fileRecord.driveName)
1816
- if (!drive) {
1817
- drive = await this.#getOrCreateDrive(fileRecord.driveName, {
1818
- server: true,
1819
- client: true,
1820
- })
1899
+ async #hasLocalDriveContent(drive, key) {
1900
+ try {
1901
+ return await drive.has(key)
1902
+ } catch {
1903
+ return false
1904
+ }
1905
+ }
1906
+
1907
+ async #getLocalCidContent(cid, options = {}) {
1908
+ const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1909
+ const fileRecord = this.#publishedFiles.find(
1910
+ f =>
1911
+ f.cid === cid &&
1912
+ (options.public || this.#recordMatchesOwner(f, ownerAddress))
1913
+ )
1914
+ if (!options.allowHoldingFallback && !fileRecord) {
1915
+ return null
1916
+ }
1917
+ const holding = this.#holdings.find(item => item.cid === cid)
1918
+ const { driveName } = this.#getCidInfo(cid)
1919
+ const drive = await this.#getOrCreateDrive(
1920
+ fileRecord?.driveName || holding?.driveName || driveName,
1921
+ { server: true, client: false }
1922
+ )
1923
+ const driveKey = '/' + cid
1924
+
1925
+ try {
1926
+ const entry = await drive.entry(driveKey, { wait: false })
1927
+ if (!entry?.value?.blob) {
1928
+ return null
1929
+ }
1930
+ const hasContent = await this.#hasLocalDriveContent(drive, driveKey)
1931
+ if (!hasContent) {
1932
+ return null
1933
+ }
1934
+
1935
+ const size =
1936
+ Number(entry.value.blob.byteLength) ||
1937
+ Number(fileRecord?.size) ||
1938
+ Number(holding?.size) ||
1939
+ 0
1940
+ return {
1941
+ drive,
1942
+ entry,
1943
+ size,
1944
+ fileRecord: fileRecord || {
1945
+ cid,
1946
+ fileName: holding?.fileName || cid,
1947
+ driveName: holding?.driveName || driveName,
1948
+ localPath: holding?.localPath || null,
1949
+ size,
1950
+ ownerAddress,
1951
+ },
1952
+ }
1953
+ } catch {
1954
+ return null
1821
1955
  }
1822
- await this.#syncDrive(drive)
1823
- return drive
1824
1956
  }
1825
1957
 
1826
1958
  // --- 频道管理 ---
@@ -1848,14 +1980,16 @@ export class MostBoxEngine extends EventEmitter {
1848
1980
 
1849
1981
  const existing = this.#channels.find(c => c.name === name)
1850
1982
  if (existing) {
1851
- if (ownerAddress && !Array.isArray(existing.members)) {
1852
- existing.members = []
1853
- }
1854
- if (ownerAddress && !existing.members.includes(ownerAddress)) {
1855
- existing.members.push(ownerAddress)
1983
+ if (this.#upsertChannelMember(existing, options)) {
1856
1984
  this.#saveChannelsMetadata()
1857
1985
  }
1858
- return { name: existing.name, key: existing.coreKey }
1986
+ return {
1987
+ name: existing.name,
1988
+ key: existing.coreKey,
1989
+ coreKey: existing.coreKey,
1990
+ createdAt: existing.createdAt,
1991
+ type: existing.type,
1992
+ }
1859
1993
  }
1860
1994
 
1861
1995
  const ns = this.#store.namespace(`channel-${name}`)
@@ -1882,9 +2016,10 @@ export class MostBoxEngine extends EventEmitter {
1882
2016
  createdAt: new Date().toISOString(),
1883
2017
  type: channelType,
1884
2018
  ownerAddress,
1885
- members: ownerAddress ? [ownerAddress] : [],
2019
+ members: [],
1886
2020
  remoteCoreKeys: [],
1887
2021
  }
2022
+ this.#upsertChannelMember(channelInfo, options)
1888
2023
 
1889
2024
  this.#channels.push(channelInfo)
1890
2025
  const coreKeyHex = b4a.toString(core.key, 'hex')
@@ -1901,7 +2036,13 @@ export class MostBoxEngine extends EventEmitter {
1901
2036
  console.log(`[MostBox] Channel created: ${name}`)
1902
2037
  this.emit('channel:joined', { name, key: channelInfo.coreKey })
1903
2038
 
1904
- return { name, key: channelInfo.coreKey }
2039
+ return {
2040
+ name,
2041
+ key: channelInfo.coreKey,
2042
+ coreKey: channelInfo.coreKey,
2043
+ createdAt: channelInfo.createdAt,
2044
+ type: channelInfo.type,
2045
+ }
1905
2046
  }
1906
2047
 
1907
2048
  /**
@@ -1916,11 +2057,7 @@ export class MostBoxEngine extends EventEmitter {
1916
2057
 
1917
2058
  const existing = this.#channels.find(c => c.name === name)
1918
2059
  if (existing) {
1919
- if (ownerAddress && !Array.isArray(existing.members)) {
1920
- existing.members = []
1921
- }
1922
- if (ownerAddress && !existing.members.includes(ownerAddress)) {
1923
- existing.members.push(ownerAddress)
2060
+ if (this.#upsertChannelMember(existing, options)) {
1924
2061
  this.#saveChannelsMetadata()
1925
2062
  }
1926
2063
  if (coreKey && coreKey !== existing.coreKey) {
@@ -1933,7 +2070,13 @@ export class MostBoxEngine extends EventEmitter {
1933
2070
  }
1934
2071
  await this.#openRemoteChannelCore(name, coreKey)
1935
2072
  }
1936
- return { name: existing.name, key: existing.coreKey }
2073
+ return {
2074
+ name: existing.name,
2075
+ key: existing.coreKey,
2076
+ coreKey: existing.coreKey,
2077
+ createdAt: existing.createdAt,
2078
+ type: existing.type,
2079
+ }
1937
2080
  }
1938
2081
 
1939
2082
  if (!coreKey) {
@@ -1969,10 +2112,11 @@ export class MostBoxEngine extends EventEmitter {
1969
2112
  createdAt: new Date().toISOString(),
1970
2113
  type: 'group',
1971
2114
  ownerAddress,
1972
- members: ownerAddress ? [ownerAddress] : [],
2115
+ members: [],
1973
2116
  remoteCoreKeys:
1974
2117
  remoteCoreKeyHex === localCoreKeyHex ? [] : [remoteCoreKeyHex],
1975
2118
  }
2119
+ this.#upsertChannelMember(channelInfo, options)
1976
2120
 
1977
2121
  this.#channels.push(channelInfo)
1978
2122
  if (!this.#channelCores.has(name)) {
@@ -1991,7 +2135,13 @@ export class MostBoxEngine extends EventEmitter {
1991
2135
  console.log(`[MostBox] Joined channel: ${name}`)
1992
2136
  this.emit('channel:joined', { name, key: localCoreKeyHex })
1993
2137
 
1994
- return { name, key: localCoreKeyHex }
2138
+ return {
2139
+ name,
2140
+ key: localCoreKeyHex,
2141
+ coreKey: localCoreKeyHex,
2142
+ createdAt: channelInfo.createdAt,
2143
+ type: channelInfo.type,
2144
+ }
1995
2145
  }
1996
2146
 
1997
2147
  /**
@@ -2011,7 +2161,7 @@ export class MostBoxEngine extends EventEmitter {
2011
2161
  const channel = this.#channels[index]
2012
2162
  if (ownerAddress && Array.isArray(channel.members)) {
2013
2163
  channel.members = channel.members.filter(
2014
- member => normalizeOwnerAddress(member) !== ownerAddress
2164
+ member => normalizeOwnerAddress(member?.address) !== ownerAddress
2015
2165
  )
2016
2166
  if (channel.members.length > 0) {
2017
2167
  this.#saveChannelsMetadata()
@@ -2112,7 +2262,7 @@ export class MostBoxEngine extends EventEmitter {
2112
2262
  return this.#channels
2113
2263
  .filter(c => {
2114
2264
  if (!ownerAddress) return true
2115
- return Array.isArray(c.members) && c.members.includes(ownerAddress)
2265
+ return this.#channelHasMember(c, ownerAddress)
2116
2266
  })
2117
2267
  .filter(c => {
2118
2268
  if (type) return c.type === type
@@ -2129,6 +2279,18 @@ export class MostBoxEngine extends EventEmitter {
2129
2279
  }))
2130
2280
  }
2131
2281
 
2282
+ getChannelMembers(name, options = {}) {
2283
+ this.#ensureInitialized()
2284
+ this.#assertChannelMember(name, options.ownerAddress)
2285
+
2286
+ const channel = this.#channels.find(c => c.name === name)
2287
+ if (!channel) {
2288
+ throw new Error('频道不存在')
2289
+ }
2290
+
2291
+ return this.#getChannelMembers(channel)
2292
+ }
2293
+
2132
2294
  /**
2133
2295
  * 获取频道消息
2134
2296
  * @param {string} name - 频道名
@@ -2180,7 +2342,11 @@ export class MostBoxEngine extends EventEmitter {
2180
2342
  const start = Math.max(0, total - offset - limit)
2181
2343
  const end = total - offset
2182
2344
 
2183
- return unique.slice(start, end).map(({ _coreKey, _index, ...msg }) => msg)
2345
+ return unique
2346
+ .slice(start, end)
2347
+ .map(({ _coreKey, _index, ...msg }) =>
2348
+ this.#normalizeChannelMessageForResponse(name, msg)
2349
+ )
2184
2350
  }
2185
2351
 
2186
2352
  /**
@@ -2195,6 +2361,7 @@ export class MostBoxEngine extends EventEmitter {
2195
2361
  async sendMessage(name, content, author, authorName, options = {}) {
2196
2362
  this.#ensureInitialized()
2197
2363
  this.#assertChannelMember(name, options.ownerAddress)
2364
+ const channel = this.#channels.find(c => c.name === name)
2198
2365
 
2199
2366
  const localKeyHex = this.#channelLocalCoreKey.get(name)
2200
2367
  const coresMap = this.#channelCores.get(name)
@@ -2215,6 +2382,16 @@ export class MostBoxEngine extends EventEmitter {
2215
2382
  if (attachment && trimmed !== attachment.link) {
2216
2383
  throw new ValidationError('attachment content must match link')
2217
2384
  }
2385
+ if (
2386
+ channel &&
2387
+ this.#upsertChannelMember(channel, {
2388
+ ownerAddress: options.ownerAddress,
2389
+ displayName: authorName,
2390
+ avatar: options.avatar,
2391
+ })
2392
+ ) {
2393
+ this.#saveChannelsMetadata()
2394
+ }
2218
2395
 
2219
2396
  const message = {
2220
2397
  type: 'message',
@@ -2304,11 +2481,125 @@ export class MostBoxEngine extends EventEmitter {
2304
2481
  if (!channel) {
2305
2482
  throw new Error('频道不存在')
2306
2483
  }
2484
+ if (!this.#channelHasMember(channel, normalizedOwner)) {
2485
+ throw new PermissionError('未加入该频道')
2486
+ }
2487
+ }
2488
+
2489
+ #channelHasMember(channel, ownerAddress) {
2490
+ const normalizedOwner = normalizeOwnerAddress(ownerAddress)
2491
+ if (!normalizedOwner || !Array.isArray(channel?.members)) return false
2492
+ return channel.members.some(
2493
+ member => normalizeOwnerAddress(member?.address) === normalizedOwner
2494
+ )
2495
+ }
2496
+
2497
+ #upsertChannelMember(channel, options = {}) {
2498
+ const address = normalizeOwnerAddress(options.ownerAddress)
2499
+ if (!address) return false
2500
+
2501
+ if (!Array.isArray(channel.members)) {
2502
+ channel.members = []
2503
+ }
2504
+
2505
+ const displayName = normalizeChannelDisplayName(options.displayName, address)
2506
+ const avatar = normalizeChannelAvatar(options.avatar)
2507
+ const existing = channel.members.find(
2508
+ member => normalizeOwnerAddress(member?.address) === address
2509
+ )
2510
+
2511
+ if (existing) {
2512
+ let changed = false
2513
+ if (existing.address !== address) {
2514
+ existing.address = address
2515
+ changed = true
2516
+ }
2517
+ if (displayName && existing.displayName !== displayName) {
2518
+ existing.displayName = displayName
2519
+ changed = true
2520
+ }
2521
+ if (avatar && existing.avatar !== avatar) {
2522
+ existing.avatar = avatar
2523
+ changed = true
2524
+ }
2525
+ if (!existing.joinedAt) {
2526
+ existing.joinedAt = new Date().toISOString()
2527
+ changed = true
2528
+ }
2529
+ return changed
2530
+ }
2531
+
2532
+ const member = {
2533
+ address,
2534
+ displayName,
2535
+ joinedAt: new Date().toISOString(),
2536
+ }
2537
+ if (avatar) {
2538
+ member.avatar = avatar
2539
+ }
2540
+ channel.members.push(member)
2541
+ return true
2542
+ }
2543
+
2544
+ #getChannelMembers(channel) {
2545
+ const members = Array.isArray(channel?.members) ? channel.members : []
2546
+ return members
2547
+ .map((member, index) => ({
2548
+ address: normalizeOwnerAddress(member?.address),
2549
+ displayName: normalizeChannelDisplayName(
2550
+ member?.displayName,
2551
+ normalizeOwnerAddress(member?.address)
2552
+ ),
2553
+ avatar: normalizeChannelAvatar(member?.avatar),
2554
+ joinedAt: String(member?.joinedAt || ''),
2555
+ _index: index,
2556
+ }))
2557
+ .filter(member => member.address && member.joinedAt)
2558
+ .sort((a, b) => {
2559
+ const timeDiff =
2560
+ new Date(a.joinedAt).getTime() - new Date(b.joinedAt).getTime()
2561
+ return timeDiff || a._index - b._index
2562
+ })
2563
+ .map(({ _index, ...member }) =>
2564
+ member.avatar ? member : { ...member, avatar: undefined }
2565
+ )
2566
+ }
2567
+
2568
+ #normalizeChannelMessageForResponse(channelName, message) {
2569
+ const attachment = message?.attachment
2570
+ if (!attachment?.cid || !attachment.fileName) {
2571
+ return message
2572
+ }
2573
+
2574
+ const oldFileName = sanitizeFilename(String(attachment.fileName))
2575
+ const channelPrefix = `${CHAT_FILE_ROOT}/${channelName}/`
2576
+ const fileName = oldFileName.startsWith(channelPrefix)
2577
+ ? oldFileName
2578
+ : `${channelPrefix}${getPathBaseName(oldFileName)}`
2579
+ const link = buildMostLink(attachment.cid, fileName)
2580
+ const content =
2581
+ typeof message.content === 'string' &&
2582
+ (message.content === attachment.link ||
2583
+ parseMostLink(message.content).cid === attachment.cid)
2584
+ ? link
2585
+ : message.content
2586
+
2307
2587
  if (
2308
- !Array.isArray(channel.members) ||
2309
- !channel.members.includes(normalizedOwner)
2588
+ fileName === attachment.fileName &&
2589
+ link === attachment.link &&
2590
+ content === message.content
2310
2591
  ) {
2311
- throw new PermissionError('未加入该频道')
2592
+ return message
2593
+ }
2594
+
2595
+ return {
2596
+ ...message,
2597
+ content,
2598
+ attachment: {
2599
+ ...attachment,
2600
+ fileName,
2601
+ link,
2602
+ },
2312
2603
  }
2313
2604
  }
2314
2605
 
@@ -2504,7 +2795,7 @@ export class MostBoxEngine extends EventEmitter {
2504
2795
  size,
2505
2796
  localPath: record.localPath || null,
2506
2797
  topic: topicHex,
2507
- driveName: record.driveName || driveName,
2798
+ driveName,
2508
2799
  source: record.source || 'manual',
2509
2800
  }
2510
2801
  }
@@ -2692,6 +2983,31 @@ export class MostBoxEngine extends EventEmitter {
2692
2983
  return normalizeOwnerAddress(record.ownerAddress) === normalizedOwner
2693
2984
  }
2694
2985
 
2986
+ #assertDisplayNameAvailable(fileName, options = {}) {
2987
+ const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
2988
+ const safeFileName = sanitizeFilename(fileName)
2989
+ const folder = getDisplayPathFolder(safeFileName)
2990
+ const baseName = getPathBaseName(safeFileName)
2991
+ const conflict = this.#publishedFiles.find(file => {
2992
+ if (
2993
+ options.excludeCid &&
2994
+ file.cid === options.excludeCid &&
2995
+ this.#recordMatchesOwner(file, ownerAddress)
2996
+ ) {
2997
+ return false
2998
+ }
2999
+ if (!this.#recordMatchesOwner(file, ownerAddress)) return false
3000
+ const existingFileName = sanitizeFilename(file.fileName)
3001
+ return (
3002
+ getDisplayPathFolder(existingFileName) === folder &&
3003
+ getPathBaseName(existingFileName) === baseName
3004
+ )
3005
+ })
3006
+ if (conflict) {
3007
+ throw new ConflictError(`已有同名文件: ${safeFileName}`)
3008
+ }
3009
+ }
3010
+
2695
3011
  #hasPublishedReference(cid) {
2696
3012
  return this.#publishedFiles.some(file => file.cid === cid)
2697
3013
  }
@@ -2740,20 +3056,6 @@ export class MostBoxEngine extends EventEmitter {
2740
3056
  }
2741
3057
  }
2742
3058
 
2743
- async #syncDrive(drive, timeout = DRIVE_SYNC_TIMEOUT) {
2744
- try {
2745
- const updated = await Promise.race([
2746
- drive.update(),
2747
- new Promise((_, reject) =>
2748
- setTimeout(() => reject(new Error('Sync timeout')), timeout)
2749
- ),
2750
- ])
2751
- return updated
2752
- } catch {
2753
- return false
2754
- }
2755
- }
2756
-
2757
3059
  #getMetadataPath() {
2758
3060
  return path.join(this.#options.dataPath, 'published-files.json')
2759
3061
  }
@@ -2911,7 +3213,10 @@ export class MostBoxEngine extends EventEmitter {
2911
3213
  if (entry && entry.type === 'message') {
2912
3214
  this.emit('channel:message', {
2913
3215
  channel: channelName,
2914
- message: entry,
3216
+ message: this.#normalizeChannelMessageForResponse(
3217
+ channelName,
3218
+ entry
3219
+ ),
2915
3220
  })
2916
3221
  }
2917
3222
  } catch (err) {