most-box 0.1.1 → 0.1.3

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 (231) hide show
  1. package/README.md +39 -19
  2. package/electron/afterPack.cjs +87 -0
  3. package/electron/main.js +156 -8
  4. package/electron/preload.js +6 -0
  5. package/electron/updateChecker.js +97 -0
  6. package/electron/updateChecker.test.js +147 -0
  7. package/out/404/index.html +2 -2
  8. package/out/404.html +2 -2
  9. package/out/__next.__PAGE__.txt +6 -6
  10. package/out/__next._full.txt +16 -16
  11. package/out/__next._head.txt +3 -3
  12. package/out/__next._index.txt +8 -8
  13. package/out/__next._tree.txt +5 -5
  14. package/out/_next/static/chunks/04mo7rr..0_1q.js +1 -0
  15. package/out/_next/static/chunks/06rf3qq5ggs6v.js +1 -0
  16. package/out/_next/static/chunks/07td.jq7xff84.css +1 -0
  17. package/out/_next/static/chunks/0_0oph_z1az14.js +1 -0
  18. package/out/_next/static/chunks/{0qou.u2e2dy48.css → 0adx~d-j05c9d.css} +2 -2
  19. package/out/_next/static/chunks/0cl7d~7abnk_p.css +1 -0
  20. package/out/_next/static/chunks/0d306t1wvjpdx.js +1 -0
  21. package/out/_next/static/chunks/0g_a~e050bgzg.css +1 -0
  22. package/out/_next/static/chunks/{0o6lrkxy4jwag.js → 0gcsdf57gcm6h.js} +1 -1
  23. package/out/_next/static/chunks/0hpev4am9jpmu.css +1 -0
  24. package/out/_next/static/chunks/0m_5nb6x8qy._.js +1 -0
  25. package/out/_next/static/chunks/0n.ayxmsar6e5.js +1 -0
  26. package/out/_next/static/chunks/{0usvo~vu7r8np.js → 0o9ce4cyf76by.js} +1 -1
  27. package/out/_next/static/chunks/0olqjomda37-e.js +1 -0
  28. package/out/_next/static/chunks/{0o98f1yq..o.8.js → 0pt.5cg1t09qs.js} +1 -1
  29. package/out/_next/static/chunks/0qgx9t4jx16ua.css +1 -0
  30. package/out/_next/static/chunks/0s~g.l~x049o2.js +1 -0
  31. package/out/_next/static/chunks/0ukyg~tkm~h2m.css +1 -0
  32. package/out/_next/static/chunks/0voe1.ttrh84k.css +1 -0
  33. package/out/_next/static/chunks/0wtf0xsiicxx6.js +1 -0
  34. package/out/_next/static/chunks/0x.ky97owcxxs.js +1 -0
  35. package/out/_next/static/chunks/0xdwau5k2augv.css +4 -0
  36. package/out/_next/static/chunks/0ysj5b94vu4ri.js +1 -0
  37. package/out/_next/static/chunks/12nr19.nnn6s3.js +5 -0
  38. package/out/_next/static/chunks/{0qub_r0x_r-e9.css → 12pep-2t-qg4n.css} +1 -1
  39. package/out/_next/static/chunks/14_inksek_rth.js +2 -0
  40. package/out/_next/static/chunks/153-sz7s.qml2.js +1 -0
  41. package/out/_next/static/chunks/17cwkb2yn_akx.js +1 -0
  42. package/out/_next/static/chunks/184hxsuf-5c84.js +1 -0
  43. package/out/_next/static/chunks/{turbopack-0xs6mybc~5t_3.js → turbopack-0xta0kqwzkf28.js} +1 -1
  44. package/out/_not-found/__next._full.txt +13 -13
  45. package/out/_not-found/__next._head.txt +3 -3
  46. package/out/_not-found/__next._index.txt +8 -8
  47. package/out/_not-found/__next._not-found.__PAGE__.txt +4 -4
  48. package/out/_not-found/__next._not-found.txt +3 -3
  49. package/out/_not-found/__next._tree.txt +3 -3
  50. package/out/_not-found/index.html +2 -2
  51. package/out/_not-found/index.txt +13 -13
  52. package/out/admin/__next._full.txt +15 -15
  53. package/out/admin/__next._head.txt +3 -3
  54. package/out/admin/__next._index.txt +8 -8
  55. package/out/admin/__next._tree.txt +4 -4
  56. package/out/admin/__next.admin.__PAGE__.txt +4 -4
  57. package/out/admin/__next.admin.txt +4 -4
  58. package/out/admin/index.html +2 -2
  59. package/out/admin/index.txt +15 -15
  60. package/out/app/__next._full.txt +14 -14
  61. package/out/app/__next._head.txt +3 -3
  62. package/out/app/__next._index.txt +8 -8
  63. package/out/app/__next._tree.txt +3 -3
  64. package/out/app/__next.app.__PAGE__.txt +4 -4
  65. package/out/app/__next.app.txt +3 -3
  66. package/out/app/index.html +2 -2
  67. package/out/app/index.txt +14 -14
  68. package/out/chat/__next._full.txt +15 -15
  69. package/out/chat/__next._head.txt +3 -3
  70. package/out/chat/__next._index.txt +8 -8
  71. package/out/chat/__next._tree.txt +4 -4
  72. package/out/chat/__next.chat.__PAGE__.txt +4 -4
  73. package/out/chat/__next.chat.txt +4 -4
  74. package/out/chat/index.html +2 -2
  75. package/out/chat/index.txt +15 -15
  76. package/out/chat/join/__next._full.txt +25 -0
  77. package/out/chat/join/__next._head.txt +5 -0
  78. package/out/{changelog → chat/join}/__next._index.txt +8 -8
  79. package/out/chat/join/__next._tree.txt +5 -0
  80. package/out/chat/join/__next.chat.join.__PAGE__.txt +9 -0
  81. package/out/chat/join/__next.chat.join.txt +5 -0
  82. package/out/chat/join/__next.chat.txt +5 -0
  83. package/out/chat/join/index.html +15 -0
  84. package/out/chat/join/index.txt +25 -0
  85. package/out/download/__next._full.txt +37 -33
  86. package/out/download/__next._head.txt +3 -3
  87. package/out/download/__next._index.txt +8 -8
  88. package/out/download/__next._tree.txt +5 -5
  89. package/out/download/__next.download.__PAGE__.txt +9 -14
  90. package/out/download/__next.download.txt +3 -3
  91. package/out/download/index.html +2 -2
  92. package/out/download/index.txt +37 -33
  93. package/out/favicon.ico +0 -0
  94. package/out/gandengyan/__next._full.txt +25 -0
  95. package/out/{changelog → gandengyan}/__next._head.txt +3 -3
  96. package/out/{docs → gandengyan}/__next._index.txt +8 -8
  97. package/out/gandengyan/__next._tree.txt +5 -0
  98. package/out/gandengyan/__next.gandengyan.__PAGE__.txt +10 -0
  99. package/out/gandengyan/__next.gandengyan.txt +5 -0
  100. package/out/gandengyan/index.html +15 -0
  101. package/out/gandengyan/index.txt +25 -0
  102. package/out/index.html +2 -2
  103. package/out/index.txt +16 -16
  104. package/out/note/__next._full.txt +14 -14
  105. package/out/note/__next._head.txt +3 -3
  106. package/out/note/__next._index.txt +8 -8
  107. package/out/note/__next._tree.txt +3 -3
  108. package/out/note/__next.note.__PAGE__.txt +4 -4
  109. package/out/note/__next.note.txt +3 -3
  110. package/out/note/index.html +2 -2
  111. package/out/note/index.txt +14 -14
  112. package/out/ping/__next._full.txt +16 -16
  113. package/out/ping/__next._head.txt +3 -3
  114. package/out/ping/__next._index.txt +8 -8
  115. package/out/ping/__next._tree.txt +5 -5
  116. package/out/ping/__next.ping.__PAGE__.txt +5 -5
  117. package/out/ping/__next.ping.txt +4 -4
  118. package/out/ping/index.html +2 -2
  119. package/out/ping/index.txt +16 -16
  120. package/out/web3/__next._full.txt +15 -15
  121. package/out/web3/__next._head.txt +3 -3
  122. package/out/web3/__next._index.txt +8 -8
  123. package/out/web3/__next._tree.txt +4 -4
  124. package/out/web3/__next.web3.__PAGE__.txt +4 -4
  125. package/out/web3/__next.web3.txt +4 -4
  126. package/out/web3/ed25519/__next._full.txt +13 -13
  127. package/out/web3/ed25519/__next._head.txt +3 -3
  128. package/out/web3/ed25519/__next._index.txt +8 -8
  129. package/out/web3/ed25519/__next._tree.txt +4 -4
  130. package/out/web3/ed25519/__next.web3.ed25519.__PAGE__.txt +2 -2
  131. package/out/web3/ed25519/__next.web3.ed25519.txt +3 -3
  132. package/out/web3/ed25519/__next.web3.txt +4 -4
  133. package/out/web3/ed25519/index.html +1 -1
  134. package/out/web3/ed25519/index.txt +13 -13
  135. package/out/web3/index.html +2 -2
  136. package/out/web3/index.txt +15 -15
  137. package/out/web3/tools/__next._full.txt +13 -13
  138. package/out/web3/tools/__next._head.txt +3 -3
  139. package/out/web3/tools/__next._index.txt +8 -8
  140. package/out/web3/tools/__next._tree.txt +4 -4
  141. package/out/web3/tools/__next.web3.tools.__PAGE__.txt +2 -2
  142. package/out/web3/tools/__next.web3.tools.txt +3 -3
  143. package/out/web3/tools/__next.web3.txt +4 -4
  144. package/out/web3/tools/index.html +1 -1
  145. package/out/web3/tools/index.txt +13 -13
  146. package/package.json +44 -35
  147. package/public/favicon.ico +0 -0
  148. package/server/index.js +142 -1304
  149. package/server/src/config.js +1 -1
  150. package/server/src/core/channelAttachment.js +68 -0
  151. package/server/src/core/cid.js +2 -88
  152. package/server/src/core/cidTopic.js +29 -0
  153. package/server/src/core/mostLink.js +88 -0
  154. package/server/src/games/gandengyan.js +675 -0
  155. package/server/src/http/access.js +127 -0
  156. package/server/src/http/app.js +1102 -0
  157. package/server/src/http/errors.js +35 -0
  158. package/server/src/http/nodeLogs.js +53 -0
  159. package/server/src/http/nodeStatus.js +146 -0
  160. package/server/src/http/staticFiles.js +84 -0
  161. package/server/src/http/uploads.js +114 -0
  162. package/server/src/index.js +799 -211
  163. package/server/src/node/config.js +38 -6
  164. package/server/src/utils/api.js +305 -14
  165. package/server/src/utils/auth.js +63 -0
  166. package/server/src/utils/dateTime.js +30 -0
  167. package/server/src/utils/downloadMessages.js +89 -0
  168. package/server/src/utils/errors.js +7 -0
  169. package/server/src/utils/mostWallet.js +151 -0
  170. package/server/src/utils/mp.js +2 -26
  171. package/server/src/utils/noteBackup.js +2 -5
  172. package/server/src/utils/noteUtils.js +11 -3
  173. package/server/src/utils/userIdentity.js +0 -1
  174. package/out/_next/static/chunks/00-u5nq76f0.j.js +0 -1
  175. package/out/_next/static/chunks/00fm8lijienf1.js +0 -1
  176. package/out/_next/static/chunks/00o9ht.f2qm00.css +0 -4
  177. package/out/_next/static/chunks/00zi-erhjrny2.js +0 -2
  178. package/out/_next/static/chunks/084xf0edl9sfo.js +0 -1
  179. package/out/_next/static/chunks/09f1gfke9m5wg.css +0 -1
  180. package/out/_next/static/chunks/09xyi6fpro_d-.css +0 -1
  181. package/out/_next/static/chunks/0_npg_pcoywti.js +0 -5
  182. package/out/_next/static/chunks/0_r_mk1~6bosc.js +0 -1
  183. package/out/_next/static/chunks/0arm0a6adt7cc.css +0 -1
  184. package/out/_next/static/chunks/0c9j3eq_14vv2.css +0 -1
  185. package/out/_next/static/chunks/0d4bueddmcnca.js +0 -1
  186. package/out/_next/static/chunks/0gtwvy1z9ksa7.css +0 -1
  187. package/out/_next/static/chunks/0ho~log~~-jwp.css +0 -1
  188. package/out/_next/static/chunks/0j27tcmtt4ly7.js +0 -1
  189. package/out/_next/static/chunks/0j3v4mq67wtnh.js +0 -1
  190. package/out/_next/static/chunks/0lkmf5ry.s_7w.js +0 -1
  191. package/out/_next/static/chunks/0p486m03-zfoi.js +0 -1
  192. package/out/_next/static/chunks/0r1~k82nji8sf.js +0 -1
  193. package/out/_next/static/chunks/0v7qp4hv-_._r.js +0 -1
  194. package/out/_next/static/chunks/0wuwlgcn6gxqt.js +0 -1
  195. package/out/_next/static/chunks/0xl5_avhu._i8.js +0 -1
  196. package/out/_next/static/chunks/10kvl8vj_plm-.js +0 -1
  197. package/out/_next/static/chunks/16m27azcs4k6w.js +0 -1
  198. package/out/changelog/__next._full.txt +0 -25
  199. package/out/changelog/__next._tree.txt +0 -5
  200. package/out/changelog/__next.changelog.__PAGE__.txt +0 -10
  201. package/out/changelog/__next.changelog.txt +0 -5
  202. package/out/changelog/index.html +0 -15
  203. package/out/changelog/index.txt +0 -25
  204. package/out/docs/__next._full.txt +0 -25
  205. package/out/docs/__next._head.txt +0 -5
  206. package/out/docs/__next._tree.txt +0 -5
  207. package/out/docs/__next.docs.__PAGE__.txt +0 -10
  208. package/out/docs/__next.docs.txt +0 -5
  209. package/out/docs/getting-started/__next._full.txt +0 -25
  210. package/out/docs/getting-started/__next._head.txt +0 -5
  211. package/out/docs/getting-started/__next._index.txt +0 -9
  212. package/out/docs/getting-started/__next._tree.txt +0 -5
  213. package/out/docs/getting-started/__next.docs.getting-started.__PAGE__.txt +0 -10
  214. package/out/docs/getting-started/__next.docs.getting-started.txt +0 -5
  215. package/out/docs/getting-started/__next.docs.txt +0 -5
  216. package/out/docs/getting-started/index.html +0 -15
  217. package/out/docs/getting-started/index.txt +0 -25
  218. package/out/docs/index.html +0 -15
  219. package/out/docs/index.txt +0 -25
  220. package/out/note/edit/__next._full.txt +0 -24
  221. package/out/note/edit/__next._head.txt +0 -5
  222. package/out/note/edit/__next._index.txt +0 -9
  223. package/out/note/edit/__next._tree.txt +0 -4
  224. package/out/note/edit/__next.note.edit.__PAGE__.txt +0 -9
  225. package/out/note/edit/__next.note.edit.txt +0 -5
  226. package/out/note/edit/__next.note.txt +0 -5
  227. package/out/note/edit/index.html +0 -15
  228. package/out/note/edit/index.txt +0 -24
  229. /package/out/_next/static/{sIuUKxnnGU7K9Tu9UDKE8 → aPEZ4zaaR5W3WpSZ0dFsa}/_buildManifest.js +0 -0
  230. /package/out/_next/static/{sIuUKxnnGU7K9Tu9UDKE8 → aPEZ4zaaR5W3WpSZ0dFsa}/_clientMiddlewareManifest.js +0 -0
  231. /package/out/_next/static/{sIuUKxnnGU7K9Tu9UDKE8 → aPEZ4zaaR5W3WpSZ0dFsa}/_ssgManifest.js +0 -0
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  // 文件大小限制
6
- export const MAX_FILE_SIZE = 100 * 1024 * 1024 * 1024 // 100 GB
6
+ export const MAX_FILE_SIZE = 10 * 1024 * 1024 * 1024 // 10 GB
7
7
 
