@libp2p/utils 6.7.1 → 6.7.2-a02cb0461

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 (120) hide show
  1. package/README.md +16 -1
  2. package/dist/index.min.js +6 -1
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/abstract-message-stream.d.ts +129 -0
  5. package/dist/src/abstract-message-stream.d.ts.map +1 -0
  6. package/dist/src/abstract-message-stream.js +389 -0
  7. package/dist/src/abstract-message-stream.js.map +1 -0
  8. package/dist/src/abstract-multiaddr-connection.d.ts +26 -0
  9. package/dist/src/abstract-multiaddr-connection.d.ts.map +1 -0
  10. package/dist/src/abstract-multiaddr-connection.js +66 -0
  11. package/dist/src/abstract-multiaddr-connection.js.map +1 -0
  12. package/dist/src/abstract-stream-muxer.d.ts +53 -0
  13. package/dist/src/abstract-stream-muxer.d.ts.map +1 -0
  14. package/dist/src/abstract-stream-muxer.js +169 -0
  15. package/dist/src/abstract-stream-muxer.js.map +1 -0
  16. package/dist/src/abstract-stream.d.ts +14 -130
  17. package/dist/src/abstract-stream.d.ts.map +1 -1
  18. package/dist/src/abstract-stream.js +39 -321
  19. package/dist/src/abstract-stream.js.map +1 -1
  20. package/dist/src/errors.d.ts +8 -0
  21. package/dist/src/errors.d.ts.map +1 -1
  22. package/dist/src/errors.js +8 -0
  23. package/dist/src/errors.js.map +1 -1
  24. package/dist/src/index.d.ts +33 -1
  25. package/dist/src/index.d.ts.map +1 -1
  26. package/dist/src/index.js +33 -1
  27. package/dist/src/index.js.map +1 -1
  28. package/dist/src/length-prefixed-decoder.d.ts +37 -0
  29. package/dist/src/length-prefixed-decoder.d.ts.map +1 -0
  30. package/dist/src/length-prefixed-decoder.js +64 -0
  31. package/dist/src/length-prefixed-decoder.js.map +1 -0
  32. package/dist/src/message-queue.d.ts +61 -0
  33. package/dist/src/message-queue.d.ts.map +1 -0
  34. package/dist/src/message-queue.js +93 -0
  35. package/dist/src/message-queue.js.map +1 -0
  36. package/dist/src/mock-muxer.d.ts +57 -0
  37. package/dist/src/mock-muxer.d.ts.map +1 -0
  38. package/dist/src/mock-muxer.js +204 -0
  39. package/dist/src/mock-muxer.js.map +1 -0
  40. package/dist/src/mock-stream.d.ts +31 -0
  41. package/dist/src/mock-stream.d.ts.map +1 -0
  42. package/dist/src/mock-stream.js +69 -0
  43. package/dist/src/mock-stream.js.map +1 -0
  44. package/dist/src/multiaddr/index.d.ts +7 -0
  45. package/dist/src/multiaddr/index.d.ts.map +1 -0
  46. package/dist/src/multiaddr/index.js +7 -0
  47. package/dist/src/multiaddr/index.js.map +1 -0
  48. package/dist/src/multiaddr-connection-pair.d.ts +25 -0
  49. package/dist/src/multiaddr-connection-pair.d.ts.map +1 -0
  50. package/dist/src/multiaddr-connection-pair.js +103 -0
  51. package/dist/src/multiaddr-connection-pair.js.map +1 -0
  52. package/dist/src/queue/index.d.ts +5 -0
  53. package/dist/src/queue/index.d.ts.map +1 -1
  54. package/dist/src/queue/index.js +24 -9
  55. package/dist/src/queue/index.js.map +1 -1
  56. package/dist/src/rate-limiter.d.ts +1 -15
  57. package/dist/src/rate-limiter.d.ts.map +1 -1
  58. package/dist/src/rate-limiter.js +1 -14
  59. package/dist/src/rate-limiter.js.map +1 -1
  60. package/dist/src/socket-writer.browser.d.ts +2 -0
  61. package/dist/src/socket-writer.browser.d.ts.map +1 -0
  62. package/dist/src/socket-writer.browser.js +4 -0
  63. package/dist/src/socket-writer.browser.js.map +1 -0
  64. package/dist/src/socket-writer.d.ts +19 -0
  65. package/dist/src/socket-writer.d.ts.map +1 -0
  66. package/dist/src/socket-writer.js +43 -0
  67. package/dist/src/socket-writer.js.map +1 -0
  68. package/dist/src/stream-pair.d.ts +42 -0
  69. package/dist/src/stream-pair.d.ts.map +1 -0
  70. package/dist/src/stream-pair.js +40 -0
  71. package/dist/src/stream-pair.js.map +1 -0
  72. package/dist/src/stream-utils.d.ts +199 -0
  73. package/dist/src/stream-utils.d.ts.map +1 -0
  74. package/dist/src/stream-utils.js +369 -0
  75. package/dist/src/stream-utils.js.map +1 -0
  76. package/package.json +19 -163
  77. package/src/abstract-message-stream.ts +549 -0
  78. package/src/abstract-multiaddr-connection.ts +93 -0
  79. package/src/abstract-stream-muxer.ts +239 -0
  80. package/src/abstract-stream.ts +51 -464
  81. package/src/errors.ts +10 -0
  82. package/src/index.ts +33 -1
  83. package/src/length-prefixed-decoder.ts +98 -0
  84. package/src/message-queue.ts +156 -0
  85. package/src/mock-muxer.ts +304 -0
  86. package/src/mock-stream.ts +101 -0
  87. package/src/multiaddr/index.ts +6 -0
  88. package/src/multiaddr-connection-pair.ts +147 -0
  89. package/src/queue/index.ts +30 -9
  90. package/src/rate-limiter.ts +3 -30
  91. package/src/socket-writer.browser.ts +3 -0
  92. package/src/socket-writer.ts +64 -0
  93. package/src/stream-pair.ts +90 -0
  94. package/src/stream-utils.ts +874 -0
  95. package/dist/src/abort-options.d.ts +0 -7
  96. package/dist/src/abort-options.d.ts.map +0 -1
  97. package/dist/src/abort-options.js +0 -14
  98. package/dist/src/abort-options.js.map +0 -1
  99. package/dist/src/array-equals.d.ts +0 -24
  100. package/dist/src/array-equals.d.ts.map +0 -1
  101. package/dist/src/array-equals.js +0 -31
  102. package/dist/src/array-equals.js.map +0 -1
  103. package/dist/src/close-source.d.ts +0 -4
  104. package/dist/src/close-source.d.ts.map +0 -1
  105. package/dist/src/close-source.js +0 -11
  106. package/dist/src/close-source.js.map +0 -1
  107. package/dist/src/close.d.ts +0 -21
  108. package/dist/src/close.d.ts.map +0 -1
  109. package/dist/src/close.js +0 -49
  110. package/dist/src/close.js.map +0 -1
  111. package/dist/src/stream-to-ma-conn.d.ts +0 -23
  112. package/dist/src/stream-to-ma-conn.d.ts.map +0 -1
  113. package/dist/src/stream-to-ma-conn.js +0 -75
  114. package/dist/src/stream-to-ma-conn.js.map +0 -1
  115. package/dist/typedoc-urls.json +0 -147
  116. package/src/abort-options.ts +0 -20
  117. package/src/array-equals.ts +0 -34
  118. package/src/close-source.ts +0 -14
  119. package/src/close.ts +0 -65
  120. package/src/stream-to-ma-conn.ts +0 -105
