node-rtc-connection 1.0.18 → 2.0.4

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 (65) hide show
  1. package/README.md +94 -85
  2. package/dist/index.cjs +20 -5421
  3. package/dist/index.mjs +25 -5413
  4. package/dist/types/crypto/der.d.ts +107 -0
  5. package/dist/types/crypto/x509.d.ts +56 -0
  6. package/dist/types/datachannel/RTCDataChannel.d.ts +179 -0
  7. package/dist/types/dtls/RTCCertificate.d.ts +163 -0
  8. package/dist/types/dtls/cipher.d.ts +81 -0
  9. package/dist/types/dtls/connection.d.ts +81 -0
  10. package/dist/types/dtls/prf.d.ts +29 -0
  11. package/dist/types/dtls/protocol.d.ts +127 -0
  12. package/dist/types/foundation/ByteBufferQueue.d.ts +71 -0
  13. package/dist/types/foundation/RTCError.d.ts +152 -0
  14. package/dist/types/ice/RTCIceCandidate.d.ts +161 -0
  15. package/dist/types/ice/ice-agent.d.ts +154 -0
  16. package/dist/types/ice/stun-message.d.ts +92 -0
  17. package/dist/types/index.d.ts +29 -0
  18. package/dist/types/peerconnection/RTCPeerConnection.d.ts +74 -0
  19. package/dist/types/sctp/association.d.ts +77 -0
  20. package/dist/types/sctp/chunks.d.ts +200 -0
  21. package/dist/types/sctp/crc32c.d.ts +24 -0
  22. package/dist/types/sctp/datachannel-manager.d.ts +51 -0
  23. package/dist/types/sctp/dcep.d.ts +56 -0
  24. package/dist/types/sdp/RTCSessionDescription.d.ts +73 -0
  25. package/dist/types/sdp/sdp-utils.d.ts +103 -0
  26. package/dist/types/stun/stun-client.d.ts +119 -0
  27. package/dist/types/transport-stack.d.ts +68 -0
  28. package/package.json +26 -21
  29. package/src/crypto/der.ts +205 -0
  30. package/src/crypto/x509.ts +146 -0
  31. package/src/datachannel/RTCDataChannel.ts +388 -0
  32. package/src/dtls/RTCCertificate.ts +396 -0
  33. package/src/dtls/cipher.ts +198 -0
  34. package/src/dtls/connection.ts +974 -0
  35. package/src/dtls/prf.ts +62 -0
  36. package/src/dtls/protocol.ts +204 -0
  37. package/src/foundation/{ByteBufferQueue.js → ByteBufferQueue.ts} +74 -72
  38. package/src/foundation/{RTCError.js → RTCError.ts} +110 -60
  39. package/src/ice/{RTCIceCandidate.js → RTCIceCandidate.ts} +140 -92
  40. package/src/ice/ice-agent.ts +609 -0
  41. package/src/ice/stun-message.ts +260 -0
  42. package/src/index.ts +72 -0
  43. package/src/peerconnection/RTCPeerConnection.ts +430 -0
  44. package/src/sctp/association.ts +523 -0
  45. package/src/sctp/chunks.ts +350 -0
  46. package/src/sctp/crc32c.ts +57 -0
  47. package/src/sctp/datachannel-manager.ts +187 -0
  48. package/src/sctp/dcep.ts +94 -0
  49. package/src/sdp/{RTCSessionDescription.js → RTCSessionDescription.ts} +42 -29
  50. package/src/sdp/sdp-utils.ts +229 -0
  51. package/src/stun/stun-client.ts +936 -0
  52. package/src/transport-stack.ts +165 -0
  53. package/dist/index.cjs.map +0 -1
  54. package/dist/index.mjs.map +0 -1
  55. package/src/datachannel/RTCDataChannel.js +0 -354
  56. package/src/dtls/RTCCertificate.js +0 -310
  57. package/src/dtls/RTCDtlsTransport.js +0 -247
  58. package/src/ice/RTCIceTransport.js +0 -998
  59. package/src/index.d.ts +0 -400
  60. package/src/index.js +0 -92
  61. package/src/network/network-transport.js +0 -478
  62. package/src/peerconnection/RTCPeerConnection.js +0 -851
  63. package/src/sctp/RTCSctpTransport.js +0 -253
  64. package/src/sdp/sdp-utils.js +0 -224
  65. package/src/stun/stun-client.js +0 -643
