most-box 0.2.6 → 0.2.8

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 (116) hide show
  1. package/README.md +15 -1
  2. package/electron/main.js +30 -420
  3. package/electron/preload.js +1 -16
  4. package/electron/updateChecker.js +12 -30
  5. package/electron/updateChecker.test.js +14 -55
  6. package/out/admin/index.html +0 -0
  7. package/out/app/index.html +0 -0
  8. package/out/assets/{FilePreviewOverlay-DqH7uKb7.js → FilePreviewOverlay-D8H61qbp.js} +1 -1
  9. package/out/assets/LanguageToggle-CSQtRZ3A.js +1 -0
  10. package/out/assets/MarketingHeader-CrYsQsQ5.js +1 -0
  11. package/out/assets/MarketingLayout-CQurMOSD.js +1 -0
  12. package/out/assets/{MarketingThemeToggle-BLuQ_uE-.js → MarketingThemeToggle-CIKP8x9W.js} +1 -1
  13. package/out/assets/{MilkdownEditor-f2vRIY21.js → MilkdownEditor-DrsyaR4h.js} +1 -1
  14. package/out/assets/{OpenSidebarButton-BKX4B_yG.js → OpenSidebarButton-DnEgqP0S.js} +1 -1
  15. package/out/assets/{SidebarAccount-D6wj_ijc.js → SidebarAccount-B4OAl0as.js} +1 -1
  16. package/out/assets/SidebarHomeLink-BdsUM4Kt.js +1 -0
  17. package/out/assets/arrow-right-BU9c_SL4.js +1 -0
  18. package/out/assets/{circle-alert-Dyc-4wje.js → circle-alert-iuHzciph.js} +1 -1
  19. package/out/assets/{copy-D8HSH5Ki.js → copy-DEzFUzeX.js} +1 -1
  20. package/out/assets/{download-Q6jKMPIG.js → download-jEPn2njL.js} +1 -1
  21. package/out/assets/{downloadValidation-B-w8D_0W.js → downloadValidation-DbVOwdmC.js} +1 -1
  22. package/out/assets/{external-link-GQcZwDTT.js → external-link-BFaoZeK0.js} +1 -1
  23. package/out/assets/{file-text-CVl5SZPJ.js → file-text-DPA1riJ_.js} +1 -1
  24. package/out/assets/{folder-BtIdk-YN.js → folder-Cfgc70_F.js} +1 -1
  25. package/out/assets/{hard-drive-Cew_LD0N.js → hard-drive-Dar_AZEq.js} +1 -1
  26. package/out/assets/i18n-NjvOSuV6.js +1 -0
  27. package/out/assets/index-BZ-f0CZd.js +31 -0
  28. package/out/assets/index-Cde4g_dk.css +1 -0
  29. package/out/assets/index.lazy-B7AbDiMU.js +3 -0
  30. package/out/assets/{index.lazy-DujygWms.js → index.lazy-BsciBHf_.js} +1 -1
  31. package/out/assets/index.lazy-BxoGfWEW.js +1 -0
  32. package/out/assets/index.lazy-CKbrHko5.js +1 -0
  33. package/out/assets/index.lazy-CgKPe02l.js +1 -0
  34. package/out/assets/index.lazy-Citucq1G.js +1 -0
  35. package/out/assets/index.lazy-CvKEcWlH.js +2 -0
  36. package/out/assets/{index.lazy-WXDn5r_l.js → index.lazy-DB9Ht9LJ.js} +1 -1
  37. package/out/assets/index.lazy-DVeqmqaA.js +1 -0
  38. package/out/assets/index.lazy-hF807bh0.js +1 -0
  39. package/out/assets/index.lazy-oFaoa4qT.js +1 -0
  40. package/out/assets/index.lazy-rfgjFZNH.js +1 -0
  41. package/out/assets/index.lazy-zpQXhgmn.js +2 -0
  42. package/out/assets/{key-round-D1zfZzvP.js → key-round-DNcpSuMw.js} +1 -1
  43. package/out/assets/{loader-BSclU8WE.js → loader-BXQtdens.js} +1 -1
  44. package/out/assets/{lock-C9VP0ezG.js → lock-CLIE8cct.js} +1 -1
  45. package/out/assets/{message-square-Dg3YjjmO.js → message-square-Dp09WY1I.js} +1 -1
  46. package/out/assets/{mp-FQvFEcYM.js → mp-B6kdA94c.js} +1 -1
  47. package/out/assets/{music-BeCPak70.js → music-B19Tg557.js} +1 -1
  48. package/out/assets/{notebook-pen-DO1CJiqn.js → notebook-pen-C8TlK5sB.js} +1 -1
  49. package/out/assets/play-B-BjsTZz.js +1 -0
  50. package/out/assets/plus-4hygj-1Z.js +1 -0
  51. package/out/assets/{save-BVeMjaW1.js → save-BjrbPwhJ.js} +1 -1
  52. package/out/assets/search-DSkiWdvX.js +1 -0
  53. package/out/assets/{send-C1J-eGNs.js → send-BL4d5iOt.js} +1 -1
  54. package/out/assets/{shield-check-CZYDVJoh.js → shield-check-DzDuWO8r.js} +1 -1
  55. package/out/assets/smartphone-tRRFFO0a.js +1 -0
  56. package/out/assets/{trash-2-C_LtCiNh.js → trash-2-V12tJ8lI.js} +1 -1
  57. package/out/assets/triangle-alert-DGWc8ZHu.js +1 -0
  58. package/out/assets/{ui-PnUvY9zL.js → ui-BpDGD3IR.js} +2 -2
  59. package/out/assets/{upload-DgxxldtV.js → upload-CoCptKya.js} +1 -1
  60. package/out/assets/{useChannelMessages-CZHmH5n-.js → useChannelMessages-B6RMaNDH.js} +1 -1
  61. package/out/assets/useGameRoom-CRJL0kcm.js +1 -0
  62. package/out/assets/userProfile-DBkH4s29.js +1 -0
  63. package/out/assets/{wallet-DBTWBi6K.js → wallet-T7ONZ3Kg.js} +1 -1
  64. package/out/assets/{wifi-pP6SJLcu.js → wifi-Bgo8eHY0.js} +1 -1
  65. package/out/chat/index.html +0 -0
  66. package/out/chat/join/index.html +0 -0
  67. package/out/download/index.html +2 -2
  68. package/out/game/gandengyan/index.html +0 -0
  69. package/out/game/index.html +0 -0
  70. package/out/game/zhajinhua/index.html +0 -0
  71. package/out/index.html +2 -2
  72. package/out/note/index.html +0 -0
  73. package/out/ping/index.html +2 -2
  74. package/out/profile/index.html +0 -0
  75. package/out/web3/index.html +0 -0
  76. package/package.json +5 -8
  77. package/server/src/core/channelIdentity.js +3 -5
  78. package/server/src/core/gameRoom.js +18 -43
  79. package/server/src/core/ownerMetadata.js +3 -4
  80. package/server/src/core/releaseManifest.js +91 -0
  81. package/server/src/core/shared.js +50 -0
  82. package/server/src/core/zhajinhua.js +12 -33
  83. package/server/src/games/gandengyan.js +7 -14
  84. package/server/src/http/nodeStatus.js +0 -6
  85. package/server/src/http/routes/channelRoutes.js +1 -13
  86. package/server/src/http/routes/nodeRoutes.js +1 -1
  87. package/server/src/index.js +44 -298
  88. package/server/src/utils/api.js +47 -0
  89. package/server/src/utils/auth.js +2 -5
  90. package/server/src/utils/dateTime.js +1 -3
  91. package/out/assets/LanguageToggle-BoBNesNU.js +0 -1
  92. package/out/assets/MarketingHeader-Derv67Vs.js +0 -1
  93. package/out/assets/MarketingLayout-fc2mymJm.js +0 -1
  94. package/out/assets/SidebarHomeLink-ByOHwlH8.js +0 -1
  95. package/out/assets/arrow-right-BCi9KXDX.js +0 -1
  96. package/out/assets/cloud-DfaFxhLj.js +0 -1
  97. package/out/assets/i18n--maTEG0d.js +0 -1
  98. package/out/assets/index-B2-kpfu5.css +0 -1
  99. package/out/assets/index-Cg4kEvx8.js +0 -31
  100. package/out/assets/index.lazy-BAq__8ON.js +0 -2
  101. package/out/assets/index.lazy-BPh8D_H9.js +0 -1
  102. package/out/assets/index.lazy-Bn4kDToA.js +0 -1
  103. package/out/assets/index.lazy-BqHgW5fE.js +0 -1
  104. package/out/assets/index.lazy-CLYRM_kh.js +0 -1
  105. package/out/assets/index.lazy-CMSCQucz.js +0 -1
  106. package/out/assets/index.lazy-Cut4XkPH.js +0 -1
  107. package/out/assets/index.lazy-DKOSJyaQ.js +0 -2
  108. package/out/assets/index.lazy-DjPbRI_L.js +0 -1
  109. package/out/assets/index.lazy-DxAGUwlf.js +0 -3
  110. package/out/assets/index.lazy-ghLI7p1x.js +0 -1
  111. package/out/assets/play-CnhsLC5C.js +0 -1
  112. package/out/assets/plus-BpjwXzbO.js +0 -1
  113. package/out/assets/search-CsAnnJyH.js +0 -1
  114. package/out/assets/triangle-alert-DOwc-41Y.js +0 -1
  115. package/out/assets/useGameRoom-B8Ds_PKe.js +0 -1
  116. package/out/assets/userProfile-CRGZ8PUF.js +0 -1
