@dxos/hypercore 0.1.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -0
  3. package/dist/src/crypto.d.ts +13 -0
  4. package/dist/src/crypto.d.ts.map +1 -0
  5. package/dist/src/crypto.js +45 -0
  6. package/dist/src/crypto.js.map +1 -0
  7. package/dist/src/defaults.d.ts +18 -0
  8. package/dist/src/defaults.d.ts.map +1 -0
  9. package/dist/src/defaults.js +44 -0
  10. package/dist/src/defaults.js.map +1 -0
  11. package/dist/src/hypercore-factory.d.ts +23 -0
  12. package/dist/src/hypercore-factory.d.ts.map +1 -0
  13. package/dist/src/hypercore-factory.js +44 -0
  14. package/dist/src/hypercore-factory.js.map +1 -0
  15. package/dist/src/hypercore-factory.test.d.ts +2 -0
  16. package/dist/src/hypercore-factory.test.d.ts.map +1 -0
  17. package/dist/src/hypercore-factory.test.js +46 -0
  18. package/dist/src/hypercore-factory.test.js.map +1 -0
  19. package/dist/src/hypercore-protocol.test.d.ts +2 -0
  20. package/dist/src/hypercore-protocol.test.d.ts.map +1 -0
  21. package/dist/src/hypercore-protocol.test.js +191 -0
  22. package/dist/src/hypercore-protocol.test.js.map +1 -0
  23. package/dist/src/hypercore.test.d.ts +2 -0
  24. package/dist/src/hypercore.test.d.ts.map +1 -0
  25. package/dist/src/hypercore.test.js +79 -0
  26. package/dist/src/hypercore.test.js.map +1 -0
  27. package/dist/src/index.d.ts +5 -0
  28. package/dist/src/index.d.ts.map +1 -0
  29. package/dist/src/index.js +24 -0
  30. package/dist/src/index.js.map +1 -0
  31. package/dist/src/iterator.d.ts +26 -0
  32. package/dist/src/iterator.d.ts.map +1 -0
  33. package/dist/src/iterator.js +37 -0
  34. package/dist/src/iterator.js.map +1 -0
  35. package/dist/src/iterator.test.d.ts +2 -0
  36. package/dist/src/iterator.test.d.ts.map +1 -0
  37. package/dist/src/iterator.test.js +61 -0
  38. package/dist/src/iterator.test.js.map +1 -0
  39. package/dist/src/multiplexer.d.ts +21 -0
  40. package/dist/src/multiplexer.d.ts.map +1 -0
  41. package/dist/src/multiplexer.js +103 -0
  42. package/dist/src/multiplexer.js.map +1 -0
  43. package/dist/src/multiplexer.test.d.ts +2 -0
  44. package/dist/src/multiplexer.test.d.ts.map +1 -0
  45. package/dist/src/multiplexer.test.js +142 -0
  46. package/dist/src/multiplexer.test.js.map +1 -0
  47. package/dist/src/replicate.test.d.ts +2 -0
  48. package/dist/src/replicate.test.d.ts.map +1 -0
  49. package/dist/src/replicate.test.js +197 -0
  50. package/dist/src/replicate.test.js.map +1 -0
  51. package/dist/src/streams.test.d.ts +2 -0
  52. package/dist/src/streams.test.d.ts.map +1 -0
  53. package/dist/src/streams.test.js +65 -0
  54. package/dist/src/streams.test.js.map +1 -0
  55. package/dist/src/testing.d.ts +11 -0
  56. package/dist/src/testing.d.ts.map +1 -0
  57. package/dist/src/testing.js +36 -0
  58. package/dist/src/testing.js.map +1 -0
  59. package/package.json +50 -0
  60. package/src/crypto.ts +46 -0
  61. package/src/defaults.ts +46 -0
  62. package/src/hypercore-factory.test.ts +53 -0
  63. package/src/hypercore-factory.ts +44 -0
  64. package/src/hypercore-protocol.test.ts +236 -0
  65. package/src/hypercore.test.ts +98 -0
  66. package/src/index.ts +8 -0
  67. package/src/iterator.test.ts +66 -0
  68. package/src/iterator.ts +35 -0
  69. package/src/multiplexer.test.ts +172 -0
  70. package/src/multiplexer.ts +122 -0
  71. package/src/replicate.test.ts +241 -0
  72. package/src/streams.test.ts +75 -0
  73. package/src/testing.ts +40 -0
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2019 DXOS.org
4
+ //
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const chai_1 = require("chai");
10
+ const faker_1 = __importDefault(require("faker"));
11
+ const async_1 = require("@dxos/async");
12
+ const crypto_1 = require("@dxos/crypto");
13
+ const log_1 = require("@dxos/log");
14
+ const hypercore_factory_1 = require("./hypercore-factory");
15
+ const iterator_1 = require("./iterator");
16
+ const testing_1 = require("./testing");
17
+ const noop = () => { };
18
+ describe('Replication', function () {
19
+ const factory1 = new hypercore_factory_1.HypercoreFactory();
20
+ const factory2 = new hypercore_factory_1.HypercoreFactory();
21
+ it('replicates feeds', async function () {
22
+ const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
23
+ const core1 = factory1.createFeed(publicKey, { secretKey });
24
+ const core2 = factory2.createFeed(publicKey);
25
+ // Open.
26
+ {
27
+ const [ready, done] = (0, async_1.latch)({ count: 2 });
28
+ core1.open(done);
29
+ core2.open(done);
30
+ await ready();
31
+ }
32
+ const numBlocks = 10;
33
+ // Sync.
34
+ {
35
+ const stream1 = core1.replicate(true);
36
+ const stream2 = core2.replicate(false);
37
+ const [streamsClosed, onClose] = (0, async_1.latch)({ count: 2 });
38
+ stream1.pipe(stream2, onClose).pipe(stream1, onClose);
39
+ (0, chai_1.expect)(core1.stats.peers).to.have.lengthOf(1);
40
+ (0, chai_1.expect)(core2.stats.peers).to.have.lengthOf(1);
41
+ // Wait for complete sync.
42
+ core2.on('sync', () => {
43
+ stream1.end();
44
+ stream2.end();
45
+ });
46
+ // Write.
47
+ for (let i = 0; i < numBlocks; i++) {
48
+ core1.append(`test-${i}`, noop);
49
+ }
50
+ await streamsClosed();
51
+ }
52
+ // Close.
53
+ {
54
+ const [closed, close] = (0, async_1.latch)({ count: 2 });
55
+ core1.close(close);
56
+ core1.close(close);
57
+ await closed();
58
+ }
59
+ (0, chai_1.expect)(core1.stats.totals.uploadedBlocks).to.eq(numBlocks);
60
+ (0, chai_1.expect)(core2.stats.totals.downloadedBlocks).to.eq(numBlocks);
61
+ });
62
+ it('replicates feeds in batches', async function () {
63
+ const numBlocks = 100;
64
+ // Replicating feeds must have the same public key.
65
+ const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
66
+ const core1 = factory1.createFeed(publicKey, { secretKey });
67
+ const core2 = factory2.createFeed(publicKey);
68
+ // Open.
69
+ {
70
+ const [ready, done] = (0, async_1.latch)({ count: 2 });
71
+ core1.open(done);
72
+ core2.open(done);
73
+ await ready();
74
+ }
75
+ const stream1 = core1.replicate(true);
76
+ const stream2 = core2.replicate(false);
77
+ // Start replication.
78
+ // NOTE: Replication won't start unless the public keys on both sides are the same.
79
+ const [streamsClosed, onClose] = (0, async_1.latch)({ count: 2 });
80
+ stream1.pipe(stream2, onClose).pipe(stream1, onClose);
81
+ (0, chai_1.expect)(core1.stats.peers).to.have.lengthOf(1);
82
+ (0, chai_1.expect)(core2.stats.peers).to.have.lengthOf(1);
83
+ // Replicate messages.
84
+ {
85
+ // Wait until all uploaded.
86
+ const [waitForDownloaded, incDownload] = (0, async_1.latch)({ count: numBlocks });
87
+ // Monitor uploads.
88
+ let uploaded = 0;
89
+ core1.on('upload', () => {
90
+ uploaded++;
91
+ (0, log_1.log)('up', { uploaded, length: core1.length }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 111 });
92
+ });
93
+ // Monitor downloads.
94
+ let downloaded = 0;
95
+ core2.on('download', (seq, data) => {
96
+ downloaded++;
97
+ const { id } = JSON.parse(data.toString());
98
+ (0, chai_1.expect)(id).to.eq(seq);
99
+ (0, log_1.log)('down', { downloaded, length: core2.length }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 120 });
100
+ (0, chai_1.expect)(downloaded).to.be.lessThanOrEqual(uploaded);
101
+ incDownload();
102
+ });
103
+ // Monitor sync points (multiple since delayed writes).
104
+ const sync = { started: 0, complete: 0 };
105
+ core2.on('sync', () => {
106
+ (0, log_1.log)('sync', { events: ++sync.started }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 128 });
107
+ core2.download();
108
+ });
109
+ // Write batch of messages with delay.
110
+ (0, testing_1.batch)((next, i, remaining) => {
111
+ const size = faker_1.default.datatype.number({
112
+ min: 1,
113
+ max: Math.min(10, remaining)
114
+ });
115
+ for (let j = 0; j < size; j++) {
116
+ core1.append(JSON.stringify((0, testing_1.createDataItem)(i + j)), noop);
117
+ }
118
+ // Random delay.
119
+ setTimeout(() => {
120
+ next(size);
121
+ }, faker_1.default.datatype.number({ min: 0, max: 100 }));
122
+ }, numBlocks);
123
+ // Done.
124
+ await waitForDownloaded();
125
+ (0, chai_1.expect)(uploaded).to.eq(downloaded);
126
+ }
127
+ // Close streams.
128
+ {
129
+ stream1.end();
130
+ stream2.end();
131
+ await streamsClosed();
132
+ (0, chai_1.expect)(stream1.destroyed).to.be.true;
133
+ (0, chai_1.expect)(stream2.destroyed).to.be.true;
134
+ }
135
+ // Close feeds.
136
+ {
137
+ await core1.close();
138
+ await core2.close();
139
+ (0, chai_1.expect)(core1.writable).to.be.false;
140
+ (0, chai_1.expect)(core1.stats.totals.uploadedBlocks).to.eq(numBlocks);
141
+ (0, chai_1.expect)(core2.stats.totals.downloadedBlocks).to.eq(numBlocks);
142
+ }
143
+ }).timeout(5000);
144
+ it('replicates feeds with read stream', async function () {
145
+ const numBlocks = 10;
146
+ const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
147
+ const core1 = factory1.createFeed(publicKey, { secretKey });
148
+ const core2 = factory2.createFeed(publicKey);
149
+ // Open.
150
+ {
151
+ const [ready, done] = (0, async_1.latch)({ count: 2 });
152
+ core1.open(done);
153
+ core2.open(done);
154
+ await ready();
155
+ }
156
+ (0, chai_1.expect)(core1.opened).to.be.true;
157
+ (0, chai_1.expect)(core2.opened).to.be.true;
158
+ const stream1 = core1.replicate(true, { live: true });
159
+ const stream2 = core2.replicate(false, { live: true });
160
+ const [done, onClose] = (0, async_1.latch)({ count: 2 });
161
+ // Start replication.
162
+ {
163
+ stream1.pipe(stream2, onClose).pipe(stream1, onClose);
164
+ (0, chai_1.expect)(core1.stats.peers).to.have.lengthOf(1);
165
+ (0, chai_1.expect)(core2.stats.peers).to.have.lengthOf(1);
166
+ let sync = 0;
167
+ core2.on('sync', () => {
168
+ (0, log_1.log)('sync', { events: ++sync }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 206 });
169
+ });
170
+ }
171
+ // Writer.
172
+ {
173
+ setTimeout(async () => {
174
+ for (const _ of Array.from(Array(numBlocks))) {
175
+ const block = {
176
+ text: faker_1.default.lorem.sentence()
177
+ };
178
+ core1.append(JSON.stringify(block), noop);
179
+ }
180
+ });
181
+ }
182
+ // Reader.
183
+ {
184
+ const [done, inc] = (0, async_1.latch)({ count: numBlocks });
185
+ setTimeout(async () => {
186
+ for await (const _ of (0, iterator_1.createReadable)(core2.createReadStream({ live: true }))) {
187
+ inc();
188
+ }
189
+ });
190
+ await done();
191
+ stream1.end();
192
+ stream2.end();
193
+ }
194
+ await done();
195
+ }).timeout(5000);
196
+ });
197
+ //# sourceMappingURL=replicate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replicate.test.js","sourceRoot":"","sources":["../../src/replicate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=streams.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.test.d.ts","sourceRoot":"","sources":["../../src/streams.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2019 DXOS.org
4
+ //
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const node_util_1 = __importDefault(require("node:util"));
10
+ const streamx_1 = require("streamx");
11
+ const async_1 = require("@dxos/async");
12
+ const crypto_1 = require("@dxos/crypto");
13
+ const log_1 = require("@dxos/log");
14
+ const hypercore_factory_1 = require("./hypercore-factory");
15
+ describe('Streams', function () {
16
+ it('reads from stream', async function () {
17
+ const factory = new hypercore_factory_1.HypercoreFactory();
18
+ const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
19
+ const core = factory.createFeed(publicKey, { secretKey });
20
+ const numBlocks = 10;
21
+ const [closed, setClosed] = (0, async_1.latch)();
22
+ const [processed, incProcessed] = (0, async_1.latch)({ count: numBlocks });
23
+ const stream = core.createReadStream({ live: true });
24
+ const consumer = stream.pipe(new streamx_1.Writable({
25
+ write: (data, next) => {
26
+ (0, log_1.log)('received', { data: String(data) }, { file: "packages/common/hypercore/src/streams.test.ts", line: 28 });
27
+ incProcessed();
28
+ next();
29
+ }
30
+ }));
31
+ {
32
+ const append = node_util_1.default.promisify(core.append.bind(core));
33
+ for (const i of Array.from(Array(numBlocks)).keys()) {
34
+ await append(`message-${i}`);
35
+ }
36
+ }
37
+ await processed();
38
+ {
39
+ consumer.once('close', () => {
40
+ (0, log_1.log)('closed', {}, { file: "packages/common/hypercore/src/streams.test.ts", line: 46 });
41
+ setClosed();
42
+ });
43
+ consumer.destroy();
44
+ await closed();
45
+ }
46
+ });
47
+ it('feed closed while stream is open', async function () {
48
+ const factory = new hypercore_factory_1.HypercoreFactory();
49
+ const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
50
+ const core = factory.createFeed(publicKey, { secretKey });
51
+ const [closed, setClosed] = (0, async_1.latch)({ count: 1 });
52
+ {
53
+ const stream = core.createReadStream({ live: true });
54
+ stream.once('close', () => {
55
+ (0, log_1.log)('closed', {}, { file: "packages/common/hypercore/src/streams.test.ts", line: 64 });
56
+ setClosed();
57
+ });
58
+ stream.destroy();
59
+ }
60
+ await closed();
61
+ const close = node_util_1.default.promisify(core.close.bind(core));
62
+ await close();
63
+ });
64
+ });
65
+ //# sourceMappingURL=streams.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.test.js","sourceRoot":"","sources":["../../src/streams.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare const noop: () => void;
2
+ export declare const py: (obj: any, fn: Function) => Function;
3
+ export declare type TestDataItem = {
4
+ id: number;
5
+ text: string;
6
+ };
7
+ export declare const createDataItem: (n: number) => TestDataItem;
8
+ declare type BatchCallback = (next: (num: number) => void, index: number, remaining: number) => void;
9
+ export declare const batch: (cb: BatchCallback, total: number) => void;
10
+ export {};
11
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/testing.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,IAAI,YAAW,CAAC;AAE7B,eAAO,MAAM,EAAE,QAAS,GAAG,MAAM,QAAQ,aAAiC,CAAC;AAG3E,oBAAY,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,eAAO,MAAM,cAAc,MAAO,MAAM,KAAG,YAGzC,CAAC;AAEH,aAAK,aAAa,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;AAG7F,eAAO,MAAM,KAAK,OAAQ,aAAa,SAAS,MAAM,SAiBrD,CAAC"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2019 DXOS.org
4
+ //
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.batch = exports.createDataItem = exports.py = exports.noop = void 0;
10
+ const faker_1 = __importDefault(require("faker"));
11
+ const node_util_1 = __importDefault(require("node:util"));
12
+ const noop = () => { };
13
+ exports.noop = noop;
14
+ const py = (obj, fn) => node_util_1.default.promisify(fn.bind(obj));
15
+ exports.py = py;
16
+ const createDataItem = (n) => ({
17
+ id: n,
18
+ text: faker_1.default.lorem.sentence()
19
+ });
20
+ exports.createDataItem = createDataItem;
21
+ // TODO(burdon): Factor out.
22
+ const batch = (cb, total) => {
23
+ let i = 0;
24
+ const f = () => {
25
+ const remaining = total - i;
26
+ cb((num = 1) => {
27
+ i += num;
28
+ if (i < total) {
29
+ f();
30
+ }
31
+ }, i, remaining);
32
+ };
33
+ f();
34
+ };
35
+ exports.batch = batch;
36
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/testing.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;AAEF,kDAA0B;AAC1B,0DAA6B;AAEtB,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;AAAhB,QAAA,IAAI,QAAY;AAEtB,MAAM,EAAE,GAAG,CAAC,GAAQ,EAAE,EAAY,EAAE,EAAE,CAAC,mBAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAA9D,QAAA,EAAE,MAA4D;AAKpE,MAAM,cAAc,GAAG,CAAC,CAAS,EAAgB,EAAE,CAAC,CAAC;IAC1D,EAAE,EAAE,CAAC;IACL,IAAI,EAAE,eAAK,CAAC,KAAK,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAHU,QAAA,cAAc,kBAGxB;AAIH,4BAA4B;AACrB,MAAM,KAAK,GAAG,CAAC,EAAiB,EAAE,KAAa,EAAE,EAAE;IACxD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,CAAC,GAAG,GAAG,EAAE;QACb,MAAM,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;QAC5B,EAAE,CACA,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;YACV,CAAC,IAAI,GAAG,CAAC;YACT,IAAI,CAAC,GAAG,KAAK,EAAE;gBACb,CAAC,EAAE,CAAC;aACL;QACH,CAAC,EACD,CAAC,EACD,SAAS,CACV,CAAC;IACJ,CAAC,CAAC;IAEF,CAAC,EAAE,CAAC;AACN,CAAC,CAAC;AAjBW,QAAA,KAAK,SAiBhB"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@dxos/hypercore",
3
+ "version": "0.1.0",
4
+ "description": "Hypercore wrapper and utils.",
5
+ "homepage": "https://dxos.org",
6
+ "bugs": "https://github.com/dxos/dxos/issues",
7
+ "license": "MIT",
8
+ "author": "DXOS.org",
9
+ "main": "./dist/src/index.js",
10
+ "browser": {
11
+ "node:assert": "assert",
12
+ "node:util": "util"
13
+ },
14
+ "types": "./dist/src/index.d.ts",
15
+ "files": [
16
+ "dist",
17
+ "src"
18
+ ],
19
+ "dependencies": {
20
+ "@dxos/async": "0.1.0",
21
+ "@dxos/codec-protobuf": "0.1.0",
22
+ "@dxos/crypto": "0.1.0",
23
+ "@dxos/debug": "0.1.0",
24
+ "@dxos/keys": "0.1.0",
25
+ "@dxos/random-access-storage": "0.1.0",
26
+ "assert": "^2.0.0",
27
+ "hypercore": "^9.12.0",
28
+ "hypercore-protocol": "^8.0.7",
29
+ "readable-stream": "^3.6.0",
30
+ "streamx": "^2.12.5",
31
+ "util": "^0.12.4"
32
+ },
33
+ "devDependencies": {
34
+ "@dxos/log": "0.1.0",
35
+ "@dxos/util": "0.1.0",
36
+ "@types/debug": "^4.1.7",
37
+ "@types/faker": "^5.5.9",
38
+ "@types/randombytes": "^2.0.0",
39
+ "@types/readable-stream": "^2.3.9",
40
+ "debug": "^4.3.3",
41
+ "faker": "^5.5.3",
42
+ "random-access-memory": "^4.1.0"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "check": "true"
49
+ }
50
+ }
package/src/crypto.ts ADDED
@@ -0,0 +1,46 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import assert from 'assert';
6
+ import { AbstractValueEncoding, Crypto } from 'hypercore';
7
+ import { callbackify } from 'node:util';
8
+
9
+ import { Codec } from '@dxos/codec-protobuf';
10
+ import { Signer, verifySignature } from '@dxos/crypto';
11
+ import { PublicKey } from '@dxos/keys';
12
+
13
+ /**
14
+ * Create encoding (e.g., from protobuf codec).
15
+ */
16
+ export const createCodecEncoding = <T>(codec: Codec<T>): AbstractValueEncoding<T> => ({
17
+ encode: (obj: T) => Buffer.from(codec.encode(obj)),
18
+ decode: (buffer: Buffer) => codec.decode(buffer)
19
+ });
20
+
21
+ /**
22
+ * Create a custom hypercore crypto signer.
23
+ */
24
+ // TODO(burdon): Create test without adding deps.
25
+ export const createCrypto = (signer: Signer, publicKey: PublicKey): Crypto => {
26
+ assert(signer);
27
+ assert(publicKey);
28
+
29
+ return {
30
+ sign: (message, secretKey, cb) => {
31
+ callbackify(signer.sign.bind(signer!))(publicKey, message, (err, result) => {
32
+ if (err) {
33
+ cb(err, null);
34
+ return;
35
+ }
36
+
37
+ cb(null, Buffer.from(result));
38
+ });
39
+ },
40
+
41
+ verify: async (message, signature, key, cb) => {
42
+ // NOTE: Uses the public key passed into function.
43
+ callbackify(verifySignature)(publicKey, message, signature, cb);
44
+ }
45
+ };
46
+ };
@@ -0,0 +1,46 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import type { HypercoreOptions, ReadStreamOptions, ReplicationOptions, WriteStreamOptions } from 'hypercore';
6
+
7
+ /**
8
+ * https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-feed--hypercorestorage-key-options
9
+ */
10
+ export const defaultFeedOptions: HypercoreOptions = {
11
+ createIfMissing: true,
12
+ valueEncoding: 'binary'
13
+ };
14
+
15
+ /**
16
+ * https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-stream--feedcreatereadstreamoptions
17
+ */
18
+ export const defaultReadStreamOptions: ReadStreamOptions = {
19
+ start: 0,
20
+ end: Infinity,
21
+ snapshot: true,
22
+ tail: false,
23
+ live: false,
24
+ timeout: 0,
25
+ wait: true,
26
+ batch: 1
27
+ };
28
+
29
+ /**
30
+ * https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-stream--feedcreatewritestreamopts
31
+ */
32
+ export const defaultWriteStreamOptions: WriteStreamOptions = {
33
+ maxBlockSize: Infinity
34
+ };
35
+
36
+ /**
37
+ * https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-stream--feedreplicateisinitiator-options
38
+ */
39
+ export const defaultReplicateOptions: ReplicationOptions = {
40
+ live: false,
41
+ ack: false,
42
+ download: true,
43
+ upload: true,
44
+ encrypted: true,
45
+ noise: true
46
+ };
@@ -0,0 +1,53 @@
1
+ //
2
+ // Copyright 2019 DXOS.org
3
+ //
4
+
5
+ import { expect } from 'chai';
6
+ import faker from 'faker';
7
+
8
+ import { createKeyPair } from '@dxos/crypto';
9
+
10
+ import { HypercoreFactory } from './hypercore-factory';
11
+ import { createDataItem, py } from './testing';
12
+
13
+ describe('HypercoreFactory', function () {
14
+ it('appends to, and read from, multiple feeds', async function () {
15
+ const factory = new HypercoreFactory();
16
+
17
+ const numFeeds = 10;
18
+ const numBlocks = 100;
19
+
20
+ // Create feeds.
21
+ const feeds = await Promise.all(
22
+ Array.from({ length: numFeeds }).map(async () => {
23
+ const { publicKey, secretKey } = createKeyPair();
24
+ return await factory.openFeed(publicKey, { secretKey });
25
+ })
26
+ );
27
+
28
+ // Write data.
29
+ {
30
+ const data = Array.from({ length: numBlocks }).map((_, i) => createDataItem(i));
31
+ for await (const datum of data) {
32
+ const feed = faker.random.arrayElement(feeds);
33
+ await py(feed, feed.append)(Buffer.from(JSON.stringify(datum)));
34
+ }
35
+ }
36
+
37
+ // Test.
38
+ {
39
+ const total = feeds.reduce((result, feed) => result + feed.length, 0);
40
+ expect(total).to.eq(numBlocks);
41
+
42
+ const feed = faker.random.arrayElement(feeds);
43
+ const block1 = await py(feed, feed.head)();
44
+ const block2 = await py(feed, feed.get)(feed.length - 1);
45
+ expect(block1.toString()).to.eq(block2.toString());
46
+
47
+ const blocks = await py(feed, feed.getBatch)(0, feed.length);
48
+ expect(blocks.length).to.eq(feed.length);
49
+ }
50
+
51
+ await Promise.all(feeds.map((feed) => feed.close()));
52
+ });
53
+ });
@@ -0,0 +1,44 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import assert from 'assert';
6
+ import hypercore from 'hypercore';
7
+ import type { Hypercore, HypercoreOptions } from 'hypercore';
8
+
9
+ import { createStorage, Directory, StorageType } from '@dxos/random-access-storage';
10
+
11
+ import { py } from './testing';
12
+
13
+ /**
14
+ * Creates feeds with default properties.
15
+ */
16
+ export class HypercoreFactory<T> {
17
+ // prettier-ignore
18
+ constructor(
19
+ private readonly _root: Directory = createStorage({ type: StorageType.RAM }).createDirectory(),
20
+ private readonly _options?: HypercoreOptions
21
+ ) {
22
+ assert(this._root);
23
+ }
24
+
25
+ /**
26
+ * Creates a feed using a storage factory prefixed with the feed's key.
27
+ * NOTE: We have to use our `random-access-storage` implementation since the native ones
28
+ * do not behave uniformly across platforms.
29
+ */
30
+ createFeed(publicKey: Buffer, options?: HypercoreOptions): Hypercore<T> {
31
+ const directory = this._root.createDirectory(publicKey.toString());
32
+ const storage = (filename: string) => directory.getOrCreateFile(filename).native;
33
+ return hypercore(storage, publicKey, Object.assign({}, this._options, options));
34
+ }
35
+
36
+ /**
37
+ * Creates and opens a feed.
38
+ */
39
+ async openFeed(publicKey: Buffer, options?: HypercoreOptions): Promise<Hypercore<T>> {
40
+ const feed = this.createFeed(publicKey, options);
41
+ await py(feed, feed.open)(); // TODO(burdon): Sometimes strange bug if done inside function.
42
+ return feed;
43
+ }
44
+ }