most-box 0.1.4 → 0.1.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 (186) hide show
  1. package/README.md +7 -4
  2. package/electron/main.js +31 -10
  3. package/out/404/index.html +2 -2
  4. package/out/404.html +2 -2
  5. package/out/__next.__PAGE__.txt +6 -6
  6. package/out/__next._full.txt +15 -15
  7. package/out/__next._head.txt +3 -3
  8. package/out/__next._index.txt +7 -7
  9. package/out/__next._tree.txt +4 -4
  10. package/out/_next/static/chunks/{0hpev4am9jpmu.css → 0.4ov9319fecg.css} +1 -1
  11. package/out/_next/static/chunks/0._8s6pbfw.xk.js +1 -0
  12. package/out/_next/static/chunks/02jvyg27pp0mz.js +1 -0
  13. package/out/_next/static/chunks/{0pt.5cg1t09qs.js → 08qqf0rsi3oot.js} +1 -1
  14. package/out/_next/static/chunks/{0adx~d-j05c9d.css → 09h7l4i38xc7q.css} +1 -1
  15. package/out/_next/static/chunks/09hqx79-jkvm_.css +1 -0
  16. package/out/_next/static/chunks/09vcm1ku9k7o8.js +1 -0
  17. package/out/_next/static/chunks/0c6e_d2jq179x.js +1 -0
  18. package/out/_next/static/chunks/0ccalho416.d7.js +1 -0
  19. package/out/_next/static/chunks/0exj_tg.ew-t3.js +1 -0
  20. package/out/_next/static/chunks/0f-wz5d~tv-r4.js +1 -0
  21. package/out/_next/static/chunks/0f0jhsujtf-61.js +1 -0
  22. package/out/_next/static/chunks/0ig8a4sazk3~2.css +1 -0
  23. package/out/_next/static/chunks/0iq1h7g4dudg8.js +1 -0
  24. package/out/_next/static/chunks/0knnzo9aih48r.js +1 -0
  25. package/out/_next/static/chunks/0nzyk~sg_tn._.js +1 -0
  26. package/out/_next/static/chunks/0w~2fjq86t7c7.css +1 -0
  27. package/out/_next/static/chunks/0xrqerhosrp9~.js +1 -0
  28. package/out/_next/static/chunks/14-fm9r_mom81.js +1 -0
  29. package/out/_next/static/chunks/14jhy~xia8lh8.js +1 -0
  30. package/out/_next/static/chunks/{turbopack-0xta0kqwzkf28.js → turbopack-05qngmxam3ar~.js} +1 -1
  31. package/out/_not-found/__next._full.txt +12 -12
  32. package/out/_not-found/__next._head.txt +3 -3
  33. package/out/_not-found/__next._index.txt +7 -7
  34. package/out/_not-found/__next._not-found.__PAGE__.txt +4 -4
  35. package/out/_not-found/__next._not-found.txt +3 -3
  36. package/out/_not-found/__next._tree.txt +2 -2
  37. package/out/_not-found/index.html +2 -2
  38. package/out/_not-found/index.txt +12 -12
  39. package/out/admin/__next._full.txt +14 -14
  40. package/out/admin/__next._head.txt +3 -3
  41. package/out/admin/__next._index.txt +7 -7
  42. package/out/admin/__next._tree.txt +3 -3
  43. package/out/admin/__next.admin.__PAGE__.txt +4 -4
  44. package/out/admin/__next.admin.txt +4 -4
  45. package/out/admin/index.html +2 -2
  46. package/out/admin/index.txt +14 -14
  47. package/out/app/__next._full.txt +13 -13
  48. package/out/app/__next._head.txt +3 -3
  49. package/out/app/__next._index.txt +7 -7
  50. package/out/app/__next._tree.txt +2 -2
  51. package/out/app/__next.app.__PAGE__.txt +4 -4
  52. package/out/app/__next.app.txt +3 -3
  53. package/out/app/index.html +2 -2
  54. package/out/app/index.txt +13 -13
  55. package/out/chat/__next._full.txt +14 -14
  56. package/out/chat/__next._head.txt +3 -3
  57. package/out/chat/__next._index.txt +7 -7
  58. package/out/chat/__next._tree.txt +3 -3
  59. package/out/chat/__next.chat.__PAGE__.txt +4 -4
  60. package/out/chat/__next.chat.txt +4 -4
  61. package/out/chat/index.html +2 -2
  62. package/out/chat/index.txt +14 -14
  63. package/out/chat/join/__next._full.txt +14 -14
  64. package/out/chat/join/__next._head.txt +3 -3
  65. package/out/chat/join/__next._index.txt +7 -7
  66. package/out/chat/join/__next._tree.txt +3 -3
  67. package/out/chat/join/__next.chat.join.__PAGE__.txt +4 -4
  68. package/out/chat/join/__next.chat.join.txt +3 -3
  69. package/out/chat/join/__next.chat.txt +4 -4
  70. package/out/chat/join/index.html +2 -2
  71. package/out/chat/join/index.txt +14 -14
  72. package/out/download/__next._full.txt +33 -35
  73. package/out/download/__next._head.txt +3 -3
  74. package/out/download/__next._index.txt +7 -7
  75. package/out/download/__next._tree.txt +3 -3
  76. package/out/download/__next.download.__PAGE__.txt +6 -6
  77. package/out/download/__next.download.txt +3 -3
  78. package/out/download/index.html +2 -2
  79. package/out/download/index.txt +33 -35
  80. package/out/favicon.ico +0 -0
  81. package/out/game/__next._full.txt +11 -11
  82. package/out/game/__next._head.txt +3 -3
  83. package/out/game/__next._index.txt +7 -7
  84. package/out/game/__next._tree.txt +2 -2
  85. package/out/game/__next.game.__PAGE__.txt +2 -2
  86. package/out/game/__next.game.txt +3 -3
  87. package/out/game/gandengyan/__next._full.txt +13 -13
  88. package/out/game/gandengyan/__next._head.txt +3 -3
  89. package/out/game/gandengyan/__next._index.txt +7 -7
  90. package/out/game/gandengyan/__next._tree.txt +2 -2
  91. package/out/game/gandengyan/__next.game.gandengyan.__PAGE__.txt +4 -4
  92. package/out/game/gandengyan/__next.game.gandengyan.txt +3 -3
  93. package/out/game/gandengyan/__next.game.txt +3 -3
  94. package/out/game/gandengyan/index.html +2 -2
  95. package/out/game/gandengyan/index.txt +13 -13
  96. package/out/game/index.html +1 -1
  97. package/out/game/index.txt +11 -11
  98. package/out/game/zhajinhua/__next._full.txt +13 -13
  99. package/out/game/zhajinhua/__next._head.txt +3 -3
  100. package/out/game/zhajinhua/__next._index.txt +7 -7
  101. package/out/game/zhajinhua/__next._tree.txt +2 -2
  102. package/out/game/zhajinhua/__next.game.txt +3 -3
  103. package/out/game/zhajinhua/__next.game.zhajinhua.__PAGE__.txt +4 -4
  104. package/out/game/zhajinhua/__next.game.zhajinhua.txt +3 -3
  105. package/out/game/zhajinhua/index.html +2 -2
  106. package/out/game/zhajinhua/index.txt +13 -13
  107. package/out/index.html +2 -2
  108. package/out/index.txt +15 -15
  109. package/out/logo-512.png +0 -0
  110. package/out/logo.ico +0 -0
  111. package/out/logo.svg +12 -0
  112. package/out/note/__next._full.txt +13 -13
  113. package/out/note/__next._head.txt +3 -3
  114. package/out/note/__next._index.txt +7 -7
  115. package/out/note/__next._tree.txt +2 -2
  116. package/out/note/__next.note.__PAGE__.txt +4 -4
  117. package/out/note/__next.note.txt +3 -3
  118. package/out/note/index.html +2 -2
  119. package/out/note/index.txt +13 -13
  120. package/out/ping/__next._full.txt +14 -14
  121. package/out/ping/__next._head.txt +3 -3
  122. package/out/ping/__next._index.txt +7 -7
  123. package/out/ping/__next._tree.txt +3 -3
  124. package/out/ping/__next.ping.__PAGE__.txt +5 -5
  125. package/out/ping/__next.ping.txt +3 -3
  126. package/out/ping/index.html +2 -2
  127. package/out/ping/index.txt +14 -14
  128. package/out/web3/__next._full.txt +13 -13
  129. package/out/web3/__next._head.txt +3 -3
  130. package/out/web3/__next._index.txt +7 -7
  131. package/out/web3/__next._tree.txt +2 -2
  132. package/out/web3/__next.web3.__PAGE__.txt +4 -4
  133. package/out/web3/__next.web3.txt +3 -3
  134. package/out/web3/ed25519/__next._full.txt +11 -11
  135. package/out/web3/ed25519/__next._head.txt +3 -3
  136. package/out/web3/ed25519/__next._index.txt +7 -7
  137. package/out/web3/ed25519/__next._tree.txt +2 -2
  138. package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +2 -2
  139. package/out/web3/ed25519/__next.web3.ed25519.txt +3 -3
  140. package/out/web3/ed25519/__next.web3.txt +3 -3
  141. package/out/web3/ed25519/index.html +1 -1
  142. package/out/web3/ed25519/index.txt +11 -11
  143. package/out/web3/index.html +2 -2
  144. package/out/web3/index.txt +13 -13
  145. package/out/web3/tools/__next._full.txt +11 -11
  146. package/out/web3/tools/__next._head.txt +3 -3
  147. package/out/web3/tools/__next._index.txt +7 -7
  148. package/out/web3/tools/__next._tree.txt +2 -2
  149. package/out/web3/tools/__next.web3.tools.__PAGE__.txt +2 -2
  150. package/out/web3/tools/__next.web3.tools.txt +3 -3
  151. package/out/web3/tools/__next.web3.txt +3 -3
  152. package/out/web3/tools/index.html +1 -1
  153. package/out/web3/tools/index.txt +11 -11
  154. package/package.json +5 -5
  155. package/public/favicon.ico +0 -0
  156. package/public/logo-512.png +0 -0
  157. package/public/logo.ico +0 -0
  158. package/public/logo.svg +12 -0
  159. package/server/src/games/gandengyan.js +9 -5
  160. package/server/src/http/app.js +15 -13
  161. package/server/src/http/uploads.js +1 -0
  162. package/server/src/index.js +266 -89
  163. package/server/src/utils/avatar.js +3 -2
  164. package/out/_next/static/chunks/03gsbg0fr00ey.js +0 -1
  165. package/out/_next/static/chunks/0ao1lbi4b.sfa.js +0 -1
  166. package/out/_next/static/chunks/0fo9-h4knidcz.js +0 -1
  167. package/out/_next/static/chunks/0g_a~e050bgzg.css +0 -1
  168. package/out/_next/static/chunks/0i9sfdypwuw8~.js +0 -1
  169. package/out/_next/static/chunks/0olqjomda37-e.js +0 -1
  170. package/out/_next/static/chunks/0puk.7e.tr2zy.js +0 -1
  171. package/out/_next/static/chunks/0qgx9t4jx16ua.css +0 -1
  172. package/out/_next/static/chunks/0s1k6rlwy02c2.js +0 -1
  173. package/out/_next/static/chunks/0sgltmtk_9s8p.css +0 -1
  174. package/out/_next/static/chunks/0snehvtvu1n4q.js +0 -1
  175. package/out/_next/static/chunks/0s~g.l~x049o2.js +0 -1
  176. package/out/_next/static/chunks/0u38kke9vhobe.js +0 -1
  177. package/out/_next/static/chunks/0vd4_a5x-wpdh.js +0 -1
  178. package/out/_next/static/chunks/10f-t2n4y1zx8.js +0 -1
  179. package/out/_next/static/chunks/13jdyag9a-~kk.js +0 -1
  180. package/out/_next/static/chunks/153-sz7s.qml2.js +0 -1
  181. package/out/_next/static/chunks/17cwkb2yn_akx.js +0 -1
  182. /package/out/_next/static/{sSvbBrwXZY-4lBmcHshga → 2smv1H9Y4Z2Ri-SL-UFgR}/_buildManifest.js +0 -0
  183. /package/out/_next/static/{sSvbBrwXZY-4lBmcHshga → 2smv1H9Y4Z2Ri-SL-UFgR}/_clientMiddlewareManifest.js +0 -0
  184. /package/out/_next/static/{sSvbBrwXZY-4lBmcHshga → 2smv1H9Y4Z2Ri-SL-UFgR}/_ssgManifest.js +0 -0
  185. /package/out/{pwa-512x512.png → avatar.png} +0 -0
  186. /package/public/{pwa-512x512.png → avatar.png} +0 -0