8
8
  // 网络超时(毫秒)
9
9
  export const CONNECTION_TIMEOUT = 120000
@@ -0,0 +1,68 @@
1
+ import { parseMostLink, validateCidString } from './cid.js'
2
+ import { sanitizeFilename } from '../utils/security.js'
3
+ import { ValidationError } from '../utils/errors.js'
4
+
5
+ const CHANNEL_ATTACHMENT_KINDS = new Set([
6
+ 'image',
7
+ 'video',
8
+ 'audio',
9
+ 'text',
10
+ 'file',
11
+ ])
12
+
13
+ export function normalizeChannelAttachment(input) {
14
+ if (input === undefined || input === null) return null
15
+ if (typeof input !== 'object' || Array.isArray(input)) {
16
+ throw new ValidationError('attachment must be an object')
17
+ }
18
+
19
+ const kind = String(input.kind || '').trim()
20
+ if (!CHANNEL_ATTACHMENT_KINDS.has(kind)) {
21
+ throw new ValidationError('Invalid attachment kind')
22
+ }
23
+
24
+ const cid = String(input.cid || '').trim()
25
+ const cidValidation = validateCidString(cid)
26
+ if (!cidValidation.valid) {
27
+ throw new ValidationError(cidValidation.error)
28
+ }
29
+
30
+ const fileName = sanitizeFilename(String(input.fileName || ''))
31
+ if (!fileName || fileName === 'unnamed_file') {
32
+ throw new ValidationError('attachment fileName is required')
33
+ }
34
+
35
+ const parsed = parseMostLink(String(input.link || '').trim())
36
+ if (parsed.error) {
37
+ throw new ValidationError(parsed.error)
38
+ }
39
+ if (parsed.cid !== cid) {
40
+ throw new ValidationError('attachment link CID mismatch')
41
+ }
42
+
43
+ const linkFileName = sanitizeFilename(parsed.fileName)
44
+ if (linkFileName !== fileName) {
45
+ throw new ValidationError('attachment link filename mismatch')
46
+ }
47
+
48
+ const attachment = {
49
+ kind,
50
+ cid,
51
+ fileName,
52
+ link: `most://${cid}?filename=${encodeURIComponent(fileName)}`,
53
+ }
54
+
55
+ if (typeof input.mimeType === 'string' && input.mimeType.length <= 100) {
56
+ attachment.mimeType = input.mimeType
57
+ }
58
+
59
+ if (input.size !== undefined && input.size !== null) {
60
+ const size = Number(input.size)
61
+ if (!Number.isFinite(size) || size < 0) {
62
+ throw new ValidationError('attachment size must be a non-negative number')
63
+ }
64
+ attachment.size = Math.floor(size)
65
+ }
66
+
67
+ return attachment
68
+ }
@@ -6,7 +6,8 @@
6
6
  import fs from 'node:fs'
