most-box 0.0.4 → 0.0.7

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 (187) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +222 -182
  3. package/electron/main.js +67 -0
  4. package/out/404/index.html +2 -2
  5. package/out/404.html +2 -2
  6. package/out/__next.__PAGE__.txt +6 -4
  7. package/out/__next._full.txt +20 -17
  8. package/out/__next._head.txt +3 -3
  9. package/out/__next._index.txt +6 -5
  10. package/out/__next._tree.txt +4 -2
  11. package/out/_next/static/chunks/003jnm.v5tzw5.js +1 -0
  12. package/out/_next/static/chunks/00re8v.gbcywn.js +1 -0
  13. package/out/_next/static/chunks/00s106sbq8t9v.js +1 -0
  14. package/out/_next/static/chunks/012hi627qrdnn.js +1 -0
  15. package/out/_next/static/chunks/0174xh3wfsjm1.js +2 -0
  16. package/out/_next/static/chunks/01xlw8hd842-c.js +1 -0
  17. package/out/_next/static/chunks/02~o2nmo5pmy1.js +1 -0
  18. package/out/_next/static/chunks/07t.dhhokszz5.css +1 -0
  19. package/out/_next/static/chunks/0_wia9ofmsi1c.css +2 -0
  20. package/out/_next/static/chunks/0ah8fihozo2_u.js +5 -0
  21. package/out/_next/static/chunks/0bzupvr5gt3k9.js +31 -0
  22. package/out/_next/static/chunks/0d3shmwh5_nmn.js +1 -0
  23. package/out/_next/static/chunks/0e_h0d3ekzks8.css +1 -0
  24. package/out/_next/static/chunks/0gdluj423gso1.js +1 -0
  25. package/out/_next/static/chunks/0gmoiq06srjay.css +1 -0
  26. package/out/_next/static/chunks/0ho~log~~-jwp.css +1 -0
  27. package/out/_next/static/chunks/0imkasy7kb67u.js +1 -0
  28. package/out/_next/static/chunks/0jjc_b9q_ldi2.js +1 -0
  29. package/out/_next/static/chunks/0jl~j62iz2uvr.js +1 -0
  30. package/out/_next/static/chunks/0lqslm813wk_h.js +1 -0
  31. package/out/_next/static/chunks/{0bogtdbh.dcu1.js → 0n~dq4kpx9xxx.js} +1 -1
  32. package/out/_next/static/chunks/0pqt~8bl3ukh4.js +4 -0
  33. package/out/_next/static/chunks/0q782fxxd0lx~.js +1 -0
  34. package/out/_next/static/chunks/0qub_r0x_r-e9.css +1 -0
  35. package/out/_next/static/chunks/0slwj0c46k5cu.js +1 -0
  36. package/out/_next/static/chunks/0sorqk.oc6b7j.css +1 -0
  37. package/out/_next/static/chunks/0tapzqc6hgvx-.js +1 -0
  38. package/out/_next/static/chunks/0xsc7z5x8n7wg.js +1 -0
  39. package/out/_next/static/chunks/0zm~gys2jwl0g.js +1 -0
  40. package/out/_next/static/chunks/turbopack-0a_g3u0ud~jb8.js +1 -0
  41. package/out/_not-found/__next._full.txt +19 -15
  42. package/out/_not-found/__next._head.txt +3 -3
  43. package/out/_not-found/__next._index.txt +6 -5
  44. package/out/_not-found/__next._not-found.__PAGE__.txt +9 -0
  45. package/out/_not-found/__next._not-found.txt +3 -3
  46. package/out/_not-found/__next._tree.txt +2 -2
  47. package/out/_not-found/index.html +2 -2
  48. package/out/_not-found/index.txt +19 -15
  49. package/out/app/__next._full.txt +20 -0
  50. package/out/app/__next._head.txt +5 -0
  51. package/out/app/__next._index.txt +7 -0
  52. package/out/app/__next._tree.txt +2 -0
  53. package/out/app/__next.app.__PAGE__.txt +9 -0
  54. package/out/app/__next.app.txt +5 -0
  55. package/out/app/index.html +15 -0
  56. package/out/app/index.txt +20 -0
  57. package/out/changelog/__next._full.txt +22 -0
  58. package/out/changelog/__next._head.txt +5 -0
  59. package/out/changelog/__next._index.txt +7 -0
  60. package/out/changelog/__next._tree.txt +3 -0
  61. package/out/changelog/__next.changelog.__PAGE__.txt +10 -0
  62. package/out/changelog/__next.changelog.txt +5 -0
  63. package/out/changelog/index.html +15 -0
  64. package/out/changelog/index.txt +22 -0
  65. package/out/chat/__next._full.txt +20 -18
  66. package/out/chat/__next._head.txt +3 -3
  67. package/out/chat/__next._index.txt +6 -5
  68. package/out/chat/__next._tree.txt +3 -3
  69. package/out/chat/__next.chat.__PAGE__.txt +9 -0
  70. package/out/chat/__next.chat.txt +5 -4
  71. package/out/chat/index.html +2 -2
  72. package/out/chat/index.txt +20 -18
  73. package/out/docs/__next._full.txt +22 -0
  74. package/out/docs/__next._head.txt +5 -0
  75. package/out/docs/__next._index.txt +7 -0
  76. package/out/docs/__next._tree.txt +3 -0
  77. package/out/docs/__next.docs.__PAGE__.txt +10 -0
  78. package/out/docs/__next.docs.txt +5 -0
  79. package/out/docs/getting-started/__next._full.txt +22 -0
  80. package/out/docs/getting-started/__next._head.txt +5 -0
  81. package/out/docs/getting-started/__next._index.txt +7 -0
  82. package/out/docs/getting-started/__next._tree.txt +3 -0
  83. package/out/docs/getting-started/__next.docs.getting-started.__PAGE__.txt +10 -0
  84. package/out/docs/getting-started/__next.docs.getting-started.txt +5 -0
  85. package/out/docs/getting-started/__next.docs.txt +5 -0
  86. package/out/docs/getting-started/index.html +15 -0
  87. package/out/docs/getting-started/index.txt +22 -0
  88. package/out/docs/index.html +15 -0
  89. package/out/docs/index.txt +22 -0
  90. package/out/download/__next._full.txt +34 -0
  91. package/out/download/__next._head.txt +5 -0
  92. package/out/download/__next._index.txt +7 -0
  93. package/out/download/__next._tree.txt +4 -0
  94. package/out/download/__next.download.__PAGE__.txt +16 -0
  95. package/out/download/__next.download.txt +5 -0
  96. package/out/download/index.html +15 -0
  97. package/out/download/index.txt +34 -0
  98. package/out/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  99. package/out/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
  100. package/out/fonts/jetbrains-mono-latin-600-normal.woff2 +0 -0
  101. package/out/fonts/jetbrains-mono-latin-700-normal.woff2 +0 -0
  102. package/out/index.html +2 -2
  103. package/out/index.txt +20 -17
  104. package/out/ping/__next._full.txt +21 -0
  105. package/out/ping/__next._head.txt +5 -0
  106. package/out/ping/__next._index.txt +7 -0
  107. package/out/ping/__next._tree.txt +4 -0
  108. package/out/ping/__next.ping.__PAGE__.txt +10 -0
  109. package/out/ping/__next.ping.txt +5 -0
  110. package/out/ping/index.html +15 -0
  111. package/out/ping/index.txt +21 -0
  112. package/out/pwa-512x512.png +0 -0
  113. package/out/web3/__next._full.txt +21 -0
  114. package/out/web3/__next._head.txt +5 -0
  115. package/out/web3/__next._index.txt +7 -0
  116. package/out/web3/__next._tree.txt +3 -0
  117. package/out/web3/__next.web3.__PAGE__.txt +9 -0
  118. package/out/web3/__next.web3.txt +6 -0
  119. package/out/web3/ed25519/__next._full.txt +20 -0
  120. package/out/web3/ed25519/__next._head.txt +5 -0
  121. package/out/web3/ed25519/__next._index.txt +7 -0
  122. package/out/web3/ed25519/__next._tree.txt +3 -0
  123. package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +6 -0
  124. package/out/web3/ed25519/__next.web3.ed25519.txt +5 -0
  125. package/out/web3/ed25519/__next.web3.txt +6 -0
  126. package/out/web3/ed25519/index.html +1 -0
  127. package/out/web3/ed25519/index.txt +20 -0
  128. package/out/web3/index.html +15 -0
  129. package/out/web3/index.txt +21 -0
  130. package/out/web3/tools/__next._full.txt +20 -0
  131. package/out/web3/tools/__next._head.txt +5 -0
  132. package/out/web3/tools/__next._index.txt +7 -0
  133. package/out/web3/tools/__next._tree.txt +3 -0
  134. package/out/web3/tools/__next.web3.tools.__PAGE__.txt +6 -0
  135. package/out/web3/tools/__next.web3.tools.txt +5 -0
  136. package/out/web3/tools/__next.web3.txt +6 -0
  137. package/out/web3/tools/index.html +1 -0
  138. package/out/web3/tools/index.txt +20 -0
  139. package/package.json +162 -53
  140. package/public/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  141. package/public/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
  142. package/public/fonts/jetbrains-mono-latin-600-normal.woff2 +0 -0
  143. package/public/fonts/jetbrains-mono-latin-700-normal.woff2 +0 -0
  144. package/public/pwa-512x512.png +0 -0
  145. package/server/cli.js +3 -0
  146. package/server/index.js +995 -0
  147. package/{src → server/src}/config.js +51 -50
  148. package/{src → server/src}/core/cid.js +157 -150
  149. package/{src → server/src}/index.js +1952 -1669
  150. package/server/src/utils/api.js +68 -0
  151. package/server/src/utils/avatar.js +11 -0
  152. package/{src → server/src}/utils/errors.js +70 -66
  153. package/server/src/utils/mostWallet.js +42 -0
  154. package/server/src/utils/mp.js +105 -0
  155. package/{src → server/src}/utils/security.js +173 -169
  156. package/server/src/utils/userIdentity.js +93 -0
  157. package/cli.js +0 -2
  158. package/out/_next/static/chunks/00l-yd3t8dvwz.js +0 -5
  159. package/out/_next/static/chunks/03k8t3tgym~8~.js +0 -1
  160. package/out/_next/static/chunks/09vfh8lfuacc0.css +0 -1
  161. package/out/_next/static/chunks/0dbhjjzl8qfwv.js +0 -1
  162. package/out/_next/static/chunks/0f73psqhr8dre.css +0 -1
  163. package/out/_next/static/chunks/0fbi7z4_.4j1j.js +0 -1
  164. package/out/_next/static/chunks/0ht900cau6_ur.js +0 -31
  165. package/out/_next/static/chunks/0ohm.ia-4ec60.js +0 -1
  166. package/out/_next/static/chunks/0u5ydb-f0.vxl.js +0 -1
  167. package/out/_next/static/chunks/14t2m1on-s5v~.js +0 -1
  168. package/out/_next/static/chunks/turbopack-076ce9exut_h3.js +0 -1
  169. package/out/_not-found/__next._not-found/__PAGE__.txt +0 -5
  170. package/out/app.css +0 -1535
  171. package/out/bundle.js +0 -107
  172. package/out/bundle.js.map +0 -7
  173. package/out/chat/__next.chat/__PAGE__.txt +0 -9
  174. package/out/chat-page.js +0 -112
  175. package/out/chat.css +0 -378
  176. package/out/index.js +0 -148
  177. package/public/app.css +0 -1535
  178. package/public/bundle.js +0 -107
  179. package/public/bundle.js.map +0 -7
  180. package/public/chat-page.js +0 -112
  181. package/public/chat.css +0 -378
  182. package/public/index.js +0 -148
  183. package/server.js +0 -880
  184. package/src/utils/api.js +0 -6
  185. /package/out/_next/static/{0h4f4QFk_KC9FlSRfQACk → sV38nXrv3xVVO6wvSdFlZ}/_buildManifest.js +0 -0
  186. /package/out/_next/static/{0h4f4QFk_KC9FlSRfQACk → sV38nXrv3xVVO6wvSdFlZ}/_clientMiddlewareManifest.js +0 -0
  187. /package/out/_next/static/{0h4f4QFk_KC9FlSRfQACk → sV38nXrv3xVVO6wvSdFlZ}/_ssgManifest.js +0 -0
