most-box 0.3.1 → 0.3.3

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 (171) hide show
  1. package/README.md +15 -14
  2. package/electron/main.js +1 -1
  3. package/out/admin/index.html +0 -0
  4. package/out/app/index.html +0 -0
  5. package/out/assets/AccountMenu-D36x3rKH.js +1 -0
  6. package/out/assets/AppTop-qtp-3wqv.js +1 -0
  7. package/out/assets/CopyButton-C00LHzxo.js +1 -0
  8. package/out/assets/FilePreviewOverlay-BvOCftIV.js +1 -0
  9. package/out/assets/{MarketingHeader-7B-OT2XX.js → MarketingHeader-D7AjEmWU.js} +1 -1
  10. package/out/assets/MarketingLayout-BVw4vr-u.js +1 -0
  11. package/out/assets/{MilkdownEditor-WedhCoFH.js → MilkdownEditor-DXVbZsH_.js} +92 -92
  12. package/out/assets/OpenSidebarButton-DI6Ld8um.js +1 -0
  13. package/out/assets/arrow-right-CXzRt0Fp.js +1 -0
  14. package/out/assets/arrow-up-down-B-677ip8.js +1 -0
  15. package/out/assets/chatJoinInvite-aCHhLrlm.js +1 -0
  16. package/out/assets/chatNoteDraft-CYbvcEvC.js +1 -0
  17. package/out/assets/check-iBCQl0yr.js +1 -0
  18. package/out/assets/chevron-right-D75NRNNs.js +1 -0
  19. package/out/assets/circle-alert-dfN4T6Nq.js +1 -0
  20. package/out/assets/cobol-DHLQUbN7.js +1 -0
  21. package/out/assets/copy-B7pPZ2MP.js +1 -0
  22. package/out/assets/{dist-DCX0ws1K.js → dist-1jNICPWO.js} +1 -1
  23. package/out/assets/{dist-BAJKKN4w.js → dist-B3unnv5t.js} +1 -1
  24. package/out/assets/{dist-DJdv-Ma3.js → dist-B5MBMmGa.js} +1 -1
  25. package/out/assets/{dist-CMmmtl3f.js → dist-BAqJdUtV.js} +1 -1
  26. package/out/assets/{dist-C3lbe8SW.js → dist-BBJOmVU3.js} +1 -1
  27. package/out/assets/{dist-IN8WN7NI.js → dist-BV5CqsJD.js} +1 -1
  28. package/out/assets/{dist-DBnWo8ZP.js → dist-Ba7fxbV-.js} +1 -1
  29. package/out/assets/{dist-BzqqCPi2.js → dist-BxxtNKuo.js} +1 -1
  30. package/out/assets/{dist-DvWZsW-D.js → dist-C8Ue2rSs.js} +1 -1
  31. package/out/assets/{dist-C-Tg23jc.js → dist-CIn7Xx5U.js} +1 -1
  32. package/out/assets/{dist-CbTzBiwL.js → dist-CSyRxrry.js} +3 -3
  33. package/out/assets/{dist-DTL5jL08.js → dist-CZIuQqmV.js} +1 -1
  34. package/out/assets/{dist-8QDHqrPN.js → dist-CaaBTHCc.js} +1 -1
  35. package/out/assets/{dist-yZ96GF-e.js → dist-CgReC0ZE.js} +1 -1
  36. package/out/assets/{dist-D94V9Zlh.js → dist-Ct90qYA2.js} +1 -1
  37. package/out/assets/{dist-IGpXmkFm.js → dist-DIFFjNuO.js} +1 -1
  38. package/out/assets/{dist-CqQavSZV.js → dist-DUB2IhWu.js} +1 -1
  39. package/out/assets/{dist-B0JrbG7f.js → dist-DheA_Tyz.js} +1 -1
  40. package/out/assets/{dist-Br_5lLVO.js → dist-DyZh1ncm.js} +1 -1
  41. package/out/assets/{dist-BPs0Xns9.js → dist-E74uGTy3.js} +1 -1
  42. package/out/assets/{dist-BFSyuOuw.js → dist-K2s-Uj08.js} +1 -1
  43. package/out/assets/{dist-zyJb88Zz.js → dist-RU_cpjXQ.js} +1 -1
  44. package/out/assets/{dist-chOCTzB2.js → dist-eIeCvp_6.js} +1 -1
  45. package/out/assets/{dist-CfU9fwWz.js → dist-hEE2Ub__.js} +1 -1
  46. package/out/assets/download-COQOcPqI.js +1 -0
  47. package/out/assets/downloadValidation-UPgpJbKz.js +1 -0
  48. package/out/assets/external-link-D6tHlYgS.js +1 -0
  49. package/out/assets/file-text-DiyIGL1I.js +1 -0
  50. package/out/assets/folder-BS_GbpPQ.js +1 -0
  51. package/out/assets/hard-drive-Cqa7Rstj.js +1 -0
  52. package/out/assets/index-CUzbruyP.js +31 -0
  53. package/out/assets/index-FV6RZlVI.css +1 -0
  54. package/out/assets/index.lazy-08bEbzIk.js +1 -0
  55. package/out/assets/index.lazy-6b-8jxXI.js +1 -0
  56. package/out/assets/index.lazy-B4pxVFWK.js +2 -0
  57. package/out/assets/index.lazy-Bi5KZylP.js +5 -0
  58. package/out/assets/index.lazy-CJnFeoy4.js +1 -0
  59. package/out/assets/index.lazy-CRV2-Y6z.js +3 -0
  60. package/out/assets/index.lazy-CzCHV559.js +1 -0
  61. package/out/assets/index.lazy-DrfZ9XTR.js +1 -0
  62. package/out/assets/index.lazy-DuvCRtpm.js +1 -0
  63. package/out/assets/index.lazy-DxOIgf3c.js +1 -0
  64. package/out/assets/index.lazy-FNVWBYth.js +1 -0
  65. package/out/assets/index.lazy-Itk05ouU.js +1 -0
  66. package/out/assets/index.lazy-_CazgyO7.js +1 -0
  67. package/out/assets/index.lazy-odd8ydDw.js +3 -0
  68. package/out/assets/key-round-JR8M3aHl.js +1 -0
  69. package/out/assets/loader-CwyHYZdX.js +1 -0
  70. package/out/assets/lock-CuwwlXlx.js +1 -0
  71. package/out/assets/message-square-BgsNXPft.js +1 -0
  72. package/out/assets/mp-Dv12gDTx.js +1 -0
  73. package/out/assets/music-Dn9nm9Qb.js +1 -0
  74. package/out/assets/notebook-pen-BzrCXQJE.js +1 -0
  75. package/out/assets/play-CvWKSMwY.js +1 -0
  76. package/out/assets/refresh-cw-D4BsHvhi.js +1 -0
  77. package/out/assets/save-B02sbO9Y.js +1 -0
  78. package/out/assets/scheme-tChLYBuY.js +1 -0
  79. package/out/assets/search-HW4oPOBP.js +1 -0
  80. package/out/assets/send-4dhnJGuS.js +1 -0
  81. package/out/assets/shield-check-Boae7Nc6.js +1 -0
  82. package/out/assets/smartphone-JXH-zQXB.js +1 -0
  83. package/out/assets/textile-CyzeGT9J.js +1 -0
  84. package/out/assets/trash-2-BLwoM0ME.js +1 -0
  85. package/out/assets/triangle-alert-B9sMiA9l.js +1 -0
  86. package/out/assets/upload-DVuXJt_o.js +1 -0
  87. package/out/assets/useAppStore-DOnk608w.js +4 -0
  88. package/out/assets/{useChannelMessages-Bs_RWgO4.js → useChannelMessages-CDvw-f_x.js} +1 -1
  89. package/out/assets/useGameRoom-CATo4XWU.js +1 -0
  90. package/out/assets/userProfile-BZvkCuet.js +1 -0
  91. package/out/assets/wallet-D9Iw4YWE.js +1 -0
  92. package/out/assets/wifi-ljEI_ySA.js +1 -0
  93. package/out/chat/index.html +0 -0
  94. package/out/chat/join/demo/index.html +0 -0
  95. package/out/chat/join/index.html +0 -0
  96. package/out/download/index.html +2 -2
  97. package/out/game/gandengyan/index.html +0 -0
  98. package/out/game/index.html +0 -0
  99. package/out/game/zhajinhua/index.html +0 -0
  100. package/out/index.html +2 -2
  101. package/out/note/index.html +0 -0
  102. package/out/ping/index.html +2 -2
  103. package/out/profile/index.html +0 -0
  104. package/out/web3/index.html +0 -0
  105. package/package.json +30 -26
  106. package/server/index.js +3 -0
  107. package/server/src/config.js +0 -1
  108. package/server/src/core/channelAttachment.js +2 -2
  109. package/server/src/core/gameRoom.js +12 -19
  110. package/server/src/http/routes/noteVaultRoutes.js +70 -0
  111. package/server/src/index.js +17 -8
  112. package/server/src/utils/accountBackup.js +8 -0
  113. package/server/src/utils/api.js +0 -14
  114. package/server/src/utils/auth.js +0 -7
  115. package/server/src/utils/avatar.js +6 -6
  116. package/server/src/utils/noteVault.js +197 -2
  117. package/out/assets/AccountMenu-NjOgag0d.js +0 -1
  118. package/out/assets/FilePreviewOverlay-CZp6F1s_.js +0 -1
  119. package/out/assets/MarketingLayout-CyiSCygk.js +0 -1
  120. package/out/assets/OpenSidebarButton-BoSmO8CY.js +0 -1
  121. package/out/assets/SidebarHomeLink-CkhGDvZ8.js +0 -1
  122. package/out/assets/arrow-right-DUxAoZqb.js +0 -1
  123. package/out/assets/avatar-BZwHW4ll.js +0 -4
  124. package/out/assets/circle-alert-DSZ0bG_3.js +0 -1
  125. package/out/assets/cobol-B_OZ4V-R.js +0 -1
  126. package/out/assets/copy-CK7HMulu.js +0 -1
  127. package/out/assets/download-Q1uCiwif.js +0 -1
  128. package/out/assets/downloadValidation-Ch966YTl.js +0 -1
  129. package/out/assets/external-link-DGzNJOqQ.js +0 -1
  130. package/out/assets/file-text-C3v0L_lQ.js +0 -1
  131. package/out/assets/folder-CwtLO09O.js +0 -1
  132. package/out/assets/hard-drive-B2V5USzR.js +0 -1
  133. package/out/assets/i18n-DZaOYCSO.js +0 -1
  134. package/out/assets/index-CBkHUp3F.css +0 -1
  135. package/out/assets/index-DluhgSHX.js +0 -31
  136. package/out/assets/index.lazy-B5TYRvFJ.js +0 -1
  137. package/out/assets/index.lazy-BeDctVci.js +0 -1
  138. package/out/assets/index.lazy-BjmAkVtV.js +0 -1
  139. package/out/assets/index.lazy-CHJbzlK6.js +0 -1
  140. package/out/assets/index.lazy-CITrkWMQ.js +0 -1
  141. package/out/assets/index.lazy-CTGE5fUt.js +0 -2
  142. package/out/assets/index.lazy-CUxcXUMy.js +0 -2
  143. package/out/assets/index.lazy-D84xQtPb.js +0 -3
  144. package/out/assets/index.lazy-DRqAgqpV.js +0 -1
  145. package/out/assets/index.lazy-DSAmY1q_.js +0 -1
  146. package/out/assets/index.lazy-DvbVQRSL.js +0 -1
  147. package/out/assets/index.lazy-gAJi-rJV.js +0 -1
  148. package/out/assets/index.lazy-rzyMd-Gz.js +0 -1
  149. package/out/assets/key-round-Dn5tud-4.js +0 -1
  150. package/out/assets/loader-CLoDCtNy.js +0 -1
  151. package/out/assets/lock-BEWKuIqK.js +0 -1
  152. package/out/assets/message-square-C8ZiYztG.js +0 -1
  153. package/out/assets/mp-CGBtY36n.js +0 -1
  154. package/out/assets/music-BsTA8b_M.js +0 -1
  155. package/out/assets/notebook-pen-DgWzxf2y.js +0 -1
  156. package/out/assets/play-CVkbAJJU.js +0 -1
  157. package/out/assets/plus-D1kCYb8G.js +0 -1
  158. package/out/assets/save-X5c7jlCg.js +0 -1
  159. package/out/assets/scheme-CyDdOh7e.js +0 -1
  160. package/out/assets/search-DAV9vDOq.js +0 -1
  161. package/out/assets/send-C5JjYo-A.js +0 -1
  162. package/out/assets/shield-check-DuD6OLde.js +0 -1
  163. package/out/assets/smartphone-gVFruyjO.js +0 -1
  164. package/out/assets/textile-DWBqthVk.js +0 -1
  165. package/out/assets/trash-2-CE-3Dc63.js +0 -1
  166. package/out/assets/triangle-alert-DnOxsFpB.js +0 -1
  167. package/out/assets/upload-CsnBv3pd.js +0 -1
  168. package/out/assets/useGameRoom-BxDxm3rp.js +0 -1
  169. package/out/assets/userProfile-UphvP_bG.js +0 -1
  170. package/out/assets/wallet-VDaoXwjI.js +0 -1
  171. package/out/assets/wifi-DfWbmlGE.js +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "most-box",