7
7
  import { Readable } from 'node:stream'
8
8
  import { importer } from 'ipfs-unixfs-importer'
9
- import { CID } from 'multiformats/cid'
9
+
10
+ export { validateCidString, parseMostLink } from './mostLink.js'
10
11
 
11
12
  /**
12
13
  * 用于 CID 计算的虚拟 Blockstore
@@ -89,90 +90,3 @@ export async function calculateCid(content) {
89
90
  size: totalSize,
90
91
  }
91
92
  }
92
-
93
- /**
94
- * 验证 CID 字符串
95
- * @param {string} cidString - 要验证的 CID 字符串
96
- * @returns {{ valid: boolean, error?: string }}
97
- */
98
- export function validateCidString(cidString) {
99
- if (!cidString || typeof cidString !== 'string') {
100
- return { valid: false, error: 'CID must be a non-empty string' }
101
- }
102
-
103
- let parsed
104
- try {
105
- parsed = CID.parse(cidString)
106
- } catch {
107
- return {
108
- valid: false,
109
- error: 'Invalid CID format',
110
- }
111
- }
112
-
113
- if (parsed.version !== 1) {
114
- return {
115
- valid: false,
116
- error: 'Invalid CID format: CID v1 required',
117
- }
118
- }
119
-
120
- if (parsed.multihash.digest.length !== 32) {
121
- return {
122
- valid: false,
123
- error: 'CID digest must be 32 bytes',
124
- }
125
- }
126
-
127
- return { valid: true }
128
- }
129
-
130
- /**
131
- * 解析 most:// 链接并提取 CID 与用户可见文件名
132
- * @param {string} link - most://<cid>?filename=... 格式的链接
133
- * @returns {{ cid: string, fileName?: string, error?: string }}
134
- */
135
- export function parseMostLink(link) {
136
- if (!link || typeof link !== 'string') {
137
- return { cid: '', error: 'Link must be a non-empty string' }
138
- }
139
-
140
- let url
141
- try {
142
- url = new URL(link)
143
- } catch {
144
- return { cid: '', error: 'Link must be a valid most:// URL' }
145
- }
146
-
147
- if (url.protocol !== 'most:') {
148
- return { cid: '', error: 'Link must use most:// protocol' }
149
- }
150
-
151
- if (url.pathname && url.pathname !== '/') {
152
- return { cid: '', error: 'Link path is not supported' }
153
- }
154
-
155
- const cidString = url.hostname
156
- const fileName = url.searchParams.get('filename')
157
- const unsupportedParam = [...url.searchParams.keys()].find(
158
- key => key !== 'filename'
159
- )
160
-
161
- const validation = validateCidString(cidString)
162
- if (!validation.valid) {
163
- return { cid: '', error: validation.error }
164
- }
165
-
166
- if (!fileName) {
167
- return { cid: '', error: 'filename is required' }
168
- }
169
-
170
- if (unsupportedParam) {
171
- return {
172
- cid: '',
173
- error: `Unsupported query parameter: ${unsupportedParam}`,
174
- }
175
- }
176
-
177
- return { cid: cidString, fileName }
178
- }
@@ -0,0 +1,29 @@
1
+ import b4a from 'b4a'
2
+ import { CID } from 'multiformats/cid'
3
+ import { validateCidString } from './cid.js'
4
+ import { ValidationError } from '../utils/errors.js'
5
+
6
+ export function getCidInfo(cid) {
7
+ try {
8
+ const validation = validateCidString(cid)
9
+ if (!validation.valid) {
10
+ throw new ValidationError(validation.error)
11
+ }
12
+ const parsedCid = CID.parse(cid)
13
+ const topic = b4a.from(parsedCid.multihash.digest)
14
+ if (topic.length !== 32) {
15
+ throw new ValidationError('CID digest must be 32 bytes')
16
+ }
17
+ const topicHex = b4a.toString(topic, 'hex')
18
+ return {
19
+ topic,
20
+ topicHex,
21
+ driveName: `drive-${topicHex}`,
22
+ }
23
+ } catch (err) {
24
+ if (err instanceof ValidationError) {
25
+ throw err
26
+ }
27
+ throw new ValidationError('Invalid CID format')
28
+ }
29
+ }
@@ -0,0 +1,88 @@
1
+ import { CID } from 'multiformats/cid'
2
+
3
+ /**
4
+ * 验证 CID 字符串
5
+ * @param {string} cidString - 要验证的 CID 字符串
6
+ * @returns {{ valid: boolean, error?: string }}
7
+ */
8
+ export function validateCidString(cidString) {
9
+ if (!cidString || typeof cidString !== 'string') {
10
+ return { valid: false, error: 'CID must be a non-empty string' }
11
+ }
12
+
13
+ let parsed
14
+ try {
15
+ parsed = CID.parse(cidString)
16
+ } catch {
17
+ return {
18
+ valid: false,
19
+ error: 'Invalid CID format',
20
+ }
21
+ }
22
+
23
+ if (parsed.version !== 1) {
24
+ return {
25
+ valid: false,
26
+ error: 'Invalid CID format: CID v1 required',
27
+ }
28
+ }
29
+
30
+ if (parsed.multihash.digest.length !== 32) {
31
+ return {
32
+ valid: false,
33
+ error: 'CID digest must be 32 bytes',
34
+ }
35
+ }
36
+
37
+ return { valid: true }
38
+ }
39
+
40
+ /**
41
+ * 解析 most:// 链接并提取 CID 与用户可见文件名
42
+ * @param {string} link - most://<cid>?filename=... 格式的链接
43
+ * @returns {{ cid: string, fileName?: string, error?: string }}
44
+ */
45
+ export function parseMostLink(link) {
46
+ if (!link || typeof link !== 'string') {
47
+ return { cid: '', error: 'Link must be a non-empty string' }
48
+ }
49
+
50
+ let url
51
+ try {
52
+ url = new URL(link)
53
+ } catch {
54
+ return { cid: '', error: 'Link must be a valid most:// URL' }
55
+ }
56
+
57
+ if (url.protocol !== 'most:') {
58
+ return { cid: '', error: 'Link must use most:// protocol' }
59
+ }
60
+
61
+ if (url.pathname && url.pathname !== '/') {
62
+ return { cid: '', error: 'Link path is not supported' }
63
+ }
64
+
65
+ const cidString = url.hostname
66
+ const fileName = url.searchParams.get('filename')
67
+ const unsupportedParam = [...url.searchParams.keys()].find(
68
+ key => key !== 'filename'
69
+ )
70
+
71
+ const validation = validateCidString(cidString)
72
+ if (!validation.valid) {
73
+ return { cid: '', error: validation.error }
74
+ }
75
+
76
+ if (!fileName) {
77
+ return { cid: '', error: 'filename is required' }
78
+ }
79
+
80
+ if (unsupportedParam) {
81
+ return {
82
+ cid: '',
83
+ error: `Unsupported query parameter: ${unsupportedParam}`,
84
+ }
85
+ }
86
+
87
+ return { cid: cidString, fileName }
88
+ }