@dxos/hypercore 0.1.51-main.e7215ae → 0.1.51-next.5787f10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/hypercore",
3
- "version": "0.1.51-main.e7215ae",
3
+ "version": "0.1.51-next.5787f10",
4
4
  "description": "Hypercore wrapper and utils.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -20,14 +20,14 @@
20
20
  "sodium-native": "^3.2.0",
21
21
  "sodium-universal": "^3.0.2",
22
22
  "streamx": "^2.12.5",
23
- "@dxos/async": "0.1.51-main.e7215ae",
24
- "@dxos/codec-protobuf": "0.1.51-main.e7215ae",
25
- "@dxos/crypto": "0.1.51-main.e7215ae",
26
- "@dxos/debug": "0.1.51-main.e7215ae",
27
- "@dxos/keys": "0.1.51-main.e7215ae",
28
- "@dxos/node-std": "0.1.51-main.e7215ae",
29
- "@dxos/random-access-storage": "0.1.51-main.e7215ae",
30
- "@dxos/typings": "0.1.51-main.e7215ae"
23
+ "@dxos/async": "0.1.51-next.5787f10",
24
+ "@dxos/codec-protobuf": "0.1.51-next.5787f10",
25
+ "@dxos/crypto": "0.1.51-next.5787f10",
26
+ "@dxos/debug": "0.1.51-next.5787f10",
27
+ "@dxos/keys": "0.1.51-next.5787f10",
28
+ "@dxos/node-std": "0.1.51-next.5787f10",
29
+ "@dxos/random-access-storage": "0.1.51-next.5787f10",
30
+ "@dxos/typings": "0.1.51-next.5787f10"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@faker-js/faker": "^7.3.0",
@@ -40,8 +40,8 @@
40
40
  "hypercore-protocol": "^8.0.7",
41
41
  "noise-protocol": "3.0.1",
42
42
  "random-access-memory": "^4.1.0",
43
- "@dxos/log": "0.1.51-main.e7215ae",
44
- "@dxos/util": "0.1.51-main.e7215ae"
43
+ "@dxos/log": "0.1.51-next.5787f10",
44
+ "@dxos/util": "0.1.51-next.5787f10"
45
45
  },