@@ -1,50 +1,51 @@
1
- /**
2
- * 应用配置
3
- */
4
-
5
- // 文件大小限制
6
- export const MAX_FILE_SIZE = 100 * 1024 * 1024 * 1024 // 100 GB
7
-
8
- // 网络超时(毫秒)
9
- export const CONNECTION_TIMEOUT = 120000
10
- export const DOWNLOAD_TIMEOUT = 900000
11
-
12
- // P2P 设置
13
- export const GLOBAL_SHARED_SEED_STRING = 'most-box-global-shared-seed-v1'
14
- export const MAX_PEERS = 64
15
- export const SWARM_KEEP_ALIVE_INTERVAL = 5000
16
- export const SWARM_RANDOM_PUNCH_INTERVAL = 20000
17
-
18
- // 驱动器超时(毫秒)
19
- export const DRIVE_ENTRY_TIMEOUT = 10000
20
- export const DRIVE_SYNC_TIMEOUT = 10000
21
- export const STREAM_READ_TIMEOUT = 10000
22
-
23
- // 下载轮询间隔(毫秒)
24
- export const DOWNLOAD_POLL_INTERVAL = 1000
25
-
26
- // 进度更新节流间隔(毫秒)
27
- export const PROGRESS_THROTTLE = 500
28
-
29
- // 默认读取限制
30
- export const DEFAULT_READ_LIMIT = 10000
31
-
32
- // DHT 引导节点,用于 Hyperswarm/HyperDHT
33
- // 使用与 Keet.io/HyperDHT 相同的引导节点以保证兼容性
34
- // 格式:[suggested-IP@]<host>:<port> 以避免 DNS 调用
35
- export const SWARM_BOOTSTRAP = [
36
- '88.99.3.86@node1.hyperdht.org:49737',
37
- '142.93.90.113@node2.hyperdht.org:49737',
38
- '138.68.147.8@node3.hyperdht.org:49737'
39
- ]
40
-
41
- export const FRIEND_CODE_LENGTH = 16
42
- export const FRIEND_CODE_PREFIX = 'MOST'
43
-
44
- export const CHANNEL_NAME_MIN_LENGTH = 3
45
- export const CHANNEL_NAME_MAX_LENGTH = 20
46
- export const CHANNEL_NAME_REGEX = /^[a-zA-Z0-9_-]+$/
47
- export const CHANNEL_NAME_PREFIX = 'most-box-room-'
48
- export const CHANNEL_TOPIC_STRING = 'most-box-channels-v1'
49
- export const CHANNEL_MESSAGE_LIMIT = 100
50
- export const MAX_MESSAGE_LENGTH = 10000
1
+ /**
2
+ * 应用配置
3
+ */
4
+
5
+ // 文件大小限制
6
+ export const MAX_FILE_SIZE = 100 * 1024 * 1024 * 1024 // 100 GB
7
+
8
+ // 网络超时(毫秒)
9
+ export const CONNECTION_TIMEOUT = 120000
10
+ export const DOWNLOAD_TIMEOUT = 900000
11
+
12
+ // P2P 设置
13
+ export const GLOBAL_SHARED_SEED_STRING = 'most-box-global-shared-seed-v1'
14
+ export const MAX_PEERS = 64
15
+ export const SWARM_KEEP_ALIVE_INTERVAL = 5000
16
+ export const SWARM_RANDOM_PUNCH_INTERVAL = 20000
17
+
18
+ // 驱动器超时(毫秒)
19
+ export const DRIVE_ENTRY_TIMEOUT = 10000
20
+ export const DRIVE_SYNC_TIMEOUT = 10000
21
+ export const STREAM_READ_TIMEOUT = 10000
22
+
23
+ // 文件写入块大小(字节)
24
+ export const FILE_WRITE_CHUNK_SIZE = 64 * 1024
25
+
26
+ // 下载轮询间隔(毫秒)
27
+ export const DOWNLOAD_POLL_INTERVAL_MIN = 500
28
+ export const DOWNLOAD_POLL_INTERVAL_MAX = 2000
29
+ export const DRIVE_UPDATE_INTERVAL = 2000
30
+
31
+ // 进度更新节流间隔(毫秒)
32
+ export const PROGRESS_THROTTLE = 500
33
+
34
+ // 默认读取限制
35
+ export const DEFAULT_READ_LIMIT = 10000
36
+
37
+ // DHT 引导节点,用于 Hyperswarm/HyperDHT
38
+ // 使用与 Keet.io/HyperDHT 相同的引导节点以保证兼容性
39
+ // 格式:[suggested-IP@]<host>:<port> 以避免 DNS 调用
40
+ export const SWARM_BOOTSTRAP = [
41
+ '88.99.3.86@node1.hyperdht.org:49737',
42
+ '142.93.90.113@node2.hyperdht.org:49737',
43
+ '138.68.147.8@node3.hyperdht.org:49737',
44
+ ]
45
+
46
+ export const CHANNEL_NAME_MIN_LENGTH = 3
47
+ export const CHANNEL_NAME_MAX_LENGTH = 20
48
+ export const CHANNEL_NAME_REGEX = /^[a-zA-Z0-9_-]+$/
49
+ export const CHANNEL_NAME_PREFIX = 'most-box-room-'
50
+ export const CHANNEL_MESSAGE_LIMIT = 100
51
+ export const MAX_MESSAGE_LENGTH = 10000
@@ -1,150 +1,157 @@
1
- /**
2
- * CID(内容标识符)计算模块
3
- * 处理文件的 IPFS UnixFS CID 计算
4
- */
5
-
6
- import fs from 'node:fs'
7
- import { Readable } from 'node:stream'
8
- import { importer } from 'ipfs-unixfs-importer'
9
-
10
- /**
11
- * 用于 CID 计算的虚拟 Blockstore
12
- * 不存储任何数据,仅用于流式 CID 计算
13
- */
14
- function createDummyBlockstore() {
15
- return {
16
- put: async (key, val) => key,
17
- get: async () => { throw new Error('Not implemented') },
18
- has: async () => false
19
- }
20
- }
21
-
22
- /**
23
- * 计算内容的 IPFS UnixFS CID v1
24
- * 使用流式方法高效处理大文件
25
- *
26
- * @param {string|Buffer|AsyncIterable} content - 文件路径(字符串)、Buffer 或异步迭代器
27
- * @param {object} options - 计算选项
28
- * @param {boolean} [options.rawLeaves=true] - 使用原始叶子节点以支持现代 CID
29
- * @param {number} [options.cidVersion=1] - CID 版本(0 或 1)
30
- * @param {number} [options.size] - 总字节数(可选,自动检测)
31
- * @returns {Promise<{cid: import('multiformats/cid').CID, size: number}>}
32
- */
33
- export async function calculateCid(content, options = {}) {
34
- const {
35
- rawLeaves = true,
36
- cidVersion = 1,
37
- size: providedSize
38
- } = options
39
-
40
- const blockstore = createDummyBlockstore()
41
-
42
- let rootCid = null
43
- let totalSize = providedSize || 0
44
-
45
- let source
46
-
47
- if (typeof content === 'string') {
48
- const filePath = content
49
- try {
50
- const stat = await fs.promises.stat(filePath)
51
- totalSize = stat.size
52
- } catch {
53
- // 忽略 stat 错误,大小将为 0
54
- }
55
- source = [{
56
- path: 'file',
57
- content: fs.createReadStream(filePath)
58
- }]
59
- } else if (Buffer.isBuffer(content)) {
60
- totalSize = content.length
61
- source = [{
62
- path: 'file',
63
- content: Readable.from(content)
64
- }]
65
- } else {
66
- source = [{
67
- path: 'file',
68
- content
69
- }]
70
- }
71
-
72
- try {
73
- for await (const entry of importer(source, blockstore, {
74
- cidVersion,
75
- rawLeaves,
76
- wrapWithDirectory: false
77
- })) {
78
- rootCid = entry.cid
79
- }
80
- } catch (err) {
81
- throw new Error(`Failed to calculate CID: ${err.message}`)
82
- }
83
-
84
- if (!rootCid) {
85
- throw new Error('Failed to calculate CID: no root CID generated')
86
- }
87
-
88
- return {
89
- cid: rootCid,
90
- size: totalSize
91
- }
92
- }
93
-
94
- /**
95
- * 验证 CID 字符串
96
- * @param {string} cidString - 要验证的 CID 字符串
97
- * @returns {{ valid: boolean, error?: string }}
98
- */
99
- export function validateCidString(cidString) {
100
- if (!cidString || typeof cidString !== 'string') {
101
- return { valid: false, error: 'CID must be a non-empty string' }
102
- }
103
-
104
- if (!cidString.startsWith('b')) {
105
- return { valid: false, error: 'Invalid CID format: CID v1 must start with "b"' }
106
- }
107
-
108
- return { valid: true }
109
- }
110
-
111
- /**
112
- * 解析 most:// 链接并提取 CID
113
- * @param {string} link - most://<cid> 格式的链接
114
- * @returns {{ cid: string, error?: string }}
115
- */
116
- export function parseMostLink(link) {
117
- if (!link || typeof link !== 'string') {
118
- return { cid: '', error: 'Link must be a non-empty string' }
119
- }
120
-
121
- let cidString = link
122
-
123
- if (link.startsWith('most://')) {
124
- cidString = link.replace('most://', '')
125
- }
126
-
127
- // 移除尾部斜杠和空白
128
- cidString = cidString.trim().replace(/\/+$/, '')
129
-
130
- // 移除 query string,提取 filename
131
- let fileName = null
132
- if (cidString.includes('?')) {
133
- const [cidPart, queryPart] = cidString.split('?')
134
- cidString = cidPart
135
- const params = new URLSearchParams(queryPart)
136
- fileName = params.get('filename')
137
- }
138
-
139
- // 处理可能的额外路径的 URL 解析
140
- if (cidString.includes('/')) {
141
- cidString = cidString.split('/')[0]
142
- }
143
-
144
- const validation = validateCidString(cidString)
145
- if (!validation.valid) {
146
- return { cid: '', error: validation.error }
147
- }
148
-
149
- return { cid: cidString, fileName }
150
- }
1
+ /**
2
+ * CID(内容标识符)计算模块
3
+ * 处理文件的 IPFS UnixFS CID 计算
4
+ */
5
+
6
+ import fs from 'node:fs'
7
+ import { Readable } from 'node:stream'
8
+ import { importer } from 'ipfs-unixfs-importer'
9
+
10
+ /**
11
+ * 用于 CID 计算的虚拟 Blockstore
12
+ * 不存储任何数据,仅用于流式 CID 计算
13
+ */
14
+ function createDummyBlockstore() {
15
+ return {
16
+ put: async (key, _val) => key,
17
+ get: async () => {
18
+ throw new Error('Not implemented')
19
+ },
20
+ has: async () => false,
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 计算内容的 IPFS UnixFS CID v1
26
+ * 使用流式方法高效处理大文件
27
+ *
28
+ * @param {string|Buffer|AsyncIterable} content - 文件路径(字符串)、Buffer 或异步迭代器
29
+ * @param {object} options - 计算选项
30
+ * @param {boolean} [options.rawLeaves=true] - 使用原始叶子节点以支持现代 CID
31
+ * @param {number} [options.cidVersion=1] - CID 版本(0 或 1)
32
+ * @param {number} [options.size] - 总字节数(可选,自动检测)
33
+ * @returns {Promise<{cid: import('multiformats/cid').CID, size: number}>}
34
+ */
35
+ export async function calculateCid(content, options = {}) {
36
+ const { rawLeaves = true, cidVersion = 1, size: providedSize } = options
37
+
38
+ const blockstore = createDummyBlockstore()
39
+
40
+ let rootCid = null
41
+ let totalSize = providedSize || 0
42
+
43
+ let source
44
+
45
+ if (typeof content === 'string') {
46
+ const filePath = content
47
+ try {
48
+ const stat = await fs.promises.stat(filePath)
49
+ totalSize = stat.size
50
+ } catch {
51
+ // 忽略 stat 错误,大小将为 0
52
+ }
53
+ source = [
54
+ {
55
+ path: 'file',
56
+ content: fs.createReadStream(filePath),
57
+ },
58
+ ]
59
+ } else if (Buffer.isBuffer(content)) {
60
+ totalSize = content.length
61
+ source = [
62
+ {
63
+ path: 'file',
64
+ content: Readable.from(content),
65
+ },
66
+ ]
67
+ } else {
68
+ source = [
69
+ {
70
+ path: 'file',
71
+ content,
72
+ },
73
+ ]
74
+ }
75
+
76
+ try {
77
+ for await (const entry of importer(source, blockstore, {
78
+ cidVersion,
79
+ rawLeaves,
80
+ wrapWithDirectory: false,
81
+ })) {
82
+ rootCid = entry.cid
83
+ }
84
+ } catch (err) {
85
+ throw new Error(`Failed to calculate CID: ${err.message}`)
86
+ }
87
+
88
+ if (!rootCid) {
89
+ throw new Error('Failed to calculate CID: no root CID generated')
90
+ }
91
+
92
+ return {
93
+ cid: rootCid,
94
+ size: totalSize,
95
+ }
96
+ }
97
+
98
+ /**
99
+ * 验证 CID 字符串
100
+ * @param {string} cidString - 要验证的 CID 字符串
101
+ * @returns {{ valid: boolean, error?: string }}
102
+ */
103
+ export function validateCidString(cidString) {
104
+ if (!cidString || typeof cidString !== 'string') {
105
+ return { valid: false, error: 'CID must be a non-empty string' }
106
+ }
107
+
108
+ if (!cidString.startsWith('b')) {
109
+ return {
110
+ valid: false,
111
+ error: 'Invalid CID format: CID v1 must start with "b"',
112
+ }
113
+ }
114
+
115
+ return { valid: true }
116
+ }
117
+
118
+ /**
119
+ * 解析 most:// 链接并提取 CID
120
+ * @param {string} link - most://<cid> 格式的链接
121
+ * @returns {{ cid: string, error?: string }}
122
+ */
123
+ export function parseMostLink(link) {
124
+ if (!link || typeof link !== 'string') {
125
+ return { cid: '', error: 'Link must be a non-empty string' }
126
+ }
127
+
128
+ let cidString = link
129
+
130
+ if (link.startsWith('most://')) {
131
+ cidString = link.replace('most://', '')
132
+ }
133
+
134
+ // 移除尾部斜杠和空白
135
+ cidString = cidString.trim().replace(/\/+$/, '')
136
+
137
+ // 移除 query string,提取 filename
138
+ let fileName = null
139
+ if (cidString.includes('?')) {
140
+ const [cidPart, queryPart] = cidString.split('?')
141
+ cidString = cidPart
142
+ const params = new URLSearchParams(queryPart)
143
+ fileName = params.get('filename')
144
+ }
145
+
146
+ // 处理可能的额外路径的 URL 解析
147
+ if (cidString.includes('/')) {
148
+ cidString = cidString.split('/')[0]
149
+ }
150
+
151
+ const validation = validateCidString(cidString)
152
+ if (!validation.valid) {
153
+ return { cid: '', error: validation.error }
154
+ }
155
+
156
+ return { cid: cidString, fileName }
157
+ }