most-box 0.3.4 → 0.3.5

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 (132) hide show
  1. package/out/about/index.html +20 -0
  2. package/out/admin/index.html +0 -0
  3. package/out/app/index.html +0 -0
  4. package/out/assets/AccountMenu-D-wa5tux.js +1 -0
  5. package/out/assets/AppShell-BdRKZIZ9.js +1 -0
  6. package/out/assets/AppTop-BE5kKBYH.js +1 -0
  7. package/out/assets/CopyButton-DnFqfCN9.js +1 -0
  8. package/out/assets/MarketingHeader-8gNzHawY.js +1 -0
  9. package/out/assets/MarketingLayout-BPdjpEfc.js +1 -0
  10. package/out/assets/{MilkdownEditor-BzbYt-xb.js → MilkdownEditor-C388llV6.js} +1 -1
  11. package/out/assets/OpenSidebarButton-OP8zl7ad.js +1 -0
  12. package/out/assets/arrow-right-BsHzC0ZL.js +1 -0
  13. package/out/assets/{arrow-up-down-B-677ip8.js → arrow-up-down-DvLSz6Ma.js} +1 -1
  14. package/out/assets/{userProfile-BZvkCuet.js → channelApi-C5eHetoJ.js} +1 -1
  15. package/out/assets/chatJoinInvite-CeC6H6t8.js +1 -0
  16. package/out/assets/{chatNoteDraft-CYbvcEvC.js → chatNoteDraft-DTy6In5R.js} +1 -1
  17. package/out/assets/{circle-alert-dfN4T6Nq.js → circle-alert-DXVkx8p8.js} +1 -1
  18. package/out/assets/{copy-B7pPZ2MP.js → copy-OwXDsstV.js} +1 -1
  19. package/out/assets/{download-COQOcPqI.js → download-Cy2BlfKM.js} +1 -1
  20. package/out/assets/downloadValidation-Dd43i9_9.js +1 -0
  21. package/out/assets/{external-link-D6tHlYgS.js → external-link-D_AQSgxW.js} +1 -1
  22. package/out/assets/{file-text-DiyIGL1I.js → file-text-zvTER2mN.js} +1 -1
  23. package/out/assets/fingerprint-pattern-BT73ASEB.js +1 -0
  24. package/out/assets/{folder-BS_GbpPQ.js → folder-6pYYnS2-.js} +1 -1
  25. package/out/assets/folder-open-DOJ4bB58.js +1 -0
  26. package/out/assets/format-CAKfypjK.js +1 -0
  27. package/out/assets/gamepad-2-BYqNgCQr.js +1 -0
  28. package/out/assets/{hard-drive-Cqa7Rstj.js → hard-drive-DL1KJHmG.js} +1 -1
  29. package/out/assets/i18n-C6yaqRst.js +1 -0
  30. package/out/assets/index-C6IjeTBh.css +1 -0
  31. package/out/assets/index-D1mozno-.js +31 -0
  32. package/out/assets/index.lazy-59kmyNMW.js +1 -0
  33. package/out/assets/index.lazy-B1iJsXQ8.js +3 -0
  34. package/out/assets/index.lazy-Bz77Jlzu.js +1 -0
  35. package/out/assets/index.lazy-CVFcovqX.js +1 -0
  36. package/out/assets/index.lazy-CX2l1_Gi.js +1 -0
  37. package/out/assets/index.lazy-C_J9afOY.js +1 -0
  38. package/out/assets/index.lazy-CazlK1-Y.js +3 -0
  39. package/out/assets/index.lazy-CflWbocP.js +1 -0
  40. package/out/assets/index.lazy-ClrSkRx5.js +1 -0
  41. package/out/assets/index.lazy-CsTaY5WS.js +1 -0
  42. package/out/assets/index.lazy-D7E1pb1S.js +5 -0
  43. package/out/assets/index.lazy-DzaN9qwA.js +2 -0
  44. package/out/assets/index.lazy-FvXAYdEO.js +1 -0
  45. package/out/assets/index.lazy-JwrS2vDI.js +1 -0
  46. package/out/assets/index.lazy-m9XAzMt1.js +1 -0
  47. package/out/assets/{loader-CwyHYZdX.js → loader-C4pED_QP.js} +1 -1
  48. package/out/assets/lock-yG7M7GkB.js +1 -0
  49. package/out/assets/{message-square-BgsNXPft.js → message-square-CfApq8Ou.js} +1 -1
  50. package/out/assets/mp-cEQteKUC.js +1 -0
  51. package/out/assets/{music-Dn9nm9Qb.js → music-Br2x8TKX.js} +1 -1
  52. package/out/assets/notebook-pen-Bcd3MrtD.js +1 -0
  53. package/out/assets/play-DSHtNcOe.js +1 -0
  54. package/out/assets/{refresh-cw-D4BsHvhi.js → refresh-cw-CfkUlTK9.js} +1 -1
  55. package/out/assets/{save-B02sbO9Y.js → save-CfYzXcxH.js} +1 -1
  56. package/out/assets/saveLocalFile-2CNt4X0T.js +1 -0
  57. package/out/assets/search-DLBOUfny.js +1 -0
  58. package/out/assets/{send-4dhnJGuS.js → send-Bie9hgHI.js} +1 -1
  59. package/out/assets/{shield-check-Boae7Nc6.js → shield-check-2-h_eEXp.js} +1 -1
  60. package/out/assets/{smartphone-JXH-zQXB.js → smartphone-CrsocYJo.js} +1 -1
  61. package/out/assets/trash-2-B9gno5q6.js +1 -0
  62. package/out/assets/{triangle-alert-B9sMiA9l.js → triangle-alert-BhNtjKm2.js} +1 -1
  63. package/out/assets/{upload-DVuXJt_o.js → upload-BmufnMFu.js} +1 -1
  64. package/out/assets/{useAppStore-DOnk608w.js → useAppStore-DNhyhD20.js} +1 -1
  65. package/out/assets/useChannelMessages-DDBqKBXU.js +4 -0
  66. package/out/assets/useGameRoom-asr2gyY6.js +1 -0
  67. package/out/assets/{wallet-D9Iw4YWE.js → wallet-D6HZocla.js} +1 -1
  68. package/out/assets/{wifi-ljEI_ySA.js → wifi-CILQyKk0.js} +1 -1
  69. package/out/chat/index.html +0 -0
  70. package/out/chat/join/demo/index.html +0 -0
  71. package/out/chat/join/index.html +0 -0
  72. package/out/download/index.html +2 -2
  73. package/out/game/gandengyan/index.html +0 -0
  74. package/out/game/index.html +0 -0
  75. package/out/game/zhajinhua/index.html +0 -0
  76. package/out/index.html +2 -2
  77. package/out/note/index.html +0 -0
  78. package/out/ping/index.html +2 -2
  79. package/out/profile/index.html +0 -0
  80. package/out/web3/index.html +0 -0
  81. package/package.json +1 -1
  82. package/server/index.js +18 -1
  83. package/server/src/core/channelVoice.js +164 -0
  84. package/server/src/core/mostLink.js +30 -13
  85. package/server/src/http/nodeStatus.js +2 -2
  86. package/server/src/http/routes/fileRoutes.js +10 -8
  87. package/server/src/http/uploads.js +53 -15
  88. package/server/src/index.js +126 -57
  89. package/server/src/node/config.js +4 -4
  90. package/server/src/utils/api.js +9 -1
  91. package/server/src/utils/avatar.js +1 -10
  92. package/server/src/utils/downloadMessages.js +7 -7
  93. package/server/src/utils/errors.js +11 -1
  94. package/server/src/utils/userIdentity.js +0 -1
  95. package/out/assets/AccountMenu-ptQklqvD.js +0 -1
  96. package/out/assets/AppTop-Cy0ZOCxO.js +0 -1
  97. package/out/assets/CopyButton-C8PIDSJZ.js +0 -1
  98. package/out/assets/FilePreviewOverlay-faaTnmlN.js +0 -1
  99. package/out/assets/MarketingHeader-CxJ_OVOW.js +0 -1
  100. package/out/assets/MarketingLayout-CiN5KYcE.js +0 -1
  101. package/out/assets/OpenSidebarButton-CGhXxQ5Z.js +0 -1
  102. package/out/assets/arrow-right-CXzRt0Fp.js +0 -1
  103. package/out/assets/chatJoinInvite-B-ucvYdg.js +0 -1
  104. package/out/assets/check-iBCQl0yr.js +0 -1
  105. package/out/assets/chevron-right-D75NRNNs.js +0 -1
  106. package/out/assets/downloadValidation-UPgpJbKz.js +0 -1
  107. package/out/assets/format-CR8oUWq6.js +0 -1
  108. package/out/assets/index-D0Uk9-58.js +0 -31
  109. package/out/assets/index-FV6RZlVI.css +0 -1
  110. package/out/assets/index.lazy-B6XDJ8fg.js +0 -1
  111. package/out/assets/index.lazy-BFdWbm3R.js +0 -1
  112. package/out/assets/index.lazy-BzIt7fP4.js +0 -1
  113. package/out/assets/index.lazy-CLkb32nv.js +0 -1
  114. package/out/assets/index.lazy-CNmqW4-r.js +0 -1
  115. package/out/assets/index.lazy-Cnkj-gAd.js +0 -3
  116. package/out/assets/index.lazy-Cx1bp84f.js +0 -5
  117. package/out/assets/index.lazy-CxLzR674.js +0 -2
  118. package/out/assets/index.lazy-D4RjTGu-.js +0 -3
  119. package/out/assets/index.lazy-D9xLqvqW.js +0 -1
  120. package/out/assets/index.lazy-DNCF6MTJ.js +0 -1
  121. package/out/assets/index.lazy-MY-mUG5Z.js +0 -1
  122. package/out/assets/index.lazy-erUKA2rI.js +0 -1
  123. package/out/assets/index.lazy-qTjgLKhY.js +0 -1
  124. package/out/assets/key-round-JR8M3aHl.js +0 -1
  125. package/out/assets/lock-CuwwlXlx.js +0 -1
  126. package/out/assets/mp-Dv12gDTx.js +0 -1
  127. package/out/assets/notebook-pen-BzrCXQJE.js +0 -1
  128. package/out/assets/play-CvWKSMwY.js +0 -1
  129. package/out/assets/search-HW4oPOBP.js +0 -1
  130. package/out/assets/trash-2-BLwoM0ME.js +0 -1
  131. package/out/assets/useChannelMessages-CDvw-f_x.js +0 -4
  132. package/out/assets/useGameRoom-CS1w4IqP.js +0 -1
