@autonomys/auto-drive 0.5.0

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 (67) hide show
  1. package/README.md +1 -0
  2. package/dist/cid/index.d.ts +9 -0
  3. package/dist/cid/index.d.ts.map +1 -0
  4. package/dist/cid/index.js +20 -0
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +3 -0
  8. package/dist/ipld/chunker.d.ts +17 -0
  9. package/dist/ipld/chunker.d.ts.map +1 -0
  10. package/dist/ipld/chunker.js +77 -0
  11. package/dist/ipld/index.d.ts +4 -0
  12. package/dist/ipld/index.d.ts.map +1 -0
  13. package/dist/ipld/index.js +3 -0
  14. package/dist/ipld/nodes.d.ts +11 -0
  15. package/dist/ipld/nodes.d.ts.map +1 -0
  16. package/dist/ipld/nodes.js +60 -0
  17. package/dist/ipld/utils.d.ts +5 -0
  18. package/dist/ipld/utils.d.ts.map +1 -0
  19. package/dist/ipld/utils.js +10 -0
  20. package/dist/metadata/index.d.ts +3 -0
  21. package/dist/metadata/index.d.ts.map +1 -0
  22. package/dist/metadata/index.js +2 -0
  23. package/dist/metadata/offchain/base.d.ts +4 -0
  24. package/dist/metadata/offchain/base.d.ts.map +1 -0
  25. package/dist/metadata/offchain/base.js +1 -0
  26. package/dist/metadata/offchain/file.d.ts +16 -0
  27. package/dist/metadata/offchain/file.d.ts.map +1 -0
  28. package/dist/metadata/offchain/file.js +18 -0
  29. package/dist/metadata/offchain/folder.d.ts +17 -0
  30. package/dist/metadata/offchain/folder.d.ts.map +1 -0
  31. package/dist/metadata/offchain/folder.js +9 -0
  32. package/dist/metadata/offchain/index.d.ts +4 -0
  33. package/dist/metadata/offchain/index.d.ts.map +1 -0
  34. package/dist/metadata/offchain/index.js +3 -0
  35. package/dist/metadata/onchain/index.d.ts +3 -0
  36. package/dist/metadata/onchain/index.d.ts.map +1 -0
  37. package/dist/metadata/onchain/index.js +2 -0
  38. package/dist/metadata/onchain/protobuf/OnchainMetadat.d.ts +26 -0
  39. package/dist/metadata/onchain/protobuf/OnchainMetadat.d.ts.map +1 -0
  40. package/dist/metadata/onchain/protobuf/OnchainMetadat.js +108 -0
  41. package/dist/metadata/onchain/protobuf/onchainMetadata.d.ts +26 -0
  42. package/dist/metadata/onchain/protobuf/onchainMetadata.d.ts.map +1 -0
  43. package/dist/metadata/onchain/protobuf/onchainMetadata.js +108 -0
  44. package/dist/metadata/onchain/utils.d.ts +4 -0
  45. package/dist/metadata/onchain/utils.d.ts.map +1 -0
  46. package/dist/metadata/onchain/utils.js +12 -0
  47. package/jest.config.ts +17 -0
  48. package/package.json +42 -0
  49. package/src/cid/index.ts +26 -0
  50. package/src/index.ts +3 -0
  51. package/src/ipld/chunker.ts +117 -0
  52. package/src/ipld/index.ts +3 -0
  53. package/src/ipld/nodes.ts +134 -0
  54. package/src/ipld/utils.ts +15 -0
  55. package/src/metadata/index.ts +2 -0
  56. package/src/metadata/offchain/base.ts +4 -0
  57. package/src/metadata/offchain/file.ts +36 -0
  58. package/src/metadata/offchain/folder.ts +28 -0
  59. package/src/metadata/offchain/index.ts +3 -0
  60. package/src/metadata/onchain/index.ts +2 -0
  61. package/src/metadata/onchain/protobuf/OnchainMetadata.proto +19 -0
  62. package/src/metadata/onchain/protobuf/OnchainMetadata.ts +133 -0
  63. package/src/metadata/onchain/utils.ts +15 -0
  64. package/tests/chunker.spec.ts +157 -0
  65. package/tests/cid.spec.ts +20 -0
  66. package/tests/nodes.spec.ts +70 -0
  67. package/tsconfig.json +14 -0