3
- "version": "0.3.1",
4
- "description": "MostBox - P2P file sharing application",
3
+ "version": "0.3.3",
4
+ "description": "MostBox - chat-first P2P toolbox for files, notes, and game rooms",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
7
7
  "bin": {
@@ -30,8 +30,8 @@
30
30
  "typecheck": "tsc -p tsconfig.typecheck.json",
31
31
  "typecheck:strict-router": "tsc -p tsconfig.strict-router.json",
32
32
  "check:static-output": "node scripts/check-static-output.mjs",
33
- "format": "npx prettier --write .",
34
- "lint": "npx eslint .",
33
+ "format": "prettier --write .",
34
+ "lint": "eslint .",
35
35
  "r2:cors": "node scripts/configure-r2-cors.mjs",
36
36
  "electron:dev": "concurrently \"npm run build\" \"wait-on out/index.html && electron .\"",
37
37
  "electron:rebuild": "electron-rebuild -f -w sodium-native",
@@ -44,29 +44,33 @@
44
44
  },
45
45
  "keywords": [
46
46
  "p2p",
47
+ "chat",
47
48
  "file-sharing",
49
+ "file-transfer",
48
50
  "hyperswarm",
51
+ "hypercore",
49
52
  "hyperdrive"
50
53
  ],