@@ -0,0 +1,147 @@
1
+ import { StreamMessageEvent } from '@libp2p/interface'
2
+ import { defaultLogger } from '@libp2p/logger'
3
+ import { multiaddr } from '@multiformats/multiaddr'
4
+ import { pEvent } from 'p-event'
5
+ import { raceSignal } from 'race-signal'
6
+ import { AbstractMultiaddrConnection } from './abstract-multiaddr-connection.ts'
7
+ import { MessageQueue } from './message-queue.ts'
8
+ import type { SendResult } from './abstract-message-stream.ts'
9
+ import type { AbstractMultiaddrConnectionInit } from './abstract-multiaddr-connection.ts'
10
+ import type { MessageQueueEvents, MessageQueueInit } from './message-queue.ts'
11
+ import type { AbortOptions, Logger, MultiaddrConnection, MessageStreamDirection, TypedEventTarget } from '@libp2p/interface'
12
+ import type { Multiaddr } from '@multiformats/multiaddr'
13
+ import type { Uint8ArrayList } from 'uint8arraylist'
14
+
15
+ interface MockMultiaddrConnectionMessages extends MessageQueueEvents {
16
+ close: Event
17
+ pause: Event
18
+ resume: Event
19
+ }
20
+
21
+ export interface MockMultiaddrConnectionInit extends AbstractMultiaddrConnectionInit {
22
+ id: string,
23
+ log: Logger,
24
+ direction: MessageStreamDirection
25
+ local: MessageQueue<MockMultiaddrConnectionMessages>
26
+ remote: TypedEventTarget<MockMultiaddrConnectionMessages>
27
+ remoteAddr: Multiaddr
28
+ }
29
+
30
+ let multiaddrConnectionId = 0
31
+
32
+ class MockMultiaddrConnection extends AbstractMultiaddrConnection {
33
+ private local: MessageQueue<MockMultiaddrConnectionMessages>
34
+ private remote: TypedEventTarget<MockMultiaddrConnectionMessages>
35
+
36
+ constructor (init: MockMultiaddrConnectionInit) {
37
+ super(init)
38
+
39
+ this.local = init.local
40
+ this.remote = init.remote
41
+
42
+ this.local.addEventListener('drain', () => {
43
+ this.safeDispatchEvent('drain')
44
+ })
45
+
46
+ this.remote.addEventListener('message', (evt) => {
47
+ if (this.status !== 'open') {
48
+ return
49
+ }
50
+
51
+ this.onData(evt.data)
52
+ })
53
+ this.remote.addEventListener('reset', (evt) => {
54
+ if (this.status !== 'open') {
55
+ return
56
+ }
57
+
58
+ this.onRemoteReset()
59
+ })
60
+ this.remote.addEventListener('close', (evt) => {
61
+ this.onTransportClosed()
62
+ })
63
+ this.remote.addEventListener('pause', (evt) => {
64
+ this.local.pause()
65
+ })
66
+ this.remote.addEventListener('resume', (evt) => {
67
+ this.local.resume()
68
+ })
69
+ }
70
+
71
+ sendData (data: Uint8ArrayList): SendResult {
72
+ const canSendMore = this.local.send(new StreamMessageEvent(data))
73
+
74
+ return {
75
+ sentBytes: data.byteLength,
76
+ canSendMore
77
+ }
78
+ }
79
+
80
+ sendReset (): void {
81
+ this.local.send(new Event('reset'))
82
+ }
83
+
84
+ async sendClose (options?: AbortOptions): Promise<void> {
85
+ if (this.local.needsDrain) {
86
+ await pEvent(this.local, 'drain', {
87
+ signal: options?.signal
88
+ })
89
+ }
90
+
91
+ return raceSignal(new Promise<void>((resolve, reject) => {
92
+ this.local.send(new Event('close'))
93
+ this.local.onIdle().then(resolve, reject)
94
+ }), options?.signal)
95
+ }
96
+
97
+ sendPause (): void {
98
+ this.local.send(new Event('pause'))
99
+ }
100
+
101
+ sendResume (): void {
102
+ this.local.send(new Event('resume'))
103
+ }
104
+ }
105
+
106
+ export interface MultiaddrConnectionPairOptions extends MessageQueueInit {
107
+ outbound?: Partial<MockMultiaddrConnectionInit>
108
+ inbound?: Partial<MockMultiaddrConnectionInit>
109
+ }
110
+
111
+ export function multiaddrConnectionPair (opts: MultiaddrConnectionPairOptions = {}): [MultiaddrConnection, MultiaddrConnection] {
112
+ const inboundId = `${multiaddrConnectionId++}`
113
+ const outboundId = `${multiaddrConnectionId++}`
114
+
115
+ const outboundLog = defaultLogger().forComponent(`libp2p:mock-maconn:outbound:${inboundId}`)
116
+ const inboundLog = defaultLogger().forComponent(`libp2p:mock-maconn:inbound:${outboundId}`)
117
+
118
+ const targetA = new MessageQueue<MockMultiaddrConnectionMessages>({
119
+ ...opts,
120
+ log: outboundLog
121
+ })
122
+ const targetB = new MessageQueue<MockMultiaddrConnectionMessages>({
123
+ ...opts,
124
+ log: inboundLog
125
+ })
126
+
127
+ return [
128
+ new MockMultiaddrConnection({
129
+ ...opts.outbound,
130
+ id: outboundId,
131
+ direction: 'outbound',
132
+ local: targetA,
133
+ remote: targetB,
134
+ remoteAddr: opts?.outbound?.remoteAddr ?? multiaddr(`/ip4/127.0.0.1/tcp/${outboundId}`),
135
+ log: outboundLog
136
+ }),
137
+ new MockMultiaddrConnection({
138
+ ...opts.inbound,
139
+ id: inboundId,
140
+ direction: 'inbound',
141
+ local: targetB,
142
+ remote: targetA,
143
+ remoteAddr: opts?.inbound?.remoteAddr ?? multiaddr(`/ip4/127.0.0.1/tcp/${inboundId}`),
144
+ log: inboundLog
145
+ })
146
+ ]
147
+ }
@@ -1,7 +1,7 @@
1
1
  import { AbortError } from '@libp2p/interface'