@@ -48,7 +48,6 @@ import {
48
48
  SWARM_KEEP_ALIVE_INTERVAL,
49
49
  SWARM_RANDOM_PUNCH_INTERVAL,
50
50
  DRIVE_ENTRY_TIMEOUT,
51
- DRIVE_SYNC_TIMEOUT,
52
51
  STREAM_READ_TIMEOUT,
53
52
  FILE_WRITE_CHUNK_SIZE,
54
53
  DOWNLOAD_POLL_INTERVAL_MIN,
@@ -67,12 +66,28 @@ import {
67
66
  } from './config.js'
68
67
 
69
68
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
69
+ const CHAT_FILE_ROOT = 'chat-file'
70
70
 
71
71
  function normalizeOwnerAddress(address) {
72
72
  const value = String(address || '').trim()
73
73
  return /^0x[a-fA-F0-9]{40}$/.test(value) ? value.toLowerCase() : ''
74
74
  }
75
75
 
76
+ function getPathBaseName(fileName) {
77
+ const parts = String(fileName || '').split('/').filter(Boolean)
78
+ return parts[parts.length - 1] || 'unnamed_file'
79
+ }
80
+
81
+ function getDisplayPathFolder(fileName) {
82
+ const parts = String(fileName || '').split('/').filter(Boolean)
83
+ parts.pop()
84
+ return parts.join('/')
85
+ }
86
+
87
+ function buildMostLink(cid, fileName) {
88
+ return `most://${cid}?filename=${encodeURIComponent(fileName)}`
89
+ }
90
+
76
91
  function createOfflineSwarm() {
77
92
  return {
78
93
  connections: new Set(),
@@ -528,6 +543,10 @@ export class MostBoxEngine extends EventEmitter {
528
543
  }
529
544
  }
530
545
 
546
+ this.#assertDisplayNameAvailable(safeFileName, {
547
+ ownerAddress,
548
+ })
549
+
531
550
  // 获取或创建该 CID 对应的 drive
532
551
  let drive = this.#drives.get(name)
533
552
 
@@ -644,39 +663,48 @@ export class MostBoxEngine extends EventEmitter {
644
663
  const cidString = parsed.cid
645
664
  console.log(`[MostBox] Parsed CID: ${cidString}`)
646
665
  const { driveName: name } = this.#getCidInfo(cidString)
666
+ const linkFileName = sanitizeFilename(parsed.fileName)
647
667
 
648
- const existingFile = this.#publishedFiles.find(
649
- f => f.cid === cidString && this.#recordMatchesOwner(f, ownerAddress)
650
- )
651
- if (existingFile) {
652
- console.log(`[MostBox] File already exists: ${existingFile.fileName}`)
668
+ const localContent = await this.#getLocalCidContent(cidString, {
669
+ ownerAddress,
670
+ public: true,
671
+ allowHoldingFallback: true,
672
+ })
673
+ if (localContent) {
674
+ const existingFile = localContent.fileRecord
675
+ console.log(
676
+ `[MostBox] CID content already exists locally: ${cidString}`
677
+ )
653
678
  const existingHolding = this.#holdings.find(
654
679
  item => item.cid === cidString
655
680
  )
656
- const existingSize = Number(existingFile.size)
657
681
  await this.#joinCidTopicInternal(cidString, {
658
682
  server: true,
659
683
  client: false,
660
684
  })
661
685
  this.#upsertHolding({
662
686
  cid: cidString,
663
- fileName: existingFile.fileName,
687
+ fileName:
688
+ existingHolding?.fileName || existingFile?.fileName || linkFileName,
664
689
  size:
665
690
  existingHolding?.size ??
666
- (Number.isFinite(existingSize) ? existingSize : 0),
691
+ (Number.isFinite(localContent.size) ? localContent.size : 0),
667
692
  localPath:
668
- existingHolding?.localPath || existingFile.localPath || null,
669
- driveName: existingFile.driveName || name,
693
+ existingHolding?.localPath || existingFile?.localPath || null,
694
+ driveName: existingFile?.driveName || name,
670
695
  source: existingHolding?.source || 'published',
671
696
  })
672
697
  return {
673
698
  taskId,
674
- fileName: existingFile.fileName,
699
+ fileName: linkFileName,
675
700
  alreadyExists: true,
676
701
  }
677
702
  }
678
703
 
679
- const linkFileName = parsed.fileName
704
+ this.#assertDisplayNameAvailable(linkFileName, {
705
+ ownerAddress,
706
+ excludeCid: cidString,
707
+ })
680
708
 
681
709
  if (taskState.aborted) throw new Error('Download cancelled')
682
710
 
@@ -924,11 +952,14 @@ export class MostBoxEngine extends EventEmitter {
924
952
  const existingIndex = this.#publishedFiles.findIndex(
925
953
  f => f.cid === cidString && this.#recordMatchesOwner(f, ownerAddress)
926
954
  )
955
+ this.#assertDisplayNameAvailable(sanitizedFileName, {
956
+ ownerAddress,
957
+ excludeCid: cidString,
958
+ })
927
959
  if (existingIndex !== -1) {
928
960
  const existing = this.#publishedFiles[existingIndex]
929
- if (existing.fileName !== sanitizedFileName) {
930
- throw new Error(`文件已存在: ${existing.fileName}`)
931
- }
961
+ existing.fileName = sanitizedFileName
962
+ existing.driveName = name
932
963
  existing.publishedAt = new Date().toISOString()
933
964
  } else {
934
965
  this.#publishedFiles.push({
@@ -959,6 +990,35 @@ export class MostBoxEngine extends EventEmitter {
959
990
  }
960
991
  }
961
992
 