@@ -20,9 +20,9 @@ import { Duplex } from 'node:stream'
20
20
 
21
21
  import { calculateCid, parseMostLink, buildMostLink } from './core/cid.js'
22
22
  import { normalizeChannelAttachment } from './core/channelAttachment.js'
23
+ import { normalizeChannelVoiceEvent } from './core/channelVoice.js'
23
24
  import { getCidInfo } from './core/cidTopic.js'
24
25
  import {
25
- CHAT_FILE_ROOT,
26
26
  TRANSIENT_CHANNEL_TYPES,
27
27
  CHANNEL_DISCOVERY_TIMEOUT,
28
28
  CHANNEL_CANDIDATE_TTL,
@@ -95,7 +95,11 @@ import {
95
95
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
96
96
  const CHANNEL_PRESENCE_HEARTBEAT_MS = 15 * 1000
97
97
  const CHANNEL_PRESENCE_TIMEOUT_MS = 45 * 1000
98
- const CHANNEL_WELCOME_MESSAGE = '我加入了群聊'
98
+ const CHANNEL_MEMBER_JOINED_EVENT = 'channel.member.joined'
99
+
100
+ function isChannelHistoryEntry(entry) {
101
+ return entry?.type === 'message' || entry?.type === 'system'
102
+ }
99
103
 
100
104
  function createMemoryDuplexPair() {
101
105
  let left
@@ -203,6 +207,16 @@ export class MostBoxEngine extends EventEmitter {
203
207
  return this.#getChannelPresenceList(channel.channelKey)
204
208
  }
205
209
 
210
+ sendChannelVoiceEvent(channelKeyInput, input = {}, options = {}) {
211
+ this.#ensureInitialized()
212
+ this.#assertChannelMember(channelKeyInput, options.ownerAddress)
213
+ const channel = this.#resolveChannel(channelKeyInput, options.ownerAddress)
214
+ const event = normalizeChannelVoiceEvent(channel.channelKey, input, options)
215
+ this.#broadcastChannelVoice(event)
216
+ this.emit('channel:voice', event)
217
+ return event
218
+ }
219
+
206
220
  joinChannelPresence(channelKeyInput, options = {}) {
207
221
  this.#ensureInitialized()
208
222
  this.#assertChannelMember(channelKeyInput, options.ownerAddress)
@@ -728,7 +742,7 @@ export class MostBoxEngine extends EventEmitter {
728
742
  * @param {object} [options] - 下载选项
729
743
  * @param {number} [options.timeout] - 等待 P2P 内容的超时时间(毫秒)
730
744
  * @param {number} [options.streamReadTimeout] - 下载流无进度超时时间(毫秒)
731
- * @returns {Promise<{ taskId: string, fileName: string, savedPath: string, alreadyExists?: boolean }>}
745
+ * @returns {Promise<{ taskId: string, fileName: string, savedPath?: string, localAvailable?: boolean, alreadyExists?: boolean }>}
732
746
  */
733
747
  async downloadFile(link, taskId = null, options = {}) {
734
748
  this.#ensureInitialized()
@@ -767,12 +781,38 @@ export class MostBoxEngine extends EventEmitter {
767
781
  })
768
782
  if (localContent) {
769
783
  const existingFile = localContent.fileRecord
784
+ const publishedBucket = this.#getPublishedBucket(ownerAddress, true)
785
+ const existingIndex = publishedBucket.findIndex(
786
+ f => f.cid === cidString
787
+ )
788
+ const alreadyInOwnerLibrary = existingIndex !== -1
770
789
  console.log(
771
790
  `[MostBox] CID content already exists locally: ${cidString}`
772
791
  )
773
792
  const existingHolding = this.#holdings.find(
774
793
  item => item.cid === cidString
775
794
  )
795
+ const localSize =
796
+ Number(existingHolding?.size) ||
797
+ (Number.isFinite(localContent.size) ? localContent.size : 0)
798
+ if (!alreadyInOwnerLibrary) {
799
+ this.#assertDisplayNameAvailable(linkFileName, {
800
+ ownerAddress,
801
+ excludeCid: cidString,
802
+ })
803
+ const syncUpdatedAt = Date.now()
804
+ publishedBucket.push({
805
+ fileName: linkFileName,
806
+ cid: cidString,
807
+ driveName: existingFile?.driveName || name,
808
+ size: localSize,
809
+ source: 'downloaded',
810
+ publishedAt: new Date(syncUpdatedAt).toISOString(),
811
+ starred: false,
812
+ syncUpdatedAt,
813
+ })
814
+ this.#savePublishedMetadata()
815
+ }
776
816
  await this.#joinCidTopicInternal(cidString, {
777
817
  server: true,
778
818
  client: false,
@@ -780,17 +820,21 @@ export class MostBoxEngine extends EventEmitter {
780
820
  this.#upsertHolding({
781
821
  cid: cidString,
782
822
  fileName:
783
- existingHolding?.fileName || existingFile?.fileName || linkFileName,
784
- size:
785
- existingHolding?.size ??
786
- (Number.isFinite(localContent.size) ? localContent.size : 0),
823
+ existingHolding?.fileName ||
824
+ (alreadyInOwnerLibrary ? existingFile?.fileName : linkFileName) ||
825
+ linkFileName,
826
+ size: localSize,
787
827
  driveName: existingFile?.driveName || name,
788
- source: existingHolding?.source || 'published',
828
+ source:
829
+ existingHolding?.source ||
830
+ (alreadyInOwnerLibrary ? existingFile?.source : 'downloaded') ||
831
+ 'downloaded',
789
832
  })
790
833
  return {
791
834
  taskId,
792
835
  fileName: linkFileName,
793
- alreadyExists: true,
836
+ localAvailable: true,
837
+ alreadyExists: alreadyInOwnerLibrary,
794
838
  }
795
839
  }
796
840
 
@@ -1120,7 +1164,10 @@ export class MostBoxEngine extends EventEmitter {
1120
1164
  cid: parsed.cid,
1121
1165
  fileName: sanitizeFilename(parsed.fileName),
1122
1166
  size: localContent.size,
1123
- alreadyExists: true,
1167
+ localAvailable: true,
1168
+ alreadyExists: this.#getPublishedBucket(ownerAddress).some(
1169
+ f => f.cid === parsed.cid
1170
+ ),
1124
1171
  }