@@ -1,4 +1,5 @@
1
1
  import crypto from 'node:crypto'
2
+ import { normalizeAvatar, normalizeDisplayName } from './shared.js'
2
3
 
3
4
  export const CHAT_FILE_ROOT = 'chat-file'
4
5
  export const TRANSIENT_CHANNEL_TYPES = new Set(['game'])
@@ -8,14 +9,11 @@ export const CHANNEL_CANDIDATE_TTL = 30 * 1000
8
9
  const CHANNEL_WRITER_ID_BYTES = 8
9
10
 
10
11
  export function normalizeChannelDisplayName(input, fallbackAddress = '') {
11
- const value = String(input || '').trim()
12
- if (value) return value.slice(0, 50)
13
- return fallbackAddress ? fallbackAddress.slice(0, 10) : ''
12
+ return normalizeDisplayName(input, fallbackAddress ? fallbackAddress.slice(0, 10) : '')
14
13
  }
15
14
 
16
15
  export function normalizeChannelAvatar(input) {
17
- const value = String(input || '').trim()
18
- return value ? value.slice(0, 4096) : ''
16
+ return normalizeAvatar(input)
19
17
  }
20
18
 
21
19
  export function normalizeChannelId(input) {
@@ -1,3 +1,15 @@
1
+ import {
2
+ createEventId,
3
+ normalizeAddress,
4
+ normalizeAvatar,
5
+ normalizeDisplayName,
6
+ normalizeRoomCode,
7
+ randomInt,
8
+ shortAddress,
9
+ } from './shared.js'
10
+
11
+ export { normalizeAddress } from './shared.js'
12
+
1
13
  export const GAME_CHANNEL_TYPE = 'game'
2
14
  export const GAME_EVENT_KIND = 'mostbox.game.event'
3
15
  export const GAME_EVENT_VERSION = 1
@@ -12,11 +24,7 @@ export function normalizeGameId(input) {
12
24
  }
13
25
 
14
26
  export function normalizeGameRoomCode(input) {
15
- return String(input || '')
16
- .trim()
17
- .toUpperCase()
18
- .replace(/[^A-Z0-9]/g, '')
19
- .slice(0, 8)
27
+ return normalizeRoomCode(input)
20
28
  }
21
29
 
22
30
  export function isValidGameRoomCode(input) {
@@ -166,10 +174,11 @@ export function createPlayerFromPayload(input, messageOrAuthor) {
166
174
  const author = message.author
167
175
  const address = normalizeAddress(input.address || author)
168
176
  if (!address || normalizeAddress(author) !== address) return null
169
- const name =
170
- String(message.authorName || input.name || '').trim().slice(0, 50) ||
177
+ const name = normalizeDisplayName(
178
+ message.authorName || input.name,
171
179
  shortAddress(address)
172
- const avatar = String(message.avatar || input.avatar || '').trim()
180
+ )
181
+ const avatar = normalizeAvatar(message.avatar || input.avatar)
173
182
  const publicKey = String(input.publicKey || '').trim()
174
183
  const player = {
175
184
  address,
@@ -177,7 +186,7 @@ export function createPlayerFromPayload(input, messageOrAuthor) {
177
186
  publicKey,
178
187
  joinedAt: Number(input.joinedAt || Date.now()),
179
188
  }
180
- if (avatar) player.avatar = avatar.slice(0, 4096)
189
+ if (avatar) player.avatar = avatar
181
190
  return player
182
191
  }
183
192
 
@@ -193,11 +202,6 @@ export function normalizeGamePlayer(input) {
193
202
  }
194
203
  }
195
204
 
196
- export function normalizeAddress(value) {
197
- const address = String(value || '').trim()
198
- return /^0x[a-fA-F0-9]{40}$/.test(address) ? address.toLowerCase() : ''
199
- }
200
-
201
205
  function upsertPlayer(players, playerMap, player) {
202
206
  const existing = playerMap.get(player.address)
203
207
  if (existing) {
@@ -213,32 +217,3 @@ function sortMessages(messages) {
213
217
  (a, b) => Number(a.timestamp || 0) - Number(b.timestamp || 0)
214
218
  )
215
219
  }
216
-
217
- function createEventId(prefix) {
218
- return `${prefix}_${Date.now()}_${randomHex(4)}`
219
- }
220
-
221
- function randomInt(max) {
222
- if (globalThis.crypto?.getRandomValues) {
223
- const value = new Uint32Array(1)
224
- globalThis.crypto.getRandomValues(value)
225
- return value[0] % max
226
- }
227
- return Math.floor(Math.random() * max)
228
- }
229
-
230
- function randomHex(byteLength) {
231
- const bytes = new Uint8Array(byteLength)
232
- if (globalThis.crypto?.getRandomValues) {
233
- globalThis.crypto.getRandomValues(bytes)
234
- } else {
235
- for (let i = 0; i < bytes.length; i++) {
236
- bytes[i] = Math.floor(Math.random() * 256)
237
- }
238
- }
239
- return [...bytes].map(byte => byte.toString(16).padStart(2, '0')).join('')
240
- }
241
-
242
- function shortAddress(address) {
243
- return address ? `${address.slice(0, 6)}...${address.slice(-4)}` : ''
244
- }
@@ -1,9 +1,8 @@
1
+ import { normalizeAddress } from './shared.js'
2
+
1
3
  export const DEFAULT_OWNER_BUCKET = '__local__'
2
4
 
3
- export function normalizeOwnerAddress(address) {
4
- const value = String(address || '').trim()
5
- return /^0x[a-fA-F0-9]{40}$/.test(value) ? value.toLowerCase() : ''
6
- }
5
+ export const normalizeOwnerAddress = normalizeAddress
7
6
 
8
7
  export function getOwnerBucketKey(address) {
9
8
  return normalizeOwnerAddress(address) || DEFAULT_OWNER_BUCKET
@@ -0,0 +1,91 @@
1
+ export const RELEASE_PLATFORMS = ['windows', 'macos', 'linux']
2
+ export const RELEASE_ARCHES = ['x64', 'arm64']
3
+ export const RELEASE_ASSET_KINDS = ['installer']
4
+
5
+ export const RELEASE_TARGETS = Object.freeze([
6
+ { platform: 'windows', arch: 'x64' },
7
+ { platform: 'windows', arch: 'arm64' },
8
+ { platform: 'macos', arch: 'x64' },
9
+ { platform: 'macos', arch: 'arm64' },
10
+ { platform: 'linux', arch: 'x64' },
11
+ { platform: 'linux', arch: 'arm64' },
12
+ ])
13
+
14
+ const RELEASE_PLATFORM_SET = new Set(RELEASE_PLATFORMS)
15
+ const RELEASE_ARCH_SET = new Set(RELEASE_ARCHES)
16
+ const RELEASE_ASSET_KIND_SET = new Set(RELEASE_ASSET_KINDS)
17
+
18
+ function isRecord(value) {
19
+ return typeof value === 'object' && value !== null
20
+ }
21
+
22
+ function isNonEmptyString(value) {
23
+ return typeof value === 'string' && value.trim().length > 0
24
+ }
25
+
26
+ function isPositiveFiniteNumber(value) {
27
+ return Number.isFinite(value) && value > 0
28
+ }
29
+
30
+ function isOptionalNonEmptyString(value) {
31
+ return typeof value === 'undefined' || isNonEmptyString(value)
32
+ }
33
+
34
+ export function isReleaseAsset(value) {
35
+ if (!isRecord(value)) return false
36
+
37
+ return (
38
+ RELEASE_PLATFORM_SET.has(value.platform) &&
39
+ RELEASE_ARCH_SET.has(value.arch) &&
40
+ RELEASE_ASSET_KIND_SET.has(value.kind) &&
41
+ isNonEmptyString(value.filename) &&
42
+ isPositiveFiniteNumber(value.size) &&
43
+ isNonEmptyString(value.cid) &&
44
+ isNonEmptyString(value.githubUrl) &&
45
+ isOptionalNonEmptyString(value.r2Url)
46
+ )
47
+ }
48
+
49
+ export function isReleaseManifest(value) {
50
+ if (!isRecord(value)) return false
51
+ if (!isNonEmptyString(value.version)) return false
52
+ if (!isNonEmptyString(value.publishedAt)) return false
53
+ if (!Array.isArray(value.assets)) return false
54
+
55
+ return value.assets.every(isReleaseAsset)
56
+ }
57
+
58
+ export function getReleaseAssetKey(asset) {
59
+ return `${asset.platform}:${asset.arch}`
60
+ }
61
+
62
+ export function getInstallerReleaseAssets(manifest) {
63
+ if (!isReleaseManifest(manifest)) return []
64
+ return manifest.assets.filter(asset => asset.kind === 'installer')
65
+ }
66
+
67
+ export function hasR2ReleaseAssets(assets) {
68
+ if (!Array.isArray(assets)) return false
69
+ return assets.some(asset => isRecord(asset) && isNonEmptyString(asset.r2Url))
70
+ }
71
+
72
+ export function resolveReleaseAssetDownload(asset, preferredSource = 'r2') {
73
+ if (
74
+ preferredSource === 'r2' &&
75
+ isRecord(asset) &&
76
+ isNonEmptyString(asset.r2Url)
77
+ ) {
78
+ return {
79
+ source: 'r2',
80
+ url: asset.r2Url,
81
+ }
82
+ }
83
+
84
+ return {
85
+ source: 'github',
86
+ url:
87
+ isRecord(asset) && isNonEmptyString(asset.githubUrl)
88
+ ? asset.githubUrl
89
+ : '',
90
+ }
91
+ }
@@ -0,0 +1,50 @@
1
+ export function normalizeAddress(value) {
2
+ const address = String(value || '').trim()
3
+ return /^0x[a-fA-F0-9]{40}$/.test(address) ? address.toLowerCase() : ''
4
+ }
5
+
6
+ export function shortAddress(address) {
7
+ return address ? `${address.slice(0, 6)}...${address.slice(-4)}` : ''
8
+ }
9
+
10
+ export function normalizeAvatar(value) {
11
+ return String(value || '').trim().slice(0, 4096)
12
+ }
13
+
14
+ export function normalizeDisplayName(value, fallback = '', maxLength = 50) {
15
+ const displayName = String(value || '').trim()
16
+ return (displayName || String(fallback || '')).slice(0, maxLength)
17
+ }
18
+
19
+ export function normalizeRoomCode(value) {
20
+ return String(value || '')
21
+ .trim()
22
+ .toUpperCase()
23
+ .replace(/[^A-Z0-9]/g, '')
24
+ .slice(0, 8)
25
+ }
26
+
27
+ export function createEventId(prefix) {
28
+ return `${prefix}_${Date.now()}_${randomHex(4)}`
29
+ }
30
+
31
+ export function randomInt(max) {
32
+ if (globalThis.crypto?.getRandomValues) {
33
+ const value = new Uint32Array(1)
34
+ globalThis.crypto.getRandomValues(value)
35
+ return value[0] % max
36
+ }
37
+ return Math.floor(Math.random() * max)
38
+ }
39
+
40
+ export function randomHex(byteLength) {
41
+ const bytes = new Uint8Array(byteLength)
42
+ if (globalThis.crypto?.getRandomValues) {
43
+ globalThis.crypto.getRandomValues(bytes)
44
+ } else {
45
+ for (let i = 0; i < bytes.length; i++) {
46
+ bytes[i] = Math.floor(Math.random() * 256)
47
+ }
48
+ }
49
+ return [...bytes].map(byte => byte.toString(16).padStart(2, '0')).join('')
50
+ }
@@ -1,3 +1,11 @@
1
+ import {
2
+ createEventId as createSharedEventId,
3
+ normalizeAddress,
4
+ normalizeAvatar,
5
+ normalizeRoomCode as normalizeSharedRoomCode,
6
+ shortAddress,
7
+ } from './shared.js'
8
+
1
9
  export const ZHJ_INITIAL_CHIPS = 1000
2
10
  export const ZHJ_ANTE = 10
3
11
  export const ZHJ_MIN_PLAYERS = 2
@@ -28,15 +36,11 @@ const CATEGORY_LABEL = {
28
36
  }
29
37
 
30
38
  export function normalizeRoomCode(input) {
31
- return String(input || '')
32
- .trim()
33
- .toUpperCase()
34
- .replace(/[^A-Z0-9]/g, '')
35
- .slice(0, 8)
39
+ return normalizeSharedRoomCode(input)
36
40
  }
37
41
 
38
42
  export function createEventId(prefix = 'zhajinhua') {
39
- return `${prefix}_${Date.now()}_${randomHex(4)}`
43
+ return createSharedEventId(prefix)
40
44
  }
41
45
 
42
46
  export function createRoundId() {
@@ -196,7 +200,7 @@ export function startRound({ roomCode, players, hostAddress, previousSeq = 0, pr
196
200
  return {
197
201
  address: player.address,
198
202
  name: player.name,
199
- avatar: cleanAvatar(player.avatar),
203
+ avatar: normalizeAvatar(player.avatar),
200
204
  publicKey: player.publicKey,
201
205
  chips: Number(player.chips) - ZHJ_ANTE,
202
206
  status: 'active',
@@ -598,7 +602,7 @@ function normalizeRoundPlayer(input) {
598
602
  return {
599
603
  address,
600
604
  name: String(input.name || shortAddress(address)).slice(0, 50),
601
- avatar: cleanAvatar(input.avatar),
605
+ avatar: normalizeAvatar(input.avatar),
602
606
  publicKey: String(input.publicKey || ''),
603
607
  chips: Math.max(0, Number(input.chips) || 0),
604
608
  status: input.status === 'folded' ? 'folded' : 'active',
@@ -607,31 +611,6 @@ function normalizeRoundPlayer(input) {
607
611
  }
608
612
  }
609
613
 
610
- function normalizeAddress(value) {
611
- const address = String(value || '').trim()
612
- return /^0x[a-fA-F0-9]{40}$/.test(address) ? address.toLowerCase() : ''
613
- }
614
-
615
- function shortAddress(address) {
616
- return address ? `${address.slice(0, 6)}...${address.slice(-4)}` : ''
617
- }
618
-
619
- function cleanAvatar(value) {
620
- return String(value || '').trim().slice(0, 4096)
621
- }
622
-
623
614
  function clone(value) {
624
615
  return JSON.parse(JSON.stringify(value))
625
616
  }
626
-
627
- function randomHex(byteLength) {
628
- const bytes = new Uint8Array(byteLength)
629
- if (globalThis.crypto?.getRandomValues) {
630
- globalThis.crypto.getRandomValues(bytes)
631
- } else {
632
- for (let i = 0; i < bytes.length; i++) {
633
- bytes[i] = Math.floor(Math.random() * 256)
634
- }
635
- }
636
- return [...bytes].map(byte => byte.toString(16).padStart(2, '0')).join('')
637
- }
@@ -1,3 +1,5 @@
1
+ import { normalizeAddress, normalizeAvatar } from '../core/shared.js'
2
+
1
3
  const SUITS = ['S', 'H', 'C', 'D']
2
4
  const RANKS = ['3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A', '2']
3
5
  const STRAIGHT_RANKS = RANKS.filter(rank => rank !== '2')
@@ -30,7 +32,7 @@ export function createGanDengYanRoom({
30
32
  players: roomPlayers.slice(0, 6).map((player, seat) => ({
31
33
  address: player.address,
32
34
  name: cleanName(player.name),
33
- avatar: cleanAvatar(player.avatar),
35
+ avatar: normalizeAvatar(player.avatar),
34
36
  seat,
35
37
  hand: [],
36
38
  handCount: 0,
@@ -64,7 +66,7 @@ export function syncGanDengYanLobby(room, players = []) {
64
66
  .map((player, seat) => ({
65
67
  address: player.address,
66
68
  name: cleanName(player.name),
67
- avatar: cleanAvatar(player.avatar),
69
+ avatar: normalizeAvatar(player.avatar),
68
70
  seat,
69
71
  hand: [],
70
72
  handCount: 0,
@@ -260,7 +262,7 @@ export function publicGanDengYanRoom(room) {
260
262
  players: orderedPlayers(room).map(player => ({
261
263
  address: player.address,
262
264
  name: player.name,
263
- avatar: cleanAvatar(player.avatar),
265
+ avatar: normalizeAvatar(player.avatar),
264
266
  seat: player.seat,
265
267
  handCount: player.hand?.length ?? player.handCount ?? 0,
266
268
  score: Number(player.score ?? INITIAL_SCORE),
@@ -435,7 +437,7 @@ function normalizePlayers(players) {
435
437
  .map(player => ({
436
438
  address: normalizeAddress(player.address),
437
439
  name: cleanName(player.name),
438
- avatar: cleanAvatar(player.avatar),
440
+ avatar: normalizeAvatar(player.avatar),
439
441
  publicKey: String(player.publicKey || ''),
440
442
  }))
441
443
  .filter(player => {
@@ -451,7 +453,7 @@ function normalizeRoundPlayer(input) {
451
453
  return {
452
454
  address,
453
455
  name: cleanName(input.name),
454
- avatar: cleanAvatar(input.avatar),
456
+ avatar: normalizeAvatar(input.avatar),
455
457
  seat: Number(input.seat || 0),
456
458
  hand: Array.isArray(input.hand) ? input.hand.map(normalizeCard).filter(Boolean) : [],
457
459
  handCount: Number(input.handCount || 0),
@@ -677,15 +679,6 @@ function rollDice(random) {
677
679
  return Math.floor(random() * 6) + 1
678
680
  }
679
681
 
680
- function normalizeAddress(value) {
681
- const address = String(value || '').trim()
682
- return /^0x[a-fA-F0-9]{40}$/.test(address) ? address.toLowerCase() : ''
683
- }
684
-
685
682
  function cleanName(name) {
686
683
  return String(name || '玩家').trim().slice(0, 16) || '玩家'
687
684
  }
688
-
689
- function cleanAvatar(avatar) {
690
- return String(avatar || '').trim().slice(0, 4096)
691
- }
@@ -260,12 +260,6 @@ export function buildOpenApiSpec(appPort) {
260
260
  responses: { 200: { description: 'Created channel message' } },
261
261
  },
262
262
  },
263
- '/api/channels/{name}/members': {
264
- get: {
265
- summary: 'List P2P channel members',
266
- responses: { 200: { description: 'Channel members' } },
267
- },
268
- },
269
263
  '/api/channels/{name}/peers': {
270
264
  get: {
271
265
  summary: 'List currently connected channel peers',
@@ -1,4 +1,4 @@
1
- import { normalizeAddress } from '../../utils/auth.js'
1
+ import { normalizeAddress } from '../../core/shared.js'
2
2
  import { badRequestOrAppError } from '../errors.js'
3
3
 
4
4
  export function registerChannelRoutes(app, { engine }) {
@@ -72,18 +72,6 @@ export function registerChannelRoutes(app, { engine }) {
72
72
  }
73
73
  })
74
74
 
75
- app.get('/api/channels/:name/members', c => {
76
- try {
77
- return c.json(
78
- engine.getChannelMembers(c.req.param('name'), {
79
- ownerAddress: c.get('userAddress'),
80
- })
81
- )
82
- } catch (err) {
83
- return badRequestOrAppError(c, err)
84
- }
85
- })
86
-
87
75
  app.post('/api/channels/:name/messages', async c => {
88
76
  const name = c.req.param('name')
89
77
  const body = await c.req.json()
@@ -1,4 +1,4 @@
1
- import { normalizeAddress } from '../../utils/auth.js'
1
+ import { normalizeAddress } from '../../core/shared.js'
2
2
  import { evaluateStorageLimits } from '../../node/config.js'
3
3
  import {
4
4
  isLoopbackRemoteAddress,