most-box 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -24
- package/electron/main.js +19 -2
- package/electron/preload.cjs +8 -0
- package/out/admin/index.html +0 -0
- package/out/app/index.html +0 -0
- package/out/assets/AccountMenu-BgbcUc0m.js +1 -0
- package/out/assets/AppTop-DZFTO9-m.js +1 -0
- package/out/assets/CopyButton-B03fpFFc.js +1 -0
- package/out/assets/FilePreviewOverlay-CA04_Ved.js +1 -0
- package/out/assets/MarketingHeader-BVJy8hXd.js +1 -0
- package/out/assets/MarketingLayout-Cltu-DRw.js +1 -0
- package/out/assets/{MilkdownEditor-BTq9bDAf.js → MilkdownEditor-Dw_ze7EE.js} +92 -92
- package/out/assets/OpenSidebarButton-C2UJYXKh.js +1 -0
- package/out/assets/arrow-right-CXzRt0Fp.js +1 -0
- package/out/assets/chatJoinInvite-BcPz_IV5.js +1 -0
- package/out/assets/chatNoteDraft-CYbvcEvC.js +1 -0
- package/out/assets/check-iBCQl0yr.js +1 -0
- package/out/assets/circle-alert-dfN4T6Nq.js +1 -0
- package/out/assets/cobol-DHLQUbN7.js +1 -0
- package/out/assets/copy-B7pPZ2MP.js +1 -0
- package/out/assets/{dist-DCX0ws1K.js → dist-1jNICPWO.js} +1 -1
- package/out/assets/{dist-BAJKKN4w.js → dist-B3unnv5t.js} +1 -1
- package/out/assets/{dist-DJdv-Ma3.js → dist-B5MBMmGa.js} +1 -1
- package/out/assets/{dist-CMmmtl3f.js → dist-BAqJdUtV.js} +1 -1
- package/out/assets/{dist-C3lbe8SW.js → dist-BBJOmVU3.js} +1 -1
- package/out/assets/{dist-IN8WN7NI.js → dist-BV5CqsJD.js} +1 -1
- package/out/assets/{dist-DBnWo8ZP.js → dist-Ba7fxbV-.js} +1 -1
- package/out/assets/{dist-BzqqCPi2.js → dist-BxxtNKuo.js} +1 -1
- package/out/assets/{dist-DvWZsW-D.js → dist-C8Ue2rSs.js} +1 -1
- package/out/assets/{dist-C-Tg23jc.js → dist-CIn7Xx5U.js} +1 -1
- package/out/assets/{dist-CbTzBiwL.js → dist-CSyRxrry.js} +3 -3
- package/out/assets/{dist-DTL5jL08.js → dist-CZIuQqmV.js} +1 -1
- package/out/assets/{dist-8QDHqrPN.js → dist-CaaBTHCc.js} +1 -1
- package/out/assets/{dist-yZ96GF-e.js → dist-CgReC0ZE.js} +1 -1
- package/out/assets/{dist-D94V9Zlh.js → dist-Ct90qYA2.js} +1 -1
- package/out/assets/{dist-IGpXmkFm.js → dist-DIFFjNuO.js} +1 -1
- package/out/assets/{dist-CqQavSZV.js → dist-DUB2IhWu.js} +1 -1
- package/out/assets/{dist-B0JrbG7f.js → dist-DheA_Tyz.js} +1 -1
- package/out/assets/{dist-Br_5lLVO.js → dist-DyZh1ncm.js} +1 -1
- package/out/assets/{dist-BPs0Xns9.js → dist-E74uGTy3.js} +1 -1
- package/out/assets/{dist-BFSyuOuw.js → dist-K2s-Uj08.js} +1 -1
- package/out/assets/{dist-zyJb88Zz.js → dist-RU_cpjXQ.js} +1 -1
- package/out/assets/{dist-chOCTzB2.js → dist-eIeCvp_6.js} +1 -1
- package/out/assets/{dist-CfU9fwWz.js → dist-hEE2Ub__.js} +1 -1
- package/out/assets/download-COQOcPqI.js +1 -0
- package/out/assets/downloadValidation-Zvllo2SZ.js +1 -0
- package/out/assets/external-link-D6tHlYgS.js +1 -0
- package/out/assets/file-text-DiyIGL1I.js +1 -0
- package/out/assets/folder-DAcox9xz.js +1 -0
- package/out/assets/folder-open-Di0oALaC.js +1 -0
- package/out/assets/hard-drive-Cqa7Rstj.js +1 -0
- package/out/assets/index-B6acG3-t.css +1 -0
- package/out/assets/index-DjBN7bZV.js +31 -0
- package/out/assets/index.lazy-BUODxlbz.js +1 -0
- package/out/assets/index.lazy-Ba2rqd32.js +3 -0
- package/out/assets/index.lazy-Bdh8QUOx.js +1 -0
- package/out/assets/index.lazy-BfAHB94y.js +1 -0
- package/out/assets/index.lazy-Bo0LfJNK.js +2 -0
- package/out/assets/index.lazy-C9-w4fAF.js +3 -0
- package/out/assets/index.lazy-CNQbNKyf.js +1 -0
- package/out/assets/index.lazy-Cd0znkpY.js +1 -0
- package/out/assets/index.lazy-CtUrBLS0.js +1 -0
- package/out/assets/index.lazy-CyNgk0ta.js +1 -0
- package/out/assets/index.lazy-D3HxQTg_.js +1 -0
- package/out/assets/index.lazy-DSsE3iyf.js +1 -0
- package/out/assets/index.lazy-DWXndrGa.js +1 -0
- package/out/assets/index.lazy-Dk7cmQ-j.js +2 -0
- package/out/assets/key-round-JR8M3aHl.js +1 -0
- package/out/assets/loader-CwyHYZdX.js +1 -0
- package/out/assets/lock-CuwwlXlx.js +1 -0
- package/out/assets/message-square-BgsNXPft.js +1 -0
- package/out/assets/mp-Dv12gDTx.js +1 -0
- package/out/assets/music-Dn9nm9Qb.js +1 -0
- package/out/assets/notebook-pen-SWT-zZ4v.js +1 -0
- package/out/assets/play-CvWKSMwY.js +1 -0
- package/out/assets/refresh-cw-D4BsHvhi.js +1 -0
- package/out/assets/save-B02sbO9Y.js +1 -0
- package/out/assets/scheme-tChLYBuY.js +1 -0
- package/out/assets/search-HW4oPOBP.js +1 -0
- package/out/assets/send-4dhnJGuS.js +1 -0
- package/out/assets/shield-check-Boae7Nc6.js +1 -0
- package/out/assets/smartphone-JXH-zQXB.js +1 -0
- package/out/assets/textile-CyzeGT9J.js +1 -0
- package/out/assets/trash-2-BLwoM0ME.js +1 -0
- package/out/assets/triangle-alert-B9sMiA9l.js +1 -0
- package/out/assets/upload-DVuXJt_o.js +1 -0
- package/out/assets/useAppStore-DOnk608w.js +4 -0
- package/out/assets/{useChannelMessages-DOaWHdAP.js → useChannelMessages-CDvw-f_x.js} +1 -1
- package/out/assets/useGameRoom-B1_r6bc7.js +1 -0
- package/out/assets/userProfile-BZvkCuet.js +1 -0
- package/out/assets/wallet-D9Iw4YWE.js +1 -0
- package/out/assets/wifi-ljEI_ySA.js +1 -0
- package/out/chat/index.html +0 -0
- package/out/chat/join/demo/index.html +0 -0
- package/out/chat/join/index.html +0 -0
- package/out/download/index.html +2 -2
- package/out/game/gandengyan/index.html +0 -0
- package/out/game/index.html +0 -0
- package/out/game/zhajinhua/index.html +0 -0
- package/out/index.html +2 -2
- package/out/note/index.html +0 -0
- package/out/ping/index.html +2 -2
- package/out/profile/index.html +0 -0
- package/out/web3/index.html +0 -0
- package/package.json +28 -28
- package/server/index.js +3 -0
- package/server/src/config.js +0 -1
- package/server/src/core/gameRoom.js +12 -19
- package/server/src/http/app.js +2 -0
- package/server/src/http/routePolicy.js +1 -0
- package/server/src/http/routes/noteVaultRoutes.js +155 -0
- package/server/src/index.js +9 -0
- package/server/src/utils/accountBackup.js +8 -0
- package/server/src/utils/api.js +0 -14
- package/server/src/utils/auth.js +0 -7
- package/server/src/utils/avatar.js +6 -6
- package/server/src/utils/noteVault.js +522 -0
- package/electron/preload.js +0 -6
- package/out/assets/FilePreviewOverlay-CM5IqnZD.js +0 -1
- package/out/assets/LanguageToggle-CSQtRZ3A.js +0 -1
- package/out/assets/MarketingHeader-B45AaM29.js +0 -1
- package/out/assets/MarketingLayout-A00pEOa2.js +0 -1
- package/out/assets/MarketingThemeToggle-CIKP8x9W.js +0 -1
- package/out/assets/OpenSidebarButton-D8qfUGzU.js +0 -1
- package/out/assets/SidebarAccount-_RBE5K_o.js +0 -1
- package/out/assets/SidebarHomeLink-qMFEGjZt.js +0 -1
- package/out/assets/arrow-right-BU9c_SL4.js +0 -1
- package/out/assets/circle-alert-iuHzciph.js +0 -1
- package/out/assets/cobol-B_OZ4V-R.js +0 -1
- package/out/assets/copy-DEzFUzeX.js +0 -1
- package/out/assets/download-jEPn2njL.js +0 -1
- package/out/assets/downloadValidation-CSXwoQKW.js +0 -1
- package/out/assets/external-link-BFaoZeK0.js +0 -1
- package/out/assets/file-text-DPA1riJ_.js +0 -1
- package/out/assets/folder-Cfgc70_F.js +0 -1
- package/out/assets/hard-drive-Dar_AZEq.js +0 -1
- package/out/assets/i18n-NjvOSuV6.js +0 -1
- package/out/assets/index-BHZhApbo.css +0 -1
- package/out/assets/index-C-_ZwxuN.js +0 -31
- package/out/assets/index.lazy-0YYV0CR3.js +0 -1
- package/out/assets/index.lazy-BTYGr9Vb.js +0 -1
- package/out/assets/index.lazy-BVAtQtTa.js +0 -3
- package/out/assets/index.lazy-BbdLA2L-.js +0 -1
- package/out/assets/index.lazy-CbiLtziY.js +0 -1
- package/out/assets/index.lazy-CcEdBg3i.js +0 -2
- package/out/assets/index.lazy-CePHsLXG.js +0 -1
- package/out/assets/index.lazy-DG_3_VdF.js +0 -1
- package/out/assets/index.lazy-DR0rWEWZ.js +0 -2
- package/out/assets/index.lazy-DSyTSCJD.js +0 -1
- package/out/assets/index.lazy-DUhsuPLv.js +0 -1
- package/out/assets/index.lazy-DVnhWbzH.js +0 -1
- package/out/assets/index.lazy-DZpkg1DJ.js +0 -1
- package/out/assets/key-round-DNcpSuMw.js +0 -1
- package/out/assets/loader-BXQtdens.js +0 -1
- package/out/assets/lock-CLIE8cct.js +0 -1
- package/out/assets/message-square-Dp09WY1I.js +0 -1
- package/out/assets/mp-B6kdA94c.js +0 -1
- package/out/assets/music-B19Tg557.js +0 -1
- package/out/assets/notebook-pen-C8TlK5sB.js +0 -1
- package/out/assets/play-B-BjsTZz.js +0 -1
- package/out/assets/plus-4hygj-1Z.js +0 -1
- package/out/assets/save-BjrbPwhJ.js +0 -1
- package/out/assets/scheme-CyDdOh7e.js +0 -1
- package/out/assets/search-DSkiWdvX.js +0 -1
- package/out/assets/send-BL4d5iOt.js +0 -1
- package/out/assets/shield-check-DzDuWO8r.js +0 -1
- package/out/assets/smartphone-tRRFFO0a.js +0 -1
- package/out/assets/textile-DWBqthVk.js +0 -1
- package/out/assets/trash-2-V12tJ8lI.js +0 -1
- package/out/assets/triangle-alert-DGWc8ZHu.js +0 -1
- package/out/assets/ui-BpDGD3IR.js +0 -4
- package/out/assets/upload-CoCptKya.js +0 -1
- package/out/assets/useGameRoom-hHkV65ii.js +0 -1
- package/out/assets/userProfile-DwZip0Dt.js +0 -1
- package/out/assets/wallet-T7ONZ3Kg.js +0 -1
- package/out/assets/wifi-Bgo8eHY0.js +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "most-box",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "MostBox - P2P
|
|
3
|
+
"version": "0.3.2",
|
|
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": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"start": "vite",
|
|
20
20
|
"server": "node --watch server/index.js",
|
|
21
|
-
"
|
|
21
|
+
"desktop": "npm run electron:dev",
|
|
22
22
|
"build": "vite build && node scripts/prepare-start-static.mjs",
|
|
23
23
|
"preview": "vite preview",
|
|
24
24
|
"serve": "npm run build && node server/index.js",
|
|
@@ -27,9 +27,6 @@
|
|
|
27
27
|
"test:desktop": "node --test electron/*.test.js",
|
|
28
28
|
"test:frontend": "node --test src/tests/*.test.js",
|
|
29
29
|
"test:protocol": "node --test --test-name-pattern \"extracts CID and filename|matches golden CID samples|publishes a file from Buffer|lists published files|pulls through local seed nodes\" server/tests/unit/cid.test.js server/tests/integration/cid.test.js server/tests/integration/engine.test.js",
|
|
30
|
-
"android": "npm --prefix mobile/android start",
|
|
31
|
-
"android:build": "npm --prefix mobile/android run apk",
|
|
32
|
-
"android:test": "npm --prefix mobile/android test",
|
|
33
30
|
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
34
31
|
"typecheck:strict-router": "tsc -p tsconfig.strict-router.json",
|
|
35
32
|
"check:static-output": "node scripts/check-static-output.mjs",
|
|
@@ -47,29 +44,32 @@
|
|
|
47
44
|
},
|
|
48
45
|
"keywords": [
|
|
49
46
|
"p2p",
|
|
47
|
+
"chat",
|
|
50
48
|
"file-sharing",
|
|
49
|
+
"file-transfer",
|
|
51
50
|
"hyperswarm",
|
|
51
|
+
"hypercore",
|
|
52
52
|
"hyperdrive"
|
|
53
53
|
],
|
|
54
54
|
"license": "MIT",
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@dicebear/
|
|
57
|
-
"@dicebear/
|
|
58
|
-
"@hono/node-server": "^2.0.
|
|
59
|
-
"@tanstack/react-router": "^1.170.
|
|
60
|
-
"@tanstack/react-start": "^1.168.
|
|
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
61
|
"b4a": "^1.8.1",
|
|
62
62
|
"busboy": "^1.6.0",
|
|
63
|
-
"corestore": "^7.
|
|
63
|
+
"corestore": "^7.11.0",
|
|
64
64
|
"dayjs": "^1.11.21",
|
|
65
|
-
"ethers": "^6.
|
|
65
|
+
"ethers": "^6.17.0",
|
|
66
66
|
"eventemitter3": "^5.0.4",
|
|
67
|
-
"hono": "^4.12.
|
|
68
|
-
"hypercore": "^11.33.
|
|
67
|
+
"hono": "^4.12.27",
|
|
68
|
+
"hypercore": "^11.33.2",
|
|
69
69
|
"hyperdrive": "^13.3.2",
|
|
70
70
|
"hyperswarm": "^4.17.0",
|
|
71
71
|
"ipfs-unixfs-importer": "^17.0.1",
|
|
72
|
-
"multiformats": "^14.0.
|
|
72
|
+
"multiformats": "^14.0.2",
|
|
73
73
|
"tweetnacl": "^1.0.3",
|
|
74
74
|
"ws": "^8.21.0"
|
|
75
75
|
},
|
|
@@ -77,26 +77,26 @@
|
|
|
77
77
|
"@electron/rebuild": "^4.0.4",
|
|
78
78
|
"@eslint/js": "^10.0.1",
|
|
79
79
|
"@iconify/react": "^6.0.2",
|
|
80
|
-
"@mantine/hooks": "^9.
|
|
80
|
+
"@mantine/hooks": "^9.4.0",
|
|
81
81
|
"@milkdown/crepe": "^7.21.2",
|
|
82
82
|
"@milkdown/utils": "^7.21.2",
|
|
83
|
-
"@types/react": "^19.2.
|
|
84
|
-
"@vitejs/plugin-react": "^6.0.
|
|
83
|
+
"@types/react": "^19.2.17",
|
|
84
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
85
85
|
"concurrently": "^10.0.3",
|
|
86
|
-
"electron": "^42.
|
|
87
|
-
"electron-builder": "^26.
|
|
88
|
-
"esbuild": "^0.28.
|
|
89
|
-
"eslint": "^10.
|
|
90
|
-
"globals": "^17.
|
|
86
|
+
"electron": "^42.5.0",
|
|
87
|
+
"electron-builder": "^26.15.3",
|
|
88
|
+
"esbuild": "^0.28.1",
|
|
89
|
+
"eslint": "^10.5.0",
|
|
90
|
+
"globals": "^17.7.0",
|
|
91
91
|
"ky": "^2.0.2",
|
|
92
|
-
"lucide-react": "^1.
|
|
93
|
-
"prettier": "^3.8.
|
|
92
|
+
"lucide-react": "^1.21.0",
|
|
93
|
+
"prettier": "^3.8.4",
|
|
94
94
|
"qrcode.react": "^4.2.0",
|
|
95
95
|
"react": "^19.2.7",
|
|
96
96
|
"react-dom": "^19.2.7",
|
|
97
97
|
"typescript": "6.0.3",
|
|
98
|
-
"typescript-eslint": "^8.
|
|
99
|
-
"vite": "^8.0
|
|
98
|
+
"typescript-eslint": "^8.62.0",
|
|
99
|
+
"vite": "^8.1.0",
|
|
100
100
|
"wait-on": "^9.0.10",
|
|
101
101
|
"zustand": "^5.0.14"
|
|
102
102
|
},
|
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
|
)
|
package/server/src/config.js
CHANGED
|
@@ -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 || '')
|
|
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 || '')
|
|
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))
|
|
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(
|
|
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) {
|
package/server/src/http/app.js
CHANGED
|
@@ -31,6 +31,7 @@ import { registerStaticRoutes } from './staticFiles.js'
|
|
|
31
31
|
import { registerChannelRoutes } from './routes/channelRoutes.js'
|
|
32
32
|
import { registerFileRoutes } from './routes/fileRoutes.js'
|
|
33
33
|
import { registerNodeRoutes } from './routes/nodeRoutes.js'
|
|
34
|
+
import { registerNoteVaultRoutes } from './routes/noteVaultRoutes.js'
|
|
34
35
|
import { registerSeedRoutes } from './routes/seedRoutes.js'
|
|
35
36
|
|
|
36
37
|
export { UPLOAD_TMP_DIR } from './uploads.js'
|
|
@@ -302,6 +303,7 @@ export function createApp(engine, options = {}) {
|
|
|
302
303
|
registerSeedRoutes(app, { engine, appendNodeLog, broadcastNodeStatus })
|
|
303
304
|
registerFileRoutes(app, { engine, configStore, wsBroadcast })
|
|
304
305
|
registerChannelRoutes(app, { engine })
|
|
306
|
+
registerNoteVaultRoutes(app, { configStore, isRemoteRequest })
|
|
305
307
|
|
|
306
308
|
registerStaticRoutes(app)
|
|
307
309
|
|
|
@@ -28,6 +28,7 @@ export function requiresUserAuth(path) {
|
|
|
28
28
|
path === '/api/trash' ||
|
|
29
29
|
path === '/api/move' ||
|
|
30
30
|
path === '/api/folder/rename' ||
|
|
31
|
+
path.startsWith('/api/note-vault') ||
|
|
31
32
|
path.startsWith('/api/files/') ||
|
|
32
33
|
path.startsWith('/api/trash/') ||
|
|
33
34
|
path.startsWith('/api/channels')
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { errorJson } from '../errors.js'
|
|
2
|
+
import { PermissionError } from '../../utils/errors.js'
|
|
3
|
+
import {
|
|
4
|
+
configureNoteVault,
|
|
5
|
+
createMarkdownFile,
|
|
6
|
+
createNoteVaultSnapshot,
|
|
7
|
+
deleteMarkdownFile,
|
|
8
|
+
getConfiguredNoteVaultPath,
|
|
9
|
+
getNoteVaultStatus,
|
|
10
|
+
listMarkdownFiles,
|
|
11
|
+
moveMarkdownFile,
|
|
12
|
+
readMarkdownFile,
|
|
13
|
+
restoreNoteVaultSnapshot,
|
|
14
|
+
writeMarkdownFile,
|
|
15
|
+
} from '../../utils/noteVault.js'
|
|
16
|
+
|
|
17
|
+
function assertNoteVaultAccess(c, isRemoteRequest) {
|
|
18
|
+
if (process.env.ELECTRON_APP !== 'true') {
|
|
19
|
+
throw new PermissionError('Note vault is only available in Electron')
|
|
20
|
+
}
|
|
21
|
+
if (isRemoteRequest(c)) {
|
|
22
|
+
throw new PermissionError('Note vault is only available locally')
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getBodyPath(body) {
|
|
27
|
+
return String(body.path || body.vaultPath || '').trim()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function registerNoteVaultRoutes(app, { configStore, isRemoteRequest }) {
|
|
31
|
+
app.get('/api/note-vault/status', async c => {
|
|
32
|
+
try {
|
|
33
|
+
assertNoteVaultAccess(c, isRemoteRequest)
|
|
34
|
+
return c.json(await getNoteVaultStatus(configStore.configDir))
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return errorJson(c, err)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
app.post('/api/note-vault/config', async c => {
|
|
41
|
+
try {
|
|
42
|
+
assertNoteVaultAccess(c, isRemoteRequest)
|
|
43
|
+
const body = await c.req.json()
|
|
44
|
+
const status = await configureNoteVault(
|
|
45
|
+
configStore.configDir,
|
|
46
|
+
getBodyPath(body)
|
|
47
|
+
)
|
|
48
|
+
return c.json({ success: true, ...status })
|
|
49
|
+
} catch (err) {
|
|
50
|
+
return errorJson(c, err)
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
app.get('/api/note-vault/files', async c => {
|
|
55
|
+
try {
|
|
56
|
+
assertNoteVaultAccess(c, isRemoteRequest)
|
|
57
|
+
const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
|
|
58
|
+
return c.json({ files: await listMarkdownFiles(vaultPath) })
|
|
59
|
+
} catch (err) {
|
|
60
|
+
return errorJson(c, err)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
app.get('/api/note-vault/file', async c => {
|
|
65
|
+
try {
|
|
66
|
+
assertNoteVaultAccess(c, isRemoteRequest)
|
|
67
|
+
const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
|
|
68
|
+
const file = await readMarkdownFile(vaultPath, c.req.query('path'))
|
|
69
|
+
return c.json(file)
|
|
70
|
+
} catch (err) {
|
|
71
|
+
return errorJson(c, err)
|
|
72
|
+
}
|
|
73
|
+
})
|
|
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
|
+
|
|
91
|
+
app.put('/api/note-vault/file', async c => {
|
|
92
|
+
try {
|
|
93
|
+
assertNoteVaultAccess(c, isRemoteRequest)
|
|
94
|
+
const body = await c.req.json()
|
|
95
|
+
const vaultPath = await getConfiguredNoteVaultPath(configStore.configDir)
|
|
96
|
+
const file = await writeMarkdownFile(
|
|
97
|
+
vaultPath,
|
|
98
|
+
String(body.path || ''),
|
|
99
|
+
String(body.content || '')
|
|
100
|
+
)
|
|
101
|
+
return c.json({ success: true, file })
|
|
102
|
+
} catch (err) {
|
|
103
|
+
return errorJson(c, err)
|
|
104
|
+
}
|
|
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
|
+
})
|
|
155
|
+
}
|
package/server/src/index.js
CHANGED
|
@@ -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
|
|
package/server/src/utils/api.js
CHANGED
|
@@ -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 = {}
|
package/server/src/utils/auth.js
CHANGED
|
@@ -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 {
|
|
2
|
-
import
|
|
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
|
-
|
|
53
|
+
const avatar = new Avatar(new Style(botttsNeutralDefinition), {
|
|
54
54
|
seed: 'most.box@' + address,
|
|
55
|
-
flip:
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
flip: 'horizontal',
|
|
56
|
+
})
|
|
57
|
+
return avatar.toDataUri()
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export function generateAvatar(address, avatar) {
|