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
package/server/src/index.js
CHANGED
|
@@ -93,6 +93,7 @@ import {
|
|
|
93
93
|
} from './config.js'
|
|
94
94
|
|
|
95
95
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
96
|
+
const CHANNEL_WELCOME_MESSAGE = '我加入了群聊'
|
|
96
97
|
|
|
97
98
|
function createMemoryDuplexPair() {
|
|
98
99
|
let left
|
|
@@ -1939,290 +1940,6 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
1939
1940
|
return result
|
|
1940
1941
|
}
|
|
1941
1942
|
|
|
1942
|
-
/**
|
|
1943
|
-
* 按 CID 将内容下载到指定路径,不写入用户文件列表。
|
|
1944
|
-
* 用于桌面客户端更新等内部缓存场景。
|
|
1945
|
-
* @param {object} input - 下载参数
|
|
1946
|
-
* @param {string} input.cid - 文件 CID
|
|
1947
|
-
* @param {string} input.targetPath - 目标文件路径
|
|
1948
|
-
* @param {string} [input.fileName] - 持有记录展示名
|
|
1949
|
-
* @param {string} [input.taskId] - 下载任务 ID
|
|
1950
|
-
* @param {number} [input.timeout] - 等待 P2P 内容的超时时间
|
|
1951
|
-
* @param {number} [input.streamReadTimeout] - 下载流无进度超时时间
|
|
1952
|
-
* @param {boolean} [input.overwrite=true] - 是否覆盖已存在目标文件
|
|
1953
|
-
* @param {string} [input.source='update'] - holding 来源
|
|
1954
|
-
*/
|
|
1955
|
-
async downloadCidToPath(input = {}) {
|
|
1956
|
-
this.#ensureInitialized()
|
|
1957
|
-
|
|
1958
|
-
const cid = input.cid
|
|
1959
|
-
const targetPath = input.targetPath
|
|
1960
|
-
if (!cid) throw new ValidationError('cid is required')
|
|
1961
|
-
if (!targetPath) throw new ValidationError('targetPath is required')
|
|
1962
|
-
|
|
1963
|
-
this.#getCidInfo(cid)
|
|
1964
|
-
const taskId =
|
|
1965
|
-
input.taskId || `cid_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
|
|
1966
|
-
const taskState = { aborted: false, readStream: null, writeStream: null }
|
|
1967
|
-
const timeout = input.timeout || this.#options.downloadTimeout
|
|
1968
|
-
const streamReadTimeout =
|
|
1969
|
-
input.streamReadTimeout ?? STREAM_READ_TIMEOUT
|
|
1970
|
-
const fileName = sanitizeFilename(input.fileName || path.basename(targetPath))
|
|
1971
|
-
const overwrite = input.overwrite !== false
|
|
1972
|
-
const resolvedTargetPath = path.resolve(targetPath)
|
|
1973
|
-
const targetDir = path.dirname(resolvedTargetPath)
|
|
1974
|
-
const tempPath = `${resolvedTargetPath}.part`
|
|
1975
|
-
|
|
1976
|
-
this.#activeDownloads.set(taskId, taskState)
|
|
1977
|
-
|
|
1978
|
-
try {
|
|
1979
|
-
const writableCheck = await checkDirectoryWritable(targetDir)
|
|
1980
|
-
if (!writableCheck.writable) {
|
|
1981
|
-
throw new PermissionError(writableCheck.error)
|
|
1982
|
-
}
|
|
1983
|
-
if (!overwrite && fs.existsSync(resolvedTargetPath)) {
|
|
1984
|
-
throw new ConflictError(`File already exists: ${resolvedTargetPath}`)
|
|
1985
|
-
}
|
|
1986
|
-
fs.rmSync(tempPath, { force: true })
|
|
1987
|
-
|
|
1988
|
-
const { driveName } = this.#getCidInfo(cid)
|
|
1989
|
-
let drive = this.#drives.get(driveName)
|
|
1990
|
-
if (!drive) {
|
|
1991
|
-
drive = await this.#getOrCreateDrive(driveName, {
|
|
1992
|
-
server: true,
|
|
1993
|
-
client: true,
|
|
1994
|
-
})
|
|
1995
|
-
this.emit('download:status', { taskId, status: 'connecting' })
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
await this.#joinCidTopicInternal(cid, {
|
|
1999
|
-
server: false,
|
|
2000
|
-
client: true,
|
|
2001
|
-
})
|
|
2002
|
-
|
|
2003
|
-
if (taskState.aborted) throw new Error('Download cancelled')
|
|
2004
|
-
this.emit('download:status', { taskId, status: 'finding-peers' })
|
|
2005
|
-
|
|
2006
|
-
const driveKey = '/' + cid
|
|
2007
|
-
const entry = await this.#waitForDriveEntry(
|
|
2008
|
-
drive,
|
|
2009
|
-
driveKey,
|
|
2010
|
-
timeout,
|
|
2011
|
-
taskId,
|
|
2012
|
-
taskState
|
|
2013
|
-
)
|
|
2014
|
-
|
|
2015
|
-
if (!entry) {
|
|
2016
|
-
throw new PeerNotFoundError(
|
|
2017
|
-
'当前没有发现可下载的在线种子,请稍后重试或确认发布者在线'
|
|
2018
|
-
)
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2021
|
-
let totalBytes = 0
|
|
2022
|
-
try {
|
|
2023
|
-
const stat = await drive.entry(entry.key)
|
|
2024
|
-
totalBytes = Number(stat?.value?.blob?.byteLength) || 0
|
|
2025
|
-
} catch {}
|
|
2026
|
-
|
|
2027
|
-
this.emit('download:status', {
|
|
2028
|
-
taskId,
|
|
2029
|
-
status: 'downloading',
|
|
2030
|
-
file: fileName,
|
|
2031
|
-
size: totalBytes ? formatFileSize(totalBytes) : null,
|
|
2032
|
-
})
|
|
2033
|
-
|
|
2034
|
-
const rs = drive.createReadStream(entry.key)
|
|
2035
|
-
const ws = fs.createWriteStream(tempPath)
|
|
2036
|
-
taskState.readStream = rs
|
|
2037
|
-
taskState.writeStream = ws
|
|
2038
|
-
|
|
2039
|
-
let loadedBytes = 0
|
|
2040
|
-
let lastProgressUpdate = 0
|
|
2041
|
-
|
|
2042
|
-
await new Promise((resolve, reject) => {
|
|
2043
|
-
let settled = false
|
|
2044
|
-
let readTimer = null
|
|
2045
|
-
|
|
2046
|
-
const clearReadTimer = () => {
|
|
2047
|
-
if (readTimer) {
|
|
2048
|
-
clearTimeout(readTimer)
|
|
2049
|
-
readTimer = null
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
|
|
2053
|
-
const fail = err => {
|
|
2054
|
-
if (settled) return
|
|
2055
|
-
settled = true
|
|
2056
|
-
clearReadTimer()
|
|
2057
|
-
rs.destroy(err)
|
|
2058
|
-
ws.destroy()
|
|
2059
|
-
fs.unlink(tempPath, () => {})
|
|
2060
|
-
reject(err)
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
|
-
const complete = () => {
|
|
2064
|
-
if (settled) return
|
|
2065
|
-
settled = true
|
|
2066
|
-
clearReadTimer()
|
|
2067
|
-
resolve()
|
|
2068
|
-
}
|
|
2069
|
-
|
|
2070
|
-
const resetReadTimer = () => {
|
|
2071
|
-
clearReadTimer()
|
|
2072
|
-
if (streamReadTimeout > 0) {
|
|
2073
|
-
readTimer = setTimeout(() => {
|
|
2074
|
-
fail(
|
|
2075
|
-
new Error(
|
|
2076
|
-
`Download stalled: no data received for ${streamReadTimeout / 1000}s`
|
|
2077
|
-
)
|
|
2078
|
-
)
|
|
2079
|
-
}, streamReadTimeout)
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
|
|
2083
|
-
resetReadTimer()
|
|
2084
|
-
|
|
2085
|
-
rs.on('data', chunk => {
|
|
2086
|
-
if (taskState.aborted) {
|
|
2087
|
-
fail(new Error('Download cancelled'))
|
|
2088
|
-
return
|
|
2089
|
-
}
|
|
2090
|
-
resetReadTimer()
|
|
2091
|
-
loadedBytes += chunk.length
|
|
2092
|
-
const now = Date.now()
|
|
2093
|
-
if (
|
|
2094
|
-
totalBytes > 0 &&
|
|
2095
|
-
now - lastProgressUpdate > PROGRESS_THROTTLE
|
|
2096
|
-
) {
|
|
2097
|
-
lastProgressUpdate = now
|
|
2098
|
-
this.emit('download:progress', {
|
|
2099
|
-
taskId,
|
|
2100
|
-
loaded: loadedBytes,
|
|
2101
|
-
total: totalBytes,
|
|
2102
|
-
percent: Math.round((loadedBytes / totalBytes) * 100),
|
|
2103
|
-
})
|
|
2104
|
-
}
|
|
2105
|
-
})
|
|
2106
|
-
|
|
2107
|
-
rs.pipe(ws)
|
|
2108
|
-
ws.on('finish', complete)
|
|
2109
|
-
ws.on('error', fail)
|
|
2110
|
-
rs.on('error', fail)
|
|
2111
|
-
rs.on('close', () => {
|
|
2112
|
-
if (taskState.aborted) fail(new Error('Download cancelled'))
|
|
2113
|
-
})
|
|
2114
|
-
ws.on('close', () => {
|
|
2115
|
-
if (taskState.aborted) fail(new Error('Download cancelled'))
|
|
2116
|
-
})
|
|
2117
|
-
})
|
|
2118
|
-
|
|
2119
|
-
if (taskState.aborted) throw new Error('Download cancelled')
|
|
2120
|
-
|
|
2121
|
-
this.emit('download:status', { taskId, status: 'verifying' })
|
|
2122
|
-
const { cid: downloadedCid, size } = await calculateCid(tempPath)
|
|
2123
|
-
if (downloadedCid.toString() !== cid) {
|
|
2124
|
-
fs.unlinkSync(tempPath)
|
|
2125
|
-
throw new IntegrityError(
|
|
2126
|
-
`File content CID mismatch. Expected ${cid}, got ${downloadedCid.toString()}.`
|
|
2127
|
-
)
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
if (fs.existsSync(resolvedTargetPath)) {
|
|
2131
|
-
fs.rmSync(resolvedTargetPath, { force: true })
|
|
2132
|
-
}
|
|
2133
|
-
fs.renameSync(tempPath, resolvedTargetPath)
|
|
2134
|
-
|
|
2135
|
-
await this.seedCidFileFromPath(cid, resolvedTargetPath, {
|
|
2136
|
-
fileName,
|
|
2137
|
-
source: input.source || 'update',
|
|
2138
|
-
})
|
|
2139
|
-
|
|
2140
|
-
const result = {
|
|
2141
|
-
taskId,
|
|
2142
|
-
cid,
|
|
2143
|
-
fileName,
|
|
2144
|
-
savedPath: resolvedTargetPath,
|
|
2145
|
-
size,
|
|
2146
|
-
}
|
|
2147
|
-
this.emit('download:success', result)
|
|
2148
|
-
return result
|
|
2149
|
-
} finally {
|
|
2150
|
-
this.#activeDownloads.delete(taskId)
|
|
2151
|
-
fs.rmSync(tempPath, { force: true })
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
|
-
|
|
2155
|
-
/**
|
|
2156
|
-
* 将本地文件按既有 CID 写入 Hyperdrive 并记录 holding,不写入用户文件列表。
|
|
2157
|
-
* @param {string} cid - 文件 CID
|
|
2158
|
-
* @param {string} filePath - 本地文件路径
|
|
2159
|
-
* @param {object} [options] - 选项
|
|
2160
|
-
* @param {string} [options.fileName] - 持有记录展示名
|
|
2161
|
-
* @param {string} [options.source='update'] - holding 来源
|
|
2162
|
-
*/
|
|
2163
|
-
async seedCidFileFromPath(cid, filePath, options = {}) {
|
|
2164
|
-
this.#ensureInitialized()
|
|
2165
|
-
if (!cid) throw new ValidationError('cid is required')
|
|
2166
|
-
if (!filePath) throw new ValidationError('filePath is required')
|
|
2167
|
-
|
|
2168
|
-
this.#getCidInfo(cid)
|
|
2169
|
-
const sizeValidation = await validateFileSize(
|
|
2170
|
-
filePath,
|
|
2171
|
-
this.#options.maxFileSize
|
|
2172
|
-
)
|
|
2173
|
-
if (!sizeValidation.valid) {
|
|
2174
|
-
throw new FileSizeError(sizeValidation.error, sizeValidation.size)
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
|
-
const { cid: actualCid } = await calculateCid(filePath)
|
|
2178
|
-
const actualCidString = actualCid.toString()
|
|
2179
|
-
if (actualCidString !== cid) {
|
|
2180
|
-
throw new IntegrityError(
|
|
2181
|
-
`File content CID mismatch. Expected ${cid}, got ${actualCidString}.`
|
|
2182
|
-
)
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
const existingHolding = this.#holdings.find(holding => holding.cid === cid)
|
|
2186
|
-
if (!existingHolding) {
|
|
2187
|
-
this.#checkCapacity(sizeValidation.size || 0)
|
|
2188
|
-
}
|
|
2189
|
-
|
|
2190
|
-
const { driveName } = this.#getCidInfo(cid)
|
|
2191
|
-
const drive = await this.#getOrCreateDrive(driveName, {
|
|
2192
|
-
server: true,
|
|
2193
|
-
client: false,
|
|
2194
|
-
})
|
|
2195
|
-
const driveKey = '/' + cid
|
|
2196
|
-
const localContent = await this.#getLocalCidContent(cid, {
|
|
2197
|
-
public: true,
|
|
2198
|
-
allowHoldingFallback: true,
|
|
2199
|
-
})
|
|
2200
|
-
|
|
2201
|
-
if (!localContent) {
|
|
2202
|
-
const readStream = fs.createReadStream(filePath)
|
|
2203
|
-
const writeStream = drive.createWriteStream(driveKey)
|
|
2204
|
-
await new Promise((resolve, reject) => {
|
|
2205
|
-
readStream.pipe(writeStream)
|
|
2206
|
-
writeStream.on('finish', resolve)
|
|
2207
|
-
writeStream.on('error', reject)
|
|
2208
|
-
readStream.on('error', reject)
|
|
2209
|
-
})
|
|
2210
|
-
}
|
|
2211
|
-
|
|
2212
|
-
await this.#joinCidTopicInternal(cid, {
|
|
2213
|
-
server: true,
|
|
2214
|
-
client: false,
|
|
2215
|
-
})
|
|
2216
|
-
|
|
2217
|
-
return this.#upsertHolding({
|
|
2218
|
-
cid,
|
|
2219
|
-
fileName: sanitizeFilename(options.fileName || path.basename(filePath)),
|
|
2220
|
-
size: sizeValidation.size || 0,
|
|
2221
|
-
driveName,
|
|
2222
|
-
source: options.source || 'update',
|
|
2223
|
-
})
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
1943
|
/**
|
|
2227
1944
|
* 读取已发布文件的内容(用于预览)
|
|
2228
1945
|
* Hyperdrive 中用 CID 作为 key 存储
|
|
@@ -2462,6 +2179,7 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2462
2179
|
channel => channel.channelKey === candidate.channelKey
|
|
2463
2180
|
)
|
|
2464
2181
|
if (existing) {
|
|
2182
|
+
const wasMember = this.#channelHasMember(existing, ownerAddress)
|
|
2465
2183
|
const writerKeysChanged = await this.#mergeChannelWriterCoreKeys(
|
|
2466
2184
|
existing,
|
|
2467
2185
|
candidate.writerCoreKeys
|
|
@@ -2472,6 +2190,7 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2472
2190
|
this.#saveChannelsMetadata()
|
|
2473
2191
|
this.#broadcastChannelHello()
|
|
2474
2192
|
}
|
|
2193
|
+
await this.#appendChannelWelcomeMessage(existing, options, wasMember)
|
|
2475
2194
|
return this.#formatChannelForResponse(existing, ownerAddress)
|
|
2476
2195
|
}
|
|
2477
2196
|
const joined = await this.#joinChannelFromCandidate(
|
|
@@ -2528,6 +2247,7 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2528
2247
|
const channelKey = buildChannelKey(channelId)
|
|
2529
2248
|
const existing = this.#channels.find(c => c.channelKey === channelKey)
|
|
2530
2249
|
if (existing) {
|
|
2250
|
+
const wasMember = this.#channelHasMember(existing, options.ownerAddress)
|
|
2531
2251
|
const writerKeysChanged = await this.#mergeChannelWriterCoreKeys(
|
|
2532
2252
|
existing,
|
|
2533
2253
|
candidate.writerCoreKeys
|
|
@@ -2538,6 +2258,7 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2538
2258
|
this.#saveChannelsMetadata()
|
|
2539
2259
|
this.#broadcastChannelHello()
|
|
2540
2260
|
}
|
|
2261
|
+
await this.#appendChannelWelcomeMessage(existing, options, wasMember)
|
|
2541
2262
|
return this.#formatChannelForResponse(existing, options.ownerAddress)
|
|
2542
2263
|
}
|
|
2543
2264
|
|
|
@@ -2730,14 +2451,6 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2730
2451
|
.map(c => this.#formatChannelForResponse(c, ownerAddress))
|
|
2731
2452
|
}
|
|
2732
2453
|
|
|
2733
|
-
getChannelMembers(channelKeyInput, options = {}) {
|
|
2734
|
-
this.#ensureInitialized()
|
|
2735
|
-
this.#assertChannelMember(channelKeyInput, options.ownerAddress)
|
|
2736
|
-
const channel = this.#resolveChannel(channelKeyInput, options.ownerAddress)
|
|
2737
|
-
|
|
2738
|
-
return this.#getChannelMembers(channel)
|
|
2739
|
-
}
|
|
2740
|
-
|
|
2741
2454
|
/**
|
|
2742
2455
|
* 获取频道消息
|
|
2743
2456
|
* @param {string} channelKeyInput - 内部频道 key,或本地唯一短频道 ID
|
|
@@ -2843,15 +2556,22 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2843
2556
|
this.#saveChannelsMetadata()
|
|
2844
2557
|
}
|
|
2845
2558
|
|
|
2559
|
+
const normalizedAvatar = normalizeChannelAvatar(options.avatar)
|
|
2846
2560
|
const message = {
|
|
2847
2561
|
type: 'message',
|
|
2848
2562
|
author,
|
|
2849
|
-
authorName
|
|
2563
|
+
authorName: normalizeChannelDisplayName(
|
|
2564
|
+
authorName,
|
|
2565
|
+
normalizeOwnerAddress(author)
|
|
2566
|
+
),
|
|
2850
2567
|
content: trimmed,
|
|
2851
2568
|
timestamp: await this.#getNextChannelMessageTimestamp(
|
|
2852
2569
|
channel.channelKey
|
|
2853
2570
|
),
|
|
2854
2571
|
}
|
|
2572
|
+
if (normalizedAvatar) {
|
|
2573
|
+
message.avatar = normalizedAvatar
|
|
2574
|
+
}
|
|
2855
2575
|
if (attachment) {
|
|
2856
2576
|
message.attachment = attachment
|
|
2857
2577
|
}
|
|
@@ -2977,6 +2697,7 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2977
2697
|
await this.#joinChannelDiscoveryTopics(channelInfo)
|
|
2978
2698
|
this.#cacheChannelCandidate(this.#channelToCandidate(channelInfo, true))
|
|
2979
2699
|
this.#saveChannelsMetadata()
|
|
2700
|
+
await this.#appendChannelWelcomeMessage(channelInfo, options, false)
|
|
2980
2701
|
this.#broadcastChannelHello()
|
|
2981
2702
|
return channelInfo
|
|
2982
2703
|
}
|
|
@@ -2994,10 +2715,12 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
2994
2715
|
channel => channel.channelKey === channelKey
|
|
2995
2716
|
)
|
|
2996
2717
|
if (existing) {
|
|
2718
|
+
const wasMember = this.#channelHasMember(existing, options.ownerAddress)
|
|
2997
2719
|
if (this.#upsertChannelMember(existing, options)) {
|
|
2998
2720
|
this.#saveChannelsMetadata()
|
|
2999
2721
|
this.#broadcastChannelHello()
|
|
3000
2722
|
}
|
|
2723
|
+
await this.#appendChannelWelcomeMessage(existing, options, wasMember)
|
|
3001
2724
|
return this.#formatChannelForResponse(existing, options.ownerAddress)
|
|
3002
2725
|
}
|
|
3003
2726
|
|
|
@@ -3328,6 +3051,32 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
3328
3051
|
return true
|
|
3329
3052
|
}
|
|
3330
3053
|
|
|
3054
|
+
async #appendChannelWelcomeMessage(channel, options = {}, wasMember = false) {
|
|
3055
|
+
const ownerAddress = normalizeOwnerAddress(options.ownerAddress)
|
|
3056
|
+
if (
|
|
3057
|
+
wasMember ||
|
|
3058
|
+
!ownerAddress ||
|
|
3059
|
+
!channel ||
|
|
3060
|
+
TRANSIENT_CHANNEL_TYPES.has(channel.type)
|
|
3061
|
+
) {
|
|
3062
|
+
return false
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
await this.sendMessage(
|
|
3066
|
+
channel.channelKey,
|
|
3067
|
+
CHANNEL_WELCOME_MESSAGE,
|
|
3068
|
+
ownerAddress,
|
|
3069
|
+
normalizeChannelDisplayName(options.displayName, ownerAddress),
|
|
3070
|
+
{
|
|
3071
|
+
ownerAddress,
|
|
3072
|
+
...(Object.prototype.hasOwnProperty.call(options, 'avatar')
|
|
3073
|
+
? { avatar: options.avatar }
|
|
3074
|
+
: {}),
|
|
3075
|
+
}
|
|
3076
|
+
)
|
|
3077
|
+
return true
|
|
3078
|
+
}
|
|
3079
|
+
|
|
3331
3080
|
#getChannelMembers(channel) {
|
|
3332
3081
|
const members = Array.isArray(channel?.members) ? channel.members : []
|
|
3333
3082
|
return members
|
|
@@ -3392,14 +3141,11 @@ export class MostBoxEngine extends EventEmitter {
|
|
|
3392
3141
|
authorAddress
|
|
3393
3142
|
)
|
|
3394
3143
|
const avatar = normalizeChannelAvatar(member.avatar)
|
|
3395
|
-
if (displayName && baseMessage?.authorName
|
|
3144
|
+
if (displayName && !String(baseMessage?.authorName || '').trim()) {
|
|
3396
3145
|
baseMessage = { ...baseMessage, authorName: displayName }
|
|
3397
3146
|
}
|
|
3398
|
-
if (avatar && baseMessage?.avatar
|
|
3147
|
+
if (avatar && !normalizeChannelAvatar(baseMessage?.avatar)) {
|
|
3399
3148
|
baseMessage = { ...baseMessage, avatar }
|
|
3400
|
-
} else if (!avatar && baseMessage?.avatar) {
|
|
3401
|
-
baseMessage = { ...baseMessage }
|
|
3402
|
-
delete baseMessage.avatar
|
|
3403
3149
|
}
|
|
3404
3150
|
}
|
|
3405
3151
|
const attachment = baseMessage?.attachment
|
package/server/src/utils/api.js
CHANGED
|
@@ -164,6 +164,49 @@ function clearActiveRemoteNode() {
|
|
|
164
164
|
)
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
function getLocalNodeHistoryItem(activeBackendUrl = getBackendUrl()) {
|
|
168
|
+
const normalizedActiveUrl = normalizeBackendUrl(activeBackendUrl)
|
|
169
|
+
const fallbackLocalUrl = getDefaultBackendUrl()
|
|
170
|
+
const localUrl = isLocalBackendUrl(normalizedActiveUrl)
|
|
171
|
+
? normalizedActiveUrl
|
|
172
|
+
: fallbackLocalUrl
|
|
173
|
+
|
|
174
|
+
if (!isLocalBackendUrl(localUrl)) return null
|
|
175
|
+
|
|
176
|
+
const url = normalizeBackendUrl(localUrl)
|
|
177
|
+
return {
|
|
178
|
+
url,
|
|
179
|
+
invite: '',
|
|
180
|
+
active: url === normalizedActiveUrl,
|
|
181
|
+
local: true,
|
|
182
|
+
updatedAt: Number.MAX_SAFE_INTEGER,
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function getNodeHistory() {
|
|
187
|
+
if (typeof window === 'undefined') return []
|
|
188
|
+
|
|
189
|
+
const activeBackendUrl = normalizeBackendUrl(getBackendUrl())
|
|
190
|
+
const localNode = getLocalNodeHistoryItem(activeBackendUrl)
|
|
191
|
+
const remoteNodes = getRemoteNodes().map((node, index) => ({
|
|
192
|
+
...node,
|
|
193
|
+
active: normalizeBackendUrl(node.url) === activeBackendUrl,
|
|
194
|
+
local: false,
|
|
195
|
+
order: index + 1,
|
|
196
|
+
}))
|
|
197
|
+
const nodes = localNode
|
|
198
|
+
? [{ ...localNode, order: 0 }, ...remoteNodes]
|
|
199
|
+
: remoteNodes
|
|
200
|
+
|
|
201
|
+
return nodes
|
|
202
|
+
.sort((a, b) => {
|
|
203
|
+
if (a.active !== b.active) return a.active ? -1 : 1
|
|
204
|
+
if (a.local !== b.local) return a.local ? -1 : 1
|
|
205
|
+
return a.order - b.order
|
|
206
|
+
})
|
|
207
|
+
.map(({ order: _order, ...node }) => node)
|
|
208
|
+
}
|
|
209
|
+
|
|
167
210
|
function normalizeBackendUrl(url) {
|
|
168
211
|
return (url || '').trim().replace(/\/+$/, '')
|
|
169
212
|
}
|
|
@@ -390,6 +433,10 @@ export function getRemoteNodesExport() {
|
|
|
390
433
|
return getRemoteNodes()
|
|
391
434
|
}
|
|
392
435
|
|
|
436
|
+
export function getNodeHistoryExport() {
|
|
437
|
+
return getNodeHistory()
|
|
438
|
+
}
|
|
439
|
+
|
|
393
440
|
export function getBackendInviteExport() {
|
|
394
441
|
return getBackendInvite()
|
|
395
442
|
}
|
package/server/src/utils/auth.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { verifyMessage } from 'ethers'
|
|
2
|
+
import { normalizeAddress } from '../core/shared.js'
|
|
2
3
|
import { mostSignMessage } from './mostWallet.js'
|
|
3
4
|
|
|
4
5
|
export const AUTH_MAX_AGE_MS = 5 * 60 * 1000
|
|
5
|
-
|
|
6
|
-
export function normalizeAddress(address) {
|
|
7
|
-
const value = String(address || '').trim()
|
|
8
|
-
return /^0x[a-fA-F0-9]{40}$/.test(value) ? value.toLowerCase() : ''
|
|
9
|
-
}
|
|
6
|
+
export { normalizeAddress }
|
|
10
7
|
|
|
11
8
|
export function buildAuthMessage(timestamp, method, path) {
|
|
12
9
|
return `${timestamp}:${String(method || 'GET').toUpperCase()}:${normalizeAuthPath(path)}`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import dayjs from 'dayjs'
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function formatTime(time) {
|
|
4
4
|
if (!time) return ''
|
|
5
5
|
const date = dayjs(Number(time))
|
|
6
6
|
const hour = date.hour()
|
|
@@ -26,5 +26,3 @@ export function formatDate(time) {
|
|
|
26
26
|
|
|
27
27
|
return date.format(`YYYY年M月D日 ${timeOfDay}h:m`)
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
export const formatTime = formatDate
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{s as t,t as n,w as r}from"./ui-PnUvY9zL.js";import{a as i,c as a,o}from"./i18n--maTEG0d.js";var s=r(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),c=r(`languages`,[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]]),l=r(`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`}]]),u=r(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]),d=r(`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`}]]),f=e();function p(){let{t:e}=i(),{state:n,installAndRestart:r}=t(),a=n.status===`checking`,o=n.status===`downloading`,s=n.status===`downloaded`,c=n.status===`installing`,l=a||o||c;if(!a&&!o&&!s&&!c)return null;let d=e(`desktopUpdate.install`);a?d=e(`desktopUpdate.checking`):o?d=n.progress>0?e(`desktopUpdate.downloadingProgress`,{progress:n.progress}):e(`desktopUpdate.downloading`):c&&(d=e(`desktopUpdate.installing`));let p=a||o?e(`desktopUpdate.downloadingTitle`):e(`desktopUpdate.readyTitle`,{version:n.version||n.filename});return(0,f.jsxs)(`button`,{type:`button`,className:`btn ${s||c?`btn-primary`:`btn-secondary`} desktop-update-button`,disabled:!s||c,title:p,"aria-live":l?`polite`:void 0,onClick:()=>{s&&r()},children:[(0,f.jsx)(u,{size:16,className:l?`spin`:void 0}),d]})}function m({className:e=``}){let{locale:t,localeName:r,setLocale:l,t:u}=i(),d=u(`common.locale.choose`),p=`${d} (${u(`common.locale.current`)}: ${r})`;return(0,f.jsx)(n,{ariaLabel:d,placement:`bottom-end`,items:o.map(e=>({key:e,label:a[e],icon:e===t?(0,f.jsx)(s,{size:16}):(0,f.jsx)(`span`,{"aria-hidden":`true`}),onSelect:()=>{e!==t&&l(e)}})),renderTrigger:t=>(0,f.jsx)(`button`,{...t,className:[`language-toggle`,e].filter(Boolean).join(` `),"aria-label":d,title:p,children:(0,f.jsx)(c,{size:16})})})}export{l as a,u as i,p as n,s as o,d as r,m as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{n as t,t as n}from"./LanguageToggle-BoBNesNU.js";import{k as r,w as i}from"./index-Cg4kEvx8.js";import{t as a}from"./MarketingThemeToggle-BLuQ_uE-.js";var o=e();function s(){return(0,o.jsx)(`nav`,{className:`mkt-nav`,children:(0,o.jsxs)(`div`,{className:`mkt-nav-inner`,children:[(0,o.jsxs)(`button`,{type:`button`,className:`mkt-nav-logo`,onClick:i(),children:[(0,o.jsx)(r,{size:18}),(0,o.jsx)(`span`,{children:`MOST PEOPLE`})]}),(0,o.jsxs)(`div`,{className:`mkt-nav-cta`,children:[(0,o.jsx)(a,{}),(0,o.jsx)(n,{className:`mkt-theme-toggle`}),(0,o.jsx)(t,{})]})]})})}export{s as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{O as t,c as n,o as r}from"./ui-PnUvY9zL.js";import{a as i}from"./i18n--maTEG0d.js";import{n as a,t as o}from"./LanguageToggle-BoBNesNU.js";import{t as s}from"./download-Q6jKMPIG.js";import{i as c}from"./index-Cg4kEvx8.js";import{t as l}from"./MarketingThemeToggle-BLuQ_uE-.js";import{t as u}from"./LogoIcon-B2fFe0l1.js";var d={name:`most-box`,version:`0.2.6`,description:`MostBox - P2P file sharing application`,type:`module`,main:`electron/main.js`,bin:{"most-box":`server/cli.js`},files:[`out`,`public`,`electron`,`server/src`,`server/index.js`,`server/cli.js`],scripts:{start:`vite`,server:`node --watch server/index.js`,dev:`vite`,build:`vite build && node scripts/prepare-start-static.mjs`,preview:`vite preview`,serve:`npm run build && node server/index.js`,test:`node --test server/tests/**/*.test.js`,"test:unit":`node --test server/tests/unit/*.test.js`,"test:frontend":`node --test src/tests/*.test.js`,"test:protocol":`node --test --test-name-pattern "extracts CID and filename|matches golden CID samples|publishes a file from Buffer|lists published files|pulls through local seed nodes" server/tests/unit/cid.test.js server/tests/integration/cid.test.js server/tests/integration/engine.test.js`,typecheck:`tsc -p tsconfig.typecheck.json`,"typecheck:strict-router":`tsc -p tsconfig.strict-router.json`,"check:static-output":`node scripts/check-static-output.mjs`,format:`npx prettier --write .`,lint:`npx eslint .`,"r2:cors":`node scripts/configure-r2-cors.mjs`,"electron:dev":`concurrently "npm run build" "wait-on out/index.html && electron ."`,"electron:rebuild":`electron-rebuild -f -w sodium-native`,"electron:build":`npm run build && npm run electron:rebuild && electron-builder`,"electron:build:win":`npm run build && npm run electron:rebuild && electron-builder --win`,"electron:build:win:x64":`npm run electron:build:win -- --x64`,"electron:build:win:arm64":`npm run electron:build:win -- --arm64`,"electron:build:mac":`npm run build && npm run electron:rebuild && electron-builder --mac`,"electron:build:linux":`npm run build && npm run electron:rebuild && electron-builder --linux`},keywords:[`p2p`,`file-sharing`,`hyperswarm`,`hyperdrive`],license:`MIT`,dependencies:{"@dicebear/collection":`^9.4.2`,"@dicebear/core":`^9.4.2`,"@hono/node-server":`^2.0.4`,"@tanstack/react-router":`^1.170.15`,"@tanstack/react-start":`^1.168.25`,b4a:`^1.8.1`,busboy:`^1.6.0`,corestore:`^7.10.0`,dayjs:`^1.11.21`,ethers:`^6.16.0`,eventemitter3:`^5.0.4`,hono:`^4.12.23`,hypercore:`^11.33.1`,hyperdrive:`^13.3.2`,hyperswarm:`^4.17.0`,"ipfs-unixfs-importer":`^17.0.1`,multiformats:`^14.0.0`,tweetnacl:`^1.0.3`,ws:`^8.21.0`},devDependencies:{"@electron/rebuild":`^4.0.4`,"@eslint/js":`^10.0.1`,"@iconify/react":`^6.0.2`,"@mantine/hooks":`^9.3.0`,"@milkdown/crepe":`^7.21.2`,"@milkdown/utils":`^7.21.2`,"@types/react":`^19.2.16`,"@vitejs/plugin-react":`^6.0.2`,concurrently:`^10.0.3`,electron:`^42.3.3`,"electron-builder":`^26.8.1`,esbuild:`^0.28.0`,eslint:`^10.4.1`,globals:`^17.6.0`,ky:`^2.0.2`,"lucide-react":`^1.17.0`,prettier:`^3.8.3`,"qrcode.react":`^4.2.0`,react:`^19.2.7`,"react-dom":`^19.2.7`,typescript:`6.0.3`,"typescript-eslint":`^8.60.1`,vite:`^8.0.16`,"wait-on":`^9.0.10`,zustand:`^5.0.14`},overrides:{"brace-expansion":`5.0.6`,postcss:`8.5.15`,ws:`$ws`},build:{appId:`com.mostbox.app`,productName:`MostBox`,publish:[{provider:`github`,releaseType:`release`}],directories:{output:`dist`},afterPack:`electron/afterPack.cjs`,files:[`out/**/*`,`electron/**/*`,`server/src/**/*`,`server/index.js`,`server/cli.js`,`package.json`,`!**/*.map`,`!electron/**/*.test.js`,`!server/tests/**/*`],asarUnpack:[`**/*.node`,`**/sodium-native/**`],protocols:[{name:`MostBox Link`,schemes:[`most`]}],win:{target:[`nsis`],artifactName:"${productName}-${version}-win-${arch}-setup.${ext}",icon:`public/logo.ico`},nsis:{oneClick:!1,allowToChangeInstallationDirectory:!0,createDesktopShortcut:!0,createStartMenuShortcut:!0,shortcutName:`MostBox`},mac:{artifactName:"${productName}-${version}-mac-${arch}.${ext}",target:[{target:`dmg`,arch:[`x64`,`arm64`]},{target:`zip`,arch:[`x64`,`arm64`]}],icon:`public/logo-512.png`,category:`public.app-category.utilities`},dmg:{contents:[{x:130,y:220},{x:410,y:220,type:`link`,path:`/Applications`}]},linux:{artifactName:"${productName}-${version}-linux-${arch}.${ext}",target:[{target:`AppImage`,arch:[`x64`,`arm64`]}],icon:`public/logo-512.png`,category:`Utility`}}},f=e(),p=[{to:`/`,labelKey:`footer.about`},{to:`/ping/`,labelKey:`footer.network`},{href:`https://github.com/most-people/most`,labelKey:null,label:`GitHub`,external:!0}],m=d.version;function h(){let{t:e}=i();return(0,f.jsx)(`footer`,{className:`mkt-footer`,children:(0,f.jsx)(`div`,{className:`mkt-container`,children:(0,f.jsxs)(`div`,{className:`mkt-footer-inner`,children:[(0,f.jsx)(`div`,{className:`mkt-footer-links`,children:p.map(n=>`external`in n?(0,f.jsx)(`a`,{href:n.href,target:`_blank`,rel:`noopener noreferrer`,children:n.label},n.href):(0,f.jsx)(t,{to:n.to,children:e(n.labelKey)},n.to))}),(0,f.jsxs)(`span`,{className:`mkt-footer-copy`,children:[`© `,new Date().getFullYear(),` MOST PEOPLE · MIT License`]}),(0,f.jsxs)(`span`,{className:`mkt-footer-build`,translate:`no`,children:[`v`,m]})]})})})}function g({children:e,header:t}){return(0,f.jsxs)(`div`,{className:`mkt-layout`,children:[t??(0,f.jsx)(_,{}),(0,f.jsx)(`main`,{className:`mkt-layout-main`,children:e}),(0,f.jsx)(h,{})]})}function _(){let e=n(e=>e.identity),d=n(e=>e.openLoginModal),{t:p}=i(),m=r(),h=e?.displayName||e?.username||p(`nav.openWeb`);return(0,f.jsx)(`nav`,{className:`mkt-nav`,children:(0,f.jsxs)(`div`,{className:`mkt-nav-inner`,children:[(0,f.jsxs)(t,{to:`/`,className:`mkt-nav-logo`,children:[(0,f.jsx)(u,{}),`MOST PEOPLE`]}),(0,f.jsxs)(`div`,{className:`mkt-nav-cta`,children:[(0,f.jsx)(l,{}),(0,f.jsx)(o,{className:`mkt-theme-toggle`}),(0,f.jsx)(a,{}),!m&&(0,f.jsxs)(t,{to:`/download/`,className:`btn btn-primary mkt-nav-preview`,children:[(0,f.jsx)(s,{size:16}),p(`nav.downloadClient`)]}),e?(0,f.jsx)(t,{to:`/profile/`,className:`mkt-nav-avatar-trigger`,"aria-label":p(`nav.profile`),title:h,children:(0,f.jsx)(`img`,{className:`mkt-nav-avatar`,src:c(e.address,e.avatar),alt:``,"aria-hidden":`true`})}):(0,f.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:d,children:p(`nav.getStarted`)})]})]})})}export{g as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e,o as t,t as n}from"./jsx-runtime-Bt-cYkS5.js";import{O as r,w as i}from"./ui-PnUvY9zL.js";import{a}from"./i18n--maTEG0d.js";import{n as o,t as s}from"./LanguageToggle-BoBNesNU.js";import{k as c}from"./index-Cg4kEvx8.js";var l=i(`menu`,[[`path`,{d:`M4 5h16`,key:`1tepv9`}],[`path`,{d:`M4 12h16`,key:`1lakjw`}],[`path`,{d:`M4 19h16`,key:`1djgab`}]]),u=t(e(),1);function d(e,t){return typeof t==`boolean`?t:typeof window<`u`&&`matchMedia`in window?window.matchMedia(e).matches:!1}function f(e,t,{getInitialValueInEffect:n}={getInitialValueInEffect:!0}){let[r,i]=(0,u.useState)(n?t:d(e));return(0,u.useEffect)(()=>{try{if(`matchMedia`in window){let t=window.matchMedia(e);i(t.matches);let n=e=>i(e.matches);return t.addEventListener(`change`,n),()=>{t.removeEventListener(`change`,n)}}}catch{return}},[e]),r||!1}function p(e=!1,t={}){let[n,r]=(0,u.useState)(e),i=(0,u.useCallback)(()=>{r(e=>e||(t.onOpen?.(),!0))},[t.onOpen]),a=(0,u.useCallback)(()=>{r(e=>e&&(t.onClose?.(),!1))},[t.onClose]);return[n,{open:i,close:a,toggle:(0,u.useCallback)(()=>{n?a():i()},[a,i,n]),set:r}]}var m=n(),h=(0,u.createContext)(null);function g(){let e=(0,u.useContext)(h);if(!e)throw Error(`useAppShell must be used within AppShell`);return e}function _({sidebar:e,className:t=``,headerTitle:n,headerRight:r,sidebarToggleReplacement:i,defaultHide:c=!1,children:d}){let[g,_]=p(!1),[v,y]=(0,u.useState)(c),b=(0,u.useRef)(c),x=f(`(max-width: 768px)`),{t:S}=a(),C=(0,u.useCallback)((e={})=>{_.close(),e.collapse&&y(!0)},[_]);(0,u.useEffect)(()=>{c!==b.current&&(c?C({collapse:!0}):y(!1),b.current=c)},[c,C]);let w=()=>{x?_.toggle():y(!v)},T=()=>{x?_.open():y(!1)},E=x?g:!v;return(0,m.jsx)(h.Provider,{value:{closeSidebar:C,openSidebar:T,isSidebarVisible:E},children:(0,m.jsxs)(`div`,{className:[`app-layout`,t].filter(Boolean).join(` `),children:[(0,m.jsx)(`div`,{className:`sidebar-overlay ${g?`visible`:``}`,onClick:()=>C()}),(0,m.jsx)(`div`,{className:`sidebar ${g?`open`:``} ${v?`collapsed`:``}`,children:e({closeSidebar:C,openSidebar:T})}),(0,m.jsxs)(`div`,{className:`main-content`,children:[(0,m.jsxs)(`header`,{className:`app-header`,children:[(0,m.jsxs)(`div`,{className:`header-left`,children:[i??(0,m.jsx)(`button`,{onClick:w,className:`btn btn-icon sidebar-toggle-btn`,"aria-label":S(x?`appShell.openMenu`:v?`appShell.expandSidebar`:`appShell.collapseSidebar`),children:(0,m.jsx)(l,{size:16})}),n]}),(0,m.jsxs)(`div`,{className:`header-right`,children:[(0,m.jsx)(o,{}),(0,m.jsx)(s,{className:`btn btn-icon app-language-toggle`}),r]})]}),d]})]})})}function v({onNavigate:e}){let{t}=a(),n=t(`common.brand`);return(0,m.jsxs)(r,{to:`/`,className:`sidebar-header sidebar-header-link`,onClick:e,"aria-label":n,title:n,children:[(0,m.jsx)(c,{size:18}),(0,m.jsx)(`h1`,{children:n})]})}export{p as i,_ as n,g as r,v as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{w as e}from"./ui-PnUvY9zL.js";var t=e(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]);export{t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{w as e}from"./ui-PnUvY9zL.js";var t=e(`cloud`,[[`path`,{d:`M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z`,key:`p7xjir`}]]);export{t};
|