51
54
  "license": "MIT",
52
55
  "dependencies": {
53
- "@dicebear/collection": "^9.4.2",
54
- "@dicebear/core": "^9.4.2",
55
- "@hono/node-server": "^2.0.4",
56
- "@tanstack/react-router": "^1.170.15",
57
- "@tanstack/react-start": "^1.168.25",
56
+ "@dicebear/core": "^10.3.0",
57
+ "@dicebear/styles": "^10.2.0",
58
+ "@hono/node-server": "^2.0.6",
59
+ "@tanstack/react-router": "^1.170.16",
60
+ "@tanstack/react-start": "^1.168.26",
61
+ "@tanstack/react-table": "^8.21.3",
58
62
  "b4a": "^1.8.1",
59
63
  "busboy": "^1.6.0",
60
- "corestore": "^7.10.0",
64
+ "corestore": "^7.11.0",
61
65
  "dayjs": "^1.11.21",
62
- "ethers": "^6.16.0",
66
+ "ethers": "^6.17.0",
63
67
  "eventemitter3": "^5.0.4",
64
- "hono": "^4.12.23",
65
- "hypercore": "^11.33.1",
68
+ "hono": "^4.12.27",
69
+ "hypercore": "^11.33.2",
66
70
  "hyperdrive": "^13.3.2",
67
71
  "hyperswarm": "^4.17.0",
68
72
  "ipfs-unixfs-importer": "^17.0.1",
69
- "multiformats": "^14.0.0",
73
+ "multiformats": "^14.0.2",
70
74
  "tweetnacl": "^1.0.3",
71
75
  "ws": "^8.21.0"
72
76
  },
