node-rtc-connection 1.0.19 → 2.0.5

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 (47) hide show
  1. package/README.md +94 -85
  2. package/index.cjs +1 -0
  3. package/index.mjs +1 -0
  4. package/package.json +14 -46
  5. package/types/crypto/der.d.ts +107 -0
  6. package/types/crypto/x509.d.ts +56 -0
  7. package/types/datachannel/RTCDataChannel.d.ts +179 -0
  8. package/types/dtls/RTCCertificate.d.ts +163 -0
  9. package/types/dtls/cipher.d.ts +81 -0
  10. package/types/dtls/connection.d.ts +81 -0
  11. package/types/dtls/prf.d.ts +29 -0
  12. package/types/dtls/protocol.d.ts +127 -0
  13. package/types/foundation/ByteBufferQueue.d.ts +71 -0
  14. package/types/foundation/RTCError.d.ts +152 -0
  15. package/types/ice/RTCIceCandidate.d.ts +161 -0
  16. package/types/ice/ice-agent.d.ts +154 -0
  17. package/types/ice/stun-message.d.ts +92 -0
  18. package/types/index.d.ts +29 -0
  19. package/types/peerconnection/RTCPeerConnection.d.ts +74 -0
  20. package/types/sctp/association.d.ts +77 -0
  21. package/types/sctp/chunks.d.ts +200 -0
  22. package/types/sctp/crc32c.d.ts +24 -0
  23. package/types/sctp/datachannel-manager.d.ts +51 -0
  24. package/types/sctp/dcep.d.ts +56 -0
  25. package/types/sdp/RTCSessionDescription.d.ts +73 -0
  26. package/types/sdp/sdp-utils.d.ts +103 -0
  27. package/types/stun/stun-client.d.ts +119 -0
  28. package/types/transport-stack.d.ts +68 -0
  29. package/dist/index.cjs +0 -5618
  30. package/dist/index.cjs.map +0 -1
  31. package/dist/index.mjs +0 -5616
  32. package/dist/index.mjs.map +0 -1
  33. package/src/datachannel/RTCDataChannel.js +0 -354
  34. package/src/dtls/RTCCertificate.js +0 -310
  35. package/src/dtls/RTCDtlsTransport.js +0 -247
  36. package/src/foundation/ByteBufferQueue.js +0 -235
  37. package/src/foundation/RTCError.js +0 -226
  38. package/src/ice/RTCIceCandidate.js +0 -301
  39. package/src/ice/RTCIceTransport.js +0 -1018
  40. package/src/index.d.ts +0 -400
  41. package/src/index.js +0 -92
  42. package/src/network/network-transport.js +0 -478
  43. package/src/peerconnection/RTCPeerConnection.js +0 -875
  44. package/src/sctp/RTCSctpTransport.js +0 -253
  45. package/src/sdp/RTCSessionDescription.js +0 -102
  46. package/src/sdp/sdp-utils.js +0 -224
  47. package/src/stun/stun-client.js +0 -777
@@ -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,102 +0,0 @@
1
- /**
2
- * @file RTCSessionDescription.js
3
- * @description Session Description Protocol (SDP) representation
4
- * @module sdp/RTCSessionDescription
5
- *
6
- * Ported from Chromium's RTCSessionDescription implementation:
7
- * - cc/rtc_session_description.idl
8
- * - cc/rtc_session_description.h
9
- */
10
-
11
- 'use strict';
12
-
13
- /**
14
- * RTCSdpType - Types of session descriptions
15
- * @readonly
16
- * @enum {string}
17
- */
18
- const RTCSdpType = Object.freeze({
19
- OFFER: 'offer',
20
- PRANSWER: 'pranswer',
21
- ANSWER: 'answer',
22
- ROLLBACK: 'rollback'
23
- });
24
-
25
- /**
26
- * @class RTCSessionDescription
27
- * @description Represents a WebRTC session description (offer/answer)
28
- *
29
- * @example
30
- * const desc = new RTCSessionDescription({
31
- * type: 'offer',
32
- * sdp: 'v=0\r\no=- 123456 2 IN IP4 127.0.0.1\r\n...'
33
- * });
34
- */
35
- class RTCSessionDescription {
36
- /**
37
- * Create an RTCSessionDescription instance.
38
- * @param {Object} [init] - Session description init
39
- * @param {string} [init.type] - SDP type (offer/answer/pranswer/rollback)
40
- * @param {string} [init.sdp] - SDP string
41
- */
42
- constructor(init = {}) {
43
- this._type = init.type || null;
44
- this._sdp = init.sdp || null;
45
-
46
- // Validate type if provided
47
- if (this._type && !Object.values(RTCSdpType).includes(this._type)) {
48
- throw new TypeError(`Invalid SDP type: ${this._type}`);
49
- }
50
- }
51
-
52
- /**
53
- * Get the SDP type.
54
- * @returns {string|null} SDP type
55
- */
56
- get type() {
57
- return this._type;
58
- }
59
-
60
- /**
61
- * Set the SDP type.
62
- * @param {string} value - SDP type
63
- */
64
- set type(value) {
65
- if (value && !Object.values(RTCSdpType).includes(value)) {
66
- throw new TypeError(`Invalid SDP type: ${value}`);
67
- }
68
- this._type = value;
69
- }
70
-
71
- /**
72
- * Get the SDP string.
73
- * @returns {string|null} SDP string
74
- */
75
- get sdp() {
76
- return this._sdp;
77
- }
78
-
79
- /**
80
- * Set the SDP string.
81
- * @param {string} value - SDP string
82
- */
83
- set sdp(value) {
84
- this._sdp = value;
85
- }
86
-
87
- /**
88
- * Convert to JSON representation.
89
- * @returns {Object} JSON representation
90
- */
91
- toJSON() {
92
- return {
93
- type: this._type,
94
- sdp: this._sdp
95
- };
96
- }
97
- }
98
-
99
- module.exports = {
100
- RTCSessionDescription,
101
- RTCSdpType
102
- };
@@ -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.substring(2),
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
- };