@fails-components/webtransport 0.0.9 → 0.1.0-macarmbuild.6

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 (90) hide show
  1. package/CMakeLists.txt +110 -73
  2. package/build.js +32 -8
  3. package/dist/lib/client.d.ts +74 -0
  4. package/dist/lib/client.d.ts.map +1 -0
  5. package/dist/lib/dom.d.ts +70 -0
  6. package/dist/lib/dom.d.ts.map +1 -0
  7. package/dist/lib/event-loop.d.ts +26 -0
  8. package/dist/lib/event-loop.d.ts.map +1 -0
  9. package/dist/lib/index.d.ts +79 -0
  10. package/dist/lib/index.d.ts.map +1 -0
  11. package/dist/lib/native.d.ts +2 -0
  12. package/dist/lib/native.d.ts.map +1 -0
  13. package/dist/lib/server.d.ts +75 -0
  14. package/dist/lib/server.d.ts.map +1 -0
  15. package/dist/lib/session.d.ts +221 -0
  16. package/dist/lib/session.d.ts.map +1 -0
  17. package/dist/lib/stream.d.ts +116 -0
  18. package/dist/lib/stream.d.ts.map +1 -0
  19. package/dist/lib/transport.d.ts +25 -0
  20. package/dist/lib/transport.d.ts.map +1 -0
  21. package/dist/lib/types.d.ts +157 -0
  22. package/dist/lib/types.d.ts.map +1 -0
  23. package/dist/lib/utils.d.ts +6 -0
  24. package/dist/lib/utils.d.ts.map +1 -0
  25. package/dist/lib/webtransport.d.ts +35 -0
  26. package/dist/lib/webtransport.d.ts.map +1 -0
  27. package/dist/test/bidirectional-streams.spec.d.ts +5 -0
  28. package/dist/test/bidirectional-streams.spec.d.ts.map +1 -0
  29. package/dist/test/datagrams.spec.d.ts +5 -0
  30. package/dist/test/datagrams.spec.d.ts.map +1 -0
  31. package/dist/test/echoclient.d.ts +2 -0
  32. package/dist/test/echoclient.d.ts.map +1 -0
  33. package/dist/test/echoserver.d.ts +2 -0
  34. package/dist/test/echoserver.d.ts.map +1 -0
  35. package/dist/test/event-loop.spec.d.ts +2 -0
  36. package/dist/test/event-loop.spec.d.ts.map +1 -0
  37. package/dist/test/fixtures/certificate.d.ts +21 -0
  38. package/dist/test/fixtures/certificate.d.ts.map +1 -0
  39. package/dist/test/fixtures/chai.d.ts +2 -0
  40. package/dist/test/fixtures/chai.d.ts.map +1 -0
  41. package/dist/test/fixtures/read-stream.d.ts +10 -0
  42. package/dist/test/fixtures/read-stream.d.ts.map +1 -0
  43. package/dist/test/fixtures/reader-value.d.ts +7 -0
  44. package/dist/test/fixtures/reader-value.d.ts.map +1 -0
  45. package/dist/test/fixtures/server.d.ts +10 -0
  46. package/dist/test/fixtures/server.d.ts.map +1 -0
  47. package/dist/test/fixtures/write-stream.d.ts +10 -0
  48. package/dist/test/fixtures/write-stream.d.ts.map +1 -0
  49. package/dist/test/test.d.ts +2 -0
  50. package/dist/test/test.d.ts.map +1 -0
  51. package/dist/test/testsuite.d.ts +25 -0
  52. package/dist/test/testsuite.d.ts.map +1 -0
  53. package/dist/test/unidirectional-streams.spec.d.ts +5 -0
  54. package/dist/test/unidirectional-streams.spec.d.ts.map +1 -0
  55. package/lib/client.js +163 -0
  56. package/lib/dom.ts +95 -0
  57. package/lib/event-loop.js +79 -0
  58. package/lib/index.js +33 -0
  59. package/lib/native.js +25 -0
  60. package/lib/server.js +165 -0
  61. package/lib/session.js +422 -0
  62. package/lib/stream.js +325 -0
  63. package/lib/transport.js +42 -0
  64. package/lib/types.ts +181 -0
  65. package/lib/utils.js +22 -0
  66. package/lib/webtransport.js +114 -0
  67. package/package.json +18 -6
  68. package/readme.md +28 -5
  69. package/src/http3client.h +0 -1
  70. package/src/http3eventloop.cc +52 -0
  71. package/src/http3eventloop.h +22 -1
  72. package/src/http3server.cc +4 -1
  73. package/src/http3server.h +8 -0
  74. package/src/http3serversession.h +1 -1
  75. package/test/bidirectional-streams.spec.js +138 -0
  76. package/test/datagrams.spec.js +132 -0
  77. package/test/echoclient.js +10 -6
  78. package/test/echoserver.js +6 -8
  79. package/test/event-loop.spec.js +24 -0
  80. package/test/{certificate.js → fixtures/certificate.js} +31 -15
  81. package/test/fixtures/chai.js +6 -0
  82. package/test/fixtures/read-stream.js +36 -0
  83. package/test/fixtures/reader-value.js +24 -0
  84. package/test/fixtures/server.js +58 -0
  85. package/test/fixtures/write-stream.js +17 -0
  86. package/test/test.js +29 -3
  87. package/test/testsuite.js +22 -0
  88. package/test/unidirectional-streams.spec.js +128 -0
  89. package/tsconfig.json +40 -0
  90. package/src/webtransport.js +0 -870