@@ -74,26 +78,26 @@
74
78
  "@electron/rebuild": "^4.0.4",
75
79
  "@eslint/js": "^10.0.1",
76
80
  "@iconify/react": "^6.0.2",
77
- "@mantine/hooks": "^9.3.0",
81
+ "@mantine/hooks": "^9.4.0",
78
82
  "@milkdown/crepe": "^7.21.2",
79
83
  "@milkdown/utils": "^7.21.2",
80
- "@types/react": "^19.2.16",
81
- "@vitejs/plugin-react": "^6.0.2",
84
+ "@types/react": "^19.2.17",
85
+ "@vitejs/plugin-react": "^6.0.3",
82
86
  "concurrently": "^10.0.3",
83
- "electron": "^42.3.3",
84
- "electron-builder": "^26.8.1",
85
- "esbuild": "^0.28.0",
86
- "eslint": "^10.4.1",
87
- "globals": "^17.6.0",
87
+ "electron": "^42.5.0",
88
+ "electron-builder": "^26.15.3",
89
+ "esbuild": "^0.28.1",
90
+ "eslint": "^10.5.0",
91
+ "globals": "^17.7.0",
88
92
  "ky": "^2.0.2",
89
- "lucide-react": "^1.17.0",
90
- "prettier": "^3.8.3",
93
+ "lucide-react": "^1.21.0",
94
+ "prettier": "^3.8.4",
91
95
  "qrcode.react": "^4.2.0",
