@peerbit/test-utils 2.3.15 → 2.3.16-52eac7b

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.
@@ -1,3 +1,4 @@
1
1
  import { TestSession } from "./session.js";
2
- export { TestSession };
2
+ declare const createMock: typeof TestSession.connectedMock;
3
+ export { TestSession, createMock };
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,QAAA,MAAM,UAAU,kCAA4B,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC"}
package/dist/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import { TestSession } from "./session.js";
2
- export { TestSession };
2
+ const createMock = TestSession.connectedMock;
3
+ export { TestSession, createMock };
3
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC"}
@@ -11,10 +11,20 @@ type CreateOptions = {
11
11
  export declare class TestSession {
12
12
  private session;
13
13
  private _peers;
14
+ private connectedGroups;
14
15
  constructor(session: SSession<Libp2pExtendServices>, peers: Peerbit[]);
15
16
  get peers(): ProgramClient[];
16
17
  connect(groups?: ProgramClient[][]): Promise<void>;
18
+ private wrapPeerStartForReconnect;
17
19
  stop(): Promise<void>;
20
+ /**
21
+ * Create a "mock-ish" session intended for fast and stable Node.js tests.
22
+ *
23
+ * Uses TCP-only transport (no WebRTC/WebSockets/circuit-relay) and disables
24
+ * the libp2p relay service by default.
25
+ */
26
+ static connectedMock(n: number, options?: CreateOptions | CreateOptions[]): Promise<TestSession>;
27
+ static disconnectedMock(n: number, options?: CreateOptions | CreateOptions[]): Promise<TestSession>;
18
28
  static connected(n: number, options?: CreateOptions | CreateOptions[]): Promise<TestSession>;
19
29
  static disconnected(n: number, options?: CreateOptions | CreateOptions[]): Promise<TestSession>;
20
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,OAAO,EACN,KAAK,mBAAmB,EAExB,KAAK,oBAAoB,EACzB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,MAAM,aAAa,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;AAEhE,KAAK,aAAa,GAAG;IAAE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1E,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,MAAM,CAAY;gBACd,OAAO,EAAE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE;IAKrE,IAAW,KAAK,IAAI,aAAa,EAAE,CAElC;IAEK,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,EAAE;IAIlC,IAAI;WAKG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;WAY9D,YAAY,CACxB,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;CA2C1C"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAGA,OAAO,EAEN,WAAW,IAAI,QAAQ,EAEvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,OAAO,EACN,KAAK,mBAAmB,EAExB,KAAK,oBAAoB,EACzB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,MAAM,aAAa,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;AAEhE,KAAK,aAAa,GAAG;IAAE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1E,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,eAAe,CAA6B;gBACxC,OAAO,EAAE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE;IAMrE,IAAW,KAAK,IAAI,aAAa,EAAE,CAElC;IAEK,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,EAAE;IAQxC,OAAO,CAAC,yBAAyB;IAqD3B,IAAI;IAcV;;;;;OAKG;WACU,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;WAYlE,gBAAgB,CAC5B,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;WAqC7B,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;WAY9D,YAAY,CACxB,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;CAgE1C"}
@@ -1,7 +1,7 @@
1
1
  import { yamux } from "@chainsafe/libp2p-yamux";
2
2
  import { DirectBlock } from "@peerbit/blocks";
3
3
  import { keychain } from "@peerbit/keychain";
4
- import { TestSession as SSession } from "@peerbit/libp2p-test-utils";
4
+ import { listenFast, TestSession as SSession, transportsFast, } from "@peerbit/libp2p-test-utils";
5
5
  import {} from "@peerbit/program";
6
6
  import { DirectSub } from "@peerbit/pubsub";
7
7
  import { waitForNeighbour as waitForPeersStreams, } from "@peerbit/stream";
@@ -12,20 +12,126 @@ import { Peerbit } from "peerbit";
12
12
  export class TestSession {
13
13
  session;
14
14
  _peers;
15
+ connectedGroups;
15
16
  constructor(session, peers) {
16
17
  this.session = session;
17
18
  this._peers = peers;
19
+ this.wrapPeerStartForReconnect();
18
20
  }
19
21
  get peers() {
20
22
  return this._peers;
21
23
  }
22
24
  async connect(groups) {
23
25
  await this.session.connect(groups?.map((x) => x.map((y) => y)));
26
+ this.connectedGroups = groups
27
+ ? groups.map((group) => new Set(group))
28
+ : [new Set(this._peers)];
24
29
  return;
25
30
  }
31
+ wrapPeerStartForReconnect() {
32
+ const patchedKey = Symbol.for("@peerbit/test-session.reconnect-on-start");
33
+ for (const peer of this._peers) {
34
+ const anyPeer = peer;
35
+ if (anyPeer[patchedKey]) {
36
+ continue;
37
+ }
38
+ anyPeer[patchedKey] = true;
39
+ const originalStart = peer.start.bind(peer);
40
+ peer.start = async () => {
41
+ await originalStart();
42
+ // Only auto-reconnect for sessions that have been explicitly connected.
43
+ // This preserves `TestSession.disconnected*()` semantics.
44
+ if (!this.connectedGroups || peer.libp2p.status !== "started") {
45
+ return;
46
+ }
47
+ const peerHash = peer.identity.publicKey.hashcode();
48
+ const peersToDial = new Set();
49
+ for (const group of this.connectedGroups) {
50
+ if (!group.has(peer))
51
+ continue;
52
+ for (const other of group) {
53
+ if (other === peer)
54
+ continue;
55
+ if (other.libp2p.status !== "started")
56
+ continue;
57
+ peersToDial.add(other);
58
+ }
59
+ }
60
+ // Re-establish connectivity after a full stop/start. Without this, tests that
61
+ // restart a peer can fail to resolve programs/blocks because no node dials.
62
+ await Promise.all([...peersToDial].map(async (other) => {
63
+ await peer.dial(other);
64
+ // Also wait for the reverse direction to be fully established; some
65
+ // protocols require a writable stream on both sides to reply.
66
+ await Promise.all([
67
+ other.services.pubsub.waitFor(peerHash, {
68
+ target: "neighbor",
69
+ timeout: 10_000,
70
+ }),
71
+ other.services.blocks.waitFor(peerHash, {
72
+ target: "neighbor",
73
+ timeout: 10_000,
74
+ }),
75
+ ]);
76
+ }));
77
+ };
78
+ }
79
+ }
26
80
  async stop() {
27
- await Promise.all(this._peers.map((x) => x.stop()));
28
- await Promise.all(this._peers.map((x) => x.libp2p.stop())); // beacuse we initialize libp2p externally (potentially), we have to close externally
81
+ await Promise.all(this._peers.map((peer) => peer.stop()));
82
+ // `Peerbit.stop()` stops libp2p for sessions created by `Peerbit.create()`,
83
+ // but in case a test injected an already-started external libp2p instance,
84
+ // ensure it's stopped (without double-stopping).
85
+ await Promise.all(this._peers.map(async (peer) => {
86
+ if (peer.libp2p.status !== "stopped") {
87
+ await peer.libp2p.stop();
88
+ }
89
+ }));
90
+ }
91
+ /**
92
+ * Create a "mock-ish" session intended for fast and stable Node.js tests.
93
+ *
94
+ * Uses TCP-only transport (no WebRTC/WebSockets/circuit-relay) and disables
95
+ * the libp2p relay service by default.
96
+ */
97
+ static async connectedMock(n, options) {
98
+ const session = await TestSession.disconnectedMock(n, options);
99
+ await session.connect();
100
+ // TODO types
101
+ await waitForPeersStreams(...session.peers.map((x) => x.services.blocks));
102
+ return session;
103
+ }
104
+ static async disconnectedMock(n, options) {
105
+ const applyMockDefaults = (o) => {
106
+ if (!o) {
107
+ return {
108
+ libp2p: {
109
+ transports: transportsFast(),
110
+ addresses: { listen: listenFast() },
111
+ services: { relay: null },
112
+ },
113
+ };
114
+ }
115
+ return {
116
+ ...o,
117
+ libp2p: {
118
+ ...(o.libp2p ?? {}),
119
+ transports: o.libp2p?.transports ?? transportsFast(),
120
+ addresses: {
121
+ ...(o.libp2p?.addresses ?? {}),
122
+ listen: o.libp2p?.addresses?.listen ?? listenFast(),
123
+ },
124
+ services: {
125
+ ...(o.libp2p?.services ?? {}),
126
+ relay: o.libp2p?.services?.relay ?? null,
127
+ },
128
+ },
129
+ };
130
+ };
131
+ const optionsWithMockDefaults = Array.isArray(options)
132
+ ? options.map(applyMockDefaults)
133
+ : applyMockDefaults(options);
134
+ return TestSession.disconnected(n, optionsWithMockDefaults);
29
135
  }
30
136
  static async connected(n, options) {
31
137
  const session = await TestSession.disconnected(n, options);
@@ -35,19 +141,36 @@ export class TestSession {
35
141
  return session;
36
142
  }
37
143
  static async disconnected(n, options) {
144
+ const useMockSession = process.env.PEERBIT_TEST_SESSION === "mock" ||
145
+ process.env.PEERBIT_TEST_SESSION === "fast" ||
146
+ process.env.PEERBIT_TEST_SESSION === "tcp";
38
147
  const m = (o) => {
39
148
  const blocksDirectory = o?.directory
40
149
  ? path.join(o.directory, "/blocks").toString()
41
150
  : undefined;
151
+ const libp2pOptions = {
152
+ ...(o?.libp2p ?? {}),
153
+ };
154
+ if (useMockSession) {
155
+ libp2pOptions.transports = libp2pOptions.transports ?? transportsFast();
156
+ libp2pOptions.addresses = {
157
+ ...(libp2pOptions.addresses ?? {}),
158
+ listen: libp2pOptions.addresses?.listen ?? listenFast(),
159
+ };
160
+ libp2pOptions.services = {
161
+ ...(libp2pOptions.services ?? {}),
162
+ relay: libp2pOptions.services?.relay ?? null,
163
+ };
164
+ }
42
165
  return {
43
- ...o?.libp2p,
166
+ ...libp2pOptions,
44
167
  services: {
45
168
  blocks: (c) => new DirectBlock(c, {
46
169
  directory: blocksDirectory,
47
170
  }),
48
171
  pubsub: (c) => new DirectSub(c, { canRelayMessage: true }),
49
172
  keychain: keychain(),
50
- ...o?.libp2p?.services,
173
+ ...libp2pOptions.services,
51
174
  }, /// TODO types
52
175
  streamMuxers: [yamux()],
53
176
  connectionMonitor: {
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/test-utils",
3
- "version": "2.3.15",
3
+ "version": "2.3.16-52eac7b",
4
4
  "description": "Test utils for Peerbit",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -63,19 +63,19 @@
63
63
  "author": "dao.xyz",
64
64
  "license": "MIT",
65
65
  "dependencies": {
66
+ "@peerbit/libp2p-test-utils": "2.2.0-52eac7b",
67
+ "peerbit": "4.4.16-52eac7b",
66
68
  "@chainsafe/libp2p-yamux": "^8.0.0",
69
+ "@peerbit/blocks": "3.1.7-52eac7b",
70
+ "@peerbit/keychain": "1.2.4-52eac7b",
71
+ "@peerbit/program": "5.6.1-52eac7b",
72
+ "@peerbit/pubsub": "4.1.4-52eac7b",
73
+ "@peerbit/stream": "4.6.0-52eac7b",
67
74
  "libp2p": "^3.1.0",
68
- "tty-table": "^4.2.1",
69
- "peerbit": "4.4.15",
70
- "@peerbit/keychain": "1.2.4",
71
- "@peerbit/libp2p-test-utils": "2.2.0",
72
- "@peerbit/program": "5.6.0",
73
- "@peerbit/blocks": "3.1.6",
74
- "@peerbit/pubsub": "4.1.3",
75
- "@peerbit/stream": "4.5.3"
75
+ "tty-table": "^4.2.1"
76
76
  },
77
77
  "devDependencies": {
78
- "@peerbit/time": "2.3.0"
78
+ "@peerbit/time": "2.3.0-52eac7b"
79
79
  },
80
80
  "localMaintainers": [
81
81
  "dao.xyz"
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  import { TestSession } from "./session.js";
2
2
 
3
- export { TestSession };
3
+ const createMock = TestSession.connectedMock;
4
+
5
+ export { TestSession, createMock };
package/src/session.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import { yamux } from "@chainsafe/libp2p-yamux";
2
2
  import { DirectBlock } from "@peerbit/blocks";
3
3
  import { keychain } from "@peerbit/keychain";
4
- import { TestSession as SSession } from "@peerbit/libp2p-test-utils";
4
+ import {
5
+ listenFast,
6
+ TestSession as SSession,
7
+ transportsFast,
8
+ } from "@peerbit/libp2p-test-utils";
5
9
  import { type ProgramClient } from "@peerbit/program";
6
10
  import { DirectSub } from "@peerbit/pubsub";
7
11
  import {
@@ -23,9 +27,11 @@ type CreateOptions = { libp2p?: Libp2pCreateOptions; directory?: string };
23
27
  export class TestSession {
24
28
  private session: SSession<Libp2pExtendServices>;
25
29
  private _peers: Peerbit[];
30
+ private connectedGroups: Set<Peerbit>[] | undefined;
26
31
  constructor(session: SSession<Libp2pExtendServices>, peers: Peerbit[]) {
27
32
  this.session = session;
28
33
  this._peers = peers;
34
+ this.wrapPeerStartForReconnect();
29
35
  }
30
36
 
31
37
  public get peers(): ProgramClient[] {
@@ -34,11 +40,134 @@ export class TestSession {
34
40
 
35
41
  async connect(groups?: ProgramClient[][]) {
36
42
  await this.session.connect(groups?.map((x) => x.map((y) => y)));
43
+ this.connectedGroups = groups
44
+ ? groups.map((group) => new Set(group as Peerbit[]))
45
+ : [new Set(this._peers)];
37
46
  return;
38
47
  }
48
+
49
+ private wrapPeerStartForReconnect() {
50
+ const patchedKey = Symbol.for("@peerbit/test-session.reconnect-on-start");
51
+ for (const peer of this._peers) {
52
+ const anyPeer = peer as any;
53
+ if (anyPeer[patchedKey]) {
54
+ continue;
55
+ }
56
+ anyPeer[patchedKey] = true;
57
+
58
+ const originalStart = peer.start.bind(peer);
59
+ peer.start = async () => {
60
+ await originalStart();
61
+
62
+ // Only auto-reconnect for sessions that have been explicitly connected.
63
+ // This preserves `TestSession.disconnected*()` semantics.
64
+ if (!this.connectedGroups || peer.libp2p.status !== "started") {
65
+ return;
66
+ }
67
+
68
+ const peerHash = peer.identity.publicKey.hashcode();
69
+ const peersToDial = new Set<Peerbit>();
70
+ for (const group of this.connectedGroups) {
71
+ if (!group.has(peer)) continue;
72
+ for (const other of group) {
73
+ if (other === peer) continue;
74
+ if (other.libp2p.status !== "started") continue;
75
+ peersToDial.add(other);
76
+ }
77
+ }
78
+
79
+ // Re-establish connectivity after a full stop/start. Without this, tests that
80
+ // restart a peer can fail to resolve programs/blocks because no node dials.
81
+ await Promise.all(
82
+ [...peersToDial].map(async (other) => {
83
+ await peer.dial(other);
84
+
85
+ // Also wait for the reverse direction to be fully established; some
86
+ // protocols require a writable stream on both sides to reply.
87
+ await Promise.all([
88
+ other.services.pubsub.waitFor(peerHash, {
89
+ target: "neighbor",
90
+ timeout: 10_000,
91
+ }),
92
+ other.services.blocks.waitFor(peerHash, {
93
+ target: "neighbor",
94
+ timeout: 10_000,
95
+ }),
96
+ ]);
97
+ }),
98
+ );
99
+ };
100
+ }
101
+ }
39
102
  async stop() {
40
- await Promise.all(this._peers.map((x) => x.stop()));
41
- await Promise.all(this._peers.map((x) => x.libp2p.stop())); // beacuse we initialize libp2p externally (potentially), we have to close externally
103
+ await Promise.all(this._peers.map((peer) => peer.stop()));
104
+ // `Peerbit.stop()` stops libp2p for sessions created by `Peerbit.create()`,
105
+ // but in case a test injected an already-started external libp2p instance,
106
+ // ensure it's stopped (without double-stopping).
107
+ await Promise.all(
108
+ this._peers.map(async (peer) => {
109
+ if (peer.libp2p.status !== "stopped") {
110
+ await peer.libp2p.stop();
111
+ }
112
+ }),
113
+ );
114
+ }
115
+
116
+ /**
117
+ * Create a "mock-ish" session intended for fast and stable Node.js tests.
118
+ *
119
+ * Uses TCP-only transport (no WebRTC/WebSockets/circuit-relay) and disables
120
+ * the libp2p relay service by default.
121
+ */
122
+ static async connectedMock(n: number, options?: CreateOptions | CreateOptions[]) {
123
+ const session = await TestSession.disconnectedMock(n, options);
124
+ await session.connect();
125
+ // TODO types
126
+ await waitForPeersStreams(
127
+ ...session.peers.map(
128
+ (x) => x.services.blocks as any as DirectStream<any>,
129
+ ),
130
+ );
131
+ return session;
132
+ }
133
+
134
+ static async disconnectedMock(
135
+ n: number,
136
+ options?: CreateOptions | CreateOptions[],
137
+ ) {
138
+ const applyMockDefaults = (o?: CreateOptions): CreateOptions | undefined => {
139
+ if (!o) {
140
+ return {
141
+ libp2p: {
142
+ transports: transportsFast(),
143
+ addresses: { listen: listenFast() },
144
+ services: { relay: null },
145
+ } as any,
146
+ };
147
+ }
148
+
149
+ return {
150
+ ...o,
151
+ libp2p: {
152
+ ...(o.libp2p ?? {}),
153
+ transports: o.libp2p?.transports ?? transportsFast(),
154
+ addresses: {
155
+ ...(o.libp2p?.addresses ?? {}),
156
+ listen: o.libp2p?.addresses?.listen ?? listenFast(),
157
+ },
158
+ services: {
159
+ ...(o.libp2p?.services ?? {}),
160
+ relay: o.libp2p?.services?.relay ?? null,
161
+ },
162
+ } as any,
163
+ };
164
+ };
165
+
166
+ const optionsWithMockDefaults = Array.isArray(options)
167
+ ? options.map(applyMockDefaults)
168
+ : applyMockDefaults(options);
169
+
170
+ return TestSession.disconnected(n, optionsWithMockDefaults as any);
42
171
  }
43
172
 
44
173
  static async connected(n: number, options?: CreateOptions | CreateOptions[]) {
@@ -57,13 +186,34 @@ export class TestSession {
57
186
  n: number,
58
187
  options?: CreateOptions | CreateOptions[],
59
188
  ) {
189
+ const useMockSession =
190
+ process.env.PEERBIT_TEST_SESSION === "mock" ||
191
+ process.env.PEERBIT_TEST_SESSION === "fast" ||
192
+ process.env.PEERBIT_TEST_SESSION === "tcp";
193
+
60
194
  const m = (o?: CreateOptions): Libp2pCreateOptionsWithServices => {
61
195
  const blocksDirectory = o?.directory
62
196
  ? path.join(o.directory, "/blocks").toString()
63
197
  : undefined;
64
198
 
199
+ const libp2pOptions: Libp2pCreateOptions = {
200
+ ...(o?.libp2p ?? {}),
201
+ };
202
+
203
+ if (useMockSession) {
204
+ libp2pOptions.transports = libp2pOptions.transports ?? transportsFast();
205
+ libp2pOptions.addresses = {
206
+ ...(libp2pOptions.addresses ?? {}),
207
+ listen: libp2pOptions.addresses?.listen ?? listenFast(),
208
+ };
209
+ libp2pOptions.services = {
210
+ ...(libp2pOptions.services ?? {}),
211
+ relay: libp2pOptions.services?.relay ?? null,
212
+ };
213
+ }
214
+
65
215
  return {
66
- ...o?.libp2p,
216
+ ...libp2pOptions,
67
217
  services: {
68
218
  blocks: (c: any) =>
69
219
  new DirectBlock(c, {
@@ -71,7 +221,7 @@ export class TestSession {
71
221
  }),
72
222
  pubsub: (c: any) => new DirectSub(c, { canRelayMessage: true }),
73
223
  keychain: keychain(),
74
- ...o?.libp2p?.services,
224
+ ...libp2pOptions.services,
75
225
  } as any, /// TODO types
76
226
  streamMuxers: [yamux()],
77
227
  connectionMonitor: {