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.
- package/README.md +15 -1
- package/electron/main.js +30 -420
- package/electron/preload.js +1 -16
- package/electron/updateChecker.js +12 -30
- package/electron/updateChecker.test.js +14 -55
- package/out/admin/index.html +0 -0
- package/out/app/index.html +0 -0
- package/out/assets/{FilePreviewOverlay-DqH7uKb7.js → FilePreviewOverlay-D8H61qbp.js} +1 -1
- package/out/assets/LanguageToggle-CSQtRZ3A.js +1 -0
- package/out/assets/MarketingHeader-CrYsQsQ5.js +1 -0
- package/out/assets/MarketingLayout-CQurMOSD.js +1 -0
- package/out/assets/{MarketingThemeToggle-BLuQ_uE-.js → MarketingThemeToggle-CIKP8x9W.js} +1 -1
- package/out/assets/{MilkdownEditor-f2vRIY21.js → MilkdownEditor-DrsyaR4h.js} +1 -1
- package/out/assets/{OpenSidebarButton-BKX4B_yG.js → OpenSidebarButton-DnEgqP0S.js} +1 -1
- package/out/assets/{SidebarAccount-D6wj_ijc.js → SidebarAccount-B4OAl0as.js} +1 -1
- package/out/assets/SidebarHomeLink-BdsUM4Kt.js +1 -0
- package/out/assets/arrow-right-BU9c_SL4.js +1 -0
- package/out/assets/{circle-alert-Dyc-4wje.js → circle-alert-iuHzciph.js} +1 -1
- package/out/assets/{copy-D8HSH5Ki.js → copy-DEzFUzeX.js} +1 -1
- package/out/assets/{download-Q6jKMPIG.js → download-jEPn2njL.js} +1 -1
- package/out/assets/{downloadValidation-B-w8D_0W.js → downloadValidation-DbVOwdmC.js} +1 -1
- package/out/assets/{external-link-GQcZwDTT.js → external-link-BFaoZeK0.js} +1 -1
- package/out/assets/{file-text-CVl5SZPJ.js → file-text-DPA1riJ_.js} +1 -1
- package/out/assets/{folder-BtIdk-YN.js → folder-Cfgc70_F.js} +1 -1
- package/out/assets/{hard-drive-Cew_LD0N.js → hard-drive-Dar_AZEq.js} +1 -1
- package/out/assets/i18n-NjvOSuV6.js +1 -0
- package/out/assets/index-BZ-f0CZd.js +31 -0
- package/out/assets/index-Cde4g_dk.css +1 -0
- package/out/assets/index.lazy-B7AbDiMU.js +3 -0
- package/out/assets/{index.lazy-DujygWms.js → index.lazy-BsciBHf_.js} +1 -1
- package/out/assets/index.lazy-BxoGfWEW.js +1 -0
- package/out/assets/index.lazy-CKbrHko5.js +1 -0
- package/out/assets/index.lazy-CgKPe02l.js +1 -0
- package/out/assets/index.lazy-Citucq1G.js +1 -0
- package/out/assets/index.lazy-CvKEcWlH.js +2 -0
- package/out/assets/{index.lazy-WXDn5r_l.js → index.lazy-DB9Ht9LJ.js} +1 -1
- package/out/assets/index.lazy-DVeqmqaA.js +1 -0
- package/out/assets/index.lazy-hF807bh0.js +1 -0
- package/out/assets/index.lazy-oFaoa4qT.js +1 -0
- package/out/assets/index.lazy-rfgjFZNH.js +1 -0
- package/out/assets/index.lazy-zpQXhgmn.js +2 -0
- package/out/assets/{key-round-D1zfZzvP.js → key-round-DNcpSuMw.js} +1 -1
- package/out/assets/{loader-BSclU8WE.js → loader-BXQtdens.js} +1 -1
- package/out/assets/{lock-C9VP0ezG.js → lock-CLIE8cct.js} +1 -1
- package/out/assets/{message-square-Dg3YjjmO.js → message-square-Dp09WY1I.js} +1 -1
- package/out/assets/{mp-FQvFEcYM.js → mp-B6kdA94c.js} +1 -1
- package/out/assets/{music-BeCPak70.js → music-B19Tg557.js} +1 -1
- package/out/assets/{notebook-pen-DO1CJiqn.js → notebook-pen-C8TlK5sB.js} +1 -1
- package/out/assets/play-B-BjsTZz.js +1 -0
- package/out/assets/plus-4hygj-1Z.js +1 -0
- package/out/assets/{save-BVeMjaW1.js → save-BjrbPwhJ.js} +1 -1
- package/out/assets/search-DSkiWdvX.js +1 -0
- package/out/assets/{send-C1J-eGNs.js → send-BL4d5iOt.js} +1 -1
- package/out/assets/{shield-check-CZYDVJoh.js → shield-check-DzDuWO8r.js} +1 -1
- package/out/assets/smartphone-tRRFFO0a.js +1 -0
- package/out/assets/{trash-2-C_LtCiNh.js → trash-2-V12tJ8lI.js} +1 -1
- package/out/assets/triangle-alert-DGWc8ZHu.js +1 -0
- package/out/assets/{ui-PnUvY9zL.js → ui-BpDGD3IR.js} +2 -2
- package/out/assets/{upload-DgxxldtV.js → upload-CoCptKya.js} +1 -1
- package/out/assets/{useChannelMessages-CZHmH5n-.js → useChannelMessages-B6RMaNDH.js} +1 -1
- package/out/assets/useGameRoom-CRJL0kcm.js +1 -0
- package/out/assets/userProfile-DBkH4s29.js +1 -0
- package/out/assets/{wallet-DBTWBi6K.js → wallet-T7ONZ3Kg.js} +1 -1
- package/out/assets/{wifi-pP6SJLcu.js → wifi-Bgo8eHY0.js} +1 -1
- package/out/chat/index.html +0 -0
- package/out/chat/join/index.html +0 -0
- package/out/download/index.html +2 -2
- package/out/game/gandengyan/index.html +0 -0
- package/out/game/index.html +0 -0
- package/out/game/zhajinhua/index.html +0 -0
- package/out/index.html +2 -2
- package/out/note/index.html +0 -0
- package/out/ping/index.html +2 -2
- package/out/profile/index.html +0 -0
- package/out/web3/index.html +0 -0
- package/package.json +5 -8
- package/server/src/core/channelIdentity.js +3 -5
- package/server/src/core/gameRoom.js +18 -43
- package/server/src/core/ownerMetadata.js +3 -4
- package/server/src/core/releaseManifest.js +91 -0
- package/server/src/core/shared.js +50 -0
- package/server/src/core/zhajinhua.js +12 -33
- package/server/src/games/gandengyan.js +7 -14
- package/server/src/http/nodeStatus.js +0 -6
- package/server/src/http/routes/channelRoutes.js +1 -13
- package/server/src/http/routes/nodeRoutes.js +1 -1
- package/server/src/index.js +44 -298
- package/server/src/utils/api.js +47 -0
- package/server/src/utils/auth.js +2 -5
- package/server/src/utils/dateTime.js +1 -3
- package/out/assets/LanguageToggle-BoBNesNU.js +0 -1
- package/out/assets/MarketingHeader-Derv67Vs.js +0 -1
- package/out/assets/MarketingLayout-fc2mymJm.js +0 -1
- package/out/assets/SidebarHomeLink-ByOHwlH8.js +0 -1
- package/out/assets/arrow-right-BCi9KXDX.js +0 -1
- package/out/assets/cloud-DfaFxhLj.js +0 -1
- package/out/assets/i18n--maTEG0d.js +0 -1
- package/out/assets/index-B2-kpfu5.css +0 -1
- package/out/assets/index-Cg4kEvx8.js +0 -31
- package/out/assets/index.lazy-BAq__8ON.js +0 -2
- package/out/assets/index.lazy-BPh8D_H9.js +0 -1
- package/out/assets/index.lazy-Bn4kDToA.js +0 -1
- package/out/assets/index.lazy-BqHgW5fE.js +0 -1
- package/out/assets/index.lazy-CLYRM_kh.js +0 -1
- package/out/assets/index.lazy-CMSCQucz.js +0 -1
- package/out/assets/index.lazy-Cut4XkPH.js +0 -1
- package/out/assets/index.lazy-DKOSJyaQ.js +0 -2
- package/out/assets/index.lazy-DjPbRI_L.js +0 -1
- package/out/assets/index.lazy-DxAGUwlf.js +0 -3
- package/out/assets/index.lazy-ghLI7p1x.js +0 -1
- package/out/assets/play-CnhsLC5C.js +0 -1
- package/out/assets/plus-BpjwXzbO.js +0 -1
- package/out/assets/search-CsAnnJyH.js +0 -1
- package/out/assets/triangle-alert-DOwc-41Y.js +0 -1
- package/out/assets/useGameRoom-B8Ds_PKe.js +0 -1
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
177
|
+
const name = normalizeDisplayName(
|
|
178
|
+
message.authorName || input.name,
|
|
171
179
|
shortAddress(address)
|
|
172
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 '../../
|
|
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()
|