@@ -0,0 +1,133 @@
1
+ /* eslint-disable import/export */
2
+ /* eslint-disable complexity */
3
+ /* eslint-disable @typescript-eslint/no-namespace */
4
+ /* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
5
+ /* eslint-disable @typescript-eslint/no-empty-interface */
6
+
7
+ import { type Codec, decodeMessage, type DecodeOptions, encodeMessage, enumeration, message } from 'protons-runtime'
8
+ import type { Uint8ArrayList } from 'uint8arraylist'
9
+
10
+ export interface IPLDNodeData {
11
+ type: MetadataType
12
+ linkDepth: number
13
+ size?: number
14
+ name?: string
15
+ data?: Uint8Array
16
+ }
17
+
18
+ export namespace IPLDNodeData {
19
+ let _codec: Codec<IPLDNodeData>
20
+
21
+ export const codec = (): Codec<IPLDNodeData> => {
22
+ if (_codec == null) {
23
+ _codec = message<IPLDNodeData>((obj, w, opts = {}) => {
24
+ if (opts.lengthDelimited !== false) {
25
+ w.fork()
26
+ }
27
+
28
+ if (obj.type != null && __MetadataTypeValues[obj.type] !== 0) {
29
+ w.uint32(8)
30
+ MetadataType.codec().encode(obj.type, w)
31
+ }
32
+
33
+ if ((obj.linkDepth != null && obj.linkDepth !== 0)) {
34
+ w.uint32(16)
35
+ w.int32(obj.linkDepth)
36
+ }
37
+
38
+ if (obj.size != null) {
39
+ w.uint32(24)
40
+ w.int32(obj.size)
41
+ }
42
+
43
+ if (obj.name != null) {
44
+ w.uint32(34)
45
+ w.string(obj.name)
46
+ }
47
+
48
+ if (obj.data != null) {
49
+ w.uint32(42)
50
+ w.bytes(obj.data)
51
+ }
52
+
53
+ if (opts.lengthDelimited !== false) {
54
+ w.ldelim()
55
+ }
56
+ }, (reader, length, opts = {}) => {
57
+ const obj: any = {
58
+ type: MetadataType.File,
59
+ linkDepth: 0
60
+ }
61
+
62
+ const end = length == null ? reader.len : reader.pos + length
63
+
64
+ while (reader.pos < end) {
65
+ const tag = reader.uint32()
66
+
67
+ switch (tag >>> 3) {
68
+ case 1: {
69
+ obj.type = MetadataType.codec().decode(reader)
70
+ break
71
+ }
72
+ case 2: {
73
+ obj.linkDepth = reader.int32()
74
+ break
75
+ }
76
+ case 3: {
77
+ obj.size = reader.int32()
78
+ break
79
+ }
80
+ case 4: {
81
+ obj.name = reader.string()
82
+ break
83
+ }
84
+ case 5: {
85
+ obj.data = reader.bytes()
86
+ break
87
+ }
88
+ default: {
89
+ reader.skipType(tag & 7)
90
+ break
91
+ }
92
+ }
93
+ }
94
+
95
+ return obj
96
+ })
97
+ }
98
+
99
+ return _codec
100
+ }
101
+
102
+ export const encode = (obj: Partial<IPLDNodeData>): Uint8Array => {
103
+ return encodeMessage(obj, IPLDNodeData.codec())
104
+ }
105
+
106
+ export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<IPLDNodeData>): IPLDNodeData => {
107
+ return decodeMessage(buf, IPLDNodeData.codec(), opts)
108
+ }
109
+ }
110
+
111
+ export enum MetadataType {
112
+ File = 'File',
113
+ FileInlink = 'FileInlink',
114
+ FileChunk = 'FileChunk',
115
+ Folder = 'Folder',
116
+ FolderInlink = 'FolderInlink',
117
+ Metadata = 'Metadata'
118
+ }
119
+
120
+ enum __MetadataTypeValues {
121
+ File = 0,
122
+ FileInlink = 1,
123
+ FileChunk = 2,
124
+ Folder = 3,
125
+ FolderInlink = 4,
126
+ Metadata = 5
127
+ }
128
+
129
+ export namespace MetadataType {
130
+ export const codec = (): Codec<MetadataType> => {
131
+ return enumeration<MetadataType>(__MetadataTypeValues)
132
+ }
133
+ }
@@ -0,0 +1,15 @@
1
+ import { decode } from '@ipld/dag-pb'
2
+ import { IPLDNodeData } from '../onchain/index.js'
3
+
4
+ export const encodeIPLDNodeData = (metadata: IPLDNodeData): Uint8Array => {
5
+ return IPLDNodeData.encode(metadata)
6
+ }
7
+
8
+ export const decodeIPLDNodeData = (data: Uint8Array): IPLDNodeData => {
9
+ const decoded = decode(data)
10
+ if (!decoded.Data) {
11
+ throw new Error('Invalid data')
12
+ }
13
+
14
+ return IPLDNodeData.decode(decoded.Data)
15
+ }
@@ -0,0 +1,157 @@
1
+ import { createNode } from '@ipld/dag-pb'
2
+ import { cidOfNode } from '../src'
3
+ import { createFileIPLDDag, createFolderIPLDDag } from '../src/ipld/chunker'
4
+ import { IPLDNodeData, MetadataType } from '../src/metadata'
5
+
6
+ describe('chunker', () => {
7
+ describe('file creation', () => {
8
+ it('create a file dag from a small buffer', () => {
9
+ const text = 'hello world'
10
+ const name = 'test.txt'
11
+ const dag = createFileIPLDDag(Buffer.from(text), name)
12
+ expect(dag.nodes.size).toBe(1)
13
+
14
+ const node = dag.nodes.get(dag.headCID)
15
+ expect(node).toBeDefined()
16
+ expect(node?.Data).toBeDefined()
17
+ const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
18
+ expect(decoded.data).toBeDefined()
19
+
20
+ /// Check the metadata
21
+ expect(decoded.name).toBe(name)
22
+ expect(decoded.type).toBe(MetadataType.File)
23
+ expect(Buffer.from(decoded.data ?? '').toString()).toBe(text)
24
+ expect(decoded.linkDepth).toBe(0)
25
+ expect(decoded.size).toBe(text.length)
26
+
27
+ /// Check no links
28
+ expect(node?.Links.length).toBe(0)
29
+ })
30
+
31
+ it('create a file dag from a large buffer', () => {
32
+ const chunkSize = 1000
33
+ const chunkNum = 10
34
+ const chunk = 'h'.repeat(chunkSize)
35
+ const text = chunk.repeat(chunkNum)
36
+
37
+ const name = 'test.txt'
38
+
39
+ const dag = createFileIPLDDag(Buffer.from(text), name, {
40
+ chunkSize,
41
+ maxLinkPerNode: chunkSize / 64,
42
+ })
43
+
44
+ expect(dag.nodes.size).toBe(chunkNum + 1)
45
+
46
+ const head = dag.nodes.get(dag.headCID)
47
+ expect(head?.Data).toBeDefined()
48
+ expect(head).toBeDefined()
49
+ expect(head?.Links.length).toBe(chunkNum)
50
+
51
+ const decoded = IPLDNodeData.decode(head?.Data ?? new Uint8Array())
52
+ expect(decoded.name).toBe(name)
53
+ expect(decoded.type).toBe(MetadataType.File)
54
+ expect(decoded.linkDepth).toBe(1)
55
+ expect(decoded.size).toBe(text.length)
56
+
57
+ Array.from(dag.nodes.entries()).forEach(([cid, node]) => {
58
+ if (cid !== dag.headCID) {
59
+ expect(node?.Links.length).toBe(0)
60
+ }
61
+ })
62
+ })
63
+
64
+ it('create a file dag with inlinks', () => {
65
+ const chunkSize = 1000
66
+ const chunkNum = 10
67
+ const chunk = 'h'.repeat(chunkSize)
68
+ const name = 'test.txt'
69
+ const text = chunk.repeat(chunkNum)
70
+
71
+ /// 10 chunks + 3 inlinks + root
72
+ const EXPECTED_NODE_COUNT = 14
73
+
74
+ const dag = createFileIPLDDag(Buffer.from(text), name, {
75
+ chunkSize,
76
+ maxLinkPerNode: 4,
77
+ })
78
+
79
+ expect(dag.nodes.size).toBe(EXPECTED_NODE_COUNT)
80
+
81
+ let [rootCount, inlinkCount, chunkCount] = [0, 0, 0]
82
+
83
+ Array.from(dag.nodes.values()).forEach((node) => {
84
+ const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
85
+ if (decoded.type === MetadataType.File) {
86
+ rootCount++
87
+ } else if (decoded.type === MetadataType.FileInlink) {
88
+ inlinkCount++
89
+ } else if (decoded.type === MetadataType.FileChunk) {
90
+ chunkCount++
91
+ } else {
92
+ throw new Error('Unexpected node type')
93
+ }
94
+ })
95
+
96
+ expect(rootCount).toBe(1)
97
+ expect(inlinkCount).toBe(3)
98
+ expect(chunkCount).toBe(10)
99
+ })
100
+ })
101
+
102
+ describe('folder creation', () => {
103
+ it('create a folder dag from a small buffer', () => {
104
+ const links = Array.from({ length: 1 }, () =>
105
+ cidOfNode(createNode(Buffer.from(Math.random().toString()))),
106
+ )
107
+ const name = 'folder'
108
+ const size = 1000
109
+ const dag = createFolderIPLDDag(links, name, size, {
110
+ maxLinkPerNode: 4,
111
+ })
112
+
113
+ expect(dag.nodes.size).toBe(1)
114
+ const node = dag.nodes.get(dag.headCID)
115
+ expect(node).toBeDefined()
116
+ expect(node?.Data).toBeDefined()
117
+ const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
118
+ expect(decoded.name).toBe(name)
119
+ expect(decoded.type).toBe(MetadataType.Folder)
120
+ expect(decoded.linkDepth).toBe(0)
121
+ expect(decoded.size).toBe(size)
122
+ })
123
+
124
+ it('create a folder dag with inlinks', () => {
125
+ const links = Array.from({ length: 10 }, () =>
126
+ cidOfNode(createNode(Buffer.from(Math.random().toString()))),
127
+ )
128
+ const name = 'folder'
129
+ const size = 1000
130
+
131
+ /// 3 inlinks + root
132
+ const EXPECTED_NODE_COUNT = 4
133
+
134
+ const dag = createFolderIPLDDag(links, name, size, {
135
+ maxLinkPerNode: 4,
136
+ })
137
+
138
+ expect(dag.nodes.size).toBe(EXPECTED_NODE_COUNT)
139
+
140
+ let [rootCount, inlinkCount] = [0, 0, 0]
141
+
142
+ Array.from(dag.nodes.values()).forEach((node) => {
143
+ const decoded = IPLDNodeData.decode(node?.Data ?? new Uint8Array())
144
+ if (decoded.type === MetadataType.Folder) {
145
+ rootCount++
146
+ } else if (decoded.type === MetadataType.FolderInlink) {
147
+ inlinkCount++
148
+ } else {
149
+ throw new Error('Unexpected node type')
150
+ }
151
+ })
152
+
153
+ expect(rootCount).toBe(1)
154
+ expect(inlinkCount).toBe(3)
155
+ })
156
+ })
157
+ })
@@ -0,0 +1,20 @@
1
+ import { createNode } from '@ipld/dag-pb'
2
+ import { CID } from 'multiformats'
3
+ import { cidOfNode, cidToString, stringToCid } from '../src/cid/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,70 @@
1
+ import { createNode } from '@ipld/dag-pb'
2
+ import { cidOfNode, createChunkedFileIpldNode, createSingleFileIpldNode } from '../src/index.js'
3
+ import { createChunkIpldNode } from '../src/ipld/nodes.js'
4
+ import { IPLDNodeData, MetadataType } from '../src/metadata/onchain/protobuf/OnchainMetadata.js'
5
+
6
+ describe('node creation', () => {
7
+ describe('files nodes', () => {
8
+ it('single file node | correctly params setup', () => {
9
+ const filename = 'test.txt'
10
+ const buffer = Buffer.from('hello world')
11
+ const node = createSingleFileIpldNode(buffer, filename)
12
+ const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
13
+ expect(decoded.name).toBe(filename)
14
+ expect(decoded.size).toBe(buffer.length)
15
+ expect(Buffer.from(decoded.data ?? '').toString()).toBe(buffer.toString())
16
+ })
17
+
18
+ it('single file root node | no name', () => {
19
+ const buffer = Buffer.from('hello world')
20
+ const node = createSingleFileIpldNode(buffer)
21
+ const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
22
+ expect(decoded.type).toBe(MetadataType.File)
23
+ expect(decoded.name).toBeUndefined()
24
+ expect(decoded.size).toBe(buffer.length)
25
+ expect(Buffer.from(decoded.data ?? '').toString()).toBe(buffer.toString())
26
+ })
27
+
28
+ it('chunked file root node | correctly params setup', () => {
29
+ const links = Array.from({ length: 10 }, () =>
30
+ cidOfNode(createNode(Buffer.from(Math.random().toString()))),
31
+ )
32
+ const size = 1000
33
+ const linkDepth = 1
34
+ const filename = 'test.txt'
35
+ const node = createChunkedFileIpldNode(links, size, linkDepth, filename)
36
+
37
+ const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
38
+ expect(decoded.type).toBe(MetadataType.File)
39
+ expect(decoded.name).toBe(filename)
40
+ expect(decoded.size).toBe(size)
41
+ expect(decoded.linkDepth).toBe(linkDepth)
42
+ })
43
+
44
+ it('chunked file root node | no name', () => {
45
+ const links = Array.from({ length: 10 }, () =>
46
+ cidOfNode(createNode(Buffer.from(Math.random().toString()))),
47
+ )
48
+ const size = 1000
49
+ const linkDepth = 1
50
+ const node = createChunkedFileIpldNode(links, size, linkDepth)
51
+
52
+ const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
53
+ expect(decoded.type).toBe(MetadataType.File)
54
+ expect(decoded.name).toBeUndefined()
55
+ expect(decoded.size).toBe(size)
56
+ expect(decoded.linkDepth).toBe(linkDepth)
57
+ })
58
+
59
+ it('file chunk node | correctly params setup', () => {
60
+ const buffer = Buffer.from('hello world')
61
+ const node = createChunkIpldNode(buffer)
62
+
63
+ const decoded = IPLDNodeData.decode(node.Data ?? new Uint8Array())
64
+ expect(decoded.type).toBe(MetadataType.FileChunk)
65
+ expect(decoded.name).toBeUndefined()
66
+ expect(decoded.size).toBe(buffer.length)
67
+ expect(decoded.linkDepth).toBe(0)
68
+ })
69
+ })
70
+ })
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
+ }