92
96
  "react": "^19.2.7",
93
97
  "react-dom": "^19.2.7",
94
98
  "typescript": "6.0.3",
95
- "typescript-eslint": "^8.60.1",
96
- "vite": "^8.0.16",
99
+ "typescript-eslint": "^8.62.0",
100
+ "vite": "^8.1.0",
97
101
  "wait-on": "^9.0.10",
98
102
  "zustand": "^5.0.14"
99
103
  },
package/server/index.js CHANGED
@@ -137,6 +137,9 @@ function bindEngineEvents({
137
137
  engine.on('channel:peer:offline', data =>
138
138
  wsBroadcast('channel:peer:offline', data)
139
139
  )
140
+ engine.on('channel:sync:available', data =>
141
+ wsBroadcast('channel:sync:available', data)
142
+ )
140
143
  engine.on('channel:presence', data =>
141
144
  wsSendToChannel(data.channelKey, 'channel:presence', data)
142
145
  )
@@ -17,7 +17,6 @@ export const SWARM_RANDOM_PUNCH_INTERVAL = 20000
17
17
 
18
18
  // 驱动器超时(毫秒)
19
19
  export const DRIVE_ENTRY_TIMEOUT = 10000
20
- export const DRIVE_SYNC_TIMEOUT = 10000
21
20
  export const STREAM_READ_TIMEOUT = 10000
22
21
 
23
22
  // 文件写入块大小(字节)
@@ -1,4 +1,4 @@
1
- import { parseMostLink, validateCidString } from './cid.js'
1
+ import { buildMostLink, parseMostLink, validateCidString } from './cid.js'
2
2
  import { sanitizeFilename } from '../utils/security.js'
3
3
  import { ValidationError } from '../utils/errors.js'
4
4
 
@@ -53,7 +53,7 @@ export function normalizeChannelAttachment(input) {
53
53
  kind,
54
54
  cid,
55
55
  fileName,
56
- link: `most://${cid}?filename=${encodeURIComponent(fileName)}`,
56
+ link: buildMostLink(cid, fileName),
57
57
  }
58
58
 
59
59
  if (typeof input.mimeType === 'string' && input.mimeType.length <= 100) {
@@ -19,7 +19,9 @@ export const GAME_IDS = ['gandengyan', 'zhajinhua']
19
19
  const ROOM_CODE_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
20
20
 
21
21
  export function normalizeGameId(input) {
22
- const value = String(input || '').trim().toLowerCase()
22
+ const value = String(input || '')
23
+ .trim()
24
+ .toLowerCase()
23
25
  return GAME_IDS.includes(value) ? value : ''
24
26
  }
25
27
 
@@ -47,7 +49,9 @@ export function gameRoomCodeToChannelName(gameId, roomCode) {
47
49
  }
48
50
 
49
51
  export function channelNameToGameRoom(input) {
50
- const value = String(input || '').trim().toLowerCase()
52
+ const value = String(input || '')
53
+ .trim()
54
+ .toLowerCase()
51
55
  const match = /^game\.([a-z0-9]+)\.([a-z0-9]+)$/.exec(value)
52
56
  if (!match) return null
53
57
  const gameId = normalizeGameId(match[1])
@@ -86,7 +90,8 @@ export function parseGameEvent(content, options = {}) {
86
90
  const gameId = normalizeGameId(event.gameId)
87
91
  const roomCode = normalizeGameRoomCode(event.roomCode)
88
92
  if (!gameId || !isValidGameRoomCode(roomCode)) return null
89
- if (options.gameId && gameId !== normalizeGameId(options.gameId)) return null
93
+ if (options.gameId && gameId !== normalizeGameId(options.gameId))
94
+ return null
90
95
  if (
91
96
  options.roomCode &&
92
97
  roomCode !== normalizeGameRoomCode(options.roomCode)
@@ -99,9 +104,7 @@ export function parseGameEvent(content, options = {}) {
99
104
  gameId,
100
105
  roomCode,
101
106
  payload:
102
- event.payload && typeof event.payload === 'object'
103
- ? event.payload
104
- : {},
107
+ event.payload && typeof event.payload === 'object' ? event.payload : {},
105
108
  }
106
109
  } catch {
107
110
  return null
@@ -132,7 +135,9 @@ export function deriveGameRoomLobby(messages = [], options = {}) {
132
135
  }
133
136
 
134
137
  if (event.event === 'player:leave') {
135
- const address = normalizeAddress(event.payload?.player?.address || message.author)
138
+ const address = normalizeAddress(
139
+ event.payload?.player?.address || message.author
140
+ )
136
141
  if (address) {
137
142
  const index = players.findIndex(p => p.address === address)
138
143
  if (index !== -1) {
@@ -190,18 +195,6 @@ export function createPlayerFromPayload(input, messageOrAuthor) {
190
195
  return player
191
196
  }
192
197
 
193
- export function normalizeGamePlayer(input) {
194
- if (!input || typeof input !== 'object') return null
195
- const address = normalizeAddress(input.address)
196
- if (!address) return null
197
- return {
198
- ...input,
199
- address,
200
- name: String(input.name || shortAddress(address)).slice(0, 50),
201
- publicKey: String(input.publicKey || ''),
202
- }
203
- }
204
-
205
198
  function upsertPlayer(players, playerMap, player) {
206
199
  const existing = playerMap.get(player.address)
207
200
  if (existing) {
@@ -2,10 +2,15 @@ import { errorJson } from '../errors.js'
2
2
  import { PermissionError } from '../../utils/errors.js'
3
3
  import {
4
4
  configureNoteVault,
5
+ createMarkdownFile,
6
+ createNoteVaultSnapshot,
7
+ deleteMarkdownFile,
5
8
  getConfiguredNoteVaultPath,
6
9
  getNoteVaultStatus,
7
10
  listMarkdownFiles,
11
+ moveMarkdownFile,
8
12
  readMarkdownFile,
13
+ restoreNoteVaultSnapshot,
9
14
  writeMarkdownFile,
10
15
  } from '../../utils/noteVault.js'
11
16
 
@@ -67,6 +72,22 @@ export function registerNoteVaultRoutes(app, { configStore, isRemoteRequest }) {
67
72
  }
68
73
  })
69
74
 
75
+ app.post('/api/note-vault/file', async c => {
76
+ try {
77
+ assertNoteVaultAccess(c, isRemoteRequest)
78
+ const body = await c.req.json()
79
+ const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
80
+ const file = await createMarkdownFile(
81
+ vaultPath,
82
+ String(body.path || ''),
83
+ String(body.content || '')
84
+ )
85
+ return c.json({ success: true, file })
86
+ } catch (err) {
87
+ return errorJson(c, err)
88
+ }
89
+ })
90
+
70
91
  app.put('/api/note-vault/file', async c => {
71
92
  try {
72
93
  assertNoteVaultAccess(c, isRemoteRequest)
@@ -82,4 +103,53 @@ export function registerNoteVaultRoutes(app, { configStore, isRemoteRequest }) {
82
103
  return errorJson(c, err)
83
104
  }
84
105
  })
106
+
107
+ app.patch('/api/note-vault/file', async c => {
108
+ try {
109
+ assertNoteVaultAccess(c, isRemoteRequest)
110
+ const body = await c.req.json()
111
+ const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
112
+ const file = await moveMarkdownFile(
113
+ vaultPath,
114
+ String(body.path || body.fromPath || ''),
115
+ String(body.newPath || body.toPath || '')
116
+ )
117
+ return c.json({ success: true, file })
118
+ } catch (err) {
119
+ return errorJson(c, err)
120
+ }
121
+ })
122
+
123
+ app.delete('/api/note-vault/file', async c => {
124
+ try {
125
+ assertNoteVaultAccess(c, isRemoteRequest)
126
+ const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
127
+ const result = await deleteMarkdownFile(vaultPath, c.req.query('path'))
128
+ return c.json({ success: true, ...result })
129
+ } catch (err) {
130
+ return errorJson(c, err)
131
+ }
132
+ })
133
+
134
+ app.get('/api/note-vault/snapshot', async c => {
135
+ try {
136
+ assertNoteVaultAccess(c, isRemoteRequest)
137
+ const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
138
+ return c.json(await createNoteVaultSnapshot(vaultPath))
139
+ } catch (err) {
140
+ return errorJson(c, err)
141
+ }
142
+ })
143
+
144
+ app.post('/api/note-vault/restore', async c => {
145
+ try {
146
+ assertNoteVaultAccess(c, isRemoteRequest)
147
+ const body = await c.req.json()
148
+ const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
149
+ const result = await restoreNoteVaultSnapshot(vaultPath, body)
150
+ return c.json({ success: true, result })
151
+ } catch (err) {
152
+ return errorJson(c, err)
153
+ }
154
+ })
85
155
  }
@@ -625,7 +625,7 @@ export class MostBoxEngine extends EventEmitter {
625
625
  })
626
626
  return {
627
627
  cid: cidString,
628
- link: `most://${cidString}?filename=${encodeURIComponent(existing.fileName)}`,
628
+ link: buildMostLink(cidString, existing.fileName),
629
629
  fileName: existing.fileName,
630
630
  alreadyExists: true,
631
631
  }
@@ -713,7 +713,7 @@ export class MostBoxEngine extends EventEmitter {
713
713
 
714
714
  const result = {
715
715
  cid: cidString,
716
- link: `most://${cidString}?filename=${encodeURIComponent(safeFileName)}`,
716
+ link: buildMostLink(cidString, safeFileName),
717
717
  fileName: safeFileName,
718
718
  }
719
719
 
@@ -1226,7 +1226,7 @@ export class MostBoxEngine extends EventEmitter {
1226
1226
  return files.map(f => ({
1227
1227
  fileName: f.fileName,
1228
1228
  cid: f.cid,
1229
- link: `most://${f.cid}?filename=${encodeURIComponent(f.fileName)}`,
1229
+ link: buildMostLink(f.cid, f.fileName),
1230
1230
  publishedAt: f.publishedAt,
1231
1231
  size: Number(f.size) || 0,
1232
1232
  starred: f.starred || false,
@@ -1318,7 +1318,7 @@ export class MostBoxEngine extends EventEmitter {
1318
1318
  return files.map(f => ({
1319
1319
  fileName: f.fileName,
1320
1320
  cid: f.cid,
1321
- link: `most://${f.cid}?filename=${encodeURIComponent(f.fileName)}`,
1321
+ link: buildMostLink(f.cid, f.fileName),
1322
1322
  publishedAt: f.publishedAt,
1323
1323
  size: Number(f.size) || 0,
1324
1324
  starred: f.starred || false,
@@ -1560,7 +1560,7 @@ export class MostBoxEngine extends EventEmitter {
1560
1560
  return {
1561
1561
  cid,
1562
1562
  fileName: safeFileName,
1563
- link: `most://${cid}?filename=${encodeURIComponent(safeFileName)}`,
1563
+ link: buildMostLink(cid, safeFileName),
1564
1564
  }
1565
1565
  }
1566
1566
 
@@ -1602,7 +1602,7 @@ export class MostBoxEngine extends EventEmitter {
1602
1602
  return {
1603
1603
  cid: file.cid,
1604
1604
  fileName: file.fileName,
1605
- link: `most://${file.cid}?filename=${encodeURIComponent(file.fileName)}`,
1605
+ link: buildMostLink(file.cid, file.fileName),
1606
1606
  }
1607
1607
  })
1608
1608
 
@@ -1725,7 +1725,7 @@ export class MostBoxEngine extends EventEmitter {
1725
1725
  seedError: seedState?.error,
1726
1726
  seedStatusUpdatedAt: seedState?.updatedAt,
1727
1727
  ...this.#getFileRuntimeStats(holding.cid),
1728
- link: `most://${holding.cid}?filename=${encodeURIComponent(holding.fileName || holding.cid)}`,
1728
+ link: buildMostLink(holding.cid, holding.fileName || holding.cid),
1729
1729
  }
1730
1730
  })
1731
1731
  }
@@ -1782,7 +1782,7 @@ export class MostBoxEngine extends EventEmitter {
1782
1782
 
1783
1783
  this.#getCidInfo(cid)
1784
1784
  const fileName = sanitizeFilename(input.fileName || `${cid}.bin`)
1785
- const link = `most://${cid}?filename=${encodeURIComponent(fileName)}`
1785
+ const link = buildMostLink(cid, fileName)
1786
1786
  const result = await this.downloadFile(link, input.taskId || null, {
1787
1787
  timeout: input.timeout,
1788
1788
  ownerAddress: input.ownerAddress,
@@ -4818,6 +4818,15 @@ export class MostBoxEngine extends EventEmitter {
4818
4818
  ])
4819
4819
  this.#saveChannelsMetadata()
4820
4820
  }
4821
+ if (channel) {
4822
+ this.emit('channel:sync:available', {
4823
+ channel: channelKey,
4824
+ channelKey,
4825
+ channelId: channel.channelId || '',
4826
+ writerCoreKey: normalizedCoreKey,
4827
+ writerCoreKeys: uniqueStrings(channel.writerCoreKeys),
4828
+ })
4829
+ }
4821
4830
  console.log(
4822
4831
  `[MostBox] Opened remote channel core ${normalizedCoreKey.slice(0, 8)}... for ${channelKey}`
4823
4832
  )
@@ -29,6 +29,14 @@ export function validateAccountBackupPayload(input) {
29
29
  if (!Array.isArray(input.notes)) {
30
30
  throw new Error('账号备份缺少 notes')
31
31
  }
32
+ if (
33
+ input.noteVault !== undefined &&
34
+ (!input.noteVault ||
35
+ typeof input.noteVault !== 'object' ||
36
+ !Array.isArray(input.noteVault.files))
37
+ ) {
38
+ throw new Error('账号备份 noteVault 格式无效')
39
+ }
32
40
  return input
33
41
  }
34
42
 
@@ -413,10 +413,6 @@ export function getBackendUrlExport() {
413
413
  return getBackendUrl()
414
414
  }
415
415
 
416
- export function getConfiguredBackendUrlExport() {
417
- return getConfiguredBackendUrl()
418
- }
419
-
420
416
  export function getSameOriginBackendUrlExport() {
421
417
  return getSameOriginBackendUrl()
422
418
  }
@@ -437,10 +433,6 @@ export function getNodeHistoryExport() {
437
433
  return getNodeHistory()
438
434
  }
439
435
 
440
- export function getBackendInviteExport() {
441
- return getBackendInvite()
442
- }
443
-
444
436
  export function getApiUrl(path) {
445
437
  const url = getBackendUrl()
446
438
  return `${url}${normalizePath(path)}`
@@ -510,12 +502,6 @@ export async function getAuthenticatedWebSocketUrl(path = '/ws') {
510
502
  return url.toString()
511
503
  }
512
504
 
513
- export async function checkBackendConnection() {
514
- const url = getBackendUrl() || getSameOriginBackendUrl()
515
- const invite = shouldAttachBackendInvite(url) ? getBackendInvite() : ''
516
- return checkBackendConnectionTarget({ url, invite })
517
- }
518
-
519
505
  async function probeHttp(cleanedUrl, invite, identity) {
520
506
  try {
521
507
  const headers = {}
@@ -51,10 +51,3 @@ export function verifyAuthHeader(header, method, path, options = {}) {
51
51
  return { ok: false, error: 'Invalid authorization signature' }
52
52
  }
53
53
  }
54
-
55
- export function parseInviteList(value = '') {
56
- return String(value || '')
57
- .split(',')
58
- .map(item => item.trim())
59
- .filter(Boolean)
60
- }
@@ -1,5 +1,5 @@
1
- import { createAvatar } from '@dicebear/core'
2
- import { botttsNeutral } from '@dicebear/collection'
1
+ import { Avatar, Style } from '@dicebear/core'
2
+ import botttsNeutralDefinition from '@dicebear/styles/bottts-neutral.json' with { type: 'json' }
3
3
 
4
4
  export const defaultAvatarIds = [
5
5
  'panda',
@@ -50,11 +50,11 @@ export function normalizeDefaultAvatarValue(avatar) {
50
50
  }
51
51
 
52
52
  function createAddressAvatar(address) {
53
- return createAvatar(botttsNeutral, {
53
+ const avatar = new Avatar(new Style(botttsNeutralDefinition), {
54
54
  seed: 'most.box@' + address,
55
- flip: true,
56
- backgroundType: ['gradientLinear'],
57
- }).toDataUri()
55
+ flip: 'horizontal',
56
+ })
57
+ return avatar.toDataUri()
58
58
  }
59
59
 
60
60
  export function generateAvatar(address, avatar) {