1125
1172
  }
1126
1173
 
@@ -1129,7 +1176,7 @@ export class MostBoxEngine extends EventEmitter {
1129
1176
  * @param {string} link - most:// 链接
1130
1177
  * @param {object} [options] - 检测选项
1131
1178
  * @param {number} [options.timeout] - 等待 P2P 内容的超时时间(毫秒)
1132
- * @returns {Promise<{ available: boolean, cid: string, fileName: string, size: number|null, alreadyExists?: boolean }>}
1179
+ * @returns {Promise<{ available: boolean, cid: string, fileName: string, size: number|null, localAvailable?: boolean, alreadyExists?: boolean }>}
1133
1180
  */
1134
1181
  async checkDownloadAvailability(link, options = {}) {
1135
1182
  this.#ensureInitialized()
@@ -1158,7 +1205,10 @@ export class MostBoxEngine extends EventEmitter {
1158
1205
  cid: cidString,
1159
1206
  fileName: sanitizeFilename(parsed.fileName),
1160
1207
  size: localContent.size,
1161
- alreadyExists: true,
1208
+ localAvailable: true,
1209
+ alreadyExists: this.#getPublishedBucket(ownerAddress).some(
1210
+ f => f.cid === cidString
1211
+ ),
1162
1212
  }
1163
1213
  }
1164
1214
 