993
+ /**
994
+ * 快速检查 most:// 链接对应的 CID 内容是否已在本机可读。
995
+ */
996
+ async getLocalCidAvailability(link, options = {}) {
997
+ this.#ensureInitialized()
998
+ const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
999
+ const parsed = parseMostLink(link)
1000
+ if (parsed.error) {
1001
+ throw new ValidationError(parsed.error)
1002
+ }
1003
+
1004
+ const localContent = await this.#getLocalCidContent(parsed.cid, {
1005
+ ownerAddress,
1006
+ public: true,
1007
+ allowHoldingFallback: true,
1008
+ })
1009
+ if (!localContent) {
1010
+ return null
1011
+ }
1012
+
1013
+ return {
1014
+ available: true,
1015
+ cid: parsed.cid,
1016
+ fileName: sanitizeFilename(parsed.fileName),
1017
+ size: localContent.size,
1018
+ alreadyExists: true,
1019
+ }
1020
+ }
1021
+
962
1022
  /**
963
1023
  * 检测 most:// 链接当前是否能找到可下载内容,但不读取文件内容。
964
1024
  * @param {string} link - most:// 链接
@@ -978,15 +1038,17 @@ export class MostBoxEngine extends EventEmitter {
978
1038
 
979
1039
  const cidString = parsed.cid
980
1040
  const { driveName: name } = this.#getCidInfo(cidString)
981
- const existingFile = this.#publishedFiles.find(
982
- f => f.cid === cidString && this.#recordMatchesOwner(f, ownerAddress)
983
- )
984
- if (existingFile) {
1041
+ const localContent = await this.#getLocalCidContent(cidString, {
1042
+ ownerAddress,
1043
+ public: true,
1044
+ allowHoldingFallback: true,
1045
+ })
1046
+ if (localContent) {
985
1047
  return {
986
1048
  available: true,
987
1049
  cid: cidString,
988
- fileName: existingFile.fileName,
989
- size: Number(existingFile.size) || null,
1050
+ fileName: sanitizeFilename(parsed.fileName),
1051
+ size: localContent.size,
990
1052
  alreadyExists: true,
991
1053
  }
992
1054
  }
@@ -1172,6 +1234,20 @@ export class MostBoxEngine extends EventEmitter {
1172
1234
 
1173
1235
  const { driveName } = this.#getCidInfo(fileRecord.cid)
1174
1236
 
1237
+ const existingIndex = this.#publishedFiles.findIndex(
1238
+ f => f.cid === fileRecord.cid && this.#recordMatchesOwner(f, ownerAddress)
1239
+ )
1240
+ if (existingIndex !== -1) {
1241
+ this.#trashFiles.splice(index, 1)
1242
+ this.#saveTrashMetadata()
1243
+ return this.listPublishedFiles({ ownerAddress })
1244
+ }
1245
+
1246
+ this.#assertDisplayNameAvailable(fileRecord.fileName, {
1247
+ ownerAddress,
1248
+ excludeCid: fileRecord.cid,
1249
+ })
1250
+
1175
1251
  this.#publishedFiles.push({
1176
1252
  fileName: fileRecord.fileName,
1177
1253
  cid: fileRecord.cid,
@@ -1361,6 +1437,10 @@ export class MostBoxEngine extends EventEmitter {
1361
1437
  throw new Error('File not found')
1362
1438
  }
1363
1439
  const safeFileName = sanitizeFilename(newFileName)
1440
+ this.#assertDisplayNameAvailable(safeFileName, {
1441
+ ownerAddress,
1442
+ excludeCid: cid,
1443
+ })
1364
1444
  this.#publishedFiles[index].fileName = safeFileName
1365
1445
  this.#publishedFiles[index].publishedAt = new Date().toISOString()
1366
1446
  this.#savePublishedMetadata()
@@ -1382,7 +1462,7 @@ export class MostBoxEngine extends EventEmitter {
1382
1462
  this.#ensureInitialized()
1383
1463
  const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1384
1464
  const prefix = oldPath + '/'
1385
- const updatedFiles = []
1465
+ const updates = []
1386
1466
 
1387
1467
  for (const file of this.#publishedFiles) {
1388
1468
  if (
@@ -1393,16 +1473,27 @@ export class MostBoxEngine extends EventEmitter {
1393
1473
  const newFileName = sanitizeFilename(
1394
1474
  remainder ? newPath + '/' + remainder : newPath
1395
1475
  )
1396
- file.fileName = newFileName
1397
- file.publishedAt = new Date().toISOString()
1398
- updatedFiles.push({
1399
- cid: file.cid,
1400
- fileName: file.fileName,
1401
- link: `most://${file.cid}?filename=${encodeURIComponent(file.fileName)}`,
1402
- })
1476
+ updates.push({ file, newFileName })
1403
1477
  }
1404
1478
  }
1405
1479
 
1480
+ for (const { file, newFileName } of updates) {
1481
+ this.#assertDisplayNameAvailable(newFileName, {
1482
+ ownerAddress,
1483
+ excludeCid: file.cid,
1484
+ })
1485
+ }
1486
+
1487
+ const updatedFiles = updates.map(({ file, newFileName }) => {
1488
+ file.fileName = newFileName
1489
+ file.publishedAt = new Date().toISOString()
1490
+ return {
1491
+ cid: file.cid,
1492
+ fileName: file.fileName,
1493
+ link: `most://${file.cid}?filename=${encodeURIComponent(file.fileName)}`,
1494
+ }
1495
+ })
1496
+
1406
1497
  if (updatedFiles.length > 0) {
1407
1498
  this.#savePublishedMetadata()
1408
1499
  }
@@ -1678,28 +1769,23 @@ export class MostBoxEngine extends EventEmitter {
1678
1769
  options = {}
1679
1770
  ) {
1680
1771
  this.#ensureInitialized()
1772
+ if (typeof offset === 'object' && offset !== null) {
1773
+ options = offset
1774
+ offset = 0
1775
+ limit = DEFAULT_READ_LIMIT
1776
+ }
1681
1777
  const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1682
1778
 
1683
- const fileRecord = this.#publishedFiles.find(
1684
- f =>
1685
- f.cid === cid &&
1686
- (options.public || this.#recordMatchesOwner(f, ownerAddress))
1687
- )
1688
- if (!fileRecord) {
1779
+ const localContent = await this.#getLocalCidContent(cid, {
1780
+ ownerAddress,
1781
+ public: options.public,
1782
+ })
1783
+ if (!localContent) {
1689
1784
  throw new Error('File not found')
1690
1785
  }
1691
1786
 
1692
- const drive = await this.#getDriveForFile(fileRecord)
1693
-
1694
- // Hyperdrive 中 key 为 '/' + cid
1695
1787
  const driveKey = '/' + cid
1696
- const entry = await drive.entry(driveKey, {
1697
- wait: true,
1698
- timeout: DRIVE_ENTRY_TIMEOUT,
1699
- })
1700
- if (!entry || !entry.value) {
1701
- throw new Error('File content not available')
1702
- }
1788
+ const { drive } = localContent
1703
1789
 
1704
1790
  const chunks = []
1705
1791
  const stream = drive.createReadStream(driveKey, {
@@ -1743,25 +1829,16 @@ export class MostBoxEngine extends EventEmitter {
1743
1829
  this.#ensureInitialized()
1744
1830
  const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1745
1831
 
1746
- const fileRecord = this.#publishedFiles.find(
1747
- f =>
1748
- f.cid === cid &&
1749
- (options.public || this.#recordMatchesOwner(f, ownerAddress))
1750
- )
1751
- if (!fileRecord) {
1832
+ const localContent = await this.#getLocalCidContent(cid, {
1833
+ ownerAddress,
1834
+ public: options.public,
1835
+ })
1836
+ if (!localContent) {
1752
1837
  throw new Error('File not found')
1753
1838
  }
1754
1839
 
1755
- const drive = await this.#getDriveForFile(fileRecord)
1756
-
1757
1840
  const driveKey = '/' + cid
1758
- const entry = await drive.entry(driveKey, {
1759
- wait: true,
1760
- timeout: DRIVE_ENTRY_TIMEOUT,
1761
- })
1762
- if (!entry || !entry.value || !entry.value.blob) {
1763
- throw new Error('File content not available')
1764
- }
1841
+ const { drive, entry, fileRecord } = localContent
1765
1842
 
1766
1843
  const totalSize = entry.value.blob.byteLength || 0
1767
1844
 
@@ -1808,19 +1885,63 @@ export class MostBoxEngine extends EventEmitter {
1808
1885
  return { buffer, fileName: fileRecord.fileName, totalSize }
1809
1886
  }
1810
1887
 
1811
- /**
1812
- * 获取文件对应的 drive,如果不存在则创建并同步
1813
- */
1814
- async #getDriveForFile(fileRecord) {
1815
- let drive = this.#drives.get(fileRecord.driveName)
1816
- if (!drive) {
1817
- drive = await this.#getOrCreateDrive(fileRecord.driveName, {
1818
- server: true,
1819
- client: true,
1820
- })
1888
+ async #hasLocalDriveContent(drive, key) {
1889
+ try {
1890
+ return await drive.has(key)
1891
+ } catch {
1892
+ return false
1893
+ }
1894
+ }
1895
+
1896
+ async #getLocalCidContent(cid, options = {}) {
1897
+ const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
1898
+ const fileRecord = this.#publishedFiles.find(
1899
+ f =>
1900
+ f.cid === cid &&
1901
+ (options.public || this.#recordMatchesOwner(f, ownerAddress))
1902
+ )
1903
+ if (!options.allowHoldingFallback && !fileRecord) {
1904
+ return null
1905
+ }
1906
+ const holding = this.#holdings.find(item => item.cid === cid)
1907
+ const { driveName } = this.#getCidInfo(cid)
1908
+ const drive = await this.#getOrCreateDrive(
1909
+ fileRecord?.driveName || holding?.driveName || driveName,
1910
+ { server: true, client: false }
1911
+ )
1912
+ const driveKey = '/' + cid
1913
+
1914
+ try {
1915
+ const entry = await drive.entry(driveKey, { wait: false })
1916
+ if (!entry?.value?.blob) {
1917
+ return null
1918
+ }
1919
+ const hasContent = await this.#hasLocalDriveContent(drive, driveKey)
1920
+ if (!hasContent) {
1921
+ return null
1922
+ }
1923
+
1924
+ const size =
1925
+ Number(entry.value.blob.byteLength) ||
1926
+ Number(fileRecord?.size) ||
1927
+ Number(holding?.size) ||
1928
+ 0
1929
+ return {
1930
+ drive,
1931
+ entry,
1932
+ size,
1933
+ fileRecord: fileRecord || {
1934
+ cid,
1935
+ fileName: holding?.fileName || cid,
1936
+ driveName: holding?.driveName || driveName,
1937
+ localPath: holding?.localPath || null,
1938
+ size,
1939
+ ownerAddress,
1940
+ },
1941
+ }
1942
+ } catch {
1943
+ return null
1821
1944
  }
1822
- await this.#syncDrive(drive)
1823
- return drive
1824
1945
  }
1825
1946
 
1826
1947
  // --- 频道管理 ---
@@ -2180,7 +2301,11 @@ export class MostBoxEngine extends EventEmitter {
2180
2301
  const start = Math.max(0, total - offset - limit)
2181
2302
  const end = total - offset
2182
2303
 
2183
- return unique.slice(start, end).map(({ _coreKey, _index, ...msg }) => msg)
2304
+ return unique
2305
+ .slice(start, end)
2306
+ .map(({ _coreKey, _index, ...msg }) =>
2307
+ this.#normalizeChannelMessageForResponse(name, msg)
2308
+ )
2184
2309
  }
