helia 0.0.0-270bb98
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 +4 -0
- package/README.md +59 -0
- package/dist/index.min.js +3 -0
- package/dist/src/helia.d.ts +19 -0
- package/dist/src/helia.d.ts.map +1 -0
- package/dist/src/helia.js +88 -0
- package/dist/src/helia.js.map +1 -0
- package/dist/src/index.d.ts +77 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/pins.d.ts +17 -0
- package/dist/src/pins.d.ts.map +1 -0
- package/dist/src/pins.js +181 -0
- package/dist/src/pins.js.map +1 -0
- package/dist/src/storage.d.ts +66 -0
- package/dist/src/storage.d.ts.map +1 -0
- package/dist/src/storage.js +174 -0
- package/dist/src/storage.js.map +1 -0
- package/dist/src/utils/dag-walkers.d.ts +22 -0
- package/dist/src/utils/dag-walkers.d.ts.map +1 -0
- package/dist/src/utils/dag-walkers.js +145 -0
- package/dist/src/utils/dag-walkers.js.map +1 -0
- package/dist/src/utils/datastore-version.d.ts +3 -0
- package/dist/src/utils/datastore-version.d.ts.map +1 -0
- package/dist/src/utils/datastore-version.js +19 -0
- package/dist/src/utils/datastore-version.js.map +1 -0
- package/package.json +176 -0
- package/src/helia.ts +100 -0
- package/src/index.ts +94 -0
- package/src/pins.ts +238 -0
- package/src/storage.ts +209 -0
- package/src/utils/dag-walkers.ts +169 -0
- package/src/utils/datastore-version.ts +23 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* eslint max-depth: ["error", 7] */
|
|
2
|
+
import * as dagPb from '@ipld/dag-pb';
|
|
3
|
+
import * as cborg from 'cborg';
|
|
4
|
+
import { Type, Token } from 'cborg';
|
|
5
|
+
import * as cborgJson from 'cborg/json';
|
|
6
|
+
import * as raw from 'multiformats/codecs/raw';
|
|
7
|
+
import { CID } from 'multiformats';
|
|
8
|
+
import { base64 } from 'multiformats/bases/base64';
|
|
9
|
+
/**
|
|
10
|
+
* Dag walker for dag-pb CIDs
|
|
11
|
+
*/
|
|
12
|
+
export const dagPbWalker = {
|
|
13
|
+
codec: dagPb.code,
|
|
14
|
+
async *walk(block) {
|
|
15
|
+
const node = dagPb.decode(block);
|
|
16
|
+
yield* node.Links.map(l => l.Hash);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Dag walker for raw CIDs
|
|
21
|
+
*/
|
|
22
|
+
export const rawWalker = {
|
|
23
|
+
codec: raw.code,
|
|
24
|
+
async *walk() {
|
|
25
|
+
// no embedded CIDs in a raw block
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
// https://github.com/ipfs/go-ipfs/issues/3570#issuecomment-273931692
|
|
29
|
+
const CID_TAG = 42;
|
|
30
|
+
/**
|
|
31
|
+
* Dag walker for dag-cbor CIDs. Does not actually use dag-cbor since
|
|
32
|
+
* all we are interested in is extracting the the CIDs from the block
|
|
33
|
+
* so we can just use cborg for that.
|
|
34
|
+
*/
|
|
35
|
+
export const cborWalker = {
|
|
36
|
+
codec: 0x71,
|
|
37
|
+
async *walk(block) {
|
|
38
|
+
const cids = [];
|
|
39
|
+
const tags = [];
|
|
40
|
+
tags[CID_TAG] = (bytes) => {
|
|
41
|
+
if (bytes[0] !== 0) {
|
|
42
|
+
throw new Error('Invalid CID for CBOR tag 42; expected leading 0x00');
|
|
43
|
+
}
|
|
44
|
+
const cid = CID.decode(bytes.subarray(1)); // ignore leading 0x00
|
|
45
|
+
cids.push(cid);
|
|
46
|
+
return cid;
|
|
47
|
+
};
|
|
48
|
+
cborg.decode(block, {
|
|
49
|
+
tags
|
|
50
|
+
});
|
|
51
|
+
yield* cids;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Borrowed from @ipld/dag-json
|
|
56
|
+
*/
|
|
57
|
+
class DagJsonTokenizer extends cborgJson.Tokenizer {
|
|
58
|
+
constructor(data, options) {
|
|
59
|
+
super(data, options);
|
|
60
|
+
this.tokenBuffer = [];
|
|
61
|
+
}
|
|
62
|
+
done() {
|
|
63
|
+
return this.tokenBuffer.length === 0 && super.done();
|
|
64
|
+
}
|
|
65
|
+
_next() {
|
|
66
|
+
if (this.tokenBuffer.length > 0) {
|
|
67
|
+
// @ts-expect-error https://github.com/Microsoft/TypeScript/issues/30406
|
|
68
|
+
return this.tokenBuffer.pop();
|
|
69
|
+
}
|
|
70
|
+
return super.next();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Implements rules outlined in https://github.com/ipld/specs/pull/356
|
|
74
|
+
*/
|
|
75
|
+
next() {
|
|
76
|
+
const token = this._next();
|
|
77
|
+
if (token.type === Type.map) {
|
|
78
|
+
const keyToken = this._next();
|
|
79
|
+
if (keyToken.type === Type.string && keyToken.value === '/') {
|
|
80
|
+
const valueToken = this._next();
|
|
81
|
+
if (valueToken.type === Type.string) { // *must* be a CID
|
|
82
|
+
const breakToken = this._next(); // swallow the end-of-map token
|
|
83
|
+
if (breakToken.type !== Type.break) {
|
|
84
|
+
throw new Error('Invalid encoded CID form');
|
|
85
|
+
}
|
|
86
|
+
this.tokenBuffer.push(valueToken); // CID.parse will pick this up after our tag token
|
|
87
|
+
return new Token(Type.tag, 42, 0);
|
|
88
|
+
}
|
|
89
|
+
if (valueToken.type === Type.map) {
|
|
90
|
+
const innerKeyToken = this._next();
|
|
91
|
+
if (innerKeyToken.type === Type.string && innerKeyToken.value === 'bytes') {
|
|
92
|
+
const innerValueToken = this._next();
|
|
93
|
+
if (innerValueToken.type === Type.string) { // *must* be Bytes
|
|
94
|
+
for (let i = 0; i < 2; i++) {
|
|
95
|
+
const breakToken = this._next(); // swallow two end-of-map tokens
|
|
96
|
+
if (breakToken.type !== Type.break) {
|
|
97
|
+
throw new Error('Invalid encoded Bytes form');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const bytes = base64.decode(`m${innerValueToken.value}`);
|
|
101
|
+
return new Token(Type.bytes, bytes, innerValueToken.value.length);
|
|
102
|
+
}
|
|
103
|
+
this.tokenBuffer.push(innerValueToken); // bail
|
|
104
|
+
}
|
|
105
|
+
this.tokenBuffer.push(innerKeyToken); // bail
|
|
106
|
+
}
|
|
107
|
+
this.tokenBuffer.push(valueToken); // bail
|
|
108
|
+
}
|
|
109
|
+
this.tokenBuffer.push(keyToken); // bail
|
|
110
|
+
}
|
|
111
|
+
return token;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Dag walker for dag-json CIDs. Does not actually use dag-json since
|
|
116
|
+
* all we are interested in is extracting the the CIDs from the block
|
|
117
|
+
* so we can just use cborg/json for that.
|
|
118
|
+
*/
|
|
119
|
+
export const jsonWalker = {
|
|
120
|
+
codec: 0x0129,
|
|
121
|
+
async *walk(block) {
|
|
122
|
+
const cids = [];
|
|
123
|
+
const tags = [];
|
|
124
|
+
tags[CID_TAG] = (string) => {
|
|
125
|
+
const cid = CID.parse(string);
|
|
126
|
+
cids.push(cid);
|
|
127
|
+
return cid;
|
|
128
|
+
};
|
|
129
|
+
cborgJson.decode(block, {
|
|
130
|
+
tags,
|
|
131
|
+
tokenizer: new DagJsonTokenizer(block, {
|
|
132
|
+
tags,
|
|
133
|
+
allowIndefinite: true,
|
|
134
|
+
allowUndefined: true,
|
|
135
|
+
allowNaN: true,
|
|
136
|
+
allowInfinity: true,
|
|
137
|
+
allowBigInt: true,
|
|
138
|
+
strict: false,
|
|
139
|
+
rejectDuplicateMapKeys: false
|
|
140
|
+
})
|
|
141
|
+
});
|
|
142
|
+
yield* cids;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=dag-walkers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dag-walkers.js","sourceRoot":"","sources":["../../../src/utils/dag-walkers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datastore-version.d.ts","sourceRoot":"","sources":["../../../src/utils/datastore-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAO,MAAM,qBAAqB,CAAA;AAOpD,wBAAsB,+BAA+B,CAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAe1F"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Key } from 'interface-datastore';
|
|
2
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
3
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
|
4
|
+
const DS_VERSION_KEY = new Key('/version');
|
|
5
|
+
const CURRENT_VERSION = 1;
|
|
6
|
+
export async function assertDatastoreVersionIsCurrent(datastore) {
|
|
7
|
+
if (!(await datastore.has(DS_VERSION_KEY))) {
|
|
8
|
+
await datastore.put(DS_VERSION_KEY, uint8ArrayFromString(`${CURRENT_VERSION}`));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const buf = await datastore.get(DS_VERSION_KEY);
|
|
12
|
+
const str = uint8ArrayToString(buf);
|
|
13
|
+
const version = parseInt(str, 10);
|
|
14
|
+
if (version !== CURRENT_VERSION) {
|
|
15
|
+
// TODO: write migrations when we break compatibility - for an example, see https://github.com/ipfs/js-ipfs-repo/tree/master/packages/ipfs-repo-migrations
|
|
16
|
+
throw new Error('Unknown datastore version, a datastore migration may be required');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=datastore-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datastore-version.js","sourceRoot":"","sources":["../../../src/utils/datastore-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,GAAG,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAEtE,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAA;AAC1C,MAAM,eAAe,GAAG,CAAC,CAAA;AAEzB,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAE,SAAoB;IACzE,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,EAAE;QAC1C,MAAM,SAAS,CAAC,GAAG,CAAC,cAAc,EAAE,oBAAoB,CAAC,GAAG,eAAe,EAAE,CAAC,CAAC,CAAA;QAE/E,OAAM;KACP;IAED,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAC/C,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAA;IACnC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAEjC,IAAI,OAAO,KAAK,eAAe,EAAE;QAC/B,0JAA0J;QAC1J,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAA;KACpF;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "helia",
|
|
3
|
+
"version": "0.0.0-270bb98",
|
|
4
|
+
"description": "An implementation of IPFS in JavaScript",
|
|
5
|
+
"license": "Apache-2.0 OR MIT",
|
|
6
|
+
"homepage": "https://github.com/ipfs/helia/tree/master/packages/helia#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/ipfs/helia.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/ipfs/helia/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"IPFS"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=16.0.0",
|
|
19
|
+
"npm": ">=7.0.0"
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"types": "./dist/src/index.d.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"src",
|
|
25
|
+
"dist",
|
|
26
|
+
"!dist/test",
|
|
27
|
+
"!**/*.tsbuildinfo"
|
|
28
|
+
],
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/src/index.d.ts",
|
|
32
|
+
"import": "./dist/src/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"eslintConfig": {
|
|
36
|
+
"extends": "ipfs",
|
|
37
|
+
"parserOptions": {
|
|
38
|
+
"sourceType": "module"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"release": {
|
|
42
|
+
"branches": [
|
|
43
|
+
"main"
|
|
44
|
+
],
|
|
45
|
+
"plugins": [
|
|
46
|
+
[
|
|
47
|
+
"@semantic-release/commit-analyzer",
|
|
48
|
+
{
|
|
49
|
+
"preset": "conventionalcommits",
|
|
50
|
+
"releaseRules": [
|
|
51
|
+
{
|
|
52
|
+
"breaking": true,
|
|
53
|
+
"release": "major"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"revert": true,
|
|
57
|
+
"release": "patch"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"type": "feat",
|
|
61
|
+
"release": "minor"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"type": "fix",
|
|
65
|
+
"release": "patch"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "docs",
|
|
69
|
+
"release": "patch"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "test",
|
|
73
|
+
"release": "patch"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"type": "deps",
|
|
77
|
+
"release": "patch"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"scope": "no-release",
|
|
81
|
+
"release": false
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
[
|
|
87
|
+
"@semantic-release/release-notes-generator",
|
|
88
|
+
{
|
|
89
|
+
"preset": "conventionalcommits",
|
|
90
|
+
"presetConfig": {
|
|
91
|
+
"types": [
|
|
92
|
+
{
|
|
93
|
+
"type": "feat",
|
|
94
|
+
"section": "Features"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "fix",
|
|
98
|
+
"section": "Bug Fixes"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "chore",
|
|
102
|
+
"section": "Trivial Changes"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"type": "docs",
|
|
106
|
+
"section": "Documentation"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"type": "deps",
|
|
110
|
+
"section": "Dependencies"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"type": "test",
|
|
114
|
+
"section": "Tests"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"@semantic-release/changelog",
|
|
121
|
+
"@semantic-release/npm",
|
|
122
|
+
"@semantic-release/github",
|
|
123
|
+
"@semantic-release/git"
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"scripts": {
|
|
127
|
+
"clean": "aegir clean",
|
|
128
|
+
"lint": "aegir lint",
|
|
129
|
+
"dep-check": "aegir dep-check",
|
|
130
|
+
"build": "aegir build",
|
|
131
|
+
"test": "aegir test",
|
|
132
|
+
"test:chrome": "aegir test -t browser --cov",
|
|
133
|
+
"test:chrome-webworker": "aegir test -t webworker",
|
|
134
|
+
"test:firefox": "aegir test -t browser -- --browser firefox",
|
|
135
|
+
"test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
|
|
136
|
+
"test:node": "aegir test -t node --cov",
|
|
137
|
+
"test:electron-main": "aegir test -t electron-main",
|
|
138
|
+
"release": "aegir release"
|
|
139
|
+
},
|
|
140
|
+
"dependencies": {
|
|
141
|
+
"@helia/interface": "0.0.0-270bb98",
|
|
142
|
+
"@ipld/dag-pb": "^4.0.2",
|
|
143
|
+
"@libp2p/interface-libp2p": "^1.1.0",
|
|
144
|
+
"@libp2p/interfaces": "^3.3.1",
|
|
145
|
+
"blockstore-core": "^3.0.0",
|
|
146
|
+
"cborg": "^1.10.0",
|
|
147
|
+
"interface-blockstore": "^4.0.1",
|
|
148
|
+
"interface-datastore": "^7.0.3",
|
|
149
|
+
"interface-store": "^3.0.4",
|
|
150
|
+
"ipfs-bitswap": "^16.0.0",
|
|
151
|
+
"it-all": "^2.0.0",
|
|
152
|
+
"it-drain": "^2.0.0",
|
|
153
|
+
"it-filter": "^2.0.0",
|
|
154
|
+
"it-merge": "^2.0.0",
|
|
155
|
+
"it-pushable": "^3.1.2",
|
|
156
|
+
"mortice": "^3.0.1",
|
|
157
|
+
"multiformats": "^11.0.1",
|
|
158
|
+
"p-defer": "^4.0.0",
|
|
159
|
+
"p-queue": "^7.3.4",
|
|
160
|
+
"progress-events": "^1.0.0",
|
|
161
|
+
"uint8arrays": "^4.0.3"
|
|
162
|
+
},
|
|
163
|
+
"devDependencies": {
|
|
164
|
+
"@chainsafe/libp2p-noise": "^11.0.0",
|
|
165
|
+
"@chainsafe/libp2p-yamux": "^3.0.5",
|
|
166
|
+
"@ipld/dag-cbor": "^9.0.0",
|
|
167
|
+
"@ipld/dag-json": "^10.0.1",
|
|
168
|
+
"@libp2p/websockets": "^5.0.3",
|
|
169
|
+
"aegir": "^38.1.0",
|
|
170
|
+
"datastore-core": "^8.0.4",
|
|
171
|
+
"libp2p": "^0.42.2"
|
|
172
|
+
},
|
|
173
|
+
"typedoc": {
|
|
174
|
+
"entryPoint": "./src/index.ts"
|
|
175
|
+
}
|
|
176
|
+
}
|
package/src/helia.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { GCOptions, Helia, InfoResponse } from '@helia/interface'
|
|
2
|
+
import type { Libp2p } from '@libp2p/interface-libp2p'
|
|
3
|
+
import type { Datastore } from 'interface-datastore'
|
|
4
|
+
import { identity } from 'multiformats/hashes/identity'
|
|
5
|
+
import { sha256, sha512 } from 'multiformats/hashes/sha2'
|
|
6
|
+
import type { MultihashHasher } from 'multiformats/hashes/interface'
|
|
7
|
+
import type { HeliaInit } from '.'
|
|
8
|
+
import { Bitswap, createBitswap } from 'ipfs-bitswap'
|
|
9
|
+
import { BlockStorage } from './storage.js'
|
|
10
|
+
import type { Pins } from '@helia/interface/pins'
|
|
11
|
+
import { PinsImpl } from './pins.js'
|
|
12
|
+
import { assertDatastoreVersionIsCurrent } from './utils/datastore-version.js'
|
|
13
|
+
import drain from 'it-drain'
|
|
14
|
+
import { CustomProgressEvent } from 'progress-events'
|
|
15
|
+
|
|
16
|
+
export class HeliaImpl implements Helia {
|
|
17
|
+
public libp2p: Libp2p
|
|
18
|
+
public blockstore: BlockStorage
|
|
19
|
+
public datastore: Datastore
|
|
20
|
+
public pins: Pins
|
|
21
|
+
|
|
22
|
+
#bitswap: Bitswap
|
|
23
|
+
|
|
24
|
+
constructor (init: HeliaInit) {
|
|
25
|
+
const hashers: MultihashHasher[] = [
|
|
26
|
+
sha256,
|
|
27
|
+
sha512,
|
|
28
|
+
identity,
|
|
29
|
+
...(init.hashers ?? [])
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
this.pins = new PinsImpl(init.datastore, init.blockstore, init.dagWalkers ?? [])
|
|
33
|
+
|
|
34
|
+
this.#bitswap = createBitswap(init.libp2p, init.blockstore, {
|
|
35
|
+
hashLoader: {
|
|
36
|
+
getHasher: async (codecOrName: string | number) => {
|
|
37
|
+
const hasher = hashers.find(hasher => {
|
|
38
|
+
return hasher.code === codecOrName || hasher.name === codecOrName
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (hasher != null) {
|
|
42
|
+
return await Promise.resolve(hasher)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new Error(`Could not load hasher for code/name "${codecOrName}"`)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
this.libp2p = init.libp2p
|
|
51
|
+
this.blockstore = new BlockStorage(init.blockstore, this.#bitswap, this.pins)
|
|
52
|
+
this.datastore = init.datastore
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async start (): Promise<void> {
|
|
56
|
+
await assertDatastoreVersionIsCurrent(this.datastore)
|
|
57
|
+
|
|
58
|
+
this.#bitswap.start()
|
|
59
|
+
await this.libp2p.start()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async stop (): Promise<void> {
|
|
63
|
+
this.#bitswap.stop()
|
|
64
|
+
await this.libp2p.stop()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async info (): Promise<InfoResponse> {
|
|
68
|
+
return {
|
|
69
|
+
peerId: this.libp2p.peerId,
|
|
70
|
+
multiaddrs: this.libp2p.getMultiaddrs(),
|
|
71
|
+
agentVersion: this.libp2p.identifyService.host.agentVersion,
|
|
72
|
+
protocolVersion: this.libp2p.identifyService.host.protocolVersion,
|
|
73
|
+
protocols: this.libp2p.getProtocols(),
|
|
74
|
+
status: this.libp2p.isStarted() ? 'running' : 'stopped'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async gc (options: GCOptions = {}): Promise<void> {
|
|
79
|
+
const releaseLock = await this.blockstore.lock.writeLock()
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const helia = this
|
|
83
|
+
const blockstore = this.blockstore.unwrap()
|
|
84
|
+
|
|
85
|
+
await drain(blockstore.deleteMany((async function * () {
|
|
86
|
+
for await (const cid of blockstore.queryKeys({})) {
|
|
87
|
+
if (await helia.pins.isPinned(cid, options)) {
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
yield cid
|
|
92
|
+
|
|
93
|
+
options.onProgress?.(new CustomProgressEvent('helia:gc:deleted', cid))
|
|
94
|
+
}
|
|
95
|
+
}())))
|
|
96
|
+
} finally {
|
|
97
|
+
releaseLock()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* Create a Helia node.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
*
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createLibp2p } from 'libp2p'
|
|
10
|
+
* import { MemoryDatastore } from 'datastore-core'
|
|
11
|
+
* import { MemoryBlockstore } from 'blockstore-core'
|
|
12
|
+
* import { createHelia } from 'helia'
|
|
13
|
+
* import { unixfs } from '@helia/unixfs'
|
|
14
|
+
* import { CID } from 'multiformats/cid'
|
|
15
|
+
*
|
|
16
|
+
* const node = await createHelia({
|
|
17
|
+
* blockstore: new MemoryBlockstore(),
|
|
18
|
+
* datastore: new MemoryDatastore(),
|
|
19
|
+
* libp2p: await createLibp2p({
|
|
20
|
+
* //... libp2p options
|
|
21
|
+
* })
|
|
22
|
+
* })
|
|
23
|
+
* const fs = unixfs(node)
|
|
24
|
+
* fs.cat(CID.parse('bafyFoo'))
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type { Helia } from '@helia/interface'
|
|
29
|
+
import type { Libp2p } from '@libp2p/interface-libp2p'
|
|
30
|
+
import type { Blockstore } from 'interface-blockstore'
|
|
31
|
+
import type { Datastore } from 'interface-datastore'
|
|
32
|
+
import type { CID } from 'multiformats/cid'
|
|
33
|
+
import type { MultihashHasher } from 'multiformats/hashes/interface'
|
|
34
|
+
import { HeliaImpl } from './helia.js'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* DAGWalkers take a block and yield CIDs encoded in that block
|
|
38
|
+
*/
|
|
39
|
+
export interface DAGWalker {
|
|
40
|
+
codec: number
|
|
41
|
+
walk: (block: Uint8Array) => AsyncGenerator<CID, void, undefined>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Options used to create a Helia node.
|
|
46
|
+
*/
|
|
47
|
+
export interface HeliaInit {
|
|
48
|
+
/**
|
|
49
|
+
* A libp2p node is required to perform network operations
|
|
50
|
+
*/
|
|
51
|
+
libp2p: Libp2p
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The blockstore is where blocks are stored
|
|
55
|
+
*/
|
|
56
|
+
blockstore: Blockstore
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The datastore is where data is stored
|
|
60
|
+
*/
|
|
61
|
+
datastore: Datastore
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* By default sha256, sha512 and identity hashes are supported for
|
|
65
|
+
* bitswap operations. To bitswap blocks with CIDs using other hashes
|
|
66
|
+
* pass appropriate MultihashHashers here.
|
|
67
|
+
*/
|
|
68
|
+
hashers?: MultihashHasher[]
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* In order to pin CIDs that correspond to a DAG, it's necessary to know
|
|
72
|
+
* how to traverse that DAG. DAGWalkers take a block and yield any CIDs
|
|
73
|
+
* encoded within that block.
|
|
74
|
+
*/
|
|
75
|
+
dagWalkers?: DAGWalker[]
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Pass `false` to not start the helia node
|
|
79
|
+
*/
|
|
80
|
+
start?: boolean
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create and return a Helia node
|
|
85
|
+
*/
|
|
86
|
+
export async function createHelia (init: HeliaInit): Promise<Helia> {
|
|
87
|
+
const helia = new HeliaImpl(init)
|
|
88
|
+
|
|
89
|
+
if (init.start !== false) {
|
|
90
|
+
await helia.start()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return helia
|
|
94
|
+
}
|