@@ -2567,7 +2617,7 @@ export class MostBoxEngine extends EventEmitter {
2567
2617
  for (let i = 0; i < core.length; i++) {
2568
2618
  try {
2569
2619
  const entry = await core.get(i)
2570
- if (entry && entry.type === 'message') {
2620
+ if (isChannelHistoryEntry(entry)) {
2571
2621
  allMessages.push({
2572
2622
  ...entry,
2573
2623
  _coreKey: coreKeyHex,
@@ -2582,7 +2632,7 @@ export class MostBoxEngine extends EventEmitter {
2582
2632
 
2583
2633
  const seen = new Set()
2584
2634
  const unique = allMessages.filter(m => {
2585
- const key = `${m._coreKey}:${m.author}:${m.timestamp}:${m.content}`
2635
+ const key = `${m._coreKey}:${m.type}:${m.event || ''}:${m.author}:${m.timestamp}:${m.content}`
2586
2636
  if (seen.has(key)) return false
2587
2637
  seen.add(key)
2588
2638
  return true
@@ -2649,7 +2699,7 @@ export class MostBoxEngine extends EventEmitter {
2649
2699
 
2650
2700
  const normalizedAvatar = normalizeChannelAvatar(options.avatar)
2651
2701
  const message = {
2652
- type: 'message',
2702
+ type: options.type === 'system' ? 'system' : 'message',
2653
2703
  author,
2654
2704
  authorName: normalizeChannelDisplayName(
2655
2705
  authorName,
@@ -2666,6 +2716,10 @@ export class MostBoxEngine extends EventEmitter {
2666
2716
  if (attachment) {
2667
2717
  message.attachment = attachment
2668
2718
  }
2719
+ if (message.type === 'system') {
2720
+ const event = String(options.event || '').trim()
2721
+ if (event) message.event = event
2722
+ }
2669
2723
 
2670
2724
  await core.append(message)
2671
2725
  if (channel) {
@@ -3158,11 +3212,13 @@ export class MostBoxEngine extends EventEmitter {
3158
3212
 
3159
3213
  await this.sendMessage(
3160
3214
  channel.channelKey,
3161
- CHANNEL_WELCOME_MESSAGE,
3215
+ CHANNEL_MEMBER_JOINED_EVENT,
3162
3216
  ownerAddress,
3163
3217
  normalizeChannelDisplayName(options.displayName, ownerAddress),
3164
3218
  {
3165
3219
  ownerAddress,
3220
+ type: 'system',
3221
+ event: CHANNEL_MEMBER_JOINED_EVENT,
3166
3222
  ...(Object.prototype.hasOwnProperty.call(options, 'avatar')
3167
3223
  ? { avatar: options.avatar }
3168
3224
  : {}),
@@ -3517,7 +3573,7 @@ export class MostBoxEngine extends EventEmitter {
3517
3573
  for (let i = 0; i < core.length; i++) {
3518
3574
  try {
3519
3575
  const entry = await core.get(i)
3520
- if (entry?.type === 'message') {
3576
+ if (isChannelHistoryEntry(entry)) {
3521
3577
  maxTimestamp = Math.max(
3522
3578
  maxTimestamp,
3523
3579
  Number(entry.timestamp) || 0
@@ -3555,42 +3611,7 @@ export class MostBoxEngine extends EventEmitter {
3555
3611
  baseMessage = { ...baseMessage, avatar }
3556
3612
  }
3557
3613
  }
3558
- const attachment = baseMessage?.attachment
3559
- if (!attachment?.cid || !attachment.fileName) {
3560
- return baseMessage
3561
- }
3562
-
3563
- const oldFileName = sanitizeFilename(String(attachment.fileName))
3564
- const channelPathName = channel?.channelId || channelKey
3565
- const channelPrefix = `${CHAT_FILE_ROOT}/${channelPathName}/`
3566
- const fileName = oldFileName.startsWith(channelPrefix)
3567
- ? oldFileName
3568
- : `${channelPrefix}${getPathBaseName(oldFileName)}`
3569
- const link = buildMostLink(attachment.cid, fileName)
3570
- const content =
3571
- typeof baseMessage.content === 'string' &&
3572
- (baseMessage.content === attachment.link ||
3573
- parseMostLink(baseMessage.content).cid === attachment.cid)
3574
- ? link
3575
- : baseMessage.content
3576
-
3577
- if (
3578
- fileName === attachment.fileName &&
3579
- link === attachment.link &&
3580
- content === baseMessage.content
3581
- ) {
3582
- return baseMessage
3583
- }
3584
-
3585
- return {
3586
- ...baseMessage,
3587
- content,
3588
- attachment: {
3589
- ...attachment,
3590
- fileName,
3591
- link,
3592
- },
3593
- }
3614
+ return baseMessage
3594
3615
  }
3595
3616
 
3596
3617
  #getCidInfo(cid) {
@@ -4549,7 +4570,7 @@ export class MostBoxEngine extends EventEmitter {
4549
4570
  err.message
4550
4571
  )
4551
4572
  }
4552
- return []
4573
+ return {}
4553
4574
  }
4554
4575
 
4555
4576
  #savePublishedMetadata() {
@@ -4603,7 +4624,7 @@ export class MostBoxEngine extends EventEmitter {
4603
4624
  err.message
4604
4625
  )
4605
4626
  }
4606
- return []
4627
+ return {}
4607
4628
  }
4608
4629
 
4609
4630
  #saveTrashMetadata() {
@@ -4760,7 +4781,7 @@ export class MostBoxEngine extends EventEmitter {
4760
4781
  for (let i = lastCoreLength; i < core.length; i++) {
4761
4782
  try {
4762
4783
  const entry = await core.get(i)
4763
- if (entry && entry.type === 'message') {
4784
+ if (isChannelHistoryEntry(entry)) {
4764
4785
  const channel = this.#channels.find(
4765
4786
  c => c.channelKey === channelKey
4766
4787
  )
@@ -4913,6 +4934,32 @@ export class MostBoxEngine extends EventEmitter {
4913
4934
  }
4914
4935
  }
4915
4936
 
4937
+ #sendChannelVoice(stream, event) {
4938
+ if (!stream || stream.destroyed || stream.writableEnded || !event) {
4939
+ this.#channelStreams.delete(stream)
4940
+ return false
4941
+ }
4942
+ try {
4943
+ stream.write(
4944
+ `${JSON.stringify({
4945
+ type: 'channel-voice',
4946
+ peerId: this.getNodeId(),
4947
+ ...event,
4948
+ })}\n`
4949
+ )
4950
+ return true
4951
+ } catch {
4952
+ this.#channelStreams.delete(stream)
4953
+ return false
4954
+ }
4955
+ }
4956
+
4957
+ #broadcastChannelVoice(event) {
4958
+ for (const stream of [...this.#channelStreams]) {
4959
+ this.#sendChannelVoice(stream, event)
4960
+ }
4961
+ }
4962
+
4916
4963
  async #processChannelHelloMessage(msg) {
4917
4964
  if (msg.type !== 'channel-hello') return null
4918
4965
 
@@ -5033,6 +5080,26 @@ export class MostBoxEngine extends EventEmitter {
5033
5080
  return peerId
5034
5081
  }
5035
5082
 
5083
+ #processChannelVoiceMessage(msg) {
5084
+ if (msg.type !== 'channel-voice') return null
5085
+ const peerId = String(msg.peerId || '').trim()
5086
+ if (!peerId || peerId === this.getNodeId()) return null
5087
+ const channelId = normalizeChannelId(msg.channelId || msg.channelKey)
5088
+ const channelKey = buildChannelKey(channelId)
5089
+ const localChannel = this.#channels.find(
5090
+ channel => channel.channelKey === channelKey
5091
+ )
5092
+ if (!localChannel) return peerId
5093
+
5094
+ try {
5095
+ const event = normalizeChannelVoiceEvent(channelKey, msg, {
5096
+ timestamp: msg.timestamp,
5097
+ })
5098
+ this.emit('channel:voice', event)
5099
+ } catch {}
5100
+ return peerId
5101
+ }
5102
+
5036
5103
  async #handleChannelConnection(conn) {
5037
5104
  const stream = conn
5038
5105
  let connectedPeerId = null
@@ -5055,7 +5122,9 @@ export class MostBoxEngine extends EventEmitter {
5055
5122
  const peerId =
5056
5123
  message.type === 'channel-presence'
5057
5124
  ? this.#processChannelPresenceMessage(message)
5058
- : await this.#processChannelHelloMessage(message)
5125
+ : message.type === 'channel-voice'
5126
+ ? this.#processChannelVoiceMessage(message)
5127
+ : await this.#processChannelHelloMessage(message)
5059
5128
  if (peerId) connectedPeerId = peerId
5060
5129
  } catch (err) {
5061
5130
  console.warn(`[MostBox] Failed to process channel data:`, err.message)
@@ -40,17 +40,17 @@ export function normalizeNodeConfig(raw = {}) {
40
40
  const rawNode = raw.node && typeof raw.node === 'object' ? raw.node : {}
41
41
 
42
42
  const capacityBytes = normalizePositiveInteger(
43
- rawNode.capacityBytes ?? raw.capacityBytes,
43
+ rawNode.capacityBytes,
44
44
  defaults.capacityBytes
45
45
  )
46
46
  const maxFileSizeBytes = normalizePositiveInteger(
47
- rawNode.maxFileSizeBytes ?? raw.maxFileSizeBytes,
47
+ rawNode.maxFileSizeBytes,
48
48
  defaults.maxFileSizeBytes
49
49
  )
50
50
  const remoteInvites = normalizeRemoteInvites(
51
- rawNode.remoteInvites ?? raw.remoteInvites ?? defaults.remoteInvites
51
+ rawNode.remoteInvites ?? defaults.remoteInvites
52
52
  )
53
- const host = normalizeHost(rawNode.host ?? raw.host, defaults.host)
53
+ const host = normalizeHost(rawNode.host, defaults.host)
54
54
  return {
55
55
  dataPath:
56
56
  typeof raw.dataPath === 'string'
@@ -348,6 +348,10 @@ export async function getApiErrorPayload(err) {
348
348
  return {
349
349
  status: response.status,
350
350
  code: typeof data?.code === 'string' ? data.code : undefined,
351
+ details:
352
+ data?.details && typeof data.details === 'object'
353
+ ? data.details
354
+ : undefined,
351
355
  error:
352
356
  typeof data?.error === 'string'
353
357
  ? data.error
@@ -398,7 +402,11 @@ export function setBackendInvite(invite) {
398
402
  export function configureBackend({ url, invite }) {
399
403
  setBackendUrl(url)
400
404
  setBackendInvite(invite)
401
- saveRemoteNode(url, invite)
405
+ if (isRemoteBackendUrl(url)) {
406
+ saveRemoteNode(url, invite)
407
+ } else if (typeof window !== 'undefined') {
408
+ clearActiveRemoteNode()
409
+ }
402
410
  }
403
411
 
404
412
  export function clearBackendConnection() {
@@ -10,19 +10,10 @@ export const defaultAvatarIds = [
10
10
  'snow-mountain',
11
11
  ]
12
12
 
13
- const legacyDefaultAvatarIdAliases = {
14
- mint: 'panda',
15
- violet: 'owl',
16
- ocean: 'dolphin',
17
- ember: 'tiger',
18
- sage: 'turtle',
19
- dusk: 'snow-mountain',
20
- }
21
-
22
13
  function normalizeDefaultAvatarId(id) {
23
14
  const value = typeof id === 'string' ? id.trim() : ''
24
15
  if (defaultAvatarIds.includes(value)) return value
25
- return legacyDefaultAvatarIdAliases[value] || ''
16
+ return ''
26
17
  }
27
18
 
28
19
  export function getDefaultAvatarValue(id) {
@@ -6,7 +6,7 @@ const DOWNLOAD_CHECK_MESSAGES = {
6
6
  offline: '无法连接本地节点,请确认 MostBox 后端正在运行后再检测。',
7
7
  missingApi: '当前后端还没有检测接口,请重启 MostBox 后端后再试。',
8
8
  validation:
9
- '链接格式不正确,请粘贴完整的 most://<cid>?filename=... 分享链接。',
9
+ '链接格式不正确,请粘贴 most://、网页入口或 CID。',
10
10
  nameConflict: '下载目录已有同名文件,请先重命名或移走后再检测。',
11
11
  noPeer:
12
12
  '暂时没有发现在线种子。请确认分享者或其他下载者仍在线做种,稍后再检测。',
@@ -18,15 +18,15 @@ const DOWNLOAD_CHECK_MESSAGES = {
18
18
 
19
19
  const LINK_VALIDATION_MESSAGES = {
20
20
  [MOST_LINK_ERROR_CODES.INVALID_URL]:
21
- '链接无法解析,请粘贴完整的 most://<cid>?filename=... 分享链接。',
21
+ '链接无法解析,请粘贴 most://、网页入口或 CID。',
22
22
  [MOST_LINK_ERROR_CODES.INVALID_PROTOCOL]:
23
- '链接协议不正确,应以 most:// 开头。',
23
+ '链接格式不正确,请确认输入末尾是有效的 CID 或 CID?filename=...。',
24
24
  [MOST_LINK_ERROR_CODES.UNSUPPORTED_PATH]:
25
- '链接里不应包含路径,请使用 most://<cid>?filename=... 格式。',
25
+ '链接路径不受支持,请确认输入末尾是 CID 或 CID?filename=...。',
26
26
  [MOST_LINK_ERROR_CODES.CID_EMPTY]:
27
- 'CID 无效,请确认 most:// 后面的内容没有缺失或被截断。',
27
+ 'CID 无效,请确认输入末尾是有效的 CID 或 CID?filename=...。',
28
28
  [MOST_LINK_ERROR_CODES.INVALID_CID_FORMAT]:
29
- 'CID 无效,请确认 most:// 后面的内容没有缺失或被截断。',
29
+ 'CID 无效,请确认输入末尾是有效的 CID 或 CID?filename=...。',
30
30
  [MOST_LINK_ERROR_CODES.CID_V1_REQUIRED]:
31
31
  'CID 格式不符合 MostBox 要求,请确认分享链接完整。',
32
32
  [MOST_LINK_ERROR_CODES.CID_DIGEST_LENGTH]:
@@ -69,7 +69,7 @@ export function getDownloadCheckErrorMessageFromPayload(
69
69
 
70
70
  export function getDownloadLinkValidationMessage(link = '') {
71
71
  const value = String(link || '').trim()
72
- if (!value) return '请先粘贴 most:// 分享链接。'
72
+ if (!value) return '请先粘贴分享链接或 CID。'
73
73
 
74
74
  const result = parseMostLink(value)
75
75
  if (!result.errorCode) return null
@@ -21,10 +21,20 @@ export class ValidationError extends AppError {
21
21
  }
22
22
 
23
23
  export class FileSizeError extends AppError {
24
- constructor(message, size) {
24
+ constructor(message, size, maxFileSizeBytes) {
25
25
  super(message, 'FILE_SIZE_ERROR')
26
26
  this.name = 'FileSizeError'
27
27
  this.size = size
28
+ const details = {}
29
+ if (Number.isFinite(Number(size))) {
30
+ details.sizeBytes = Number(size)
31
+ }
32
+ if (Number.isFinite(Number(maxFileSizeBytes))) {
33
+ details.maxFileSizeBytes = Number(maxFileSizeBytes)
34
+ }
35
+ if (Object.keys(details).length > 0) {
36
+ this.details = details
37
+ }
28
38
  }
29
39
  }
30
40
 
@@ -29,7 +29,6 @@ export function saveIdentity(identity) {
29
29
  export function clearIdentity() {
30
30
  if (typeof localStorage === 'undefined') return
31
31
  localStorage.removeItem('mostbox_identity')
32
- localStorage.removeItem('mostbox_guest_identity')
33
32
  }
34
33
 
35
34
  export function getDisplayName(address, username) {
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{B as t,E as n,W as r,t as i}from"./useAppStore-DOnk608w.js";import{t as a}from"./check-iBCQl0yr.js";import{A as o,M as s,f as c,g as l,j as u}from"./index-D0Uk9-58.js";var d=t(`languages`,[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]]),f=t(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),p=t(`sun`,[[`circle`,{cx:`12`,cy:`12`,r:`4`,key:`4exip2`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`m4.93 4.93 1.41 1.41`,key:`149t6j`}],[`path`,{d:`m17.66 17.66 1.41 1.41`,key:`ptbguv`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`m6.34 17.66-1.41 1.41`,key:`1m8zz5`}],[`path`,{d:`m19.07 4.93-1.41 1.41`,key:`1shlcs`}]]),m=t(`user`,[[`path`,{d:`M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2`,key:`975kel`}],[`circle`,{cx:`12`,cy:`7`,r:`4`,key:`17ys0d`}]]),h=e();function g(){let{locale:e,setLocale:t,t:n}=o(),r=n(`common.locale.choose`);return(0,h.jsx)(l,{ariaLabel:r,className:`language-toggle`,items:u.map(n=>({key:n,label:s[n],icon:n===e?(0,h.jsx)(a,{size:16}):(0,h.jsx)(`span`,{className:`language-toggle-placeholder`,"aria-hidden":`true`}),onSelect:()=>{n!==e&&t(n)}})),renderTrigger:e=>(0,h.jsx)(`button`,{...e,className:`header-tool-btn`,title:r,"aria-label":r,children:(0,h.jsx)(d,{size:16})})})}function _(){let{t:e}=o(),t=i(e=>e.isDarkMode),n=i(e=>e.setIsDarkMode),r=e(`common.theme.toggle`);return(0,h.jsx)(`button`,{type:`button`,className:`header-tool-btn`,title:r,"aria-label":r,"aria-pressed":t,onClick:()=>n(!t),children:t?(0,h.jsx)(p,{size:16}):(0,h.jsx)(f,{size:16})})}function v(){let{t:e}=o(),t=n(e=>e.identity),i=c(t?.address,t?.avatar),a=e(`nav.profile`);return(0,h.jsx)(r,{to:`/profile/`,className:`account-profile-link`,title:a,"aria-label":a,children:t?(0,h.jsx)(`img`,{className:`account-profile-link-avatar`,src:i,alt:``,"aria-hidden":`true`}):(0,h.jsx)(m,{size:18})})}export{m as i,_ as n,g as r,v as t};
@@ -1 +0,0 @@
1
- import{n as e,o as t,t as n}from"./jsx-runtime-Bt-cYkS5.js";import{B as r,W as i}from"./useAppStore-DOnk608w.js";import{n as a,r as o,t as s}from"./AccountMenu-ptQklqvD.js";import{A as c,E as l}from"./index-D0Uk9-58.js";var u=r(`menu`,[[`path`,{d:`M4 5h16`,key:`1tepv9`}],[`path`,{d:`M4 12h16`,key:`1lakjw`}],[`path`,{d:`M4 19h16`,key:`1djgab`}]]),d=t(e(),1);function f(e,t){return typeof t==`boolean`?t:typeof window<`u`&&`matchMedia`in window?window.matchMedia(e).matches:!1}function p(e,t,{getInitialValueInEffect:n}={getInitialValueInEffect:!0}){let[r,i]=(0,d.useState)(n?t:f(e));return(0,d.useEffect)(()=>{try{if(`matchMedia`in window){let t=window.matchMedia(e);i(t.matches);let n=e=>i(e.matches);return t.addEventListener(`change`,n),()=>{t.removeEventListener(`change`,n)}}}catch{return}},[e]),r||!1}function m(e=!1,t={}){let[n,r]=(0,d.useState)(e),i=(0,d.useCallback)(()=>{r(e=>e||(t.onOpen?.(),!0))},[t.onOpen]),a=(0,d.useCallback)(()=>{r(e=>e&&(t.onClose?.(),!1))},[t.onClose]);return[n,{open:i,close:a,toggle:(0,d.useCallback)(()=>{n?a():i()},[a,i,n]),set:r}]}var h=n(),g=(0,d.createContext)(null);function _(){let e=(0,d.useContext)(g);if(!e)throw Error(`useAppShell must be used within AppShell`);return e}function v({sidebar:e,className:t=``,headerTitle:n,headerRight:r,sidebarToggleReplacement:i,defaultHide:l=!1,hideAccountMenu:f=!1,children:_}){let[v,y]=m(!1),[b,x]=(0,d.useState)(l),S=(0,d.useRef)(l),C=p(`(max-width: 768px)`),{t:w}=c(),T=(0,d.useCallback)((e={})=>{y.close(),e.collapse&&x(!0)},[y]);(0,d.useEffect)(()=>{l!==S.current&&(l?T({collapse:!0}):x(!1),S.current=l)},[l,T]);let E=()=>{C?y.toggle():x(!b)},D=()=>{C?y.open():x(!1)},O=C?v:!b;return(0,h.jsx)(g.Provider,{value:{closeSidebar:T,openSidebar:D,isSidebarVisible:O},children:(0,h.jsxs)(`div`,{className:[`app-layout`,t].filter(Boolean).join(` `),children:[(0,h.jsx)(`div`,{className:`sidebar-overlay ${v?`visible`:``}`,onClick:()=>T()}),(0,h.jsx)(`div`,{className:`sidebar ${v?`open`:``} ${b?`collapsed`:``}`,children:e({closeSidebar:T,openSidebar:D})}),(0,h.jsxs)(`div`,{className:`main-content`,children:[(0,h.jsxs)(`header`,{className:`app-header`,children:[(0,h.jsxs)(`div`,{className:`header-left`,children:[i??(0,h.jsx)(`button`,{onClick:E,className:`btn btn-icon sidebar-toggle-btn`,"aria-label":w(C?`appShell.openMenu`:b?`appShell.expandSidebar`:`appShell.collapseSidebar`),children:(0,h.jsx)(u,{size:16})}),n]}),(0,h.jsxs)(`div`,{className:`header-right`,children:[r,(0,h.jsx)(a,{}),(0,h.jsx)(o,{}),!f&&(0,h.jsx)(s,{})]})]}),_]})]})})}function y({onNavigate:e}){let{t}=c(),n=t(`common.brand`);return(0,h.jsxs)(i,{to:`/`,className:`sidebar-header sidebar-header-link`,onClick:e,"aria-label":n,title:n,children:[(0,h.jsx)(l,{size:18}),(0,h.jsx)(`h1`,{children:n})]})}export{m as i,v as n,_ as r,y as t};
@@ -1 +0,0 @@
1
- import{n as e,o as t,t as n}from"./jsx-runtime-Bt-cYkS5.js";import{t as r}from"./check-iBCQl0yr.js";import{t as i}from"./copy-B7pPZ2MP.js";import{A as a}from"./index-D0Uk9-58.js";var o=t(e(),1),s=n();function c({text:e,label:t,copiedLabel:n,className:c=`btn btn-icon`,iconSize:l=14}){let{t:u}=a(),[d,f]=(0,o.useState)(!1),p=n||u(`common.copied`),m=t||u(`common.copy`);async function h(){try{await navigator.clipboard.writeText(e),f(!0),setTimeout(()=>f(!1),1500)}catch{}}return(0,s.jsxs)(`button`,{type:`button`,className:c,onClick:h,title:d?p:m,children:[d?(0,s.jsx)(r,{size:l}):(0,s.jsx)(i,{size:l}),t?d?p:t:null]})}export{c as t};
@@ -1 +0,0 @@
1
- import{n as e,o as t,t as n}from"./jsx-runtime-Bt-cYkS5.js";import{B as r,c as i}from"./useAppStore-DOnk608w.js";import{t as a}from"./file-text-DiyIGL1I.js";import{t as o}from"./loader-CwyHYZdX.js";import{t as s}from"./music-Dn9nm9Qb.js";import{A as c,S as l}from"./index-D0Uk9-58.js";var u=r(`pen`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]]),d=r(`film`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M3 7.5h4`,key:`zfgn84`}],[`path`,{d:`M3 12h18`,key:`1i2n21`}],[`path`,{d:`M3 16.5h4`,key:`1230mu`}],[`path`,{d:`M17 3v18`,key:`in4fa5`}],[`path`,{d:`M17 7.5h4`,key:`myr1c1`}],[`path`,{d:`M17 16.5h4`,key:`go4c1d`}]]),f=r(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]);function p(e){let t=String(e||``).split(`.`).pop()?.toLowerCase()||``,n=[`jpg`,`jpeg`,`png`,`gif`,`webp`,`svg`,`bmp`,`ico`,`tiff`,`heic`,`heif`],r=[`mp4`,`webm`,`mov`,`avi`,`mkv`,`flv`,`wmv`,`m4v`,`mpeg`,`3gp`],i=[`mp3`,`wav`,`ogg`,`flac`,`aac`,`m4a`,`wma`,`opus`],a=`txt.md.js.ts.jsx.tsx.css.scss.less.json.xml.html.htm.yaml.yml.toml.ini.cfg.conf.log.sh.bash.py.rb.go.rs.java.c.cpp.h.hpp.cs.php.sql.graphql.env.gitignore.dockerfile.readme`.split(`.`);return n.includes(t)?`image`:r.includes(t)?`video`:i.includes(t)?`audio`:a.includes(t)?`text`:`file`}var m=t(e(),1),h=n();function g(e){return e===`image`||e===`video`||e===`audio`}function _({item:e,isBackendReady:t,getFileDownloadUrl:n,onClose:r}){let{t:u}=c(),[d,f]=(0,m.useState)(``),[p,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(``),[b,x]=(0,m.useState)(``);return(0,m.useEffect)(()=>{if(e.subtype!==`text`)return;let r=!1;if(f(``),x(``),!t){f(u(`preview.loadFailed`));return}return _(!0),(async()=>{try{let t=await fetch(n(e.cid),{headers:{...await i(`GET`,`/api/files/${e.cid}/download`),Range:`bytes=0-9999`}});if(!t.ok)throw Error(u(`preview.loadFailed`));let a=await t.text();r||f(a||u(`preview.emptyFile`))}catch{r||f(u(`preview.loadFailed`))}finally{r||_(!1)}})(),()=>{r=!0}},[n,t,e.cid,e.subtype]),(0,m.useEffect)(()=>{if(!g(e.subtype)){y(``);return}if(y(``),x(``),!t){x(u(`preview.loadFailed`));return}let r=``,a=!1;return(async()=>{try{let t=await fetch(n(e.cid),{headers:await i(`GET`,`/api/files/${e.cid}/download`)});if(!t.ok)throw Error(u(`preview.loadFailed`));let o=URL.createObjectURL(await t.blob());r=o,a||y(o)}catch{a||x(u(`preview.loadFailed`))}})(),()=>{a=!0,r&&URL.revokeObjectURL(r)}},[n,t,e.cid,e.subtype]),(0,h.jsxs)(`div`,{className:`preview-overlay`,onClick:r,children:[(0,h.jsx)(`button`,{type:`button`,className:`preview-close`,onClick:r,"aria-label":u(`preview.close`),children:(0,h.jsx)(l,{size:20})}),(0,h.jsxs)(`div`,{onClick:e=>e.stopPropagation(),children:[e.subtype===`image`&&(0,h.jsx)(`div`,{className:`preview-media-wrapper`,children:v?(0,h.jsx)(`img`,{src:v,alt:e.fileName,translate:`no`}):b?(0,h.jsxs)(`div`,{className:`preview-unsupported`,children:[(0,h.jsx)(a,{size:48,className:`preview-file-icon`}),(0,h.jsx)(`p`,{translate:`no`,children:e.fileName}),(0,h.jsx)(`p`,{className:`preview-unsupported-hint`,children:b})]}):(0,h.jsx)(`div`,{className:`preview-loading`,children:(0,h.jsx)(`div`,{className:`preview-loading-spinner`})})}),e.subtype===`video`&&(0,h.jsx)(`div`,{className:`preview-media-wrapper`,children:v?(0,h.jsx)(`video`,{src:v,controls:!0}):b?(0,h.jsxs)(`div`,{className:`preview-unsupported`,children:[(0,h.jsx)(a,{size:48,className:`preview-file-icon`}),(0,h.jsx)(`p`,{translate:`no`,children:e.fileName}),(0,h.jsx)(`p`,{className:`preview-unsupported-hint`,children:b})]}):(0,h.jsx)(`div`,{className:`preview-loading`,children:(0,h.jsx)(`div`,{className:`preview-loading-spinner`})})}),e.subtype===`audio`&&(0,h.jsxs)(`div`,{className:`preview-audio`,children:[(0,h.jsx)(`div`,{className:`preview-audio-icon`,children:(0,h.jsx)(s,{size:36,color:`var(--accent)`})}),(0,h.jsx)(`p`,{className:`preview-audio-filename`,translate:`no`,children:e.fileName}),v?(0,h.jsx)(`audio`,{className:`preview-audio-player`,src:v,controls:!0}):(0,h.jsx)(`div`,{className:`preview-text-loading`,children:b?(0,h.jsx)(`p`,{children:b}):(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(o,{size:24,className:`preview-text-spinner`}),(0,h.jsx)(`p`,{children:u(`preview.audioLoading`)})]})})]}),e.subtype===`file`&&(0,h.jsxs)(`div`,{className:`preview-unsupported`,children:[(0,h.jsx)(a,{size:48,className:`preview-file-icon`}),(0,h.jsx)(`p`,{translate:`no`,children:e.fileName}),(0,h.jsx)(`p`,{className:`preview-unsupported-hint`,children:u(`preview.unsupported`)})]}),e.subtype===`text`&&(0,h.jsxs)(`div`,{className:`preview-text-container`,children:[(0,h.jsx)(`div`,{className:`preview-text-header`,children:(0,h.jsx)(`span`,{translate:`no`,children:e.fileName})}),p?(0,h.jsxs)(`div`,{className:`preview-text-loading`,children:[(0,h.jsx)(o,{size:24,className:`preview-text-spinner`}),(0,h.jsx)(`p`,{children:u(`preview.textLoading`)}),(0,h.jsx)(`p`,{className:`preview-text-loading-hint`,children:u(`preview.firstSyncHint`)})]}):(0,h.jsx)(`pre`,{className:`preview-text`,translate:`no`,children:d||u(`preview.emptyFile`)})]})]})]})}export{u as a,d as i,p as n,f as r,_ as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{n as t,r as n,t as r}from"./AccountMenu-ptQklqvD.js";import{E as i,x as a}from"./index-D0Uk9-58.js";var o=e();function s(){return(0,o.jsx)(`nav`,{className:`mkt-nav`,children:(0,o.jsxs)(`div`,{className:`mkt-nav-inner`,children:[(0,o.jsxs)(`button`,{type:`button`,className:`mkt-nav-logo`,onClick:a(),children:[(0,o.jsx)(i,{size:18}),(0,o.jsx)(`span`,{children:`MOST PEOPLE`})]}),(0,o.jsxs)(`div`,{className:`mkt-nav-cta`,children:[(0,o.jsx)(t,{}),(0,o.jsx)(n,{}),(0,o.jsx)(r,{})]})]})})}export{s as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{W as t}from"./useAppStore-DOnk608w.js";import{t as n}from"./download-COQOcPqI.js";import{n as r,r as i,t as a}from"./AccountMenu-ptQklqvD.js";import{A as o,b as s}from"./index-D0Uk9-58.js";import{t as c}from"./LogoIcon-B2fFe0l1.js";var l={name:`most-box`,version:`0.3.4`,description:`MostBox - chat-first P2P toolbox for files, notes, and game rooms`,type:`module`,main:`electron/main.js`,bin:{"most-box":`server/cli.js`},files:[`out`,`public`,`electron`,`server/src`,`server/index.js`,`server/cli.js`],scripts:{start:`vite`,server:`node --watch server/index.js`,desktop:`npm run electron:dev`,build:`vite build && node scripts/prepare-start-static.mjs`,preview:`vite preview`,serve:`npm run build && node server/index.js`,test:`node --test server/tests/**/*.test.js`,"test:unit":`node --test server/tests/unit/*.test.js`,"test:desktop":`node --test electron/*.test.js`,"test:frontend":`node --test src/tests/*.test.js`,"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`,typecheck:`tsc -p tsconfig.typecheck.json`,"typecheck:strict-router":`tsc -p tsconfig.strict-router.json`,"check:static-output":`node scripts/check-static-output.mjs`,format:`prettier --write .`,lint:`eslint .`,"r2:cors":`node scripts/configure-r2-cors.mjs`,"electron:dev":`concurrently "npm run build" "wait-on out/index.html && electron ."`,"electron:rebuild":`electron-rebuild -f -w sodium-native`,"electron:build":`npm run build && npm run electron:rebuild && electron-builder`,"electron:build:win":`npm run build && npm run electron:rebuild && electron-builder --win`,"electron:build:win:x64":`npm run electron:build:win -- --x64`,"electron:build:win:arm64":`npm run electron:build:win -- --arm64`,"electron:build:mac":`npm run build && npm run electron:rebuild && electron-builder --mac`,"electron:build:linux":`npm run build && npm run electron:rebuild && electron-builder --linux`},keywords:[`p2p`,`chat`,`file-sharing`,`file-transfer`,`hyperswarm`,`hypercore`,`hyperdrive`],license:`MIT`,dependencies:{"@dicebear/core":`^10.3.0`,"@dicebear/styles":`^10.2.0`,"@hono/node-server":`^2.0.6`,"@tanstack/react-router":`^1.170.16`,"@tanstack/react-start":`^1.168.26`,"@tanstack/react-table":`^8.21.3`,b4a:`^1.8.1`,busboy:`^1.6.0`,corestore:`^7.11.0`,dayjs:`^1.11.21`,ethers:`^6.17.0`,eventemitter3:`^5.0.4`,hono:`^4.12.27`,hypercore:`^11.33.2`,hyperdrive:`^13.3.2`,hyperswarm:`^4.17.0`,"ipfs-unixfs-importer":`^17.0.1`,multiformats:`^14.0.2`,tweetnacl:`^1.0.3`,ws:`^8.21.0`},devDependencies:{"@electron/rebuild":`^4.0.4`,"@eslint/js":`^10.0.1`,"@iconify/react":`^6.0.2`,"@mantine/hooks":`^9.4.0`,"@milkdown/crepe":`^7.21.2`,"@milkdown/utils":`^7.21.2`,"@types/react":`^19.2.17`,"@vitejs/plugin-react":`^6.0.3`,concurrently:`^10.0.3`,electron:`^42.5.0`,"electron-builder":`^26.15.3`,esbuild:`^0.28.1`,eslint:`^10.5.0`,globals:`^17.7.0`,ky:`^2.0.2`,"lucide-react":`^1.21.0`,prettier:`^3.8.4`,"qrcode.react":`^4.2.0`,react:`^19.2.7`,"react-dom":`^19.2.7`,typescript:`6.0.3`,"typescript-eslint":`^8.62.0`,vite:`^8.1.0`,"wait-on":`^9.0.10`,zustand:`^5.0.14`},overrides:{"brace-expansion":`5.0.6`,postcss:`8.5.15`,ws:`$ws`},build:{appId:`com.mostbox.app`,productName:`MostBox`,publish:[{provider:`github`,releaseType:`release`}],directories:{output:`dist`},afterPack:`electron/afterPack.cjs`,files:[`out/**/*`,`electron/**/*`,`server/src/**/*`,`server/index.js`,`server/cli.js`,`package.json`,`!**/*.map`,`!electron/**/*.test.js`,`!server/tests/**/*`],asarUnpack:[`**/*.node`,`**/sodium-native/**`],protocols:[{name:`MostBox Link`,schemes:[`most`]}],win:{target:[`nsis`],artifactName:"${productName}-${version}-win-${arch}-setup.${ext}",icon:`public/logo.ico`},nsis:{oneClick:!1,allowToChangeInstallationDirectory:!0,createDesktopShortcut:!0,createStartMenuShortcut:!0,shortcutName:`MostBox`},mac:{artifactName:"${productName}-${version}-mac-${arch}.${ext}",target:[{target:`dmg`,arch:[`x64`,`arm64`]}],icon:`public/logo-512.png`,category:`public.app-category.utilities`},dmg:{contents:[{x:130,y:220},{x:410,y:220,type:`link`,path:`/Applications`}]},linux:{artifactName:"${productName}-${version}-linux-${arch}.${ext}",target:[{target:`AppImage`,arch:[`x64`,`arm64`]}],icon:`public/logo-512.png`,category:`Utility`}}},u=e(),d=[{to:`/`,labelKey:`footer.about`},{to:`/ping/`,labelKey:`footer.network`},{href:`https://github.com/most-people/most`,labelKey:null,label:`GitHub`,external:!0}],f=l.version;function p(){let{t:e}=o();return(0,u.jsx)(`footer`,{className:`mkt-footer`,children:(0,u.jsx)(`div`,{className:`mkt-container`,children:(0,u.jsxs)(`div`,{className:`mkt-footer-inner`,children:[(0,u.jsx)(`div`,{className:`mkt-footer-links`,children:d.map(n=>`external`in n?(0,u.jsx)(`a`,{href:n.href,target:`_blank`,rel:`noopener noreferrer`,children:n.label},n.href):(0,u.jsx)(t,{to:n.to,children:e(n.labelKey)},n.to))}),(0,u.jsxs)(`span`,{className:`mkt-footer-copy`,children:[`© `,new Date().getFullYear(),` MOST PEOPLE · MIT License`]}),(0,u.jsxs)(`span`,{className:`mkt-footer-build`,translate:`no`,children:[`v`,f]})]})})})}function m({children:e,header:t}){return(0,u.jsxs)(`div`,{className:`mkt-layout`,children:[t??(0,u.jsx)(h,{}),(0,u.jsx)(`main`,{className:`mkt-layout-main`,children:e}),(0,u.jsx)(p,{})]})}function h(){let{t:e}=o(),l=s();return(0,u.jsx)(`nav`,{className:`mkt-nav`,children:(0,u.jsxs)(`div`,{className:`mkt-nav-inner`,children:[(0,u.jsxs)(t,{to:`/`,className:`mkt-nav-logo`,children:[(0,u.jsx)(c,{}),`MOST PEOPLE`]}),(0,u.jsxs)(`div`,{className:`mkt-nav-cta`,children:[(0,u.jsx)(r,{}),(0,u.jsx)(i,{}),!l&&(0,u.jsxs)(t,{to:`/download/`,className:`btn btn-primary mkt-nav-preview`,children:[(0,u.jsx)(n,{size:16}),e(`nav.downloadClient`)]}),(0,u.jsx)(a,{})]})]})})}export{m as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{B as t}from"./useAppStore-DOnk608w.js";import{r as n}from"./AppTop-Cy0ZOCxO.js";import{A as r}from"./index-D0Uk9-58.js";var i=t(`panel-left-open`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}],[`path`,{d:`m14 9 3 3-3 3`,key:`8010ee`}]]),a=e();function o({label:e,className:t=``,variant:o=`primary`}){let{isSidebarVisible:s,openSidebar:c}=n(),{t:l}=r(),u=o===`primary`?`btn-primary`:``,d=e||l(`appShell.openSidebar`);return s?null:(0,a.jsxs)(`button`,{type:`button`,className:`btn ${u} sidebar-open-hint ${t}`.trim(),onClick:c,children:[(0,a.jsx)(i,{size:16}),d]})}export{o as t};
@@ -1 +0,0 @@
1
- import{B as e}from"./useAppStore-DOnk608w.js";var t=e(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]);export{t};
@@ -1 +0,0 @@
1
- import{O as e}from"./index-D0Uk9-58.js";var t=`0x955fe80bdb8312165471fcacd6a8f83df88a770dda6f38657ca4e62ec28d5b54`,n=`https://api.most.box`;function r(t){let n=typeof t==`string`?t.trim():t;return e(n)?n:void 0}function i(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function a(e){try{return JSON.parse(e)}catch{return null}}function o(e){return typeof e==`string`?a(e):e}function s(e){return typeof e==`string`?e.trim():``}function c(e){return s(e)===`sparkbit`?`sparkbit`:void 0}function l(e){let t=o(e);if(!i(t))return null;let n=s(t.uid),a=(Array.isArray(t.channels)?t.channels:[]).filter(i).map(e=>({id:s(e.id),name:s(e.name)||void 0})).filter(e=>e.id);return!n||a.length===0?null:{node_url:s(t.node_url)||void 0,node_invite:s(t.node_invite)||void 0,locale:r(t.locale),uid:n,theme:c(t.theme),logo:s(t.logo)||void 0,logo_dark:s(t.logo_dark)||void 0,data:s(t.data)||void 0,avatar:s(t.avatar)||void 0,name:s(t.name)||void 0,channels:a}}export{t as n,l as r,n as t};
@@ -1 +0,0 @@
1
- import{B as e}from"./useAppStore-DOnk608w.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]);export{t};
@@ -1 +0,0 @@
1
- import{B as e}from"./useAppStore-DOnk608w.js";var t=e(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]);export{t};
@@ -1 +0,0 @@
1
- import{T as e,l as t,n,s as r}from"./useAppStore-DOnk608w.js";var i={CID_EMPTY:`cid_empty`,INVALID_CID_FORMAT:`invalid_cid_format`,CID_V1_REQUIRED:`cid_v1_required`,CID_DIGEST_LENGTH:`cid_digest_length`,LINK_EMPTY:`link_empty`,INVALID_URL:`invalid_url`,INVALID_PROTOCOL:`invalid_protocol`,UNSUPPORTED_PATH:`unsupported_path`,UNSUPPORTED_QUERY_PARAM:`unsupported_query_param`};function a(e){return{valid:!1,errorCode:e}}function o(e,t){return{cid:``,errorCode:e,...t?{details:t}:{}}}function s(t){if(!t||typeof t!=`string`)return a(i.CID_EMPTY);let n;try{n=e.parse(t)}catch{return a(i.INVALID_CID_FORMAT)}return n.version===1?n.multihash.digest.length===32?{valid:!0}:a(i.CID_DIGEST_LENGTH):a(i.CID_V1_REQUIRED)}function c(e){if(!e||typeof e!=`string`)return o(i.LINK_EMPTY);let t;try{t=new URL(e)}catch{return o(i.INVALID_URL)}if(t.protocol!==`most:`)return o(i.INVALID_PROTOCOL);if(t.pathname&&t.pathname!==`/`)return o(i.UNSUPPORTED_PATH);let n=t.hostname,r=t.searchParams.get(`filename`),a=[...t.searchParams.keys()].find(e=>e!==`filename`),c=s(n);return c.valid?a?o(i.UNSUPPORTED_QUERY_PARAM,{param:a}):{cid:n,fileName:r?.trim()||n}:o(c.errorCode)}function l(e,t){let n=String(t||``).trim();return n?`most://${e}?filename=${encodeURIComponent(n)}`:`most://${e}`}var u={timeout:`检测等待超时,暂时没有等到在线种子响应。请确认分享者或其他下载者仍在线做种,稍后再检测。`,offline:`无法连接本地节点,请确认 MostBox 后端正在运行后再检测。`,missingApi:`当前后端还没有检测接口,请重启 MostBox 后端后再试。`,validation:`链接格式不正确,请粘贴完整的 most://<cid>?filename=... 分享链接。`,nameConflict:`下载目录已有同名文件,请先重命名或移走后再检测。`,noPeer:`暂时没有发现在线种子。请确认分享者或其他下载者仍在线做种,稍后再检测。`,permission:`下载目录不可写,请检查目录权限后再检测。`,starting:`本地节点还没有启动完成,请稍等几秒后重新检测。`,server:`本地节点检测时出错,请稍后重试或查看节点日志。`,fallback:`检测未通过,请确认链接完整、发布者在线且本机网络正常。`};i.INVALID_URL,i.INVALID_PROTOCOL,i.UNSUPPORTED_PATH,i.CID_EMPTY,i.INVALID_CID_FORMAT,i.CID_V1_REQUIRED,i.CID_DIGEST_LENGTH;function d(e={},t=``){if(t===`TimeoutError`)return u.timeout;if(!e.status)return u.offline;if(e.status===404)return u.missingApi;switch(e.code){case`VALIDATION_ERROR`:return u.validation;case`CONFLICT`:return e.error?`${e.error},请先处理同名文件后再下载。`:u.nameConflict;case`PEER_NOT_FOUND`:return u.noPeer;case`PERMISSION_ERROR`:return e.error?`下载目录不可写:${e.error}`:u.permission;case`ENGINE_NOT_INITIALIZED`:return u.starting;default:break}return e.status===503?u.noPeer:e.status>=500?u.server:e.error?`检测未通过:${e.error}`:u.fallback}async function f(e,t){let r=new FormData;r.append(`file`,e,t||e.name);let i=await n.post(`/api/publish`,{body:r});if(!i.ok){let e=await i.json().catch(()=>({error:i.statusText}));throw Error(e.error||`Request failed`)}return i.json()}async function p(e){return d(await r(e),e&&typeof e==`object`&&`name`in e?String(e.name):``)}var m={listPublishedFiles:()=>n.get(`/api/files`).json(),listTrashFiles:()=>n.get(`/api/trash`).json(),deletePublishedFile:e=>n.delete(`/api/files/${e}`).json(),restoreTrashFile:e=>n.post(`/api/trash/${e}/restore`).json(),permanentDeleteTrashFile:e=>n.delete(`/api/trash/${e}`).json(),emptyTrash:()=>n.delete(`/api/trash`).json(),toggleStar:e=>n.post(`/api/files/${e}/star`).json(),getConfig:()=>n.get(`/api/config`).json(),getDataPath:()=>n.get(`/api/config/data-path`).json(),getNetworkAddresses:()=>n.get(`/api/network`).json(),saveConfig:e=>n.post(`/api/config`,{json:e}).json(),publishFile:f,checkDownload:(e,t={})=>{let r=typeof t.timeout==`number`?{link:e,timeout:t.timeout}:{link:e};return n.post(`/api/download/check`,{json:r,timeout:t.requestTimeout??15e3}).json()},downloadFile:e=>n.post(`/api/download`,{json:{link:e}}).json(),cacheFile:e=>n.post(`/api/files/${e}/cache`).json(),cancelDownload:e=>n.post(`/api/download/cancel`,{json:{taskId:e}}).json(),getFileDownloadUrl:e=>t(`/api/files/${e}/download`),moveFile:(e,t)=>n.post(`/api/move`,{json:{cid:e,newFileName:t}}).json(),renameFolder:(e,t)=>n.post(`/api/folder/rename`,{json:{oldPath:e,newPath:t}}).json()},h={[i.LINK_EMPTY]:`app.download.validation.empty`,[i.INVALID_URL]:`app.download.validation.invalidUrl`,[i.INVALID_PROTOCOL]:`app.download.validation.protocol`,[i.UNSUPPORTED_PATH]:`app.download.validation.path`,[i.CID_EMPTY]:`app.download.validation.invalidCid`,[i.INVALID_CID_FORMAT]:`app.download.validation.invalidCid`,[i.CID_V1_REQUIRED]:`app.download.validation.cidV1`,[i.CID_DIGEST_LENGTH]:`app.download.validation.cidDigest`};function g(e){if(!e)return{key:`app.download.validation.empty`};let t=c(e);return t.errorCode?t.errorCode===i.UNSUPPORTED_QUERY_PARAM?{key:`app.download.validation.unsupportedParam`,params:{param:t.details?.param||``}}:{key:h[t.errorCode||``]||`app.download.validation.generic`}:null}function _(e,t){let n=g(e);return n?t(n.key,n.params):null}export{c as a,l as i,m as n,p as r,_ as t};
@@ -1 +0,0 @@
1
- function e(e){let t=Number(e);return!Number.isFinite(t)||t<=0?`0 B`:t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:t<1024*1024*1024?`${(t/(1024*1024)).toFixed(1)} MB`:`${(t/(1024*1024*1024)).toFixed(2)} GB`}function t(e){let t=Number(e);if(!Number.isFinite(t)||t<=0)return``;let n=t/1024/1024;return`${n.toFixed(n>=100?0:1)} MB`}export{t as n,e as t};