@@ -1,253 +0,0 @@
1
- /**
2
- * @file RTCSctpTransport.js
3
- * @description SCTP transport implementation for WebRTC data channels.
4
- * @module sctp/RTCSctpTransport
5
- *
6
- * Ported from Chromium's RTCSctpTransport implementation:
7
- * - cc/rtc_sctp_transport.h
8
- * - cc/rtc_sctp_transport.cc
9
- * - cc/rtc_sctp_transport.idl
10
- */
11
-
12
- const EventEmitter = require('events');
13
-
14
- /**
15
- * RTCSctpTransportState - Current state of the SCTP transport
16
- * @readonly
17
- * @enum {string}
18
- */
19
- const RTCSctpTransportState = Object.freeze({
20
- CONNECTING: 'connecting',
21
- CONNECTED: 'connected',
22
- CLOSED: 'closed'
23
- });
24
-
25
- /**
26
- * Default SCTP configuration values
27
- * @private
28
- */
29
- const SCTP_DEFAULTS = {
30
- MAX_MESSAGE_SIZE: 256 * 1024, // 256 KB default
31
- MAX_CHANNELS: 65535 // Maximum number of SCTP streams
32
- };
33
-
34
- /**
35
- * @class RTCSctpTransport
36
- * @extends EventEmitter
37
- * @description Represents the SCTP transport layer for WebRTC data channels.
38
- * SCTP (Stream Control Transmission Protocol) provides reliable, message-oriented
39
- * transport over DTLS for data channels.
40
- *
41
- * Events:
42
- * - 'statechange': Fired when the transport state changes
43
- *
44
- * @example
45
- * const sctpTransport = new RTCSctpTransport(dtlsTransport);
46
- * sctpTransport.on('statechange', () => {
47
- * console.log('SCTP state:', sctpTransport.state);
48
- * console.log('Max message size:', sctpTransport.maxMessageSize);
49
- * });
50
- */
51
- class RTCSctpTransport extends EventEmitter {
52
- /**
53
- * Create an RTCSctpTransport instance.
54
- * @param {RTCDtlsTransport} dtlsTransport - The underlying DTLS transport
55
- * @param {Object} [options] - SCTP configuration options
56
- * @param {number} [options.maxMessageSize] - Maximum message size in bytes
57
- * @param {number} [options.maxChannels] - Maximum number of channels
58
- * @throws {TypeError} If dtlsTransport is not provided or invalid
59
- */
60
- constructor(dtlsTransport, options = {}) {
61
- super();
62
-
63
- if (!dtlsTransport || typeof dtlsTransport !== 'object') {
64
- throw new TypeError('dtlsTransport is required');
65
- }
66
-
67
- // Store the DTLS transport
68
- this._dtlsTransport = dtlsTransport;
69
-
70
- // Internal state
71
- this._state = RTCSctpTransportState.CONNECTING;
72
-
73
- // SCTP configuration
74
- // Keep null if explicitly passed, otherwise use default
75
- if (options.maxMessageSize === null) {
76
- this._maxMessageSize = null;
77
- } else {
78
- this._maxMessageSize = options.maxMessageSize || SCTP_DEFAULTS.MAX_MESSAGE_SIZE;
79
- }
80
- this._maxChannels = options.maxChannels !== undefined ? options.maxChannels : SCTP_DEFAULTS.MAX_CHANNELS;
81
-
82
- // Closed flags
83
- this._closed = false;
84
- this._closedFromOwner = false;
85
- this._startCompleted = false;
86
-
87
- // Listen to DTLS transport state changes
88
- this._dtlsTransport.on('statechange', () => {
89
- this._onDtlsStateChange();
90
- });
91
-
92
- // Start SCTP if DTLS is already connected
93
- if (this._dtlsTransport.state === 'connected') {
94
- this._start();
95
- }
96
- }
97
-
98
- /**
99
- * Get the underlying DTLS transport.
100
- * @returns {RTCDtlsTransport} The DTLS transport
101
- */
102
- get transport() {
103
- return this._dtlsTransport;
104
- }
105
-
106
- /**
107
- * Get the current SCTP transport state.
108
- * @returns {string} The transport state
109
- */
110
- get state() {
111
- if (this._closedFromOwner) {
112
- return RTCSctpTransportState.CLOSED;
113
- }
114
- return this._state;
115
- }
116
-
117
- /**
118
- * Get the maximum message size in bytes.
119
- * This represents the maximum size of data that can be sent in a single message.
120
- *
121
- * @returns {number} Maximum message size in bytes, or Infinity if unlimited
122
- */
123
- get maxMessageSize() {
124
- // Return Infinity if explicitly null or undefined (unlimited)
125
- if (this._maxMessageSize === null) {
126
- return Infinity;
127
- }
128
- return this._maxMessageSize;
129
- }
130
-
131
- /**
132
- * Get the maximum number of channels.
133
- * This represents the maximum number of data channels that can be opened.
134
- *
135
- * @returns {number|null} Maximum number of channels, or null if unknown
136
- */
137
- get maxChannels() {
138
- return this._maxChannels;
139
- }
140
-
141
- /**
142
- * Start the SCTP association.
143
- * Called internally when DTLS is connected.
144
- * @private
145
- */
146
- _start() {
147
- if (this._startCompleted || this._closed) {
148
- return;
149
- }
150
-
151
- this._startCompleted = true;
152
-
153
- // With real network transport, SCTP is handled by the network layer
154
- // Transition to connected immediately since we're using raw TCP/UDP
155
- setImmediate(() => {
156
- if (!this._closed && this._state === RTCSctpTransportState.CONNECTING) {
157
- this._setState(RTCSctpTransportState.CONNECTED);
158
- }
159
- });
160
- }
161
-
162
- /**
163
- * Close the SCTP transport.
164
- * Called by the owning peer connection when it closes.
165
- */
166
- close() {
167
- if (this._closed) {
168
- return;
169
- }
170
-
171
- this._closedFromOwner = true;
172
- this._closed = true;
173
-
174
- // Emit state change if not already closed
175
- if (this._state !== RTCSctpTransportState.CLOSED) {
176
- this._state = RTCSctpTransportState.CLOSED;
177
- this.emit('statechange');
178
- }
179
- }
180
-
181
- /**
182
- * Internal close method.
183
- * @param {string} reason - Reason for closing
184
- * @private
185
- */
186
- _close(reason) {
187
- if (this._closed) {
188
- return;
189
- }
190
-
191
- this._closed = true;
192
- this._setState(RTCSctpTransportState.CLOSED);
193
- }
194
-
195
- /**
196
- * Set the transport state and emit event if changed.
197
- * @param {string} newState - The new state
198
- * @private
199
- */
200
- _setState(newState) {
201
- if (this._state !== newState) {
202
- this._state = newState;
203
- this.emit('statechange');
204
- }
205
- }
206
-
207
- /**
208
- * Handle DTLS transport state changes.
209
- * @private
210
- */
211
- _onDtlsStateChange() {
212
- const dtlsState = this._dtlsTransport.state;
213
-
214
- // Start SCTP when DTLS is connected
215
- if (dtlsState === 'connected' && !this._startCompleted) {
216
- this._start();
217
- }
218
-
219
- // Close SCTP when DTLS closes or fails
220
- if (dtlsState === 'closed' || dtlsState === 'failed') {
221
- this._close('dtls-closed');
222
- }
223
- }
224
-
225
- /**
226
- * Update SCTP configuration.
227
- * @param {Object} info - SCTP transport information
228
- * @param {number} [info.maxMessageSize] - Maximum message size
229
- * @param {number} [info.maxChannels] - Maximum number of channels
230
- * @private
231
- */
232
- _updateConfiguration(info) {
233
- if (info.maxMessageSize !== undefined) {
234
- this._maxMessageSize = info.maxMessageSize;
235
- }
236
- if (info.maxChannels !== undefined) {
237
- this._maxChannels = info.maxChannels;
238
- }
239
- }
240
-
241
- /**
242
- * Check if the transport is closed.
243
- * @returns {boolean} True if closed, false otherwise
244
- */
245
- isClosed() {
246
- return this._state === RTCSctpTransportState.CLOSED;
247
- }
248
- }
249
-
250
- module.exports = {
251
- RTCSctpTransport,
252
- RTCSctpTransportState
253
- };
@@ -1,224 +0,0 @@
1
- /**
2
- * @file sdp-utils.js
3
- * @description SDP parsing and generation utilities
4
- * @module sdp/sdp-utils
5
- */
6
-
7
- 'use strict';
8
-
9
- /**
10
- * Generate a simple SDP offer for data channel only
11
- * @param {Object} options - Generation options
12
- * @param {string} options.iceUfrag - ICE username fragment
13
- * @param {string} options.icePwd - ICE password
14
- * @param {Array<Object>} options.fingerprints - DTLS fingerprints
15
- * @param {Array<Object>} options.candidates - ICE candidates
16
- * @param {string} [options.setup='actpass'] - DTLS setup role
17
- * @param {string} [options.connectionAddress] - Connection IP address
18
- * @param {number} [options.connectionPort] - Connection port
19
- * @returns {string} SDP offer
20
- */
21
- function generateOffer(options) {
22
- const {
23
- iceUfrag,
24
- icePwd,
25
- fingerprints = [],
26
- candidates = [],
27
- setup = 'actpass',
28
- connectionAddress = '0.0.0.0',
29
- connectionPort = 9
30
- } = options;
31
-
32
- const sessionId = Date.now();
33
- const sessionVersion = 2;
34
-
35
- // Get primary fingerprint (SHA-256)
36
- const fingerprint = fingerprints.find(fp => fp.algorithm === 'sha-256') || fingerprints[0];
37
-
38
- let sdp = '';
39
-
40
- // Session description
41
- sdp += 'v=0\r\n';
42
- sdp += `o=- ${sessionId} ${sessionVersion} IN IP4 ${connectionAddress}\r\n`;
43
- sdp += 's=-\r\n';
44
- sdp += 't=0 0\r\n';
45
-
46
- // Bundle group (data channel only)
47
- sdp += 'a=group:BUNDLE 0\r\n';
48
- sdp += 'a=msid-semantic: WMS\r\n';
49
-
50
- // Media description for data channel (application)
51
- sdp += `m=application ${connectionPort} UDP/DTLS/SCTP webrtc-datachannel\r\n`;
52
- sdp += `c=IN IP4 ${connectionAddress}\r\n`;
53
- sdp += 'a=ice-ufrag:' + iceUfrag + '\r\n';
54
- sdp += 'a=ice-pwd:' + icePwd + '\r\n';
55
- sdp += 'a=ice-options:trickle\r\n';
56
-
57
- // DTLS fingerprint
58
- if (fingerprint) {
59
- sdp += `a=fingerprint:${fingerprint.algorithm.toUpperCase()} ${fingerprint.value}\r\n`;
60
- }
61
- sdp += `a=setup:${setup}\r\n`;
62
-
63
- // SCTP
64
- sdp += 'a=mid:0\r\n';
65
- sdp += 'a=sctp-port:5000\r\n';
66
- sdp += 'a=max-message-size:262144\r\n';
67
-
68
- // ICE candidates
69
- for (const candidate of candidates) {
70
- if (candidate.candidate) {
71
- sdp += `a=${candidate.candidate}\r\n`;
72
- }
73
- }
74
-
75
- return sdp;
76
- }
77
-
78
- /**
79
- * Generate a simple SDP answer for data channel only
80
- * @param {Object} options - Generation options
81
- * @param {string} options.iceUfrag - ICE username fragment
82
- * @param {string} options.icePwd - ICE password
83
- * @param {Array<Object>} options.fingerprints - DTLS fingerprints
84
- * @param {Array<Object>} options.candidates - ICE candidates
85
- * @param {string} [options.setup='active'] - DTLS setup role
86
- * @returns {string} SDP answer
87
- */
88
- function generateAnswer(options) {
89
- // Answer is similar to offer but with different setup role
90
- return generateOffer({
91
- ...options,
92
- setup: options.setup || 'active'
93
- });
94
- }
95
-
96
- /**
97
- * Parse SDP string to extract ICE candidates
98
- * @param {string} sdp - SDP string
99
- * @returns {Array<Object>} Array of candidate objects
100
- */
101
- function parseCandidates(sdp) {
102
- const candidates = [];
103
- const lines = sdp.split('\r\n');
104
-
105
- for (const line of lines) {
106
- if (line.startsWith('a=candidate:')) {
107
- candidates.push({
108
- candidate: line,
109
- sdpMid: '0',
110
- sdpMLineIndex: 0
111
- });
112
- }
113
- }
114
-
115
- return candidates;
116
- }
117
-
118
- /**
119
- * Parse SDP to extract ICE parameters
120
- * @param {string} sdp - SDP string
121
- * @returns {Object} ICE parameters
122
- */
123
- function parseIceParameters(sdp) {
124
- const lines = sdp.split('\r\n');
125
- const params = {
126
- usernameFragment: null,
127
- password: null
128
- };
129
-
130
- for (const line of lines) {
131
- if (line.startsWith('a=ice-ufrag:')) {
132
- params.usernameFragment = line.substring(12);
133
- } else if (line.startsWith('a=ice-pwd:')) {
134
- params.password = line.substring(10);
135
- }
136
- }
137
-
138
- return params;
139
- }
140
-
141
- /**
142
- * Parse SDP to extract DTLS parameters
143
- * @param {string} sdp - SDP string
144
- * @returns {Object} DTLS parameters
145
- */
146
- function parseDtlsParameters(sdp) {
147
- const lines = sdp.split('\r\n');
148
- const params = {
149
- role: 'auto',
150
- fingerprints: []
151
- };
152
-
153
- for (const line of lines) {
154
- if (line.startsWith('a=setup:')) {
155
- const setup = line.substring(8);
156
- if (setup === 'active') params.role = 'client';
157
- else if (setup === 'passive') params.role = 'server';
158
- else params.role = 'auto';
159
- } else if (line.startsWith('a=fingerprint:')) {
160
- const parts = line.substring(14).split(' ');
161
- if (parts.length === 2) {
162
- params.fingerprints.push({
163
- algorithm: parts[0].toLowerCase(),
164
- value: parts[1]
165
- });
166
- }
167
- }
168
- }
169
-
170
- return params;
171
- }
172
-
173
- /**
174
- * Parse SDP to extract SCTP parameters
175
- * @param {string} sdp - SDP string
176
- * @returns {Object} SCTP parameters
177
- */
178
- function parseSctpParameters(sdp) {
179
- const lines = sdp.split('\r\n');
180
- const params = {
181
- port: 5000,
182
- maxMessageSize: 262144
183
- };
184
-
185
- for (const line of lines) {
186
- if (line.startsWith('a=sctp-port:')) {
187
- params.port = parseInt(line.substring(12), 10);
188
- } else if (line.startsWith('a=max-message-size:')) {
189
- params.maxMessageSize = parseInt(line.substring(19), 10);
190
- }
191
- }
192
-
193
- return params;
194
- }
195
-
196
- /**
197
- * Generate random ICE credentials
198
- * @returns {Object} ICE credentials
199
- */
200
- function generateIceCredentials() {
201
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
202
- const randomString = (length) => {
203
- let result = '';
204
- for (let i = 0; i < length; i++) {
205
- result += chars.charAt(Math.floor(Math.random() * chars.length));
206
- }
207
- return result;
208
- };
209
-
210
- return {
211
- usernameFragment: randomString(4),
212
- password: randomString(24)
213
- };
214
- }
215
-
216
- module.exports = {
217
- generateOffer,
218
- generateAnswer,
219
- parseCandidates,
220
- parseIceParameters,
221
- parseDtlsParameters,
222
- parseSctpParameters,
223
- generateIceCredentials
224
- };