2185
2310
 
2186
2311
  /**
@@ -2312,6 +2437,44 @@ export class MostBoxEngine extends EventEmitter {
2312
2437
  }
2313
2438
  }
2314
2439
 
2440
+ #normalizeChannelMessageForResponse(channelName, message) {
2441
+ const attachment = message?.attachment
2442
+ if (!attachment?.cid || !attachment.fileName) {
2443
+ return message
2444
+ }
2445
+
2446
+ const oldFileName = sanitizeFilename(String(attachment.fileName))
2447
+ const channelPrefix = `${CHAT_FILE_ROOT}/${channelName}/`
2448
+ const fileName = oldFileName.startsWith(channelPrefix)
2449
+ ? oldFileName
2450
+ : `${channelPrefix}${getPathBaseName(oldFileName)}`
2451
+ const link = buildMostLink(attachment.cid, fileName)
2452
+ const content =
2453
+ typeof message.content === 'string' &&
2454
+ (message.content === attachment.link ||
2455
+ parseMostLink(message.content).cid === attachment.cid)
2456
+ ? link
2457
+ : message.content
2458
+
2459
+ if (
2460
+ fileName === attachment.fileName &&
2461
+ link === attachment.link &&
2462
+ content === message.content
2463
+ ) {
2464
+ return message
2465
+ }
2466
+
2467
+ return {
2468
+ ...message,
2469
+ content,
2470
+ attachment: {
2471
+ ...attachment,
2472
+ fileName,
2473
+ link,
2474
+ },
2475
+ }
2476
+ }
2477
+
2315
2478
  #getCidInfo(cid) {
2316
2479
  return getCidInfo(cid)
2317
2480
  }
@@ -2692,6 +2855,31 @@ export class MostBoxEngine extends EventEmitter {
2692
2855
  return normalizeOwnerAddress(record.ownerAddress) === normalizedOwner
2693
2856
  }
2694
2857
 
2858
+ #assertDisplayNameAvailable(fileName, options = {}) {
2859
+ const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
2860
+ const safeFileName = sanitizeFilename(fileName)
2861
+ const folder = getDisplayPathFolder(safeFileName)
2862
+ const baseName = getPathBaseName(safeFileName)
2863
+ const conflict = this.#publishedFiles.find(file => {
2864
+ if (
2865
+ options.excludeCid &&
2866
+ file.cid === options.excludeCid &&
2867
+ this.#recordMatchesOwner(file, ownerAddress)
2868
+ ) {
2869
+ return false
2870
+ }
2871
+ if (!this.#recordMatchesOwner(file, ownerAddress)) return false
2872
+ const existingFileName = sanitizeFilename(file.fileName)
2873
+ return (
2874
+ getDisplayPathFolder(existingFileName) === folder &&
2875
+ getPathBaseName(existingFileName) === baseName
2876
+ )
2877
+ })
2878
+ if (conflict) {
2879
+ throw new ConflictError(`已有同名文件: ${safeFileName}`)
2880
+ }
2881
+ }
2882
+
2695
2883
  #hasPublishedReference(cid) {
2696
2884
  return this.#publishedFiles.some(file => file.cid === cid)
2697
2885
  }
@@ -2740,20 +2928,6 @@ export class MostBoxEngine extends EventEmitter {
2740
2928
  }
2741
2929
  }
2742
2930
 
2743
- async #syncDrive(drive, timeout = DRIVE_SYNC_TIMEOUT) {
2744
- try {
2745
- const updated = await Promise.race([
2746
- drive.update(),
2747
- new Promise((_, reject) =>
2748
- setTimeout(() => reject(new Error('Sync timeout')), timeout)
2749
- ),
2750
- ])
2751
- return updated
2752
- } catch {
2753
- return false
2754
- }
2755
- }
2756
-
2757
2931
  #getMetadataPath() {
2758
2932
  return path.join(this.#options.dataPath, 'published-files.json')
2759
2933
  }
@@ -2911,7 +3085,10 @@ export class MostBoxEngine extends EventEmitter {
2911
3085
  if (entry && entry.type === 'message') {
2912
3086
  this.emit('channel:message', {
2913
3087
  channel: channelName,
2914
- message: entry,
3088
+ message: this.#normalizeChannelMessageForResponse(
3089
+ channelName,
3090
+ entry
3091
+ ),
2915
3092
  })
2916
3093
  }
2917
3094
  } catch (err) {
@@ -1,8 +1,9 @@
1
1
  import { createAvatar } from '@dicebear/core'
2
2
  import { botttsNeutral } from '@dicebear/collection'
3
3
 
4
- export function generateAvatar(address) {
5
- if (!address) return '/pwa-512x512.png'
4
+ export function generateAvatar(address, avatar) {
5
+ if (avatar) return avatar
6
+ if (!address) return '/avatar.png'
6
7
  return createAvatar(botttsNeutral, {
7
8
  seed: 'most.box@' + address,
8
9
  flip: true,
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,96699,e=>{"use strict";let t=(0,e.i(56420).default)("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"}]]);e.s(["Moon",0,t],96699)},35965,e=>{"use strict";let t=(0,e.i(56420).default)("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"}]]);e.s(["Sun",0,t],35965)},31214,e=>{"use strict";let t=(0,e.i(56420).default)("cloud",[["path",{d:"M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z",key:"p7xjir"}]]);e.s(["Cloud",0,t],31214)},51921,e=>{"use strict";let t=(0,e.i(56420).default)("music",[["path",{d:"M9 18V5l12-2v13",key:"1jmyc2"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["circle",{cx:"18",cy:"16",r:"3",key:"1hluhg"}]]);e.s(["Music",0,t],51921)},30274,e=>{"use strict";let t=(0,e.i(56420).default)("send",[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]]);e.s(["Send",0,t],30274)},21357,e=>{"use strict";let t=(0,e.i(56420).default)("play",[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]]);e.s(["Play",0,t],21357)},66595,e=>{"use strict";let t=(0,e.i(56420).default)("search",[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]]);e.s(["Search",0,t],66595)},66627,e=>{"use strict";let t=(0,e.i(56420).default)("wifi",[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]]);e.s(["Wifi",0,t],66627)},68590,e=>{"use strict";let t=(0,e.i(56420).default)("message-square",[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]]);e.s(["MessageSquare",0,t],68590)},40983,e=>{"use strict";var t=e.i(18050),n=e.i(71645),i=e.i(22016),r=e.i(96699),a=e.i(35965);function l({size:e=24}){return(0,t.jsxs)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[(0,t.jsx)("rect",{x:"2",y:"2",width:"8",height:"8",rx:"2",fill:"var(--accent)",opacity:"0.4"}),(0,t.jsx)("rect",{x:"14",y:"2",width:"8",height:"8",rx:"2",fill:"var(--accent)",opacity:"0.7"}),(0,t.jsx)("rect",{x:"2",y:"14",width:"8",height:"8",rx:"2",fill:"var(--accent)",opacity:"0.7"}),(0,t.jsx)("rect",{x:"14",y:"14",width:"8",height:"8",rx:"2",fill:"var(--accent)"})]})}function s(){let[e,s]=(0,n.useState)(!1);return(0,n.useEffect)(()=>{let e=localStorage.getItem("theme"),t=window.matchMedia("(prefers-color-scheme: dark)").matches;("dark"===e||!e&&t)&&s(!0)},[]),(0,n.useEffect)(()=>{document.documentElement.setAttribute("data-theme",e?"dark":"light"),localStorage.setItem("theme",e?"dark":"light")},[e]),(0,t.jsx)(t.Fragment,{children:(0,t.jsx)("nav",{className:"mkt-nav",children:(0,t.jsxs)("div",{className:"mkt-nav-inner",children:[(0,t.jsxs)(i.default,{href:"/",className:"mkt-nav-logo",children:[(0,t.jsx)(l,{}),"MOST PEOPLE"]}),(0,t.jsxs)("div",{className:"mkt-nav-cta",children:[(0,t.jsx)("button",{className:"mkt-theme-toggle",onClick:()=>s(!e),"aria-label":"切换主题",children:e?(0,t.jsx)(a.Sun,{size:16}):(0,t.jsx)(r.Moon,{size:16})}),(0,t.jsx)(i.default,{href:"/app/",className:"btn btn-primary",children:"开始使用"})]})]})})})}let o=[{href:"/",label:"关于"},{href:"/ping/",label:"网络"},{href:"https://github.com/most-people/most",label:"GitHub",external:!0}];function c(){return(0,t.jsx)("footer",{className:"mkt-footer",children:(0,t.jsx)("div",{className:"mkt-container",children:(0,t.jsxs)("div",{className:"mkt-footer-inner",children:[(0,t.jsx)("div",{className:"mkt-footer-links",children:o.map(e=>(0,t.jsx)(i.default,{href:e.href,...e.external?{target:"_blank",rel:"noopener noreferrer"}:{},children:e.label},e.href))}),(0,t.jsxs)("span",{className:"mkt-footer-copy",children:["© ",new Date().getFullYear()," MOST PEOPLE · MIT License"]})]})})})}e.s(["MarketingLayout",0,function({children:e}){return(0,t.jsxs)("div",{className:"mkt-layout",children:[(0,t.jsx)(s,{}),(0,t.jsx)("main",{className:"mkt-layout-main",children:e}),(0,t.jsx)(c,{})]})}],40983)},23449,e=>{"use strict";let t;var n,i=e.i(18050),r=e.i(71645);let a=Object.freeze({left:0,top:0,width:16,height:16}),l=Object.freeze({rotate:0,vFlip:!1,hFlip:!1}),s=Object.freeze({...a,...l}),o=Object.freeze({...s,body:"",hidden:!1});function c(e,t){let n,i,r=(n={},!e.hFlip!=!t.hFlip&&(n.hFlip=!0),!e.vFlip!=!t.vFlip&&(n.vFlip=!0),(i=((e.rotate||0)+(t.rotate||0))%4)&&(n.rotate=i),n);for(let n in o)n in l?n in e&&!(n in r)&&(r[n]=l[n]):n in t?r[n]=t[n]:n in e&&(r[n]=e[n]);return r}function u(e,t){let n,i,r,a=[];if("object"!=typeof e||"object"!=typeof e.icons)return a;e.not_found instanceof Array&&e.not_found.forEach(e=>{t(e,null),a.push(e)});let l=(n=e.icons,i=e.aliases||Object.create(null),r=Object.create(null),Object.keys(n).concat(Object.keys(i)).forEach(function e(t){if(n[t])return r[t]=[];if(!(t in r)){r[t]=null;let n=i[t]&&i[t].parent,a=n&&e(n);a&&(r[t]=[n].concat(a))}return r[t]}),r);for(let n in l){let i=l[n];i&&(t(n,function(e,t,n){let i=e.icons,r=e.aliases||Object.create(null),a={};function l(e){a=c(i[e]||r[e],a)}return l(t),n.forEach(l),c(e,a)}(e,n,i)),a.push(n))}return a}let f={provider:"",aliases:{},not_found:{},...a};function d(e,t){for(let n in t)if(n in e&&typeof e[n]!=typeof t[n])return!1;return!0}function h(e){if("object"!=typeof e||null===e||"string"!=typeof e.prefix||!e.icons||"object"!=typeof e.icons||!d(e,f))return null;let t=e.icons;for(let e in t){let n=t[e];if(!e||"string"!=typeof n.body||!d(n,o))return null}let n=e.aliases||Object.create(null);for(let e in n){let i=n[e],r=i.parent;if(!e||"string"!=typeof r||!t[r]&&!n[r]||!d(i,o))return null}return e}let p=Object.create(null);function g(e,t){let n=p[e]||(p[e]=Object.create(null));return n[t]||(n[t]={provider:e,prefix:t,icons:Object.create(null),missing:new Set})}function m(e,t){return h(t)?u(t,(t,n)=>{n?e.icons[t]=n:e.missing.add(t)}):[]}let y=/^[a-z0-9]+(-[a-z0-9]+)*$/,x=(e,t,n,i="")=>{let r=e.split(":");if("@"===e.slice(0,1)){if(r.length<2||r.length>3)return null;i=r.shift().slice(1)}if(r.length>3||!r.length)return null;if(r.length>1){let e=r.pop(),n=r.pop(),a={provider:r.length>0?r[0]:i,prefix:n,name:e};return t&&!b(a)?null:a}let a=r[0],l=a.split("-");if(l.length>1){let e={provider:i,prefix:l.shift(),name:l.join("-")};return t&&!b(e)?null:e}if(n&&""===i){let e={provider:i,prefix:"",name:a};return t&&!b(e,n)?null:e}return null},b=(e,t)=>!!e&&!!((t&&""===e.prefix||e.prefix)&&e.name),k=!1;function v(e){return"boolean"==typeof e&&(k=e),k}function j(e){let t="string"==typeof e?x(e,!0,k):e;if(t){let e=g(t.provider,t.prefix),n=t.name;return e.icons[n]||(e.missing.has(n)?null:void 0)}}let w=Object.freeze({width:null,height:null}),M=Object.freeze({...w,...l}),E=/(-?[0-9.]*[0-9]+[0-9.]*)/g,N=/^-?[0-9.]*[0-9]+[0-9.]*$/g;function S(e,t,n){if(1===t)return e;if(n=n||100,"number"==typeof e)return Math.ceil(e*t*n)/n;if("string"!=typeof e)return e;let i=e.split(E);if(null===i||!i.length)return e;let r=[],a=i.shift(),l=N.test(a);for(;;){if(l){let e=parseFloat(a);isNaN(e)?r.push(a):r.push(Math.ceil(e*t*n)/n)}else r.push(a);if(void 0===(a=i.shift()))return r.join("");l=!l}}let z=/\sid="(\S+)"/g,T="IconifyId"+Date.now().toString(16)+(0x1000000*Math.random()|0).toString(16),O=0,C=Object.create(null);function F(e){return C[e]||C[""]}function A(e){let t;if("string"==typeof e.resources)t=[e.resources];else if(!((t=e.resources)instanceof Array)||!t.length)return null;return{resources:t,path:e.path||"/",maxURL:e.maxURL||500,rotate:e.rotate||750,timeout:e.timeout||5e3,random:!0===e.random,index:e.index||0,dataAfterTimeout:!1!==e.dataAfterTimeout}}let I=Object.create(null),L=["https://api.simplesvg.com","https://api.unisvg.com"],P=[];for(;L.length>0;)1===L.length||Math.random()>.5?P.push(L.shift()):P.push(L.pop());I[""]=A({resources:["https://api.iconify.design"].concat(P)});let $=(()=>{let e;try{if(e=fetch,"function"==typeof e)return e}catch(e){}})();function H(e,t){e.forEach(e=>{let n=e.loaderCallbacks;n&&(e.loaderCallbacks=n.filter(e=>e.id!==t))})}let R=0,q={resources:[],index:0,timeout:2e3,rotate:750,random:!1,dataAfterTimeout:!1};function _(e){let t={...q,...e},n=[];function i(){n=n.filter(e=>"pending"===e().status)}return{query:function(e,r,a){let l=function(e,t,n,i){let r,a,l=e.resources.length,s=e.random?Math.floor(Math.random()*l):e.index;if(e.random){let t=e.resources.slice(0);for(r=[];t.length>1;){let e=Math.floor(Math.random()*t.length);r.push(t[e]),t=t.slice(0,e).concat(t.slice(e+1))}r=r.concat(t)}else r=e.resources.slice(s).concat(e.resources.slice(0,s));let o=Date.now(),c="pending",u=0,f=null,d=[],h=[];function p(){f&&(clearTimeout(f),f=null)}function g(){"pending"===c&&(c="aborted"),p(),d.forEach(e=>{"pending"===e.status&&(e.status="aborted")}),d=[]}function m(e,t){t&&(h=[]),"function"==typeof e&&h.push(e)}function y(){c="failed",h.forEach(e=>{e(void 0,a)})}function x(){d.forEach(e=>{"pending"===e.status&&(e.status="aborted")}),d=[]}return"function"==typeof i&&h.push(i),setTimeout(function i(){if("pending"!==c)return;p();let l=r.shift();if(void 0===l){if(d.length){f=setTimeout(()=>{p(),"pending"===c&&(x(),y())},e.timeout);return}y();return}let s={status:"pending",resource:l,callback:(t,n)=>{!function(t,n,l){let s="success"!==n;switch(d=d.filter(e=>e!==t),c){case"pending":break;case"failed":if(s||!e.dataAfterTimeout)return;break;default:return}if("abort"===n){a=l,y();return}if(s){a=l,d.length||(r.length?i():y());return}if(p(),x(),!e.random){let n=e.resources.indexOf(t.resource);-1!==n&&n!==e.index&&(e.index=n)}c="completed",h.forEach(e=>{e(l)})}(s,t,n)}};d.push(s),u++,f=setTimeout(i,e.rotate),n(l,t,s.callback)}),function(){return{startTime:o,payload:t,status:c,queriesSent:u,queriesPending:d.length,subscribe:m,abort:g}}}(t,e,r,(e,t)=>{i(),a&&a(e,t)});return n.push(l),l},find:function(e){return n.find(t=>e(t))||null},setIndex:e=>{t.index=e},getIndex:()=>t.index,cleanup:i}}let V=Object.create(null);function D(){}function U(e,t,n){function i(){let n=e.pendingIcons;t.forEach(t=>{n&&n.delete(t),e.icons[t]||e.missing.add(t)})}if(n&&"object"==typeof n)try{if(!m(e,n).length)return void i()}catch(e){console.error(e)}i(),e.iconsLoaderFlag||(e.iconsLoaderFlag=!0,setTimeout(()=>{e.iconsLoaderFlag=!1,e.pendingCallbacksFlag||(e.pendingCallbacksFlag=!0,setTimeout(()=>{e.pendingCallbacksFlag=!1;let t=e.loaderCallbacks?e.loaderCallbacks.slice(0):[];if(!t.length)return;let n=!1,i=e.provider,r=e.prefix;t.forEach(t=>{let a=t.icons,l=a.pending.length;a.pending=a.pending.filter(t=>{if(t.prefix!==r)return!0;let l=t.name;if(e.icons[l])a.loaded.push({provider:i,prefix:r,name:l});else{if(!e.missing.has(l))return n=!0,!0;a.missing.push({provider:i,prefix:r,name:l})}return!1}),a.pending.length!==l&&(n||H([e],t.id),t.callback(a.loaded.slice(0),a.missing.slice(0),a.pending.slice(0),t.abort))})}))}))}function B(e,t){e instanceof Promise?e.then(e=>{t(e)}).catch(()=>{t(null)}):t(e)}let G=/[\s,]+/,W={...M,inline:!1},Q={xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink","aria-hidden":!0,role:"img"},J={display:"inline-block"},K={backgroundColor:"currentColor"},X={backgroundColor:"transparent"},Y={Image:"var(--svg)",Repeat:"no-repeat",Size:"100% 100%"},Z={WebkitMask:K,mask:K,background:X};for(let e in Z){let t=Z[e];for(let n in Y)t[e+n]=Y[n]}let ee={...W,inline:!0};function et(e){return e+(e.match(/^[-0-9.]+$/)?"px":"")}if(v(!0),n={prepare:(e,t,n)=>{let i=[],r=function(e,t){let n,i=I[e];if(!i)return 0;if(i.maxURL){let e=0;i.resources.forEach(t=>{e=Math.max(e,t.length)}),n=i.maxURL-e-i.path.length-(t+".json?icons=").length}else n=0;return n}(e,t),a="icons",l={type:a,provider:e,prefix:t,icons:[]},s=0;return n.forEach((n,o)=>{(s+=n.length+1)>=r&&o>0&&(i.push(l),l={type:a,provider:e,prefix:t,icons:[]},s=n.length),l.icons.push(n)}),i.push(l),i},send:(e,t,n)=>{if(!$)return void n("abort",424);let i=function(e){if("string"==typeof e){let t=I[e];if(t)return t.path}return"/"}(t.provider);switch(t.type){case"icons":i+=t.prefix+".json?"+new URLSearchParams({icons:t.icons.join(",")}).toString();break;case"custom":{let e=t.uri;i+="/"===e.slice(0,1)?e.slice(1):e;break}default:n("abort",400);return}let r=503;$(e+i).then(e=>{let t=e.status;return 200!==t?void setTimeout(()=>{n(404===t?"abort":"next",t)}):(r=501,e.json())}).then(e=>{"object"!=typeof e||null===e?setTimeout(()=>{404===e?n("abort",e):n("next",r)}):setTimeout(()=>{n("success",e)})}).catch(()=>{n("next",r)})}},C[""]=n,"u">typeof document&&"u">typeof window){let e=window;if(void 0!==e.IconifyPreload){let t=e.IconifyPreload,n="Invalid IconifyPreload syntax.";"object"==typeof t&&null!==t&&(t instanceof Array?t:[t]).forEach(e=>{try{("object"!=typeof e||null===e||e instanceof Array||"object"!=typeof e.icons||"string"!=typeof e.prefix||!function(e,t){if("object"!=typeof e)return!1;if("string"!=typeof t&&(t=e.provider||""),k&&!t&&!e.prefix){let t=!1;return h(e)&&(e.prefix="",u(e,(e,n)=>{(function(e,t){let n=x(e,!0,k);if(!n)return!1;let i=g(n.provider,n.prefix);if(!t)return i.missing.add(n.name),!0;var r=n.name;try{if("string"==typeof t.body)return i.icons[r]={...t},!0}catch(e){}return!1})(e,n)&&(t=!0)})),t}let n=e.prefix;return!!b({prefix:n,name:"a"})&&!!m(g(t,n),e)}(e))&&console.error(n)}catch(e){console.error(n)}})}if(void 0!==e.IconifyProviders){let t=e.IconifyProviders;if("object"==typeof t&&null!==t)for(let e in t){let n="IconifyProviders["+e+"] is invalid.";try{let i=t[e];if("object"!=typeof i||!i||void 0===i.resources)continue;!function(e,t){let n=A(t);return null!==n&&(I[e]=n,!0)}(e,i)&&console.error(n)}catch(e){console.error(n)}}}}function en(e){let[n,i]=(0,r.useState)(!!e.ssr),[a,l]=(0,r.useState)({}),[o,c]=(0,r.useState)(function(t){if(t){let t=e.icon;if("object"==typeof t)return{name:"",data:t};let n=j(t);if(n)return{name:t,data:n}}return{name:""}}(!!e.ssr));function u(){let e=a.callback;e&&(e(),l({}))}function f(e){if(JSON.stringify(o)!==JSON.stringify(e))return u(),c(e),!0}(0,r.useEffect)(()=>(i(!0),u),[]),(0,r.useEffect)(()=>{n&&function t(){var n;let i=e.icon;if("object"==typeof i)return void f({name:"",data:i});let r=j(i);f({name:i,data:r})&&(void 0===r?l({callback:((e,t)=>{var n;let i,r,a,l,s,o=(n=function(e,t=!0,n=!1){let i=[];return e.forEach(e=>{let r="string"==typeof e?x(e,t,n):e;r&&i.push(r)}),i}(e,!0,v()),a={loaded:[],missing:[],pending:[]},l=Object.create(null),n.sort((e,t)=>e.provider!==t.provider?e.provider.localeCompare(t.provider):e.prefix!==t.prefix?e.prefix.localeCompare(t.prefix):e.name.localeCompare(t.name)),s={provider:"",prefix:"",name:""},n.forEach(e=>{if(s.name===e.name&&s.prefix===e.prefix&&s.provider===e.provider)return;s=e;let t=e.provider,n=e.prefix,i=e.name,r=l[t]||(l[t]=Object.create(null)),o=r[n]||(r[n]=g(t,n));(i in o.icons?a.loaded:""===n||o.missing.has(i)?a.missing:a.pending).push({provider:t,prefix:n,name:i})}),a);if(!o.pending.length){let e=!0;return t&&setTimeout(()=>{e&&t(o.loaded,o.missing,o.pending,D)}),()=>{e=!1}}let c=Object.create(null),u=[];return o.pending.forEach(e=>{let{provider:t,prefix:n}=e;if(n===r&&t===i)return;i=t,r=n,u.push(g(t,n));let a=c[t]||(c[t]=Object.create(null));a[n]||(a[n]=[])}),o.pending.forEach(e=>{let{provider:t,prefix:n,name:i}=e,r=g(t,n),a=r.pendingIcons||(r.pendingIcons=new Set);a.has(i)||(a.add(i),c[t][n].push(i))}),u.forEach(e=>{let t=c[e.provider][e.prefix];t.length&&(e.iconsToLoad?e.iconsToLoad=e.iconsToLoad.concat(t).sort():e.iconsToLoad=t,e.iconsQueueFlag||(e.iconsQueueFlag=!0,setTimeout(()=>{let t,n;e.iconsQueueFlag=!1;let{provider:i,prefix:r}=e,a=e.iconsToLoad;if(delete e.iconsToLoad,!a||!a.length)return;let l=e.loadIcon;if(e.loadIcons&&(a.length>1||!l))return void B(e.loadIcons(a,r,i),t=>{U(e,a,t)});if(l)return void a.forEach(t=>{B(l(t,r,i),n=>{let i=n?{prefix:r,icons:{[t]:n}}:null;U(e,[t],i)})});let{valid:s,invalid:o}=(t=[],n=[],a.forEach(e=>{(e.match(y)?t:n).push(e)}),{valid:t,invalid:n});if(o.length&&U(e,o,null),!s.length)return;let c=r.match(y)?F(i):null;c?c.prepare(i,r,s).forEach(t=>{!function(e,t,n){let i,r;if("string"==typeof e){let t=F(e);if(!t)return n(void 0,424);r=t.send;let a=function(e){if(!V[e]){let t=I[e];if(!t)return;let n=_(t);V[e]={config:t,redundancy:n}}return V[e]}(e);a&&(i=a.redundancy)}else{let t=A(e);if(t){i=_(t);let n=F(e.resources?e.resources[0]:"");n&&(r=n.send)}}i&&r?i.query(t,r,n)().abort:n(void 0,424)}(i,t,n=>{U(e,t.icons,n)})}):U(e,s,null)})))}),t?function(e,t,n){let i=R++,r=H.bind(null,n,i);if(!t.pending.length)return r;let a={id:i,icons:t,callback:e,abort:r};return n.forEach(e=>{(e.loaderCallbacks||(e.loaderCallbacks=[])).push(a)}),r}(t,o,u):D})([i],t)}):r&&(null==(n=e.onLoad)||n.call(e,i)))}()},[e.icon,n]);let{name:d,data:h}=o;return h?((e,n,i)=>{var a;let l,o,c,u,f,d,h,p,g,m,y,b,k,v=n.inline?ee:W,j=function(e,t){let n={...e};for(let e in t){let i=t[e],r=typeof i;e in w?(null===i||i&&("string"===r||"number"===r))&&(n[e]=i):r===typeof n[e]&&(n[e]="rotate"===e?i%4:i)}return n}(v,n),E=n.mode||"svg",N={},C=n.style||{},F={..."svg"===E?Q:{}};if(i){let e=x(i,!1,!0);if(e){let t=["iconify"];for(let n of["provider","prefix"])e[n]&&t.push("iconify--"+e[n]);F.className=t.join(" ")}}for(let e in n){let t=n[e];if(void 0!==t)switch(e){case"icon":case"style":case"children":case"onLoad":case"mode":case"ssr":case"fallback":break;case"_ref":F.ref=t;break;case"className":F[e]=(F[e]?F[e]+" ":"")+t;break;case"inline":case"hFlip":case"vFlip":j[e]=!0===t||"true"===t||1===t;break;case"flip":"string"==typeof t&&function(e,t){t.split(G).forEach(t=>{switch(t.trim()){case"horizontal":e.hFlip=!0;break;case"vertical":e.vFlip=!0}})}(j,t);break;case"color":N.color=t;break;case"rotate":"string"==typeof t?j[e]=function(e,t=0){let n=e.replace(/^-?[0-9.]*/,"");function i(e){for(;e<0;)e+=4;return e%4}if(""===n){let t=parseInt(e);return isNaN(t)?0:i(t)}if(n!==e){let t=0;switch(n){case"%":t=25;break;case"deg":t=90}if(t){let r=parseFloat(e.slice(0,e.length-n.length));return isNaN(r)?0:(r/=t)%1==0?i(r):0}}return t}(t):"number"==typeof t&&(j[e]=t);break;case"ariaHidden":case"aria-hidden":!0!==t&&"true"!==t&&delete F["aria-hidden"];break;default:void 0===v[e]&&(F[e]=t)}}let A=(c={...s,...e},u={...M,...j},f={left:c.left,top:c.top,width:c.width,height:c.height},d=c.body,[c,u].forEach(e=>{var t,n,i,r;let a,l,s=[],o=e.hFlip,c=e.vFlip,u=e.rotate;switch(o?c?u+=2:(s.push("translate("+(f.width+f.left).toString()+" "+(0-f.top).toString()+")"),s.push("scale(-1 1)"),f.top=f.left=0):c&&(s.push("translate("+(0-f.left).toString()+" "+(f.height+f.top).toString()+")"),s.push("scale(1 -1)"),f.top=f.left=0),u<0&&(u-=4*Math.floor(u/4)),u%=4){case 1:s.unshift("rotate(90 "+(a=f.height/2+f.top).toString()+" "+a.toString()+")");break;case 2:s.unshift("rotate(180 "+(f.width/2+f.left).toString()+" "+(f.height/2+f.top).toString()+")");break;case 3:s.unshift("rotate(-90 "+(a=f.width/2+f.left).toString()+" "+a.toString()+")")}u%2==1&&(f.left!==f.top&&(a=f.left,f.left=f.top,f.top=a),f.width!==f.height&&(a=f.width,f.width=f.height,f.height=a)),s.length&&(t=d,n='<g transform="'+s.join(" ")+'">',i=(l=function(e,t="defs"){let n="",i=e.indexOf("<"+t);for(;i>=0;){let r=e.indexOf(">",i),a=e.indexOf("</"+t);if(-1===r||-1===a)break;let l=e.indexOf(">",a);if(-1===l)break;n+=e.slice(r+1,a).trim(),e=e.slice(0,i).trim()+e.slice(l+1)}return{defs:n,content:e}}(t)).defs,r=n+l.content+"</g>",d=i?"<defs>"+i+"</defs>"+r:r)}),h=u.width,p=u.height,g=f.width,m=f.height,null===h?l=S(o=null===p?"1em":"auto"===p?m:p,g/m):(l="auto"===h?g:h,o=null===p?S(l,m/g):"auto"===p?m:p),y={},(b=(e,t)=>{"unset"!==t&&"undefined"!==t&&"none"!==t&&(y[e]=t.toString())})("width",l),b("height",o),y.viewBox=(k=[f.left,f.top,g,m]).join(" "),{attributes:y,viewBox:k,body:d}),I=A.attributes;if(j.inline&&(N.verticalAlign="-0.125em"),"svg"===E){F.style={...N,...C},Object.assign(F,I);let e=0,i=n.id;return"string"==typeof i&&(i=i.replace(/-/g,"_")),F.dangerouslySetInnerHTML={__html:(a=function(e,t=T){let n,i=[];for(;n=z.exec(e);)i.push(n[1]);if(!i.length)return e;let r="suffix"+(0x1000000*Math.random()|Date.now()).toString(16);return i.forEach(n=>{let i="function"==typeof t?t(n):t+(O++).toString(),a=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");e=e.replace(RegExp('([#;"])('+a+')([")]|\\.[a-z])',"g"),"$1"+i+r+"$3")}),e=e.replace(RegExp(r,"g"),"")}(A.body,i?()=>i+"ID"+e++:"iconifyReact"),void 0===t&&function(){try{t=window.trustedTypes.createPolicy("iconify",{createHTML:e=>e})}catch(e){t=null}}(),t?t.createHTML(a):a)},(0,r.createElement)("svg",F)}let{body:L,width:P,height:$}=e,H="mask"===E||"bg"!==E&&-1!==L.indexOf("currentColor"),R=function(e,t){let n=-1===e.indexOf("xlink:")?"":' xmlns:xlink="http://www.w3.org/1999/xlink"';for(let e in t)n+=" "+e+'="'+t[e]+'"';return'<svg xmlns="http://www.w3.org/2000/svg"'+n+">"+e+"</svg>"}(L,{...I,width:P+"",height:$+""});return F.style={...N,"--svg":'url("data:image/svg+xml,'+R.replace(/"/g,"'").replace(/%/g,"%25").replace(/#/g,"%23").replace(/</g,"%3C").replace(/>/g,"%3E").replace(/\s+/g," ")+'")',width:et(I.width),height:et(I.height),...J,...H?K:X,...C},(0,r.createElement)("span",F)})({...s,...h},e,d):e.children?e.children:e.fallback?e.fallback:(0,r.createElement)("span",{})}let ei=(0,r.forwardRef)((e,t)=>en({...e,_ref:t}));(0,r.forwardRef)((e,t)=>en({inline:!0,...e,_ref:t}));var er=e.i(66595),ea=e.i(31214),el=e.i(21357),es=e.i(56420);let eo=(0,es.default)("terminal",[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]]),ec=(0,es.default)("bot",[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]]),eu=(0,es.default)("at-sign",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8",key:"7n84p3"}]]),ef=(0,es.default)("camera",[["path",{d:"M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",key:"18u6gg"}],["circle",{cx:"12",cy:"13",r:"3",key:"1vg3eu"}]]);var ed=e.i(68590);let eh=(0,es.default)("book-open",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]),ep=(0,es.default)("smartphone",[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]]);var eg=e.i(30274);let em=(0,es.default)("messages-square",[["path",{d:"M16 10a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 14.286V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z",key:"1n2ejm"}],["path",{d:"M20 9a2 2 0 0 1 2 2v10.286a.71.71 0 0 1-1.212.502l-2.202-2.202A2 2 0 0 0 17.172 19H10a2 2 0 0 1-2-2v-1",key:"1qfcsi"}]]);var ey=e.i(51921);let ex=(0,es.default)("package",[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]]),eb=(0,es.default)("triangle",[["path",{d:"M13.73 4a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z",key:"14u9p9"}]]),ek=(0,es.default)("rotate-cw",[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]]);var ev=e.i(66627);let ej=[{name:"Google",host:"google.com",icon:"simple-icons:google",fallback:(0,i.jsx)(er.Search,{size:20})},{name:"Cloudflare",host:"cloudflare.com",icon:"simple-icons:cloudflare",fallback:(0,i.jsx)(ea.Cloud,{size:20})},{name:"YouTube",host:"youtube.com",icon:"simple-icons:youtube",fallback:(0,i.jsx)(el.Play,{size:20})},{name:"GitHub",host:"github.com",icon:"simple-icons:github",fallback:(0,i.jsx)(eo,{size:20})},{name:"ChatGPT",host:"chatgpt.com",icon:"simple-icons:openai",fallback:(0,i.jsx)(ec,{size:20})},{name:"X",host:"x.com",icon:"simple-icons:x",fallback:(0,i.jsx)(eu,{size:20})},{name:"Instagram",host:"instagram.com",icon:"simple-icons:instagram",fallback:(0,i.jsx)(ef,{size:20})},{name:"Reddit",host:"reddit.com",icon:"simple-icons:reddit",fallback:(0,i.jsx)(ed.MessageSquare,{size:20})},{name:"Wikipedia",host:"wikipedia.org",icon:"simple-icons:wikipedia",fallback:(0,i.jsx)(eh,{size:20})},{name:"Apple",host:"apple.com",icon:"simple-icons:apple",fallback:(0,i.jsx)(ep,{size:20})},{name:"Telegram",host:"telegram.org",icon:"simple-icons:telegram",fallback:(0,i.jsx)(eg.Send,{size:20})},{name:"Discord",host:"discord.com",icon:"simple-icons:discord",fallback:(0,i.jsx)(em,{size:20})},{name:"TikTok",host:"tiktok.com",icon:"simple-icons:tiktok",fallback:(0,i.jsx)(ey.Music,{size:20})},{name:"npm",host:"npmjs.com",icon:"simple-icons:npm",fallback:(0,i.jsx)(ex,{size:20})},{name:"Vercel",host:"vercel.com",icon:"simple-icons:vercel",fallback:(0,i.jsx)(eb,{size:20})}];function ew({icon:e,fallback:t}){let[n,a]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{let t=new Image;t.onload=()=>a(!0),t.onerror=()=>a(!1),t.src=`https://api.iconify.design/${e.replace(":","/")}.svg`},[e]),(0,i.jsxs)("span",{className:"brand-icon-wrap",children:[(0,i.jsx)("span",{className:`brand-icon-fallback ${n?"hidden":""}`,children:t}),(0,i.jsx)("span",{className:`brand-icon-real ${n?"visible":""}`,children:(0,i.jsx)(ei,{icon:e,width:20,height:20})})]})}function eM(){let[e,t]=(0,r.useState)(new Map),[n,a]=(0,r.useState)(!1),l=(0,r.useRef)(new Map),s=(0,r.useCallback)(e=>{t(t=>{let n=new Map(t);return n.set(e,{status:"pending",latency:0}),n});let n=new AbortController;l.current.set(e,n);let i=performance.now(),r=(n,i)=>{t(t=>{let r=new Map(t);return r.set(e,{status:n,latency:i}),r})},a=setTimeout(()=>{n.abort()},5e3);fetch(`https://${e}/`,{method:"HEAD",mode:"no-cors",cache:"no-store",signal:n.signal}).then(()=>{clearTimeout(a),r("ok",Math.round(performance.now()-i))}).catch(()=>{clearTimeout(a),r("timeout",0)})},[]),o=(0,r.useCallback)(()=>{a(!0);let e=new Map;ej.forEach(t=>{e.set(t.host,{status:"pending",latency:0})}),t(e);let n=new Set(ej.map(e=>e.host));ej.forEach(e=>{let i=new AbortController;l.current.set(e.host,i);let r=performance.now(),s=(i,r)=>{n.has(e.host)&&(n.delete(e.host),t(t=>{let n=new Map(t);return n.set(e.host,{status:i,latency:r}),n}),0===n.size&&a(!1))},o=setTimeout(()=>{i.abort()},5e3);fetch(`https://${e.host}/`,{method:"HEAD",mode:"no-cors",cache:"no-store",signal:i.signal}).then(()=>{clearTimeout(o),s("ok",Math.round(performance.now()-r))}).catch(()=>{clearTimeout(o),s("timeout",0)})})},[]);return(0,r.useEffect)(()=>(o(),()=>{l.current.forEach(e=>e.abort()),l.current.clear()}),[o]),(0,i.jsxs)("div",{className:"ping-page",children:[(0,i.jsxs)("div",{className:"ping-header",children:[(0,i.jsxs)("div",{className:"ping-title-wrap",children:[(0,i.jsx)(ev.Wifi,{size:28,className:"ping-title-icon"}),(0,i.jsxs)("div",{children:[(0,i.jsx)("h1",{className:"ping-title",children:"网络连通性"}),(0,i.jsx)("p",{className:"ping-subtitle",children:"通过向对应网站发送请求进行测试,延迟值仅供参考。"})]})]}),(0,i.jsx)("button",{className:"btn btn-icon",onClick:o,disabled:n,"aria-label":"重新测试全部",title:"重新测试全部",children:(0,i.jsx)(ek,{size:18,className:n?"ping-spin":""})})]}),(0,i.jsx)("div",{className:"ping-grid",children:ej.map(t=>{let n=e.get(t.host),r=!n||"pending"===n.status,a=n?.status==="timeout";return(0,i.jsxs)("div",{className:`ping-card ${r?"pending":""}`,children:[(0,i.jsxs)("div",{className:"ping-card-top",children:[(0,i.jsx)("span",{className:"ping-card-icon",children:(0,i.jsx)(ew,{icon:t.icon,fallback:t.fallback})}),(0,i.jsx)("a",{href:`https://${t.host}`,target:"_blank",rel:"noreferrer",className:"ping-card-name",children:t.name}),(0,i.jsx)("button",{className:"ping-card-refresh",onClick:()=>s(t.host),disabled:r,"aria-label":`重新测试 ${t.name}`,title:"重新测试",children:(0,i.jsx)(ek,{size:13,className:r?"ping-spin":""})})]}),(0,i.jsxs)("div",{className:"ping-card-bottom",children:[r?(0,i.jsx)("span",{className:"ping-pulse-dot"}):(0,i.jsx)("span",{className:`ping-status-label ${a?"is-error":"is-success"}`,children:a?"不可用":"可用"}),(0,i.jsx)("span",{className:`ping-latency ${r?"is-muted":a?"is-error":"is-success"}`,children:r?"--":a?"超时":`${n.latency} ms`})]})]},t.host)})})]})}var eE=e.i(40983);e.s(["default",0,function(){return(0,i.jsx)(eE.MarketingLayout,{children:(0,i.jsx)(eM,{})})}],23449)}]);
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,11241,e=>{"use strict";let s=(0,e.i(56420).default)("arrow-left",[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]]);e.s(["ArrowLeft",0,s],11241)},18566,(e,s,t)=>{s.exports=e.r(76562)},36768,e=>{"use strict";var s=e.i(18050),t=e.i(18566),a=e.i(22016),l=e.i(56420);let n=(0,l.default)("compass",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z",key:"9ktpf1"}]]);var c=e.i(11241);let r=(0,l.default)("house",[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]]);e.s(["default",0,function(){let e=(0,t.useRouter)();return(0,s.jsx)("div",{className:"not-found-page",children:(0,s.jsxs)("div",{className:"not-found-card",children:[(0,s.jsx)("div",{className:"not-found-icon",children:(0,s.jsx)(n,{size:48,strokeWidth:1.5})}),(0,s.jsx)("h1",{className:"not-found-title",children:"页面未找到"}),(0,s.jsx)("p",{className:"not-found-desc",children:"你访问的页面似乎已经迷失在 P2P 网络中了"}),(0,s.jsxs)("div",{className:"not-found-actions",children:[(0,s.jsxs)("button",{onClick:()=>e.back(),className:"btn btn-secondary",children:[(0,s.jsx)(c.ArrowLeft,{size:16}),"上一页"]}),(0,s.jsxs)(a.default,{href:"/",className:"btn btn-primary",children:[(0,s.jsx)(r,{size:16}),"回首页"]})]})]})})}],36768)}]);
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,31214,e=>{"use strict";let a=(0,e.i(56420).default)("cloud",[["path",{d:"M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z",key:"p7xjir"}]]);e.s(["Cloud",0,a],31214)},66344,e=>{"use strict";var a=e.i(47167),t=e.i(18050),l=e.i(71645),s=e.i(36162),r=e.i(31214);let i=(0,e.i(56420).default)("code",[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]]);var n=e.i(62368),o=e.i(26158),d=e.i(46513);let c="https://github.com/most-people/most/releases/latest",u=a.default.env.NEXT_PUBLIC_RELEASE_MANIFEST_URL||`${(a.default.env.NEXT_PUBLIC_R2_PUBLIC_BASE_URL||"https://download.most.box").replace(/\/+$/,"")}/releases/latest.json`,m=[{platform:"windows",arch:"x64",kind:"installer",filename:"GitHub Releases",githubUrl:c},{platform:"windows",arch:"arm64",kind:"installer",filename:"GitHub Releases",githubUrl:c},{platform:"macos",arch:"x64",kind:"installer",filename:"GitHub Releases",githubUrl:c},{platform:"macos",arch:"arm64",kind:"installer",filename:"GitHub Releases",githubUrl:c},{platform:"linux",arch:"x64",kind:"installer",filename:"GitHub Releases",githubUrl:c},{platform:"linux",arch:"arm64",kind:"installer",filename:"GitHub Releases",githubUrl:c}],h={windows:{name:"Windows",ext:".exe",desc:"Windows 10 或更高版本",icon:d.Monitor},macos:{name:"macOS",ext:".dmg",desc:"macOS 12 Monterey 或更高版本",icon:s.Apple},linux:{name:"Linux",ext:".AppImage",desc:"Ubuntu 20.04+ / Debian 11+ / 其他主流发行版",icon:o.Laptop}};function f(e){return"object"==typeof e&&null!==e}function p(e){return!!f(e)&&["windows","macos","linux"].includes(String(e.platform))&&["x64","arm64"].includes(String(e.arch))&&"installer"===e.kind&&"string"==typeof e.filename&&"string"==typeof e.githubUrl&&("string"==typeof e.r2Url||void 0===e.r2Url)}e.s(["default",0,function(){let[e,a]=(0,l.useState)(null),[s,o]=(0,l.useState)("loading"),[d,c]=(0,l.useState)("windows:x64"),[b,x]=(0,l.useState)("r2");(0,l.useEffect)(()=>{c(function(){let e;if("u"<typeof navigator)return"windows:x64";let a=(e=navigator,[e.userAgentData?.platform,navigator.platform,navigator.userAgent].filter(Boolean).join(" ").toLowerCase()),t=/arm|aarch64/.test(a)?"arm64":"x64";return/mac|darwin/.test(a)?`macos:${t}`:/linux/.test(a)?`linux:${t}`:`windows:${t}`}())},[]),(0,l.useEffect)(()=>{let e=new AbortController;return fetch(u,{cache:"no-store",signal:e.signal}).then(e=>{if(!e.ok)throw Error(`Manifest request failed: ${e.status}`);return e.json()}).then(e=>{if(!(f(e)&&"string"==typeof e.version&&"string"==typeof e.publishedAt&&Array.isArray(e.assets)&&e.assets.every(p)))throw Error("Invalid download manifest");a(e),o("ready")}).catch(e=>{e instanceof DOMException&&"AbortError"===e.name||(a(null),o("fallback"))}),()=>e.abort()},[]),(0,l.useEffect)(()=>{"fallback"===s&&x("github")},[s]);let g=e?.assets.length?e.assets:m,w=g.some(e=>e.r2Url),j="r2"===b&&w?"r2":"github";return(0,t.jsxs)("div",{className:"download-options",children:[(0,t.jsxs)("div",{className:"download-source-tabs",role:"tablist","aria-label":"下载来源",children:[(0,t.jsxs)("button",{type:"button",role:"tab","aria-selected":"r2"===j,disabled:!w,className:"r2"===j?"download-source-tab is-active":"download-source-tab",onClick:()=>x("r2"),children:[(0,t.jsx)(r.Cloud,{size:16}),"Cloudflare R2"]}),(0,t.jsxs)("button",{type:"button",role:"tab","aria-selected":"github"===j,className:"github"===j?"download-source-tab is-active":"download-source-tab",onClick:()=>x("github"),children:[(0,t.jsx)(i,{size:16}),"GitHub Releases"]})]}),(0,t.jsx)("p",{className:"download-source-note",children:"loading"===s?"正在获取 Cloudflare R2 高速镜像。":"ready"===s&&e?`当前版本 ${e.version},可切换 Cloudflare R2 或 GitHub Releases 下载。`:"无法获取高速镜像信息,已切换到 GitHub Releases 备用下载。"}),(0,t.jsx)("div",{className:"download-platform-grid",children:g.map(e=>{let a=h[e.platform],l=a.icon,s=`${e.platform}:${e.arch}`,r="r2"===j&&e.r2Url?e.r2Url:e.githubUrl,i=s===d;return(0,t.jsxs)("article",{className:i?"download-platform-card is-recommended":"download-platform-card",children:[(0,t.jsx)("div",{className:"download-platform-icon",children:(0,t.jsx)(l,{size:32})}),(0,t.jsxs)("div",{className:"download-platform-content",children:[(0,t.jsxs)("div",{className:"download-platform-heading",children:[(0,t.jsx)("h3",{children:a.name}),(0,t.jsx)("span",{children:e.arch})]}),(0,t.jsx)("p",{children:a.desc}),(0,t.jsxs)("dl",{className:"download-platform-meta",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:"来源"}),(0,t.jsx)("dd",{children:"r2"===j&&e.r2Url&&e.r2Url?"Cloudflare R2 高速镜像":"GitHub Releases"})]}),e.size?(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:"大小"}),(0,t.jsx)("dd",{children:function(e){if(!e)return"";let a=e/1024/1024;return`${a.toFixed(a>=100?0:1)} MB`}(e.size)})]}):null,e.sha256?(0,t.jsxs)("div",{children:[(0,t.jsx)("dt",{children:"SHA256"}),(0,t.jsx)("dd",{children:e.sha256.slice(0,12)})]}):null]}),(0,t.jsx)("div",{className:"download-platform-actions",children:(0,t.jsxs)("a",{href:r,className:"btn btn-primary",children:[(0,t.jsx)(n.Download,{size:16}),"下载 ",a.ext]})})]}),i?(0,t.jsx)("span",{className:"download-recommended-badge",children:"当前"}):null]},s)})})]})}],66344)}]);