2
2
  import { pushable } from 'it-pushable'
3
3
  import { TypedEventEmitter } from 'main-event'
4
- import { raceEvent } from 'race-event'
4
+ import { pEvent } from 'p-event'
5
5
  import { debounce } from '../debounce.js'
6
6
  import { QueueFullError } from '../errors.js'
7
7
  import { Job } from './job.js'
@@ -101,6 +101,8 @@ export interface QueueEvents<JobReturnType, JobOptions extends AbortOptions = Ab
101
101
 
102
102
  /**
103
103
  * A job has failed
104
+ *
105
+ * @deprecated Listen for the 'failure' event instead - it gives more context and is generally more useful, this event will be removed in a future release
104
106
  */
105
107
  error: CustomEvent<Error>
106
108
 
@@ -129,6 +131,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
129
131
  public queue: Array<Job<JobOptions, JobReturnType>>
130
132
  private pending: number
131
133
  private readonly sort?: Comparator<Job<JobOptions, JobReturnType>>
134
+ private paused: boolean
132
135
 
133
136
  constructor (init: QueueInit<JobReturnType, JobOptions> = {}) {
134
137
  super()
@@ -136,6 +139,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
136
139
  this.concurrency = init.concurrency ?? Number.POSITIVE_INFINITY
137
140
  this.maxSize = init.maxSize ?? Number.POSITIVE_INFINITY
138
141
  this.pending = 0
142
+ this.paused = false
139
143
 
140
144
  if (init.metricName != null) {
141
145
  init.metrics?.registerMetricGroup(init.metricName, {
@@ -172,7 +176,24 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
172
176
  this.safeDispatchEvent('idle')
173
177
  }
174
178
 
179
+ pause (): void {
180
+ this.paused = true
181
+ }
182
+
183
+ resume (): void {
184
+ if (!this.paused) {
185
+ return
186
+ }
187
+
188
+ this.paused = false
189
+ this.tryToStartAnother()
190
+ }
191
+
175
192
  private tryToStartAnother (): boolean {
193
+ if (this.paused) {
194
+ return false
195
+ }
196
+
176
197
  if (this.size === 0) {
177
198
  this.emitEmpty()
178
199
 
@@ -263,7 +284,6 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
263
284
  }
264
285
  }
265
286
 
266
- this.safeDispatchEvent('error', { detail: err })
267
287
  this.safeDispatchEvent('failure', { detail: { job, error: err } })
268
288
 
269
289
  throw err
@@ -299,7 +319,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
299
319
  return
300
320
  }
301
321
 
302
- await raceEvent(this, 'empty', options?.signal)
322
+ await pEvent(this, 'empty', options)
303
323
  }
304
324
 
305
325
  /**
@@ -319,7 +339,8 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
319
339
  return
320
340
  }
321
341
 
322
- await raceEvent(this, 'next', options?.signal, {
342
+ await pEvent(this, 'next', {
343
+ ...options,
323
344
  filter: () => this.size < limit
324
345
  })
325
346
  }
@@ -338,7 +359,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
338
359
  return
339
360
  }
340
361
 
341
- await raceEvent(this, 'idle', options?.signal)
362
+ await pEvent(this, 'idle', options)
342
363
  }
343
364
 
344
365
  /**
@@ -395,8 +416,8 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
395
416
  }
396
417
  }
397
418
 
398
- const onQueueError = (evt: CustomEvent<Error>): void => {
399
- cleanup(evt.detail)
419
+ const onQueueFailure = (evt: CustomEvent<QueueJobFailure<JobReturnType, JobOptions>>): void => {
420
+ cleanup(evt.detail.error)
400
421
  }
401
422
 
402
423
  const onQueueIdle = (): void => {
@@ -410,7 +431,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
410
431
 
411
432
  // add listeners
412
433
  this.addEventListener('completed', onQueueJobComplete)
413
- this.addEventListener('error', onQueueError)
434
+ this.addEventListener('failure', onQueueFailure)
414
435
  this.addEventListener('idle', onQueueIdle)
415
436
  options?.signal?.addEventListener('abort', onSignalAbort)
416
437
 
@@ -419,7 +440,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
419
440
  } finally {
420
441
  // remove listeners
421
442
  this.removeEventListener('completed', onQueueJobComplete)
422
- this.removeEventListener('error', onQueueError)
443
+ this.removeEventListener('failure', onQueueFailure)
423
444
  this.removeEventListener('idle', onQueueIdle)
424
445
  options?.signal?.removeEventListener('abort', onSignalAbort)
425
446
 
@@ -1,4 +1,3 @@
1
- import delay from 'delay'
2
1
  import { RateLimitError } from './errors.js'
3
2
 
4
3
  export interface RateLimiterInit {
@@ -23,20 +22,6 @@ export interface RateLimiterInit {
23
22
  */
24
23
  blockDuration?: number
25
24
 
26
- /**
27
- * Execute allowed actions evenly over duration
28
- *
29
- * @default false
30
- */
31
- execEvenly?: boolean
32
-
33
- /**
34
- * ms, works with execEvenly=true option
35
- *
36
- * @default duration * 1000 / points
37
- */
38
- execEvenlyMinDelayMs?: number
39
-
40
25
  /**
41
26
  * @default "rlflx"
42
27
  */
@@ -65,21 +50,17 @@ export class RateLimiter {
65
50
  protected points: number
66
51
  protected duration: number
67
52
  protected blockDuration: number
68
- protected execEvenly: boolean
69
- protected execEvenlyMinDelayMs: number
70
53
  protected keyPrefix: string
71
54
 
72
55
  constructor (opts: RateLimiterInit = {}) {
73
56
  this.points = opts.points ?? 4
74
57
  this.duration = opts.duration ?? 1
75
58
  this.blockDuration = opts.blockDuration ?? 0
76
- this.execEvenly = opts.execEvenly ?? false
77
- this.execEvenlyMinDelayMs = opts.execEvenlyMinDelayMs ?? (this.duration * 1000 / this.points)
78
59
  this.keyPrefix = opts.keyPrefix ?? 'rlflx'
79
60
  this.memoryStorage = new MemoryStorage()
80
61
  }
81
62
 
82
- async consume (key: string, pointsToConsume: number = 1, options: GetKeySecDurationOptions = {}): Promise<RateLimiterResult> {
63
+ consume (key: string, pointsToConsume: number = 1, options: GetKeySecDurationOptions = {}): RateLimiterResult {
83
64
  const rlKey = this.getKey(key)
84
65
  const secDuration = this._getKeySecDuration(options)
85
66
  let res = this.memoryStorage.incrby(rlKey, pointsToConsume, secDuration)
@@ -93,14 +74,6 @@ export class RateLimiter {
93
74
  }
94
75
 
95
76
  throw new RateLimitError('Rate limit exceeded', res)
96
- } else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
97
- // Execute evenly
98
- let delayMs = Math.ceil(res.msBeforeNext / (res.remainingPoints + 2))
99
- if (delayMs < this.execEvenlyMinDelayMs) {
100
- delayMs = res.consumedPoints * this.execEvenlyMinDelayMs
101
- }
102
-
103
- await delay(delayMs)
104
77
  }
105
78
 
106
79
  return res
@@ -241,8 +214,8 @@ export class MemoryStorage {
241
214
  this.storage.delete(key)
242
215
  }, durationMs)
243
216
 
244
- if (record.timeoutId.unref != null) {
245
- record.timeoutId.unref()
217
+ if ((record.timeoutId as any).unref != null) {
218
+ (record.timeoutId as any).unref()
246
219
  }
247
220
  }
248
221
 
@@ -0,0 +1,3 @@
1
+ export function socketWriter (): void {
2
+ throw new Error('Unsupported in browsers')
3
+ }
@@ -0,0 +1,64 @@
1
+ import stream from 'node:stream'
2
+ import { Uint8ArrayList } from 'uint8arraylist'
3
+
4
+ export interface SocketWriter {
5
+ /**
6
+ * Write any available data into the socket, if the socket's internal write
7
+ * buffer has available capacity
8
+ */
9
+ pull (): boolean
10
+
11
+ /**
12
+ * Write data into the socket, returns false if the socket's internal write
13
+ * buffer is at capacity
14
+ */
15
+ write (data: Uint8Array | Uint8Array[] | Uint8ArrayList): boolean
16
+ }
17
+
18
+ /**
19
+ * @deprecated delete if unused
20
+ */
21
+ export function socketWriter (socket: stream.Duplex): SocketWriter {
22
+ const queue = new Uint8ArrayList()
23
+
24
+ return {
25
+ pull (): boolean {
26
+ if (socket.writableNeedDrain) {
27
+ return false
28
+ }
29
+
30
+ for (const buf of queue) {
31
+ queue.consume(buf.byteLength)
32
+
33
+ if (!socket.write(buf)) {
34
+ // continue writing after drain event. this is a synchronous operation
35
+ // so it will not interleave with the `this.writeToSocket()`
36
+ // invocation in this.sendData so all data will be sent in-order
37
+ if (queue.byteLength > 0) {
38
+ socket.once('drain', () => {
39
+ this.pull()
40
+ })
41
+ }
42
+
43
+ return false
44
+ }
45
+ }
46
+
47
+ return true
48
+ },
49
+
50
+ write (data: Uint8Array | Uint8Array[] | Uint8ArrayList): boolean {
51
+ if (Array.isArray(data)) {
52
+ queue.appendAll(data)
53
+ } else {
54
+ queue.append(data)
55
+ }
56
+
57
+ if (socket.writableNeedDrain) {
58
+ return false
59
+ }
60
+
61
+ return this.pull()
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,90 @@
1
+ import { pEvent } from 'p-event'
2
+ import { mockMuxer } from './mock-muxer.ts'
3
+ import { multiaddrConnectionPair } from './multiaddr-connection-pair.ts'
4
+ import { echo } from './stream-utils.ts'
5
+ import type { MockMultiaddrConnectionInit } from './multiaddr-connection-pair.ts'
6
+ import type { Stream, StreamOptions } from '@libp2p/interface'
7
+
8
+ export interface StreamPairOptions {
9
+ /**
10
+ * How long to wait in ms before sending messages
11
+ *
12
+ * @default 1
13
+ */
14
+ delay?: number
15
+
16
+ /**
17
+ * If more than this many messages are sent within delay, write backpressure
18
+ * will be applied
19
+ */
20
+ capacity?: number
21
+
22
+ /**
23
+ * Simulate having pre-negotiated a protocol by passing it here
24
+ */
25
+ protocol?: string
26
+
27
+ /**
28
+ * Configuration options for the outbound stream
29
+ */
30
+ outbound?: StreamOptions
31
+
32
+ /**
33
+ * Configuration options for underlying outbound connection
34
+ */
35
+ outboundConnection?: Partial<MockMultiaddrConnectionInit>
36
+
37
+ /**
38
+ * Configuration options for the inbound stream
39
+ */
40
+ inbound?: StreamOptions
41
+
42
+ /**
43
+ * Configuration options for underlying inbound connection
44
+ */
45
+ inboundConnection?: Partial<MockMultiaddrConnectionInit>
46
+ }
47
+
48
+ /**
49
+ * Returns two streams connected to each other with a slight delay in sending
50
+ * messages to simulate a network
51
+ */
52
+ export async function streamPair (opts: StreamPairOptions = {}): Promise<[Stream, Stream]> {
53
+ const [outboundConnection, inboundConnection] = multiaddrConnectionPair({
54
+ ...opts,
55
+ outbound: opts.outboundConnection,
56
+ inbound: opts.inboundConnection
57
+ })
58
+
59
+ const localMuxer = mockMuxer({
60
+ streamOptions: opts.outbound
61
+ }).createStreamMuxer(outboundConnection)
62
+ const remoteMuxer = mockMuxer({
63
+ streamOptions: opts.inbound
64
+ }).createStreamMuxer(inboundConnection)
65
+
66
+ const [
67
+ inboundStream,
68
+ outboundStream
69
+ ] = await Promise.all([
70
+ pEvent<'stream', CustomEvent<Stream>>(remoteMuxer, 'stream').then(evt => {
71
+ return evt.detail
72
+ }),
73
+ localMuxer.createStream({
74
+ ...opts.outbound,
75
+ protocol: opts.protocol
76
+ })
77
+ ])
78
+
79
+ return [
80
+ outboundStream,
81
+ inboundStream
82
+ ]
83
+ }
84
+
85
+ export async function echoStream (opts: StreamPairOptions = {}): Promise<Stream> {
86
+ const [outbound, inbound] = await streamPair(opts)
87
+ echo(inbound)
88
+
89
+ return outbound
90
+ }