most-box 0.0.1
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/LICENSE +21 -0
- package/README.md +73 -0
- package/build.mjs +40 -0
- package/cli.js +2 -0
- package/package.json +44 -0
- package/public/app.jsx +1335 -0
- package/public/bundle.js +111 -0
- package/public/bundle.js.map +7 -0
- package/public/favicon.ico +0 -0
- package/public/icons/apple-touch-icon.png +0 -0
- package/public/icons/mask-icon.svg +3 -0
- package/public/icons/most.png +0 -0
- package/public/icons/pwa-192x192.png +0 -0
- package/public/icons/pwa-512x512.png +0 -0
- package/public/index.html +15 -0
- package/public/index.jsx +5 -0
- package/server.js +615 -0
- package/src/config.js +22 -0
- package/src/core/cid.js +141 -0
- package/src/index.js +1073 -0
- package/src/utils/errors.js +66 -0
- package/src/utils/security.js +166 -0
package/src/core/cid.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CID (Content Identifier) Calculation Module
|
|
3
|
+
* Handles IPFS UnixFS CID computation for files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'node:fs'
|
|
7
|
+
import { Readable } from 'node:stream'
|
|
8
|
+
import { importer } from 'ipfs-unixfs-importer'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Dummy Blockstore for CID calculation
|
|
12
|
+
* Does not store any data, only used for streaming CID computation
|
|
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
|
+
* Calculate IPFS UnixFS CID v1 for content
|
|
24
|
+
* Uses streaming approach to handle large files efficiently
|
|
25
|
+
*
|
|
26
|
+
* @param {string|Buffer|AsyncIterable} content - File path (string), Buffer, or async iterable
|
|
27
|
+
* @param {object} options - Calculation options
|
|
28
|
+
* @param {boolean} [options.rawLeaves=true] - Use raw leaves for modern CID
|
|
29
|
+
* @param {number} [options.cidVersion=1] - CID version (0 or 1)
|
|
30
|
+
* @param {number} [options.size] - Total size in bytes (optional, auto-detected for files)
|
|
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
|
+
// Ignore stat errors, size will be 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
|
+
* Validate a CID string
|
|
96
|
+
* @param {string} cidString - CID string to validate
|
|
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
|
+
* Parse a most:// link and extract the CID
|
|
113
|
+
* @param {string} link - most://<cid> format link
|
|
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
|
+
// Remove any trailing slashes or whitespace
|
|
128
|
+
cidString = cidString.trim().replace(/\/+$/, '')
|
|
129
|
+
|
|
130
|
+
// Handle URL-like parsing for potential extra paths
|
|
131
|
+
if (cidString.includes('/')) {
|
|
132
|
+
cidString = cidString.split('/')[0]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const validation = validateCidString(cidString)
|
|
136
|
+
if (!validation.valid) {
|
|
137
|
+
return { cid: '', error: validation.error }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return { cid: cidString }
|
|
141
|
+
}
|