@@ -0,0 +1,24 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { expect } from './fixtures/chai.js'
4
+ import { Http3EventLoop } from '../lib/event-loop.js'
5
+
6
+ describe.skip('event-loop', () => {
7
+ beforeEach(() => {
8
+ if (Http3EventLoop.globalLoop != null) {
9
+ // shut down loop, otherwise we have to wait for
10
+ // it to time out which takes a long time.
11
+ Http3EventLoop.globalLoop.shutdownEventLoop()
12
+ }
13
+ })
14
+
15
+ it('should start and stop the event loop', () => {
16
+ expect(Http3EventLoop.globalLoop).to.be.null()
17
+
18
+ Http3EventLoop.createGlobalEventLoop()
19
+ expect(Http3EventLoop.globalLoop).to.not.be.null()
20
+
21
+ Http3EventLoop.globalLoop?.shutdownEventLoop()
22
+ expect(Http3EventLoop.globalLoop).to.be.null()
23
+ })
24
+ })
@@ -53,16 +53,16 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53
53
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54
54
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
55
55
 
56
+ // @ts-expect-error node-forge has no types and @types/node-forge do not include oids
56
57
  import forge from 'node-forge'
57
- import { webcrypto as crypto } from 'crypto'
58
- import { X509Certificate } from 'crypto'
58
+ import { webcrypto as crypto, X509Certificate } from 'crypto'
59
59
 
60
60
  const { pki, asn1, oids } = forge
61
61
  // taken from node-forge
62
62
  /**
63
63
  * Converts an X.509 subject or issuer to an ASN.1 RDNSequence.
64
64
  *
65
- * @param obj the subject or issuer (distinguished name).
65
+ * @param {any} obj the subject or issuer (distinguished name).
66
66
  *
67
67
  * @return the ASN.1 RDNSequence.
68
68
  */
@@ -110,19 +110,19 @@ function _dnToAsn1(obj) {
110
110
  return rval
111
111
  }
112
112
 
113
+ const jan_1_1950 = new Date('1950-01-01T00:00:00Z') // eslint-disable-line camelcase
114
+ const jan_1_2050 = new Date('2050-01-01T00:00:00Z') // eslint-disable-line camelcase
113
115
  // taken from node-forge almost not modified