46
46
  "publishConfig": {
47
47
  "access": "public"
@@ -1,21 +0,0 @@
1
- import { Hypercore } from 'hypercore';
2
- import { PassThrough } from 'streamx';
3
- /**
4
- * Hypercore multiplexer.
5
- */
6
- export declare class Multiplexer {
7
- private readonly _id;
8
- private readonly _feeds;
9
- private readonly _streams;
10
- private _isOpen;
11
- private _closedTrigger;
12
- readonly input: PassThrough;
13
- readonly output: PassThrough;
14
- constructor(_id: string);
15
- get isOpen(): boolean;
16
- get feeds(): Hypercore<any>[];
17
- addFeed(core: Hypercore, initiator?: boolean): this;
18
- open(): Promise<void>;
19
- close(): Promise<void>;
20
- }
21
- //# sourceMappingURL=multiplexer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multiplexer.d.ts","sourceRoot":"","sources":["../../../src/multiplexer.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAuB,MAAM,SAAS,CAAC;AAO3D;;GAEG;AAEH,qBAAa,WAAW;IAYpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAXtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwD;IAC/E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6D;IAEtF,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAoC;IAE1D,SAAgB,KAAK,cAAqB;IAC1C,SAAgB,MAAM,cAAqB;gBAIxB,GAAG,EAAE,MAAM;IAG9B,IAAI,MAAM,YAET;IAED,IAAI,KAAK,qBAER;IAED,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,UAAQ;IA6BpC,IAAI;IAuBJ,KAAK;CA4BZ"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=multiplexer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multiplexer.test.d.ts","sourceRoot":"","sources":["../../../src/multiplexer.test.ts"],"names":[],"mappings":""}
@@ -1,174 +0,0 @@
1
- //
2
- // Copyright 2022 DXOS.org
3
- //
4
-
5
- import { faker } from '@faker-js/faker';
6
- import { expect } from 'chai';
7
- import { PassThrough, Transform } from 'streamx';
8
-
9
- import { latch } from '@dxos/async';
10
- import { createKeyPair } from '@dxos/crypto';
11
- import { PublicKey } from '@dxos/keys';
12
- import { log } from '@dxos/log';
13
- import { describe, test } from '@dxos/test';
14
-
15
- import { HypercoreFactory } from './hypercore-factory';
16
- import { Multiplexer } from './multiplexer';
17
- import { noop } from './testing';
18
- import { py } from './util';
19
-
20
- describe('Multiplexing', () => {
21
- test('multiplexes feeds', async () => {
22
- const plex1 = new Multiplexer('A');
23
- const plex2 = new Multiplexer('B');
24
-
25
- await plex1.open();
26
- await plex2.open();
27
-
28
- const numFeeds = 1;
29
- const factory = new HypercoreFactory();
30
- const feeds = await Promise.all(
31
- Array.from(Array(numFeeds)).map(async () => {
32
- const { publicKey, secretKey } = createKeyPair();
33
- const core1 = factory.createFeed(publicKey, { secretKey });
34
- const core2 = factory.createFeed(publicKey);
35
-
36
- await py(core1, core1.open)();
37
- await py(core2, core2.open)();
38
-
39
- plex1.addFeed(core1, true);
40
- plex2.addFeed(core2);
41
- return [core1, core2];
42
- }),
43
- );
44
-
45
- feeds.forEach(([core1, core2]) => {
46
- expect(core1.stats.peers.length).to.eq(1);
47
- expect(core2.stats.peers.length).to.eq(1);
48
- });
49
-
50
- const [closed, setClosed] = latch({ count: 2 });
51
-
52
- // TODO(burdon): Test with additional PassThrough.
53
- plex1.output.pipe(plex2.input, setClosed);
54
- plex2.output.pipe(plex1.input, setClosed);
55
-
56
- const numMessages = 1;
57
- const written = new Set<string>();
58
- Array.from(Array(numMessages)).forEach((_, i) => {
59
- const [core] = faker.helpers.arrayElement(feeds);
60
- written.add(core.key.toString());
61
- core.append(`test-${i}: ${faker.lorem.sentence(10)}`, noop); // Long message.
62
- });
63
-
64
- {
65
- const [synced, setSynced] = latch({ count: written.size });
66
- feeds.forEach(([, core2]) => {
67
- core2.on('sync', () => {
68
- log('sync', { feedKey: PublicKey.from(core2.key) });
69
- setSynced();
70
- });
71
- });
72
-
73
- await synced();
74
- }
75
-
76
- await plex1.close();
77
- await plex2.close();
78
- await closed();
79
-
80
- expect(plex1.isOpen).to.be.false;
81
- expect(plex2.isOpen).to.be.false;
82
-
83
- const count = feeds.reduce((total, [, core2]) => total + core2.length, 0);
84
- expect(count).to.eq(numMessages);
85
- });
86
-
87
- test('pipelines', async () => {
88
- const factory = new HypercoreFactory();
89
- const { publicKey, secretKey } = createKeyPair();
90
- const core1 = factory.createFeed(publicKey, { secretKey });
91
- const core2 = factory.createFeed(publicKey);
92
-
93
- await py(core1, core1.open)();
94
- await py(core2, core2.open)();
95
-
96
- const stream1 = core1.replicate(true, { live: true });
97
- const stream2 = core2.replicate(false, { live: true });
98
-
99
- //
100
- // Pipeline
101
- //
102
-
103
- const createWireTap = (label: string) =>
104
- new Transform({
105
- transform: (data: Buffer, next: (err: Error | null, data: Buffer) => void) => {
106
- log(label, { length: data.length });
107
- next(null, data);
108
- },
109
- });
110
-
111
- const [pipelineClosed, onStreamClose] = latch({ count: 2 });
112
- const createPipeline = (type: number) => {
113
- switch (type) {
114
- case 1:
115
- // prettier-ignore
116
- return stream1
117
- .pipe(stream2, onStreamClose)
118
- .pipe(stream1, onStreamClose);
119
-
120
- case 2:
121
- // prettier-ignore
122
- return stream1
123
- .pipe(new PassThrough())
124
- .pipe(stream2, onStreamClose)
125
- .pipe(new PassThrough())
126
- .pipe(stream1, onStreamClose);
127
-
128
- case 3:
129
- // prettier-ignore
130
- return stream1
131
- .pipe(createWireTap('send'))
132
- .pipe(stream2, onStreamClose)
133
- .pipe(createWireTap('recv'))
134
- .pipe(stream1, onStreamClose);
135
- }
136
- };
137
-
138
- const pipeline = createPipeline(3);
139
- expect(core1.stats.peers).to.have.lengthOf(1);
140
- expect(core2.stats.peers).to.have.lengthOf(1);
141
-
142
- //
143
- // Sync
144
- //
145
-
146
- const numMessages = 10;
147
- const [synced, setSynced] = latch();
148
- core2.on('sync', () => {
149
- log('sync', { send: core1.stats.totals, recv: core1.stats.totals });
150
- expect(core2.length).to.eq(10);
151
- setSynced();
152
- });
153
-
154
- Array.from(Array(numMessages)).map((_, i) => core1.append(`test-${i}: ${faker.lorem.sentence()}`, noop));
155
- await synced();
156
-
157
- //
158
- // Close
159
- //
160
-
161
- {
162
- pipeline.finalize();
163
- await pipelineClosed();
164
-
165
- const [feedsClosed, done] = latch({ count: 2 });
166
- core1.close(done);
167
- core2.close(done);
168
- await feedsClosed();
169
-
170
- expect(core1.closed).to.be.true;
171
- expect(core2.closed).to.be.true;
172
- }
173
- });
174
- });
@@ -1,122 +0,0 @@
1
- //
2
- // Copyright 2022 DXOS.org
3
- //
4
-
5
- import { Hypercore } from 'hypercore';
6
- import { ProtocolStream } from 'hypercore-protocol';
7
- import assert from 'node:assert';
8
- import { PassThrough, Transform, Writable } from 'streamx';
9
-
10
- import { latch, Trigger } from '@dxos/async';
11
- import { PublicKey } from '@dxos/keys';
12
- import { log } from '@dxos/log';
13
- import { ComplexMap } from '@dxos/util';
14
-
15
- /**
16
- * Hypercore multiplexer.
17
- */
18
- // TODO(burdon): Add encoding.
19
- export class Multiplexer {
20
- private readonly _feeds = new ComplexMap<PublicKey, Hypercore>(PublicKey.hash);
21
- private readonly _streams = new ComplexMap<PublicKey, ProtocolStream>(PublicKey.hash);
22
-
23
- private _isOpen = false;
24
- private _closedTrigger = new Trigger({ autoReset: true });
25
-
26
- public readonly input = new PassThrough();
27
- public readonly output = new PassThrough();
28
-
29
- // prettier-ignore
30
- constructor(
31
- private readonly _id: string
32
- ) {}
33
-
34
- get isOpen() {
35
- return this._isOpen;
36
- }
37
-
38
- get feeds() {
39
- return Array.from(this._feeds.values());
40
- }
41
-
42
- addFeed(core: Hypercore, initiator = false) {
43
- const stream = core.replicate(initiator, { live: true });
44
-
45
- const feedKey = PublicKey.from(core.key);
46
- this._feeds.set(feedKey, core);
47
- this._streams.set(feedKey, stream);
48
- log('added', { feedKey: PublicKey.from(feedKey) });
49
-
50
- stream
51
- .pipe(
52
- new Transform({
53
- transform: (data: Buffer, next: (err: Error | null, data: any) => void) => {
54
- log('send', { id: this._id, feedKey: PublicKey.from(feedKey), payload: data.length });
55
- next(null, {
56
- feedKey: core.key,
57
- payload: data,
58
- });
59
- },
60
- }),
61
- )
62
- .pipe(this.output, () => {
63
- log('pipeline closed', { id: this._id });
64
- this._isOpen = false;
65
- this._closedTrigger.wake();
66
- });
67
-
68
- return this;
69
- }
70
-
71
- async open() {
72
- if (this._isOpen) {
73
- return;
74
- }
75
-
76
- this.input.pipe(
77
- new Writable({
78
- write: (data: any, next: () => void) => {
79
- const { feedKey, payload } = data;
80
- const feedStream = this._streams.get(PublicKey.from(feedKey));
81
- assert(feedStream, `invalid stream: ${PublicKey.from(feedKey).truncate()}`);
82
- log('recv', { id: this._id, feedKey: PublicKey.from(feedKey), payload: (payload as Buffer).length });
83
- feedStream.write(payload);
84
- next();
85
- },
86
- }),
87
- );
88
-
89
- log('opened');
90
- this._isOpen = true;
91
- }
92
-
93
- // TODO(burdon): Test if re-entrant?
94
- async close() {
95
- if (!this._isOpen) {
96
- return;
97
- }
98
-
99
- log('closing...');
100
- const [closed, setClosed] = latch({ count: this._streams.size });
101
- Array.from(this._streams.values()).forEach((stream) => {
102
- stream.once('end', () => {
103
- log('stream closed');
104
- setClosed();
105
- });
106
-
107
- stream.finalize();
108
- });
109
-
110
- await closed();
111
-
112
- // NOTE: Depending on environment, pipeline may close before or after the stream above.
113
- if (this._isOpen) {
114
- await this._closedTrigger.wait();
115
- assert(!this._isOpen);
116
- }
117
-
118
- this._feeds.clear();
119
- this._streams.clear();
120
- log('closed');
121
- }
122
- }