@helia/interop 3.0.1 → 4.0.0-e554493
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/.aegir.js +46 -0
- package/README.md +11 -0
- package/dist/src/bin.d.ts +3 -0
- package/dist/src/bin.d.ts.map +1 -0
- package/dist/src/bin.js +20 -0
- package/dist/src/bin.js.map +1 -0
- package/dist/src/car.spec.d.ts +2 -0
- package/dist/src/car.spec.d.ts.map +1 -0
- package/dist/src/car.spec.js +77 -0
- package/dist/src/car.spec.js.map +1 -0
- package/dist/src/dag-cbor.spec.d.ts +2 -0
- package/dist/src/dag-cbor.spec.d.ts.map +1 -0
- package/dist/src/dag-cbor.spec.js +49 -0
- package/dist/src/dag-cbor.spec.js.map +1 -0
- package/dist/src/dag-json.spec.d.ts +2 -0
- package/dist/src/dag-json.spec.d.ts.map +1 -0
- package/dist/src/dag-json.spec.js +49 -0
- package/dist/src/dag-json.spec.js.map +1 -0
- package/dist/src/fixtures/connect.d.ts +7 -0
- package/dist/src/fixtures/connect.d.ts.map +1 -0
- package/dist/src/fixtures/connect.js +17 -0
- package/dist/src/fixtures/connect.js.map +1 -0
- package/dist/src/fixtures/create-helia-http.d.ts +4 -0
- package/dist/src/fixtures/create-helia-http.d.ts.map +1 -0
- package/dist/src/fixtures/create-helia-http.js +7 -0
- package/dist/src/fixtures/create-helia-http.js.map +1 -0
- package/dist/src/fixtures/create-helia.browser.d.ts +6 -0
- package/dist/src/fixtures/create-helia.browser.d.ts.map +1 -0
- package/dist/src/fixtures/create-helia.browser.js +56 -0
- package/dist/src/fixtures/create-helia.browser.js.map +1 -0
- package/dist/src/fixtures/create-helia.d.ts +6 -0
- package/dist/src/fixtures/create-helia.d.ts.map +1 -0
- package/dist/src/fixtures/create-helia.js +46 -0
- package/dist/src/fixtures/create-helia.js.map +1 -0
- package/dist/src/fixtures/create-kubo.browser.d.ts +3 -0
- package/dist/src/fixtures/create-kubo.browser.d.ts.map +1 -0
- package/dist/src/fixtures/create-kubo.browser.js +30 -0
- package/dist/src/fixtures/create-kubo.browser.js.map +1 -0
- package/dist/src/fixtures/create-kubo.d.ts +3 -0
- package/dist/src/fixtures/create-kubo.d.ts.map +1 -0
- package/dist/src/fixtures/create-kubo.js +32 -0
- package/dist/src/fixtures/create-kubo.js.map +1 -0
- package/dist/src/fixtures/create-peer-ids.d.ts +14 -0
- package/dist/src/fixtures/create-peer-ids.d.ts.map +1 -0
- package/dist/src/fixtures/create-peer-ids.js +37 -0
- package/dist/src/fixtures/create-peer-ids.js.map +1 -0
- package/dist/src/fixtures/key-types.d.ts +3 -0
- package/dist/src/fixtures/key-types.d.ts.map +1 -0
- package/dist/src/fixtures/key-types.js +6 -0
- package/dist/src/fixtures/key-types.js.map +1 -0
- package/dist/src/fixtures/memory-car.d.ts +7 -0
- package/dist/src/fixtures/memory-car.d.ts.map +1 -0
- package/dist/src/fixtures/memory-car.js +26 -0
- package/dist/src/fixtures/memory-car.js.map +1 -0
- package/dist/src/fixtures/wait-for.d.ts +7 -0
- package/dist/src/fixtures/wait-for.d.ts.map +1 -0
- package/dist/src/fixtures/wait-for.js +17 -0
- package/dist/src/fixtures/wait-for.js.map +1 -0
- package/dist/src/helia-blockstore.spec.d.ts +2 -0
- package/dist/src/helia-blockstore.spec.d.ts.map +1 -0
- package/dist/src/helia-blockstore.spec.js +48 -0
- package/dist/src/helia-blockstore.spec.js.map +1 -0
- package/dist/src/helia-hashes.spec.d.ts +2 -0
- package/dist/src/helia-hashes.spec.d.ts.map +1 -0
- package/dist/src/helia-hashes.spec.js +50 -0
- package/dist/src/helia-hashes.spec.js.map +1 -0
- package/dist/src/helia-pins.spec.d.ts +2 -0
- package/dist/src/helia-pins.spec.d.ts.map +1 -0
- package/dist/src/helia-pins.spec.js +48 -0
- package/dist/src/helia-pins.spec.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/ipns-http.spec.d.ts +2 -0
- package/dist/src/ipns-http.spec.d.ts.map +1 -0
- package/dist/src/ipns-http.spec.js +55 -0
- package/dist/src/ipns-http.spec.js.map +1 -0
- package/dist/src/ipns-pubsub.spec.d.ts +2 -0
- package/dist/src/ipns-pubsub.spec.d.ts.map +1 -0
- package/dist/src/ipns-pubsub.spec.js +151 -0
- package/dist/src/ipns-pubsub.spec.js.map +1 -0
- package/dist/src/ipns.spec.d.ts +2 -0
- package/dist/src/ipns.spec.d.ts.map +1 -0
- package/dist/src/ipns.spec.js +146 -0
- package/dist/src/ipns.spec.js.map +1 -0
- package/dist/src/json.spec.d.ts +2 -0
- package/dist/src/json.spec.d.ts.map +1 -0
- package/dist/src/json.spec.js +49 -0
- package/dist/src/json.spec.js.map +1 -0
- package/dist/src/mfs.spec.d.ts +2 -0
- package/dist/src/mfs.spec.d.ts.map +1 -0
- package/dist/src/mfs.spec.js +85 -0
- package/dist/src/mfs.spec.js.map +1 -0
- package/dist/src/strings.spec.d.ts +2 -0
- package/dist/src/strings.spec.d.ts.map +1 -0
- package/dist/src/strings.spec.js +51 -0
- package/dist/src/strings.spec.js.map +1 -0
- package/dist/src/unixfs-bitswap.spec.d.ts +2 -0
- package/dist/src/unixfs-bitswap.spec.d.ts.map +1 -0
- package/dist/src/unixfs-bitswap.spec.js +65 -0
- package/dist/src/unixfs-bitswap.spec.js.map +1 -0
- package/dist/src/unixfs-files.spec.d.ts +2 -0
- package/dist/src/unixfs-files.spec.d.ts.map +1 -0
- package/dist/src/unixfs-files.spec.js +69 -0
- package/dist/src/unixfs-files.spec.js.map +1 -0
- package/package.json +33 -20
- package/src/bin.ts +25 -0
- package/src/car.spec.ts +102 -0
- package/src/dag-cbor.spec.ts +65 -0
- package/src/dag-json.spec.ts +65 -0
- package/src/fixtures/connect.ts +19 -0
- package/src/fixtures/create-helia-http.ts +8 -0
- package/src/fixtures/create-helia.browser.ts +68 -0
- package/src/fixtures/create-helia.ts +55 -0
- package/src/fixtures/create-kubo.browser.ts +30 -0
- package/src/fixtures/create-kubo.ts +32 -0
- package/src/fixtures/create-peer-ids.ts +46 -0
- package/src/fixtures/key-types.ts +7 -0
- package/src/fixtures/memory-car.ts +33 -0
- package/src/fixtures/wait-for.ts +26 -0
- package/src/helia-blockstore.spec.ts +59 -0
- package/src/helia-hashes.spec.ts +61 -0
- package/src/helia-pins.spec.ts +64 -0
- package/src/index.ts +13 -0
- package/src/ipns-http.spec.ts +68 -0
- package/src/ipns-pubsub.spec.ts +187 -0
- package/src/ipns.spec.ts +183 -0
- package/src/json.spec.ts +65 -0
- package/src/mfs.spec.ts +105 -0
- package/src/strings.spec.ts +67 -0
- package/src/unixfs-bitswap.spec.ts +86 -0
- package/src/unixfs-files.spec.ts +89 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helia/interop",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-e554493",
|
|
4
4
|
"description": "Interop tests for Helia",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/ipfs/helia/tree/main/packages/interop#readme",
|
|
@@ -11,16 +11,24 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ipfs/helia/issues"
|
|
13
13
|
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public",
|
|
16
|
+
"provenance": true
|
|
17
|
+
},
|
|
14
18
|
"keywords": [
|
|
15
19
|
"IPFS"
|
|
16
20
|
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"helia-interop": "./dist/src/bin.js"
|
|
23
|
+
},
|
|
17
24
|
"type": "module",
|
|
18
25
|
"types": "./dist/src/index.d.ts",
|
|
19
26
|
"files": [
|
|
20
27
|
"src",
|
|
21
28
|
"dist",
|
|
22
29
|
"!dist/test",
|
|
23
|
-
"!**/*.tsbuildinfo"
|
|
30
|
+
"!**/*.tsbuildinfo",
|
|
31
|
+
".aegir.js"
|
|
24
32
|
],
|
|
25
33
|
"exports": {
|
|
26
34
|
".": {
|
|
@@ -48,28 +56,31 @@
|
|
|
48
56
|
"test:node": "aegir test -t node --cov",
|
|
49
57
|
"test:electron-main": "aegir test -t electron-main"
|
|
50
58
|
},
|
|
51
|
-
"
|
|
52
|
-
"@
|
|
53
|
-
"@helia/
|
|
54
|
-
"@helia/
|
|
55
|
-
"@helia/dag-
|
|
56
|
-
"@helia/
|
|
57
|
-
"@helia/
|
|
58
|
-
"@helia/
|
|
59
|
-
"@helia/
|
|
60
|
-
"@helia/
|
|
61
|
-
"@helia/
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@chainsafe/libp2p-gossipsub": "^11.1.0",
|
|
61
|
+
"@helia/block-brokers": "2.0.0-e554493",
|
|
62
|
+
"@helia/car": "3.0.0-e554493",
|
|
63
|
+
"@helia/dag-cbor": "3.0.0-e554493",
|
|
64
|
+
"@helia/dag-json": "3.0.0-e554493",
|
|
65
|
+
"@helia/http": "1.0.0-e554493",
|
|
66
|
+
"@helia/interface": "4.0.0-e554493",
|
|
67
|
+
"@helia/ipns": "5.0.0-e554493",
|
|
68
|
+
"@helia/json": "3.0.0-e554493",
|
|
69
|
+
"@helia/mfs": "3.0.0-e554493",
|
|
70
|
+
"@helia/routers": "1.0.0-e554493",
|
|
71
|
+
"@helia/strings": "3.0.0-e554493",
|
|
72
|
+
"@helia/unixfs": "3.0.0-e554493",
|
|
62
73
|
"@ipld/car": "^5.2.5",
|
|
63
74
|
"@ipld/dag-cbor": "^9.0.7",
|
|
64
75
|
"@libp2p/interface": "^1.1.1",
|
|
65
76
|
"@libp2p/kad-dht": "^12.0.2",
|
|
66
|
-
"@libp2p/keychain": "^4.0.
|
|
67
|
-
"@libp2p/peer-id": "^4.0.
|
|
77
|
+
"@libp2p/keychain": "^4.0.7",
|
|
78
|
+
"@libp2p/peer-id": "^4.0.5",
|
|
68
79
|
"@libp2p/peer-id-factory": "^4.0.3",
|
|
69
|
-
"@libp2p/websockets": "^8.0.
|
|
80
|
+
"@libp2p/websockets": "^8.0.10",
|
|
70
81
|
"@multiformats/sha3": "^3.0.0",
|
|
71
82
|
"aegir": "^42.1.0",
|
|
72
|
-
"helia": "
|
|
83
|
+
"helia": "4.0.0-e554493",
|
|
73
84
|
"ipfs-core-types": "^0.14.1",
|
|
74
85
|
"ipfs-unixfs-importer": "^15.2.3",
|
|
75
86
|
"ipfsd-ctl": "^13.0.0",
|
|
@@ -78,16 +89,18 @@
|
|
|
78
89
|
"it-last": "^3.0.4",
|
|
79
90
|
"it-map": "^3.0.5",
|
|
80
91
|
"it-to-buffer": "^4.0.2",
|
|
81
|
-
"kubo": "^0.
|
|
92
|
+
"kubo": "^0.26.0",
|
|
82
93
|
"kubo-rpc-client": "^3.0.1",
|
|
94
|
+
"libp2p": "^1.2.0",
|
|
83
95
|
"multiformats": "^13.0.0",
|
|
84
96
|
"p-defer": "^4.0.0",
|
|
85
97
|
"uint8arrays": "^5.0.1",
|
|
86
98
|
"wherearewe": "^2.0.1"
|
|
87
99
|
},
|
|
88
100
|
"browser": {
|
|
89
|
-
"./dist/
|
|
90
|
-
"./dist/
|
|
101
|
+
"./dist/src/fixtures/create-helia.js": "./dist/src/fixtures/create-helia.browser.js",
|
|
102
|
+
"./dist/src/fixtures/create-kubo.js": "./dist/src/fixtures/create-kubo.browser.js",
|
|
103
|
+
"./dist/src/bin.js": "./dist/src/index.js",
|
|
91
104
|
"kubo": false
|
|
92
105
|
}
|
|
93
106
|
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
|
|
4
|
+
import { spawn } from 'node:child_process'
|
|
5
|
+
import { dirname, resolve } from 'path'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
|
|
8
|
+
// aegir should be run from `node_modules/@helia/interop`
|
|
9
|
+
const cwd = resolve(dirname(fileURLToPath(import.meta.url)), '../../')
|
|
10
|
+
|
|
11
|
+
const test = spawn('npx', ['aegir', 'test'], {
|
|
12
|
+
cwd
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test.stdout.on('data', (data) => {
|
|
16
|
+
process.stdout.write(data)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test.stderr.on('data', (data) => {
|
|
20
|
+
process.stderr.write(data)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test.on('close', (code) => {
|
|
24
|
+
process.exit(code ?? 0)
|
|
25
|
+
})
|
package/src/car.spec.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
import { car } from '@helia/car'
|
|
4
|
+
import { type UnixFS, unixfs } from '@helia/unixfs'
|
|
5
|
+
import { CarReader } from '@ipld/car'
|
|
6
|
+
import { expect } from 'aegir/chai'
|
|
7
|
+
import drain from 'it-drain'
|
|
8
|
+
import toBuffer from 'it-to-buffer'
|
|
9
|
+
import { CID } from 'multiformats/cid'
|
|
10
|
+
import { createHeliaNode } from './fixtures/create-helia.js'
|
|
11
|
+
import { createKuboNode } from './fixtures/create-kubo.js'
|
|
12
|
+
import { memoryCarWriter } from './fixtures/memory-car.js'
|
|
13
|
+
import type { Car } from '@helia/car'
|
|
14
|
+
import type { HeliaLibp2p } from 'helia'
|
|
15
|
+
import type { FileCandidate } from 'ipfs-unixfs-importer'
|
|
16
|
+
import type { Controller } from 'ipfsd-ctl'
|
|
17
|
+
|
|
18
|
+
describe('@helia/car', () => {
|
|
19
|
+
let helia: HeliaLibp2p
|
|
20
|
+
let c: Car
|
|
21
|
+
let u: UnixFS
|
|
22
|
+
let kubo: Controller
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
helia = await createHeliaNode()
|
|
26
|
+
c = car(helia)
|
|
27
|
+
u = unixfs(helia)
|
|
28
|
+
kubo = await createKuboNode()
|
|
29
|
+
|
|
30
|
+
// connect helia to kubo
|
|
31
|
+
await helia.libp2p.dial(kubo.peer.addresses)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
afterEach(async () => {
|
|
35
|
+
if (helia != null) {
|
|
36
|
+
await helia.stop()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (kubo != null) {
|
|
40
|
+
await kubo.stop()
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should export a car from Helia, import and read the contents from kubo', async () => {
|
|
45
|
+
const chunkSize = 1024 * 1024
|
|
46
|
+
const size = chunkSize * 10
|
|
47
|
+
const input: Uint8Array[] = []
|
|
48
|
+
|
|
49
|
+
const candidate: FileCandidate = {
|
|
50
|
+
content: (async function * () {
|
|
51
|
+
for (let i = 0; i < size; i += chunkSize) {
|
|
52
|
+
const buf = new Uint8Array(chunkSize)
|
|
53
|
+
input.push(buf)
|
|
54
|
+
|
|
55
|
+
yield buf
|
|
56
|
+
}
|
|
57
|
+
}())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const cid = await u.addFile(candidate)
|
|
61
|
+
const writer = memoryCarWriter(cid)
|
|
62
|
+
await c.export(cid, writer)
|
|
63
|
+
|
|
64
|
+
const buf = await writer.bytes()
|
|
65
|
+
|
|
66
|
+
await drain(kubo.api.dag.import([buf]))
|
|
67
|
+
|
|
68
|
+
const output: Uint8Array[] = []
|
|
69
|
+
|
|
70
|
+
for await (const b of kubo.api.cat(cid)) {
|
|
71
|
+
output.push(b)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
expect(toBuffer(output)).to.equalBytes(toBuffer(input))
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should export a car from kubo, import and read the contents from Helia', async () => {
|
|
78
|
+
const chunkSize = 1024 * 1024
|
|
79
|
+
const size = chunkSize * 10
|
|
80
|
+
const input: Uint8Array[] = []
|
|
81
|
+
|
|
82
|
+
const candidate: FileCandidate = {
|
|
83
|
+
content: (async function * () {
|
|
84
|
+
for (let i = 0; i < size; i += chunkSize) {
|
|
85
|
+
const buf = new Uint8Array(chunkSize)
|
|
86
|
+
input.push(buf)
|
|
87
|
+
|
|
88
|
+
yield buf
|
|
89
|
+
}
|
|
90
|
+
}())
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const { cid } = await kubo.api.add(candidate.content)
|
|
94
|
+
const bytes = await toBuffer(kubo.api.dag.export(cid))
|
|
95
|
+
|
|
96
|
+
const reader = await CarReader.fromBytes(bytes)
|
|
97
|
+
|
|
98
|
+
await c.import(reader)
|
|
99
|
+
|
|
100
|
+
expect(await toBuffer(u.cat(CID.parse(cid.toString())))).to.equalBytes(toBuffer(input))
|
|
101
|
+
})
|
|
102
|
+
})
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
import { dagCbor, type DAGCBOR, type AddOptions } from '@helia/dag-cbor'
|
|
4
|
+
import * as codec from '@ipld/dag-cbor'
|
|
5
|
+
import { expect } from 'aegir/chai'
|
|
6
|
+
import { CID } from 'multiformats/cid'
|
|
7
|
+
import { createHeliaNode } from './fixtures/create-helia.js'
|
|
8
|
+
import { createKuboNode } from './fixtures/create-kubo.js'
|
|
9
|
+
import type { HeliaLibp2p } from 'helia'
|
|
10
|
+
import type { PutOptions as KuboAddOptions } from 'ipfs-core-types/src/block/index.js'
|
|
11
|
+
import type { Controller } from 'ipfsd-ctl'
|
|
12
|
+
|
|
13
|
+
describe('@helia/dag-cbor', () => {
|
|
14
|
+
let helia: HeliaLibp2p
|
|
15
|
+
let d: DAGCBOR
|
|
16
|
+
let kubo: Controller
|
|
17
|
+
|
|
18
|
+
async function expectSameCid (data: () => any, heliaOpts: Partial<AddOptions> = {}, kuboOpts: KuboAddOptions = {}): Promise<void> {
|
|
19
|
+
const heliaCid = await d.add(data(), heliaOpts)
|
|
20
|
+
const kuboCid = await kubo.api.dag.put(data(), kuboOpts)
|
|
21
|
+
|
|
22
|
+
expect(heliaCid.toString()).to.equal(kuboCid.toString())
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach(async () => {
|
|
26
|
+
helia = await createHeliaNode()
|
|
27
|
+
d = dagCbor(helia)
|
|
28
|
+
kubo = await createKuboNode()
|
|
29
|
+
|
|
30
|
+
await helia.libp2p.dial((await (kubo.api.id())).addresses)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(async () => {
|
|
34
|
+
if (helia != null) {
|
|
35
|
+
await helia.stop()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (kubo != null) {
|
|
39
|
+
await kubo.stop()
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should create the same CID for a string', async () => {
|
|
44
|
+
const candidate = (): any => ({ hello: 'world' })
|
|
45
|
+
|
|
46
|
+
await expectSameCid(candidate)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should add to helia and fetch from kubo', async () => {
|
|
50
|
+
const input = { hello: 'world' }
|
|
51
|
+
const cid = await d.add(input)
|
|
52
|
+
const block = await kubo.api.block.get(cid)
|
|
53
|
+
const output = codec.decode(block)
|
|
54
|
+
|
|
55
|
+
expect(output).to.deep.equal(input)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should add to kubo and fetch from helia', async () => {
|
|
59
|
+
const input = { hello: 'world' }
|
|
60
|
+
const cid = await kubo.api.block.put(codec.encode(input))
|
|
61
|
+
const output = await d.get(CID.parse(cid.toString()))
|
|
62
|
+
|
|
63
|
+
expect(output).to.deep.equal(input)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
import { dagJson, type DAGJSON, type AddOptions } from '@helia/dag-json'
|
|
4
|
+
import { expect } from 'aegir/chai'
|
|
5
|
+
import { CID } from 'multiformats/cid'
|
|
6
|
+
import * as codec from 'multiformats/codecs/json'
|
|
7
|
+
import { createHeliaNode } from './fixtures/create-helia.js'
|
|
8
|
+
import { createKuboNode } from './fixtures/create-kubo.js'
|
|
9
|
+
import type { HeliaLibp2p } from 'helia'
|
|
10
|
+
import type { PutOptions as KuboAddOptions } from 'ipfs-core-types/src/block/index.js'
|
|
11
|
+
import type { Controller } from 'ipfsd-ctl'
|
|
12
|
+
|
|
13
|
+
describe('@helia/dag-json', () => {
|
|
14
|
+
let helia: HeliaLibp2p
|
|
15
|
+
let d: DAGJSON
|
|
16
|
+
let kubo: Controller
|
|
17
|
+
|
|
18
|
+
async function expectSameCid (data: () => any, heliaOpts: Partial<AddOptions> = {}, kuboOpts: KuboAddOptions = { format: 'dag-json' }): Promise<void> {
|
|
19
|
+
const heliaCid = await d.add(data(), heliaOpts)
|
|
20
|
+
const kuboCid = await kubo.api.block.put(codec.encode(data()), kuboOpts)
|
|
21
|
+
|
|
22
|
+
expect(heliaCid.toString()).to.equal(kuboCid.toString())
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach(async () => {
|
|
26
|
+
helia = await createHeliaNode()
|
|
27
|
+
d = dagJson(helia)
|
|
28
|
+
kubo = await createKuboNode()
|
|
29
|
+
|
|
30
|
+
await helia.libp2p.dial((await (kubo.api.id())).addresses)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(async () => {
|
|
34
|
+
if (helia != null) {
|
|
35
|
+
await helia.stop()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (kubo != null) {
|
|
39
|
+
await kubo.stop()
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should create the same CID for a string', async () => {
|
|
44
|
+
const candidate = (): any => ({ hello: 'world' })
|
|
45
|
+
|
|
46
|
+
await expectSameCid(candidate)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should add to helia and fetch from kubo', async () => {
|
|
50
|
+
const input = { hello: 'world' }
|
|
51
|
+
const cid = await d.add(input)
|
|
52
|
+
const block = await kubo.api.block.get(cid)
|
|
53
|
+
const output = codec.decode(block)
|
|
54
|
+
|
|
55
|
+
expect(output).to.deep.equal(input)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should add to kubo and fetch from helia', async () => {
|
|
59
|
+
const input = { hello: 'world' }
|
|
60
|
+
const cid = await kubo.api.block.put(codec.encode(input))
|
|
61
|
+
const output = await d.get(CID.parse(cid.toString()))
|
|
62
|
+
|
|
63
|
+
expect(output).to.deep.equal(input)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { expect } from 'aegir/chai'
|
|
2
|
+
import type { HeliaLibp2p } from 'helia'
|
|
3
|
+
import type { Controller } from 'ipfsd-ctl'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Connect the two nodes by dialing a protocol stream
|
|
7
|
+
*/
|
|
8
|
+
export async function connect (helia: HeliaLibp2p<any>, kubo: Controller, protocol: string): Promise<void> {
|
|
9
|
+
let connected = false
|
|
10
|
+
for (const addr of kubo.peer.addresses) {
|
|
11
|
+
try {
|
|
12
|
+
await helia.libp2p.dialProtocol(addr, protocol)
|
|
13
|
+
connected = true
|
|
14
|
+
break
|
|
15
|
+
} catch { }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
expect(connected).to.be.true('could not connect Helia to Kubo')
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createHeliaHTTP as createHelia, type HeliaHTTPInit } from '@helia/http'
|
|
2
|
+
import type { Helia } from '@helia/interface'
|
|
3
|
+
|
|
4
|
+
export async function createHeliaHTTP (init: Partial<HeliaHTTPInit> = {}): Promise<Helia> {
|
|
5
|
+
return createHelia({
|
|
6
|
+
...init
|
|
7
|
+
})
|
|
8
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { bitswap } from '@helia/block-brokers'
|
|
2
|
+
import { ipnsValidator, ipnsSelector } from '@helia/ipns'
|
|
3
|
+
import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
|
|
4
|
+
import { webSockets } from '@libp2p/websockets'
|
|
5
|
+
import { all } from '@libp2p/websockets/filters'
|
|
6
|
+
import { sha3512 } from '@multiformats/sha3'
|
|
7
|
+
import { createHelia, libp2pDefaults } from 'helia'
|
|
8
|
+
import type { Libp2p } from '@libp2p/interface'
|
|
9
|
+
import type { DefaultLibp2pServices, HeliaLibp2p } from 'helia'
|
|
10
|
+
import type { Libp2pOptions } from 'libp2p'
|
|
11
|
+
|
|
12
|
+
export async function createHeliaNode (): Promise<HeliaLibp2p<Libp2p<DefaultLibp2pServices>>>
|
|
13
|
+
export async function createHeliaNode <Services extends Record<string, unknown>> (libp2pOptions: Libp2pOptions<Services>): Promise<HeliaLibp2p<Libp2p<Services & DefaultLibp2pServices>>>
|
|
14
|
+
export async function createHeliaNode (libp2pOptions?: Libp2pOptions): Promise<HeliaLibp2p<Libp2p<DefaultLibp2pServices>>> {
|
|
15
|
+
const defaults = libp2pDefaults()
|
|
16
|
+
|
|
17
|
+
// allow dialing insecure WebSockets
|
|
18
|
+
defaults.transports?.pop()
|
|
19
|
+
defaults.transports = [
|
|
20
|
+
...(defaults.transports ?? []),
|
|
21
|
+
webSockets({
|
|
22
|
+
filter: all
|
|
23
|
+
})
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
// allow dialing loopback
|
|
27
|
+
defaults.connectionGater = {
|
|
28
|
+
denyDialMultiaddr: () => false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// use LAN DHT
|
|
32
|
+
defaults.services = {
|
|
33
|
+
...(defaults.services ?? {}),
|
|
34
|
+
...(libp2pOptions?.services ?? {}),
|
|
35
|
+
dht: kadDHT({
|
|
36
|
+
validators: {
|
|
37
|
+
ipns: ipnsValidator
|
|
38
|
+
},
|
|
39
|
+
selectors: {
|
|
40
|
+
ipns: ipnsSelector
|
|
41
|
+
},
|
|
42
|
+
// skips waiting for the initial self-query to find peers
|
|
43
|
+
allowQueryWithZeroPeers: true,
|
|
44
|
+
|
|
45
|
+
protocol: '/ipfs/lan/kad/1.0.0',
|
|
46
|
+
peerInfoMapper: removePublicAddressesMapper,
|
|
47
|
+
clientMode: false
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// remove bootstrappers
|
|
52
|
+
defaults.peerDiscovery = []
|
|
53
|
+
|
|
54
|
+
// remove services that are not used in tests
|
|
55
|
+
delete defaults.services.autoNAT
|
|
56
|
+
delete defaults.services.dcutr
|
|
57
|
+
delete defaults.services.delegatedRouting
|
|
58
|
+
|
|
59
|
+
return createHelia<Libp2p<DefaultLibp2pServices>>({
|
|
60
|
+
blockBrokers: [
|
|
61
|
+
bitswap()
|
|
62
|
+
],
|
|
63
|
+
libp2p: defaults,
|
|
64
|
+
hashers: [
|
|
65
|
+
sha3512
|
|
66
|
+
]
|
|
67
|
+
})
|
|
68
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { bitswap } from '@helia/block-brokers'
|
|
2
|
+
import { ipnsValidator, ipnsSelector } from '@helia/ipns'
|
|
3
|
+
import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
|
|
4
|
+
import { sha3512 } from '@multiformats/sha3'
|
|
5
|
+
import { createHelia, libp2pDefaults } from 'helia'
|
|
6
|
+
import type { Libp2p } from '@libp2p/interface'
|
|
7
|
+
import type { DefaultLibp2pServices, HeliaLibp2p } from 'helia'
|
|
8
|
+
import type { Libp2pOptions } from 'libp2p'
|
|
9
|
+
|
|
10
|
+
export async function createHeliaNode (): Promise<HeliaLibp2p<Libp2p<DefaultLibp2pServices>>>
|
|
11
|
+
export async function createHeliaNode <Services extends Record<string, unknown>> (libp2pOptions: Libp2pOptions<Services>): Promise<HeliaLibp2p<Libp2p<Services & DefaultLibp2pServices>>>
|
|
12
|
+
export async function createHeliaNode (libp2pOptions?: Libp2pOptions): Promise<HeliaLibp2p<Libp2p<DefaultLibp2pServices>>> {
|
|
13
|
+
const defaults = libp2pDefaults()
|
|
14
|
+
defaults.addresses = {
|
|
15
|
+
listen: [
|
|
16
|
+
'/ip4/0.0.0.0/tcp/0'
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
defaults.services = {
|
|
20
|
+
...(defaults.services ?? {}),
|
|
21
|
+
...(libp2pOptions?.services ?? {}),
|
|
22
|
+
dht: kadDHT({
|
|
23
|
+
validators: {
|
|
24
|
+
ipns: ipnsValidator
|
|
25
|
+
},
|
|
26
|
+
selectors: {
|
|
27
|
+
ipns: ipnsSelector
|
|
28
|
+
},
|
|
29
|
+
// skips waiting for the initial self-query to find peers
|
|
30
|
+
allowQueryWithZeroPeers: true,
|
|
31
|
+
|
|
32
|
+
protocol: '/ipfs/lan/kad/1.0.0',
|
|
33
|
+
peerInfoMapper: removePublicAddressesMapper,
|
|
34
|
+
clientMode: false
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// remove bootstrappers, mdns, etc
|
|
39
|
+
defaults.peerDiscovery = []
|
|
40
|
+
|
|
41
|
+
// remove services that are not used in tests
|
|
42
|
+
delete defaults.services.autoNAT
|
|
43
|
+
delete defaults.services.dcutr
|
|
44
|
+
delete defaults.services.delegatedRouting
|
|
45
|
+
|
|
46
|
+
return createHelia<Libp2p<DefaultLibp2pServices>>({
|
|
47
|
+
blockBrokers: [
|
|
48
|
+
bitswap()
|
|
49
|
+
],
|
|
50
|
+
libp2p: defaults,
|
|
51
|
+
hashers: [
|
|
52
|
+
sha3512
|
|
53
|
+
]
|
|
54
|
+
})
|
|
55
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Controller, createController } from 'ipfsd-ctl'
|
|
2
|
+
import * as kuboRpcClient from 'kubo-rpc-client'
|
|
3
|
+
|
|
4
|
+
export async function createKuboNode (): Promise<Controller> {
|
|
5
|
+
return createController({
|
|
6
|
+
kuboRpcModule: kuboRpcClient,
|
|
7
|
+
test: true,
|
|
8
|
+
endpoint: process.env.IPFSD_SERVER,
|
|
9
|
+
ipfsOptions: {
|
|
10
|
+
config: {
|
|
11
|
+
Addresses: {
|
|
12
|
+
Swarm: [
|
|
13
|
+
'/ip4/0.0.0.0/tcp/0',
|
|
14
|
+
'/ip4/0.0.0.0/tcp/0/ws'
|
|
15
|
+
],
|
|
16
|
+
Gateway: '/ip4/127.0.0.1/tcp/8180'
|
|
17
|
+
},
|
|
18
|
+
Gateway: {
|
|
19
|
+
NoFetch: true,
|
|
20
|
+
ExposeRoutingAPI: true,
|
|
21
|
+
HTTPHeaders: {
|
|
22
|
+
'Access-Control-Allow-Origin': ['*'],
|
|
23
|
+
'Access-Control-Allow-Methods': ['GET', 'POST', 'PUT', 'OPTIONS']
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
args: ['--enable-pubsub-experiment', '--enable-namesys-pubsub']
|
|
29
|
+
})
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment,@typescript-eslint/prefer-ts-expect-error */
|
|
2
|
+
import { createController, type Controller } from 'ipfsd-ctl'
|
|
3
|
+
import { path as kuboPath } from 'kubo'
|
|
4
|
+
import * as kuboRpcClient from 'kubo-rpc-client'
|
|
5
|
+
|
|
6
|
+
export async function createKuboNode (): Promise<Controller> {
|
|
7
|
+
return createController({
|
|
8
|
+
kuboRpcModule: kuboRpcClient,
|
|
9
|
+
ipfsBin: kuboPath(),
|
|
10
|
+
test: true,
|
|
11
|
+
ipfsOptions: {
|
|
12
|
+
config: {
|
|
13
|
+
Addresses: {
|
|
14
|
+
Swarm: [
|
|
15
|
+
'/ip4/0.0.0.0/tcp/4001',
|
|
16
|
+
'/ip4/0.0.0.0/tcp/4002/ws'
|
|
17
|
+
],
|
|
18
|
+
Gateway: '/ip4/127.0.0.1/tcp/8180'
|
|
19
|
+
},
|
|
20
|
+
Gateway: {
|
|
21
|
+
NoFetch: true,
|
|
22
|
+
ExposeRoutingAPI: true,
|
|
23
|
+
HTTPHeaders: {
|
|
24
|
+
'Access-Control-Allow-Origin': ['*'],
|
|
25
|
+
'Access-Control-Allow-Methods': ['GET', 'POST', 'PUT', 'OPTIONS']
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
args: ['--enable-pubsub-experiment', '--enable-namesys-pubsub']
|
|
31
|
+
})
|
|
32
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import all from 'it-all'
|
|
2
|
+
import map from 'it-map'
|
|
3
|
+
import { sha256 } from 'multiformats/hashes/sha2'
|
|
4
|
+
import { compare as uint8ArrayCompare } from 'uint8arrays/compare'
|
|
5
|
+
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
6
|
+
import type { PeerId } from '@libp2p/interface'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sort peers by distance to the KadID of the passed buffer
|
|
10
|
+
*/
|
|
11
|
+
export async function sortClosestPeers (buf: Uint8Array, peers: PeerId[]): Promise<PeerId[]> {
|
|
12
|
+
const kadId = await convertBuffer(buf)
|
|
13
|
+
|
|
14
|
+
const distances = await all(
|
|
15
|
+
map(peers, async (peer) => {
|
|
16
|
+
const id = await convertPeerId(peer)
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
peer,
|
|
20
|
+
distance: uint8ArrayXor(id, kadId)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
return distances
|
|
26
|
+
.sort((a, b) => {
|
|
27
|
+
return uint8ArrayCompare(a.distance, b.distance)
|
|
28
|
+
})
|
|
29
|
+
.map((d) => d.peer)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Creates a DHT ID by hashing a Peer ID
|
|
34
|
+
*/
|
|
35
|
+
export async function convertPeerId (peerId: PeerId): Promise<Uint8Array> {
|
|
36
|
+
return convertBuffer(peerId.toBytes())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates a DHT ID by hashing a given Uint8Array
|
|
41
|
+
*/
|
|
42
|
+
export async function convertBuffer (buf: Uint8Array): Promise<Uint8Array> {
|
|
43
|
+
const multihash = await sha256.digest(buf)
|
|
44
|
+
|
|
45
|
+
return multihash.digest
|
|
46
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CarWriter } from '@ipld/car'
|
|
2
|
+
import toBuffer from 'it-to-buffer'
|
|
3
|
+
import defer from 'p-defer'
|
|
4
|
+
import type { CID } from 'multiformats/cid'
|
|
5
|
+
|
|
6
|
+
export interface MemoryCar extends Pick<CarWriter, 'put' | 'close'> {
|
|
7
|
+
bytes(): Promise<Uint8Array>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function memoryCarWriter (root: CID | CID[]): MemoryCar {
|
|
11
|
+
const deferred = defer<Uint8Array>()
|
|
12
|
+
const { writer, out } = CarWriter.create(Array.isArray(root) ? root : [root])
|
|
13
|
+
|
|
14
|
+
Promise.resolve()
|
|
15
|
+
.then(async () => {
|
|
16
|
+
deferred.resolve(await toBuffer(out))
|
|
17
|
+
})
|
|
18
|
+
.catch(err => {
|
|
19
|
+
deferred.reject(err)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
async put (block: { cid: CID, bytes: Uint8Array }): Promise<void> {
|
|
24
|
+
await writer.put(block)
|
|
25
|
+
},
|
|
26
|
+
async close (): Promise<void> {
|
|
27
|
+
await writer.close()
|
|
28
|
+
},
|
|
29
|
+
async bytes (): Promise<Uint8Array> {
|
|
30
|
+
return deferred.promise
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|