114
116
  /**
115
117
  * Converts a Date object to ASN.1
116
118
  * Handles the different format before and after 1st January 2050
117
119
  *
118
- * @param date date object.
120
+ * @param {Date} date date object.
119
121
  *
120
122
  * @return the ASN.1 object representing the date.
121
123
  */
122
-
123
- const jan_1_1950 = new Date('1950-01-01T00:00:00Z')
124
- const jan_1_2050 = new Date('2050-01-01T00:00:00Z')
125
124
  function _dateToAsn1(date) {
125
+ // eslint-disable-next-line camelcase
126
126
  if (date >= jan_1_1950 && date < jan_1_2050) {
127
127
  return asn1.create(
128
128
  asn1.Class.UNIVERSAL,
@@ -144,15 +144,15 @@ function _dateToAsn1(date) {
144
144
  /**
145
145
  * Convert signature parameters object to ASN.1
146
146
  *
147
- * @param {String} oid Signature algorithm OID
148
- * @param params The signature parametrs object
147
+ * @param {string} oid Signature algorithm OID
148
+ * @param {any} params The signature parameters object
149
149
  * @return ASN.1 object representing signature parameters
150
150
  */
151
151
  function _signatureParametersToAsn1(oid, params) {
152
+ const parts = []
153
+
152
154
  switch (oid) {
153
155
  case oids['RSASSA-PSS']:
154
- const parts = []
155
-
156
156
  if (params.hash.algorithmOid !== undefined) {
157
157
  parts.push(
158
158
  asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
@@ -217,7 +217,7 @@ function _signatureParametersToAsn1(oid, params) {
217
217
  /**
218
218
  * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate.
219
219
  *
220
- * @param cert the certificate.
220
+ * @param {any} cert the certificate.
221
221
  *
222
222
  * @return the asn1 TBSCertificate.
223
223
  */
@@ -319,6 +319,10 @@ function getTBSCertificate(cert) {
319
319
  // because serial numbers use ones' complement notation
320
320
  // this RFC in section 4.1.2.2 requires serial numbers to be positive
321
321
  // http://www.ietf.org/rfc/rfc5280.txt
322
+ /**
323
+ * @param {string} hexString
324
+ * @returns
325
+ */
322
326
  function toPositiveHex(hexString) {
323
327
  let mostSiginficativeHexAsInt = parseInt(hexString[0], 16)
324
328
  if (mostSiginficativeHexAsInt < 8) {
@@ -330,9 +334,21 @@ function toPositiveHex(hexString) {
330
334
  }
331
335
 
332
336
  // the next is an edit of the selfsigned function reduced to the function necessary for webtransport
337
+ /**
338
+ * @typedef {object} Certificate
339
+ * @property {string} public
340
+ * @property {string} private
341
+ * @property {string} cert
342
+ * @property {Uint8Array} hash
343
+ * @property {string} fingerprint
344
+ *
345
+ * @param {*} attrs
346
+ * @param {*} options
347
+ * @returns {Promise<Certificate | null>}
348
+ */
333
349
  export async function generateWebTransportCertificate(attrs, options) {
334
350
  try {
335
- let keyPair = await crypto.subtle.generateKey(
351
+ const keyPair = await crypto.subtle.generateKey(
336
352
  {
337
353
  name: 'ECDSA',
338
354
  namedCurve: 'P-256'
@@ -355,7 +371,7 @@ export async function generateWebTransportCertificate(attrs, options) {
355
371
  cert.setSubject(attrs)
356
372
  cert.setIssuer(attrs)
357
373
 
358
- let privateKey = crypto.subtle.exportKey('pkcs8', keyPair.privateKey)
374
+ const privateKey = crypto.subtle.exportKey('pkcs8', keyPair.privateKey)
359
375
  const publicKey = (cert.publicKey = await crypto.subtle.exportKey(
360
376
  'spki',
361
377
  keyPair.publicKey
@@ -392,7 +408,7 @@ export async function generateWebTransportCertificate(attrs, options) {
392
408
  oids['1.2.840.10045.4.3.2'] = 'ecdsa-with-sha256'
393
409
  oids['ecdsa-with-sha256'] = '1.2.840.10045.4.3.2'
394
410
 
395
- cert.siginfo.algorithmOid = cert.signatureOid = '1.2.840.10045.4.3.2' //'ecdsa-with-sha256'
411
+ cert.siginfo.algorithmOid = cert.signatureOid = '1.2.840.10045.4.3.2' // 'ecdsa-with-sha256'
396
412
 
397
413
  cert.tbsCertificate = getTBSCertificate(cert)
398
414
  const encoded = Buffer.from(
@@ -0,0 +1,6 @@
1
+ import chai from 'chai'
2
+ import dirtyChai from 'dirty-chai'
3
+
4
+ chai.use(dirtyChai)
5
+
6
+ export const expect = chai.expect
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Read a stream contents to the end and return it
3
+ *
4
+ * @template T
5
+ * @param {ReadableStream<T>} readable
6
+ * @param {number} [expected]
7
+ * @returns
8
+ */
9
+ export async function readStream(readable, expected) {
10
+ const reader = readable.getReader()
11
+
12
+ try {
13
+ /** @type {T[]} */
14
+ const output = []
15
+
16
+ while (true) {
17
+ const { done, value } = await reader.read()
18
+
19
+ if (done) {
20
+ break
21
+ }
22
+
23
+ if (value != null) {
24
+ output.push(value)
25
+ }
26
+
27
+ if (expected != null && output.length === expected) {
28
+ break
29
+ }
30
+ }
31
+
32
+ return output
33
+ } finally {
34
+ reader.releaseLock()
35
+ }
36
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @template T
3
+ * @param {ReadableStream<T>} readableStream
4
+ * @returns {Promise<T>}
5
+ */
6
+ export async function getReaderValue(readableStream) {
7
+ const reader = readableStream.getReader()
8
+
9
+ try {
10
+ const { done, value } = await reader.read()
11
+
12
+ if (done) {
13
+ throw new Error('Stream ended')
14
+ }
15
+
16
+ if (!value) {
17
+ throw new Error('Stream value was undefined')
18
+ }
19
+
20
+ return value
21
+ } finally {
22
+ reader.releaseLock()
23
+ }
24
+ }
@@ -0,0 +1,58 @@
1
+ import { generateWebTransportCertificate } from './certificate.js'
2
+ import { Http3Server } from '../../lib/index.js'
3
+
4
+ export async function createServer() {
5
+ const attrs = [
6
+ { shortName: 'C', value: 'DE' },
7
+ { shortName: 'ST', value: 'Berlin' },
8
+ { shortName: 'L', value: 'Berlin' },
9
+ { shortName: 'O', value: 'WebTransport Test Server' },
10
+ { shortName: 'CN', value: '127.0.0.1' }
11
+ ]
12
+
13
+ const certificate = await generateWebTransportCertificate(attrs, {
14
+ days: 13
15
+ })
16
+
17
+ if (certificate == null) {
18
+ throw new Error('Certificate generation failed')
19
+ }
20
+
21
+ const server = new Http3Server({
22
+ port: 0,
23
+ host: '127.0.0.1',
24
+ secret: 'mysecret',
25
+ cert: certificate.cert, // unclear if it is the correct format
26
+ privKey: certificate.private
27
+ })
28
+
29
+ return {
30
+ server,
31
+ certificate
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @param {import('../../lib/server.js').Http3Server} server
37
+ * @param {string} path
38
+ */
39
+ export async function getServerSession(server, path) {
40
+ const sessionStream = await server.sessionStream(path)
41
+ const sessionReader = sessionStream.getReader()
42
+
43
+ try {
44
+ const { done, value } = await sessionReader.read()
45
+
46
+ if (done) {
47
+ throw new Error('Server is gone')
48
+ }
49
+
50
+ if (!value) {
51
+ throw new Error('Session was undefined')
52
+ }
53
+
54
+ return value
55
+ } finally {
56
+ sessionReader.releaseLock()
57
+ }
58
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Write contents to a stream and close it
3
+ *
4
+ * @template T
5
+ * @param {WritableStream<T>} writable
6
+ * @param {T[]} input
7
+ * @returns
8
+ */
9
+ export async function writeStream(writable, input) {
10
+ const writer = writable.getWriter()
11
+
12
+ for (const buf of input) {
13
+ await writer.write(buf)
14
+ }
15
+
16
+ await writer.close()
17
+ }
package/test/test.js CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  // this file runs various tests
6
6
 
7
- import { generateWebTransportCertificate } from './certificate.js'
8
- import { Http3Server, WebTransport, testcheck } from '../src/webtransport.js'
7
+ import { generateWebTransportCertificate } from './fixtures/certificate.js'
8
+ import { Http3Server, WebTransport, testcheck } from '../lib/index.js'
9
9
  import { echoTestsConnection, runEchoServer } from './testsuite.js'
10
10
 
11
11
  async function run() {
@@ -17,7 +17,28 @@ async function run() {
17
17
  console.log('global event loop gone, everything alright')
18
18
  process.exit(0)
19
19
  }
20
- }, 40 * 1000)
20
+ }, 50 * 1000)
21
+ console.log('try connecting to server that does not exist')
22
+ const badClient = new WebTransport('https://127.0.0.1:49823/echo', {
23
+ serverCertificateHashes: [
24
+ {
25
+ algorithm: 'sha-256',
26
+ value: Buffer.from(
27
+ 'a589bf4f98a0158aa890328d5d3f519b9e2a5b1e61b09eb10b7a9be0e79bf148',
28
+ 'hex'
29
+ )
30
+ }
31
+ ]
32
+ })
33
+ await badClient.ready
34
+ .then(() => {
35
+ console.error('Successfully connected to a non-running server?!')
36
+ process.exit(1)
37
+ })
38
+ .catch(() => {
39
+ console.log('Did not connect to non-running server')
40
+ })
41
+
21
42
  console.log('start generating self signed certificate')
22
43
 
23
44
  const attrs = [
@@ -32,6 +53,10 @@ async function run() {
32
53
  days: 13
33
54
  })
34
55
 
56
+ if (certificate == null) {
57
+ throw new Error('Certificate generation failed')
58
+ }
59
+
35
60
  console.log('start Http3Server and startup echo tests')
36
61
  // now ramp up the server
37
62
  const http3server = new Http3Server({
@@ -52,6 +77,7 @@ async function run() {
52
77
 
53
78
  const url = 'https://127.0.0.1:8080/echo'
54
79
 
80
+ /** @type {import('../lib/dom').WebTransport | null} */
55
81
  let client = new WebTransport(url, {
56
82
  serverCertificateHashes: [{ algorithm: 'sha-256', value: certificate.hash }]
57
83
  })
package/test/testsuite.js CHANGED
@@ -2,6 +2,9 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ /**
6
+ * @param {import('../lib/dom').WebTransport} session
7
+ */
5
8
  export async function incomingBidirectionalEchoTest(session) {
6
9
  try {
7
10
  const bidiReader = session.incomingBidirectionalStreams.getReader()
@@ -24,6 +27,9 @@ export async function incomingBidirectionalEchoTest(session) {
24
27
  }
25
28
  }
26
29
 
30
+ /**
31
+ * @param {import('../lib/dom').WebTransport} session
32
+ */
27
33
  export async function outgoingBidirectionalEchoTest(session) {
28
34
  try {
29
35
  const mybidistream = await session.createBidirectionalStream()
@@ -33,6 +39,9 @@ export async function outgoingBidirectionalEchoTest(session) {
33
39
  }
34
40
  }
35
41
 
42
+ /**
43
+ * @param {import('../lib/dom').WebTransport} session
44
+ */
36
45
  export async function unidirectionalEchoTest(session) {
37
46
  try {
38
47
  const unidiReader = session.incomingUnidirectionalStreams.getReader()
@@ -56,6 +65,9 @@ export async function unidirectionalEchoTest(session) {
56
65
  }
57
66
  }
58
67
 
68
+ /**
69
+ * @param {import('../lib/dom').WebTransport} session
70
+ */
59
71
  export async function datagramEchoTest(session) {
60
72
  try {
61
73
  session.datagrams.readable.pipeTo(session.datagrams.writable)
@@ -64,6 +76,9 @@ export async function datagramEchoTest(session) {
64
76
  }
65
77
  }
66
78
 
79
+ /**
80
+ * @param {import('../lib').Http3Server} server
81
+ */
67
82
  export async function runEchoServer(server) {
68
83
  try {
69
84
  const sessionStream = await server.sessionStream('/echo')
@@ -99,6 +114,10 @@ export async function runEchoServer(server) {
99
114
  }
100
115
  }
101
116
 
117
+ /**
118
+ * @param {ArrayLike<any>} array1
119
+ * @param {ArrayLike<any>} array2
120
+ */
102
121
  function testArraysEqual(array1, array2) {
103
122
  if (array1.length !== array2.length)
104
123
  throw new Error('Array not equal in length')
@@ -107,6 +126,9 @@ function testArraysEqual(array1, array2) {
107
126
  }
108
127
  }
109
128
 
129
+ /**
130
+ * @param {import('../lib/dom').WebTransport} transport
131
+ */
110
132
  export async function echoTestsConnection(transport) {
111
133
  // some echo tests for testing the webtransport library, not for production
112
134
  const stream = await transport.createBidirectionalStream()
@@ -0,0 +1,128 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { createServer } from './fixtures/server.js'
4
+ import { getReaderValue } from './fixtures/reader-value.js'
5
+ import { WebTransport } from '../lib/index.js'
6
+ import { expect } from 'chai'
7
+ import { readStream } from './fixtures/read-stream.js'
8
+ import { writeStream } from './fixtures/write-stream.js'
9
+ import { defer } from '../lib/utils.js'
10
+
11
+ /**
12
+ * @template T
13
+ * @typedef {import('../lib/types').Deferred<T>} Deferred<T>
14
+ */
15
+
16
+ const SERVER_PATH = '/unidirectional-streams'
17
+
18
+ describe('unidirectional streams', function () {
19
+ /** @type {import('../lib/server').Http3Server} */
20
+ let server
21
+ /** @type {import('./fixtures/certificate.js').Certificate} */
22
+ let certificate
23
+ /** @type {import('../lib/dom').WebTransport | undefined} */
24
+ let client
25
+ /** @type {string} */
26
+ let url
27
+
28
+ beforeEach(async () => {
29
+ ;({ server, certificate } = await createServer())
30
+ server.startServer()
31
+ await server.ready
32
+
33
+ const address = server.address()
34
+
35
+ if (address == null || address.port == null) {
36
+ throw new Error('No address')
37
+ }
38
+
39
+ url = `https://${address.host}:${address.port}`
40
+ })
41
+
42
+ afterEach(async () => {
43
+ if (client != null) {
44
+ client.close()
45
+ }
46
+
47
+ if (server != null) {
48
+ server.stopServer()
49
+ await server.closed
50
+ }
51
+ })
52
+
53
+ it('sends data over an outgoing unidirectional stream', async () => {
54
+ this.timeout(200)
55
+ /** @type {Deferred<Uint8Array[]>} */
56
+ const serverData = defer()
57
+
58
+ // server context - waits for the client to open a bidi stream and pipes it back to them
59
+ Promise.resolve().then(async () => {
60
+ const session = await getReaderValue(server.sessionStream(SERVER_PATH))
61
+ const stream = await getReaderValue(session.incomingUnidirectionalStreams)
62
+
63
+ const output = await readStream(stream)
64
+ serverData.resolve(output)
65
+ })
66
+
67
+ // client context - connects to the server, opens a bidi stream, sends some data and reads the response
68
+ client = new WebTransport(`${url}${SERVER_PATH}`, {
69
+ serverCertificateHashes: [
70
+ {
71
+ algorithm: 'sha-256',
72
+ value: certificate.hash
73
+ }
74
+ ]
75
+ })
76
+ await client.ready
77
+
78
+ const input = [
79
+ Uint8Array.from([0, 1, 2, 3, 4]),
80
+ Uint8Array.from([5, 6, 7, 8, 9]),
81
+ Uint8Array.from([10, 11, 12, 13, 14])
82
+ ]
83
+
84
+ const stream = await client.createUnidirectionalStream()
85
+ await writeStream(stream, input)
86
+
87
+ const received = await serverData.promise
88
+ expect(received).to.deep.equal(
89
+ input,
90
+ 'Server did not receive the same bytes we sent'
91
+ )
92
+ })
93
+
94
+ it('receives data over an incoming unidirectional stream', async () => {
95
+ this.timeout(200)
96
+ const input = [
97
+ Uint8Array.from([0, 1, 2, 3, 4]),
98
+ Uint8Array.from([5, 6, 7, 8, 9]),
99
+ Uint8Array.from([10, 11, 12, 13, 14])
100
+ ]
101
+
102
+ // server context - waits for the client to connect, opens a bidi stream, sends some data and reads the response
103
+ Promise.resolve().then(async () => {
104
+ const session = await getReaderValue(server.sessionStream(SERVER_PATH))
105
+ const stream = await session.createUnidirectionalStream()
106
+
107
+ await writeStream(stream, input)
108
+ })
109
+
110
+ // client context - waits for the server to open a bidi stream then pipes it back to them
111
+ client = new WebTransport(`${url}${SERVER_PATH}`, {
112
+ serverCertificateHashes: [
113
+ {
114
+ algorithm: 'sha-256',
115
+ value: certificate.hash
116
+ }
117
+ ]
118
+ })
119
+ await client.ready
120
+
121
+ const stream = await getReaderValue(client.incomingUnidirectionalStreams)
122
+ const received = await readStream(stream)
123
+ expect(received).to.deep.equal(
124
+ input,
125
+ 'Did not receive the same bytes we sent'
126
+ )
127
+ })
128
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "compilerOptions": {
3
+ "strict": true,
4
+ // project options
5
+ "outDir": "dist",
6
+ "allowJs": true,
7
+ "checkJs": true,
8
+ "target": "ES2020",
9
+ "module": "ES2022",
10
+ "lib": ["ES2021", "ES2021.Promise", "ES2021.String", "ES2020.BigInt", "DOM", "DOM.Iterable"],
11
+ "noEmit": false,
12
+ "noEmitOnError": true,
13
+ "emitDeclarationOnly": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "incremental": true,
17
+ "composite": true,
18
+ "isolatedModules": true,
19
+ "removeComments": false,
20
+ "sourceMap": true,
21
+ // module resolution
22
+ "esModuleInterop": true,
23
+ "moduleResolution": "node",
24
+ // linter checks
25
+ "noImplicitReturns": false,
26
+ "noFallthroughCasesInSwitch": true,
27
+ "noUnusedLocals": true,
28
+ "noUnusedParameters": false,
29
+ // advanced
30
+ "importsNotUsedAsValues": "error",
31
+ "forceConsistentCasingInFileNames": true,
32
+ "skipLibCheck": true,
33
+ "stripInternal": true,
34
+ "resolveJsonModule": true
35
+ },
36
+ "include": [
37
+ "lib",
38
+ "test"
39
+ ]
40
+ }