@autonomys/auto-dag-data 0.8.2
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 +18 -0
- package/README.md +167 -0
- package/dist/cid/index.d.ts +9 -0
- package/dist/cid/index.d.ts.map +1 -0
- package/dist/cid/index.js +20 -0
- package/dist/compression/index.d.ts +7 -0
- package/dist/compression/index.d.ts.map +1 -0
- package/dist/compression/index.js +106 -0
- package/dist/compression/types.d.ts +9 -0
- package/dist/compression/types.d.ts.map +1 -0
- package/dist/compression/types.js +1 -0
- package/dist/encryption/index.d.ts +8 -0
- package/dist/encryption/index.d.ts.map +1 -0
- package/dist/encryption/index.js +121 -0
- package/dist/encryption/types.d.ts +5 -0
- package/dist/encryption/types.d.ts.map +1 -0
- package/dist/encryption/types.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/ipld/blockstore/base.d.ts +9 -0
- package/dist/ipld/blockstore/base.d.ts.map +1 -0
- package/dist/ipld/blockstore/base.js +1 -0
- package/dist/ipld/blockstore/index.d.ts +3 -0
- package/dist/ipld/blockstore/index.d.ts.map +1 -0
- package/dist/ipld/blockstore/index.js +2 -0
- package/dist/ipld/blockstore/memory.d.ts +13 -0
- package/dist/ipld/blockstore/memory.d.ts.map +1 -0
- package/dist/ipld/blockstore/memory.js +57 -0
- package/dist/ipld/builders.d.ts +12 -0
- package/dist/ipld/builders.d.ts.map +1 -0
- package/dist/ipld/builders.js +13 -0
- package/dist/ipld/chunker.d.ts +30 -0
- package/dist/ipld/chunker.d.ts.map +1 -0
- package/dist/ipld/chunker.js +219 -0
- package/dist/ipld/index.d.ts +5 -0
- package/dist/ipld/index.d.ts.map +1 -0
- package/dist/ipld/index.js +4 -0
- package/dist/ipld/nodes.d.ts +15 -0
- package/dist/ipld/nodes.d.ts.map +1 -0
- package/dist/ipld/nodes.js +92 -0
- package/dist/ipld/utils.d.ts +8 -0
- package/dist/ipld/utils.d.ts.map +1 -0
- package/dist/ipld/utils.js +50 -0
- package/dist/metadata/index.d.ts +3 -0
- package/dist/metadata/index.d.ts.map +1 -0
- package/dist/metadata/index.js +2 -0
- package/dist/metadata/offchain/base.d.ts +4 -0
- package/dist/metadata/offchain/base.d.ts.map +1 -0
- package/dist/metadata/offchain/base.js +1 -0
- package/dist/metadata/offchain/file.d.ts +18 -0
- package/dist/metadata/offchain/file.d.ts.map +1 -0
- package/dist/metadata/offchain/file.js +16 -0
- package/dist/metadata/offchain/folder.d.ts +22 -0
- package/dist/metadata/offchain/folder.d.ts.map +1 -0
- package/dist/metadata/offchain/folder.js +27 -0
- package/dist/metadata/offchain/index.d.ts +4 -0
- package/dist/metadata/offchain/index.d.ts.map +1 -0
- package/dist/metadata/offchain/index.js +3 -0
- package/dist/metadata/onchain/index.d.ts +3 -0
- package/dist/metadata/onchain/index.d.ts.map +1 -0
- package/dist/metadata/onchain/index.js +2 -0
- package/dist/metadata/onchain/protobuf/OnchainMetadata.d.ts +69 -0
- package/dist/metadata/onchain/protobuf/OnchainMetadata.d.ts.map +1 -0
- package/dist/metadata/onchain/protobuf/OnchainMetadata.js +322 -0
- package/dist/metadata/onchain/utils.d.ts +4 -0
- package/dist/metadata/onchain/utils.d.ts.map +1 -0
- package/dist/metadata/onchain/utils.js +12 -0
- package/dist/src/cid/index.d.ts +9 -0
- package/dist/src/cid/index.d.ts.map +1 -0
- package/dist/src/cid/index.js +20 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/ipld/builders.d.ts +11 -0
- package/dist/src/ipld/builders.d.ts.map +1 -0
- package/dist/src/ipld/builders.js +13 -0
- package/dist/src/ipld/chunker.d.ts +22 -0
- package/dist/src/ipld/chunker.d.ts.map +1 -0
- package/dist/src/ipld/chunker.js +144 -0
- package/dist/src/ipld/index.d.ts +4 -0
- package/dist/src/ipld/index.d.ts.map +1 -0
- package/dist/src/ipld/index.js +3 -0
- package/dist/src/ipld/nodes.d.ts +15 -0
- package/dist/src/ipld/nodes.d.ts.map +1 -0
- package/dist/src/ipld/nodes.js +89 -0
- package/dist/src/ipld/utils.d.ts +5 -0
- package/dist/src/ipld/utils.d.ts.map +1 -0
- package/dist/src/ipld/utils.js +51 -0
- package/dist/src/metadata/index.d.ts +3 -0
- package/dist/src/metadata/index.d.ts.map +1 -0
- package/dist/src/metadata/index.js +2 -0
- package/dist/src/metadata/offchain/base.d.ts +4 -0
- package/dist/src/metadata/offchain/base.d.ts.map +1 -0
- package/dist/src/metadata/offchain/base.js +1 -0
- package/dist/src/metadata/offchain/file.d.ts +16 -0
- package/dist/src/metadata/offchain/file.d.ts.map +1 -0
- package/dist/src/metadata/offchain/file.js +19 -0
- package/dist/src/metadata/offchain/folder.d.ts +17 -0
- package/dist/src/metadata/offchain/folder.d.ts.map +1 -0
- package/dist/src/metadata/offchain/folder.js +10 -0
- package/dist/src/metadata/offchain/index.d.ts +4 -0
- package/dist/src/metadata/offchain/index.d.ts.map +1 -0
- package/dist/src/metadata/offchain/index.js +3 -0
- package/dist/src/metadata/onchain/index.d.ts +3 -0
- package/dist/src/metadata/onchain/index.d.ts.map +1 -0
- package/dist/src/metadata/onchain/index.js +2 -0
- package/dist/src/metadata/onchain/protobuf/OnchainMetadata.d.ts +28 -0
- package/dist/src/metadata/onchain/protobuf/OnchainMetadata.d.ts.map +1 -0
- package/dist/src/metadata/onchain/protobuf/OnchainMetadata.js +112 -0
- package/dist/src/metadata/onchain/utils.d.ts +4 -0
- package/dist/src/metadata/onchain/utils.d.ts.map +1 -0
- package/dist/src/metadata/onchain/utils.js +12 -0
- package/dist/utils/async.d.ts +3 -0
- package/dist/utils/async.d.ts.map +1 -0
- package/dist/utils/async.js +48 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/types.d.ts +2 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +1 -0
- package/jest.config.ts +17 -0
- package/package.json +46 -0
- package/src/cid/index.ts +26 -0
- package/src/compression/index.ts +84 -0
- package/src/compression/types.ts +11 -0
- package/src/encryption/index.ts +99 -0
- package/src/encryption/types.ts +4 -0
- package/src/index.ts +5 -0
- package/src/ipld/builders.ts +40 -0
- package/src/ipld/chunker.ts +245 -0
- package/src/ipld/index.ts +4 -0
- package/src/ipld/nodes.ts +208 -0
- package/src/ipld/utils.ts +21 -0
- package/src/metadata/index.ts +2 -0
- package/src/metadata/offchain/base.ts +4 -0
- package/src/metadata/offchain/file.ts +41 -0
- package/src/metadata/offchain/folder.ts +54 -0
- package/src/metadata/offchain/index.ts +3 -0
- package/src/metadata/onchain/index.ts +2 -0
- package/src/metadata/onchain/protobuf/OnchainMetadata.proto +46 -0
- package/src/metadata/onchain/protobuf/OnchainMetadata.ts +397 -0
- package/src/metadata/onchain/utils.ts +15 -0
- package/src/utils/async.ts +20 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/types.ts +1 -0
- package/tests/chunker.spec.ts +294 -0
- package/tests/cid.spec.ts +20 -0
- package/tests/compression.spec.ts +58 -0
- package/tests/encryption.spec.ts +67 -0
- package/tests/nodes.spec.ts +74 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { BaseBlockstore, MemoryBlockstore } from 'blockstore-core'
|
|
2
|
+
import { cidOfNode, cidToString } from '../src'
|
|
3
|
+
import {
|
|
4
|
+
processFileToIPLDFormat,
|
|
5
|
+
processFolderToIPLDFormat,
|
|
6
|
+
processMetadataToIPLDFormat,
|
|
7
|
+
} from '../src/ipld/chunker'
|
|
8
|
+
import { createNode, decodeNode, PBNode } from '../src/ipld/utils'
|
|
9
|
+
import { IPLDNodeData, MetadataType, OffchainMetadata } from '../src/metadata'
|
|
10
|
+
|
|
11
|
+
describe('chunker', () => {
|
|
12
|
+
describe('file creation', () => {
|
|
13
|
+
it('create a file dag from a small buffer', async () => {
|
|
14
|
+
const text = 'hello world'
|
|
15
|
+
const size = text.length
|
|
16
|
+
const name = 'test.txt'
|
|
17
|
+
const blockstore = new MemoryBlockstore()
|
|
18
|
+
|
|
19
|
+
await processFileToIPLDFormat(blockstore, bufferToIterable(Buffer.from(text)), size, name)
|
|
20
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
21
|
+
expect(nodes.length).toBe(1)
|
|
22
|
+
|
|
23
|
+
const node = nodes[0]
|
|
24
|
+
expect(node).toBeDefined()
|
|
25
|
+
expect(node?.Data).toBeDefined()
|
|
26
|
+
const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
|
|
27
|
+
expect(decoded.data).toBeDefined()
|
|
28
|
+
|
|
29
|
+
/// Check the metadata
|
|
30
|
+
expect(decoded.name).toBe(name)
|
|
31
|
+
expect(decoded.type).toBe(MetadataType.File)
|
|
32
|
+
expect(Buffer.from(decoded.data ?? '').toString()).toBe(text)
|
|
33
|
+
expect(decoded.linkDepth).toBe(0)
|
|
34
|
+
expect(decoded.size).toBe(text.length)
|
|
35
|
+
|
|
36
|
+
/// Check no links
|
|
37
|
+
expect(node?.Links.length).toBe(0)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('create a file dag from a large buffer', async () => {
|
|
41
|
+
const maxChunkSize = 1000
|
|
42
|
+
const chunkNum = 10
|
|
43
|
+
const chunk = 'h'.repeat(maxChunkSize)
|
|
44
|
+
const text = chunk.repeat(chunkNum)
|
|
45
|
+
const size = text.length
|
|
46
|
+
|
|
47
|
+
const name = 'test.txt'
|
|
48
|
+
/// 1 chunk + root
|
|
49
|
+
const EXPECTED_NODE_COUNT = 2
|
|
50
|
+
|
|
51
|
+
const blockstore = new MemoryBlockstore()
|
|
52
|
+
const headCID = await processFileToIPLDFormat(
|
|
53
|
+
blockstore,
|
|
54
|
+
bufferToIterable(Buffer.from(text)),
|
|
55
|
+
size,
|
|
56
|
+
name,
|
|
57
|
+
{
|
|
58
|
+
maxChunkSize,
|
|
59
|
+
maxLinkPerNode: maxChunkSize / 64,
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
64
|
+
expect(nodes.length).toBe(EXPECTED_NODE_COUNT)
|
|
65
|
+
|
|
66
|
+
const head = decodeNode(await blockstore.get(headCID))
|
|
67
|
+
expect(head?.Data).toBeDefined()
|
|
68
|
+
expect(head).toBeDefined()
|
|
69
|
+
expect(head?.Links.length).toBe(chunkNum)
|
|
70
|
+
|
|
71
|
+
const decoded = IPLDNodeData.decode(head?.Data ?? new Uint8Array())
|
|
72
|
+
expect(decoded.name).toBe(name)
|
|
73
|
+
expect(decoded.type).toBe(MetadataType.File)
|
|
74
|
+
expect(decoded.linkDepth).toBe(1)
|
|
75
|
+
expect(decoded.size).toBe(text.length)
|
|
76
|
+
|
|
77
|
+
nodes.forEach((node) => {
|
|
78
|
+
if (cidToString(cidOfNode(node)) !== cidToString(headCID)) {
|
|
79
|
+
expect(node?.Links.length).toBe(0)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('create a file dag with inlinks', async () => {
|
|
85
|
+
const maxChunkSize = 1000
|
|
86
|
+
const chunkNum = 10
|
|
87
|
+
const chunk = 'h'.repeat(maxChunkSize)
|
|
88
|
+
const name = 'test.txt'
|
|
89
|
+
const text = chunk.repeat(chunkNum)
|
|
90
|
+
const size = text.length
|
|
91
|
+
|
|
92
|
+
/// 1 chunks + 2 inlinks + root
|
|
93
|
+
const EXPECTED_NODE_COUNT = 4
|
|
94
|
+
|
|
95
|
+
const blockstore = new MemoryBlockstore()
|
|
96
|
+
const headCID = await processFileToIPLDFormat(
|
|
97
|
+
blockstore,
|
|
98
|
+
bufferToIterable(Buffer.from(text)),
|
|
99
|
+
size,
|
|
100
|
+
name,
|
|
101
|
+
{
|
|
102
|
+
maxChunkSize,
|
|
103
|
+
maxLinkPerNode: 4,
|
|
104
|
+
},
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
108
|
+
expect(nodes.length).toBe(EXPECTED_NODE_COUNT)
|
|
109
|
+
|
|
110
|
+
let [rootCount, inlinkCount, chunkCount] = [0, 0, 0]
|
|
111
|
+
|
|
112
|
+
nodes.forEach((node) => {
|
|
113
|
+
const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
|
|
114
|
+
if (decoded.type === MetadataType.File) {
|
|
115
|
+
rootCount++
|
|
116
|
+
} else if (decoded.type === MetadataType.FileInlink) {
|
|
117
|
+
inlinkCount++
|
|
118
|
+
} else if (decoded.type === MetadataType.FileChunk) {
|
|
119
|
+
chunkCount++
|
|
120
|
+
} else {
|
|
121
|
+
throw new Error('Unexpected node type')
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
expect(rootCount).toBe(1)
|
|
126
|
+
expect(inlinkCount).toBe(2)
|
|
127
|
+
expect(chunkCount).toBe(1)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
describe('folder creation', () => {
|
|
132
|
+
it('create a folder dag from a small buffer', async () => {
|
|
133
|
+
const links = Array.from({ length: 1 }, () =>
|
|
134
|
+
cidOfNode(createNode(Buffer.from(Math.random().toString()))),
|
|
135
|
+
)
|
|
136
|
+
const name = 'folder'
|
|
137
|
+
const size = 1000
|
|
138
|
+
const blockstore = new MemoryBlockstore()
|
|
139
|
+
const headCID = processFolderToIPLDFormat(blockstore, links, name, size, {
|
|
140
|
+
maxLinkPerNode: 4,
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
144
|
+
expect(nodes.length).toBe(1)
|
|
145
|
+
const node = nodes[0]
|
|
146
|
+
expect(node).toBeDefined()
|
|
147
|
+
expect(node?.Data).toBeDefined()
|
|
148
|
+
const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
|
|
149
|
+
expect(decoded.name).toBe(name)
|
|
150
|
+
expect(decoded.type).toBe(MetadataType.Folder)
|
|
151
|
+
expect(decoded.linkDepth).toBe(0)
|
|
152
|
+
expect(decoded.size).toBe(size)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('create a folder dag with inlinks', async () => {
|
|
156
|
+
const links = Array.from({ length: 10 }, () =>
|
|
157
|
+
cidOfNode(createNode(Buffer.from(Math.random().toString()))),
|
|
158
|
+
)
|
|
159
|
+
const name = 'folder'
|
|
160
|
+
const size = 1000
|
|
161
|
+
|
|
162
|
+
/// 3 inlinks + root
|
|
163
|
+
const EXPECTED_NODE_COUNT = 4
|
|
164
|
+
|
|
165
|
+
const blockstore = new MemoryBlockstore()
|
|
166
|
+
const headCID = processFolderToIPLDFormat(blockstore, links, name, size, {
|
|
167
|
+
maxLinkPerNode: 4,
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
171
|
+
expect(nodes.length).toBe(EXPECTED_NODE_COUNT)
|
|
172
|
+
|
|
173
|
+
let [rootCount, inlinkCount] = [0, 0, 0]
|
|
174
|
+
|
|
175
|
+
nodes.forEach((node) => {
|
|
176
|
+
const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
|
|
177
|
+
if (decoded.type === MetadataType.Folder) {
|
|
178
|
+
rootCount++
|
|
179
|
+
} else if (decoded.type === MetadataType.FolderInlink) {
|
|
180
|
+
inlinkCount++
|
|
181
|
+
} else {
|
|
182
|
+
throw new Error('Unexpected node type')
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
expect(rootCount).toBe(1)
|
|
187
|
+
expect(inlinkCount).toBe(3)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
describe('metadata creation', () => {
|
|
192
|
+
it('create a metadata dag from a small buffer', async () => {
|
|
193
|
+
const metadata: OffchainMetadata = {
|
|
194
|
+
type: 'file',
|
|
195
|
+
dataCid: 'test',
|
|
196
|
+
name: 'test',
|
|
197
|
+
mimeType: 'text/plain',
|
|
198
|
+
totalSize: 1000,
|
|
199
|
+
totalChunks: 10,
|
|
200
|
+
chunks: [],
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const blockstore = new MemoryBlockstore()
|
|
204
|
+
const headCID = await processMetadataToIPLDFormat(blockstore, metadata)
|
|
205
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
206
|
+
expect(nodes.length).toBe(1)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('large metadata dag represented into multiple nodes', async () => {
|
|
210
|
+
const metadata: OffchainMetadata = {
|
|
211
|
+
type: 'file',
|
|
212
|
+
dataCid: 'test',
|
|
213
|
+
name: 'test',
|
|
214
|
+
mimeType: 'text/plain'.repeat(100),
|
|
215
|
+
totalSize: 1000,
|
|
216
|
+
totalChunks: 10,
|
|
217
|
+
chunks: [],
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const blockstore = new MemoryBlockstore()
|
|
221
|
+
const headCID = await processMetadataToIPLDFormat(blockstore, metadata, {
|
|
222
|
+
maxChunkSize: 200,
|
|
223
|
+
maxLinkPerNode: 2,
|
|
224
|
+
})
|
|
225
|
+
const nodes = await nodesFromBlockstore(blockstore)
|
|
226
|
+
expect(nodes.length).toBeGreaterThan(1)
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
describe('asyncronous chunking equivalence', () => {
|
|
231
|
+
it('chunk a small file buffer', async () => {
|
|
232
|
+
const buffer = Buffer.from('hello world')
|
|
233
|
+
const blockstore = new MemoryBlockstore()
|
|
234
|
+
const chunkedBlockstore = new MemoryBlockstore()
|
|
235
|
+
const singleBufferCID = await processFileToIPLDFormat(
|
|
236
|
+
blockstore,
|
|
237
|
+
bufferToIterable(buffer),
|
|
238
|
+
buffer.length,
|
|
239
|
+
'test.txt',
|
|
240
|
+
)
|
|
241
|
+
const chunkedBufferCID = await processFileToIPLDFormat(
|
|
242
|
+
chunkedBlockstore,
|
|
243
|
+
separateBufferToIterable(buffer, 5),
|
|
244
|
+
buffer.length,
|
|
245
|
+
'test.txt',
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
expect(singleBufferCID).toEqual(chunkedBufferCID)
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('chunk a large file buffer', async () => {
|
|
252
|
+
const buffer = Buffer.from('hello world')
|
|
253
|
+
const blockstore = new MemoryBlockstore()
|
|
254
|
+
const chunkedBlockstore = new MemoryBlockstore()
|
|
255
|
+
const singleBufferCID = await processFileToIPLDFormat(
|
|
256
|
+
blockstore,
|
|
257
|
+
bufferToIterable(buffer),
|
|
258
|
+
buffer.length,
|
|
259
|
+
'test.txt',
|
|
260
|
+
)
|
|
261
|
+
const chunkedBufferCID = await processFileToIPLDFormat(
|
|
262
|
+
chunkedBlockstore,
|
|
263
|
+
separateBufferToIterable(buffer, 5),
|
|
264
|
+
buffer.length,
|
|
265
|
+
'test.txt',
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
expect(singleBufferCID).toEqual(chunkedBufferCID)
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
const bufferToIterable = (buffer: Buffer): AsyncIterable<Buffer> => {
|
|
274
|
+
return (async function* () {
|
|
275
|
+
yield buffer
|
|
276
|
+
})()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const separateBufferToIterable = (buffer: Buffer, chunkSize: number): AsyncIterable<Buffer> => {
|
|
280
|
+
return (async function* () {
|
|
281
|
+
while (buffer.length > 0) {
|
|
282
|
+
yield buffer.subarray(0, chunkSize)
|
|
283
|
+
buffer = buffer.subarray(chunkSize)
|
|
284
|
+
}
|
|
285
|
+
})()
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const nodesFromBlockstore = async (blockstore: BaseBlockstore): Promise<PBNode[]> => {
|
|
289
|
+
const nodes: PBNode[] = []
|
|
290
|
+
for await (const pair of blockstore.getAll()) {
|
|
291
|
+
nodes.push(decodeNode(pair.block))
|
|
292
|
+
}
|
|
293
|
+
return nodes
|
|
294
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CID } from 'multiformats'
|
|
2
|
+
import { cidOfNode, cidToString, stringToCid } from '../src/cid/index.js'
|
|
3
|
+
import { createNode } from '../src/ipld/index.js'
|
|
4
|
+
|
|
5
|
+
const randomCIDString = cidOfNode(createNode(new Uint8Array([]), [])).toString()
|
|
6
|
+
|
|
7
|
+
describe('CID', () => {
|
|
8
|
+
it('should generate a valid CID from a node', () => {
|
|
9
|
+
const node = createNode(new Uint8Array([1, 2, 3]), [])
|
|
10
|
+
const cid = cidOfNode(node).toString()
|
|
11
|
+
expect(cid).toBeDefined()
|
|
12
|
+
expect(cidToString(stringToCid(cid))).toEqual(cid)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should convert CID string back to CID object', () => {
|
|
16
|
+
const cidObject = stringToCid(randomCIDString)
|
|
17
|
+
expect(cidObject).toBeInstanceOf(CID)
|
|
18
|
+
expect(cidToString(cidObject)).toEqual(randomCIDString)
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { compressFile, COMPRESSION_CHUNK_SIZE, CompressionAlgorithm, decompressFile } from '../src'
|
|
2
|
+
|
|
3
|
+
describe('compression', () => {
|
|
4
|
+
it('compresses and decompresses a file with default options', async () => {
|
|
5
|
+
const file = Buffer.from('hello'.repeat(1000))
|
|
6
|
+
|
|
7
|
+
const compressed = compressFile(
|
|
8
|
+
(async function* () {
|
|
9
|
+
yield file
|
|
10
|
+
})(),
|
|
11
|
+
{
|
|
12
|
+
algorithm: CompressionAlgorithm.ZLIB,
|
|
13
|
+
level: 9,
|
|
14
|
+
},
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const decompressed = decompressFile(compressed, {
|
|
18
|
+
algorithm: CompressionAlgorithm.ZLIB,
|
|
19
|
+
level: 9,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
let decompressedBuffer = Buffer.alloc(0)
|
|
23
|
+
for await (const chunk of decompressed) {
|
|
24
|
+
decompressedBuffer = Buffer.concat([decompressedBuffer, chunk])
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
expect(decompressedBuffer.toString()).toBe(file.toString())
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('compresses and decompresses a file with custom chunk size', async () => {
|
|
31
|
+
const file = Buffer.from('hello'.repeat(1000))
|
|
32
|
+
const chunkSize = 100
|
|
33
|
+
|
|
34
|
+
const compressed = compressFile(
|
|
35
|
+
(async function* () {
|
|
36
|
+
yield file
|
|
37
|
+
})(),
|
|
38
|
+
{
|
|
39
|
+
algorithm: CompressionAlgorithm.ZLIB,
|
|
40
|
+
level: 9,
|
|
41
|
+
chunkSize,
|
|
42
|
+
},
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
const decompressed = decompressFile(compressed, {
|
|
46
|
+
algorithm: CompressionAlgorithm.ZLIB,
|
|
47
|
+
level: 9,
|
|
48
|
+
chunkSize,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
let decompressedBuffer = Buffer.alloc(0)
|
|
52
|
+
for await (const chunk of decompressed) {
|
|
53
|
+
decompressedBuffer = Buffer.concat([decompressedBuffer, chunk])
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
expect(decompressedBuffer.toString()).toBe(file.toString())
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { decryptFile, encryptFile, EncryptionAlgorithm } from '../src'
|
|
2
|
+
|
|
3
|
+
describe('encryption', () => {
|
|
4
|
+
it('encrypts and decrypts a file with default chunk size', async () => {
|
|
5
|
+
const chunk = 'hello'
|
|
6
|
+
const file = Buffer.from(chunk.repeat(1000))
|
|
7
|
+
const password = 'password'
|
|
8
|
+
const salt = 'salt'
|
|
9
|
+
|
|
10
|
+
const encrypted = encryptFile(
|
|
11
|
+
(async function* () {
|
|
12
|
+
yield file
|
|
13
|
+
})(),
|
|
14
|
+
password,
|
|
15
|
+
{
|
|
16
|
+
algorithm: EncryptionAlgorithm.AES_256_GCM,
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const decrypted = decryptFile(encrypted, password, {
|
|
21
|
+
algorithm: EncryptionAlgorithm.AES_256_GCM,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
let decryptedBuffer = Buffer.alloc(0)
|
|
25
|
+
for await (const chunk of decrypted) {
|
|
26
|
+
decryptedBuffer = Buffer.concat([decryptedBuffer, chunk])
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
expect(decryptedBuffer.toString()).toBe(file.toString())
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('encrypts and decrypts a file with custom chunk size', async () => {
|
|
33
|
+
const chunk = 'hello'
|
|
34
|
+
const file = Buffer.from(chunk.repeat(1000))
|
|
35
|
+
const password = 'password'
|
|
36
|
+
const salt = 'salt'
|
|
37
|
+
const IV_SIZE = 16
|
|
38
|
+
const TAG_SIZE = 16
|
|
39
|
+
|
|
40
|
+
const encryptingSize = 100
|
|
41
|
+
|
|
42
|
+
const encrypted = encryptFile(
|
|
43
|
+
(async function* () {
|
|
44
|
+
yield file
|
|
45
|
+
})(),
|
|
46
|
+
password,
|
|
47
|
+
{
|
|
48
|
+
algorithm: EncryptionAlgorithm.AES_256_GCM,
|
|
49
|
+
chunkSize: encryptingSize,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const decryptingSize = encryptingSize + IV_SIZE + TAG_SIZE
|
|
54
|
+
|
|
55
|
+
const decrypted = decryptFile(encrypted, password, {
|
|
56
|
+
algorithm: EncryptionAlgorithm.AES_256_GCM,
|
|
57
|
+
chunkSize: decryptingSize,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
let decryptedBuffer = Buffer.alloc(0)
|
|
61
|
+
for await (const chunk of decrypted) {
|
|
62
|
+
decryptedBuffer = Buffer.concat([decryptedBuffer, chunk])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
expect(decryptedBuffer.toString()).toBe(file.toString())
|
|
66
|
+
})
|
|
67
|
+
})
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cidOfNode,
|
|
3
|
+
createChunkedFileIpldNode,
|
|
4
|
+
createFileChunkIpldNode,
|
|
5
|
+
createSingleFileIpldNode,
|
|
6
|
+
} from '../src/index.js'
|
|
7
|
+
import { createNode } from '../src/ipld/index.js'
|
|
8
|
+
import { IPLDNodeData, MetadataType } from '../src/metadata/onchain/protobuf/OnchainMetadata.js'
|
|
9
|
+
|
|
10
|
+
describe('node creation', () => {
|
|
11
|
+
describe('files nodes', () => {
|
|
12
|
+
it('single file node | correctly params setup', () => {
|
|
13
|
+
const filename = 'test.txt'
|
|
14
|
+
const buffer = Buffer.from('hello world')
|
|
15
|
+
const node = createSingleFileIpldNode(buffer, filename)
|
|
16
|
+
const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
|
|
17
|
+
expect(decoded.name).toBe(filename)
|
|
18
|
+
expect(decoded.size).toBe(buffer.length)
|
|
19
|
+
expect(Buffer.from(decoded.data ?? '').toString()).toBe(buffer.toString())
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('single file root node | no name', () => {
|
|
23
|
+
const buffer = Buffer.from('hello world')
|
|
24
|
+
const node = createSingleFileIpldNode(buffer)
|
|
25
|
+
const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
|
|
26
|
+
expect(decoded.type).toBe(MetadataType.File)
|
|
27
|
+
expect(decoded.name).toBeUndefined()
|
|
28
|
+
expect(decoded.size).toBe(buffer.length)
|
|
29
|
+
expect(Buffer.from(decoded.data ?? '').toString()).toBe(buffer.toString())
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('chunked file root node | correctly params setup', () => {
|
|
33
|
+
const links = Array.from({ length: 10 }, () =>
|
|
34
|
+
cidOfNode(createNode(Buffer.from(Math.random().toString()))),
|
|
35
|
+
)
|
|
36
|
+
const size = 1000
|
|
37
|
+
const linkDepth = 1
|
|
38
|
+
const filename = 'test.txt'
|
|
39
|
+
const node = createChunkedFileIpldNode(links, size, linkDepth, filename)
|
|
40
|
+
|
|
41
|
+
const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
|
|
42
|
+
expect(decoded.type).toBe(MetadataType.File)
|
|
43
|
+
expect(decoded.name).toBe(filename)
|
|
44
|
+
expect(decoded.size).toBe(size)
|
|
45
|
+
expect(decoded.linkDepth).toBe(linkDepth)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('chunked file root node | no name', () => {
|
|
49
|
+
const links = Array.from({ length: 10 }, () =>
|
|
50
|
+
cidOfNode(createNode(Buffer.from(Math.random().toString()))),
|
|
51
|
+
)
|
|
52
|
+
const size = 1000
|
|
53
|
+
const linkDepth = 1
|
|
54
|
+
const node = createChunkedFileIpldNode(links, size, linkDepth)
|
|
55
|
+
|
|
56
|
+
const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
|
|
57
|
+
expect(decoded.type).toBe(MetadataType.File)
|
|
58
|
+
expect(decoded.name).toBeUndefined()
|
|
59
|
+
expect(decoded.size).toBe(size)
|
|
60
|
+
expect(decoded.linkDepth).toBe(linkDepth)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('file chunk node | correctly params setup', () => {
|
|
64
|
+
const buffer = Buffer.from('hello world')
|
|
65
|
+
const node = createFileChunkIpldNode(buffer)
|
|
66
|
+
|
|
67
|
+
const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
|
|
68
|
+
expect(decoded.type).toBe(MetadataType.FileChunk)
|
|
69
|
+
expect(decoded.name).toBeUndefined()
|
|
70
|
+
expect(decoded.size).toBe(buffer.length)
|
|
71
|
+
expect(decoded.linkDepth).toBe(0)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "./src/",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"module": "NodeNext",
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"stripInternal": true,
|
|
11
|
+
"resolveJsonModule": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"]
|
|
14
|
+
}
|