node-datachannel 0.6.0 → 0.8.0

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.
package/CMakeLists.txt CHANGED
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15)
2
2
  cmake_policy(SET CMP0091 NEW)
3
3
  cmake_policy(SET CMP0042 NEW)
4
4
 
5
- project(node_datachannel VERSION 0.6.0)
5
+ project(node_datachannel VERSION 0.8.0)
6
6
 
7
7
  # -Dnapi_build_version=8
8
8
  add_definitions(-DNAPI_VERSION=8)
@@ -29,7 +29,7 @@ include(FetchContent)
29
29
  FetchContent_Declare(
30
30
  libdatachannel
31
31
  GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
32
- GIT_TAG "v0.20.2"
32
+ GIT_TAG "v0.20.3"
33
33
  )
34
34
 
35
35
  option(NO_MEDIA "Disable media transport support in libdatachannel" OFF)
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "electron-squirrel-startup": "^1.0.0",
37
- "node-datachannel": "^0.5.2"
37
+ "node-datachannel": "^0.8.0"
38
38
  },
39
39
  "cmake-js": {
40
40
  "runtime": "electron",
@@ -0,0 +1,7 @@
1
+ /** @type {import('jest').Config} */
2
+ const config = {
3
+ verbose: true,
4
+ testPathIgnorePatterns: ['<rootDir>/node_modules/', 'multiple-run.test'],
5
+ };
6
+
7
+ module.exports = config;
package/lib/index.cjs ADDED
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var module$1 = require('module');
6
+ var stream = require('stream');
7
+
8
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
9
+ /**
10
+ * Turns a node-datachannel DataChannel into a real Node.js stream, complete with buffering,
11
+ * backpressure (up to a point - if the buffer fills up, messages are dropped), and
12
+ * support for piping data elsewhere.
13
+ *
14
+ * Read & written data may be either UTF-8 strings or Buffers - this difference exists at
15
+ * the protocol level, and is preserved here throughout.
16
+ */
17
+ class DataChannelStream extends stream.Duplex {
18
+ constructor(rawChannel, streamOptions) {
19
+ super({
20
+ allowHalfOpen: false, // Default to autoclose on end().
21
+ ...streamOptions,
22
+ objectMode: true, // Preserve the string/buffer distinction (WebRTC treats them differently)
23
+ });
24
+
25
+ this._rawChannel = rawChannel;
26
+ this._readActive = true;
27
+
28
+ rawChannel.onMessage((msg) => {
29
+ if (!this._readActive) return; // If the buffer is full, drop messages.
30
+
31
+ // If the push is rejected, we pause reading until the next call to _read().
32
+ this._readActive = this.push(msg);
33
+ });
34
+
35
+ // When the DataChannel closes, the readable & writable ends close
36
+ rawChannel.onClosed(() => {
37
+ this.push(null);
38
+ this.destroy();
39
+ });
40
+
41
+ rawChannel.onError((errMsg) => {
42
+ this.destroy(new Error(`DataChannel error: ${errMsg}`));
43
+ });
44
+
45
+ // Buffer all writes until the DataChannel opens
46
+ if (!rawChannel.isOpen()) {
47
+ this.cork();
48
+ rawChannel.onOpen(() => this.uncork());
49
+ }
50
+ }
51
+
52
+ _read() {
53
+ // Stop dropping messages, if the buffer filling up meant we were doing so before.
54
+ this._readActive = true;
55
+ }
56
+
57
+ _write(chunk, encoding, callback) {
58
+ let sentOk;
59
+
60
+ try {
61
+ if (Buffer.isBuffer(chunk)) {
62
+ sentOk = this._rawChannel.sendMessageBinary(chunk);
63
+ } else if (typeof chunk === 'string') {
64
+ sentOk = this._rawChannel.sendMessage(chunk);
65
+ } else {
66
+ const typeName = chunk.constructor.name || typeof chunk;
67
+ throw new Error(`Cannot write ${typeName} to DataChannel stream`);
68
+ }
69
+ } catch (err) {
70
+ return callback(err);
71
+ }
72
+
73
+ if (sentOk) {
74
+ callback(null);
75
+ } else {
76
+ callback(new Error('Failed to write to DataChannel'));
77
+ }
78
+ }
79
+
80
+ _final(callback) {
81
+ if (!this.allowHalfOpen) this.destroy();
82
+ callback(null);
83
+ }
84
+
85
+ _destroy(maybeErr, callback) {
86
+ // When the stream is destroyed, we close the DataChannel.
87
+ this._rawChannel.close();
88
+ callback(maybeErr);
89
+ }
90
+
91
+ get label() {
92
+ return this._rawChannel.getLabel();
93
+ }
94
+
95
+ get id() {
96
+ return this._rawChannel.getId();
97
+ }
98
+
99
+ get protocol() {
100
+ return this._rawChannel.getProtocol();
101
+ }
102
+ }
103
+
104
+ // createRequire is native in node version >= 12
105
+ const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
106
+
107
+ const nodeDataChannel = require$1('../build/Release/node_datachannel.node');
108
+
109
+ const {
110
+ initLogger,
111
+ cleanup,
112
+ preload,
113
+ setSctpSettings,
114
+ RtcpReceivingSession,
115
+ Track,
116
+ Video,
117
+ Audio,
118
+ DataChannel,
119
+ PeerConnection,
120
+ WebSocket,
121
+ WebSocketServer,
122
+ } = nodeDataChannel;
123
+
124
+ var index = {
125
+ ...nodeDataChannel,
126
+ DataChannelStream,
127
+ };
128
+
129
+ exports.Audio = Audio;
130
+ exports.DataChannel = DataChannel;
131
+ exports.DataChannelStream = DataChannelStream;
132
+ exports.PeerConnection = PeerConnection;
133
+ exports.RtcpReceivingSession = RtcpReceivingSession;
134
+ exports.Track = Track;
135
+ exports.Video = Video;
136
+ exports.WebSocket = WebSocket;
137
+ exports.WebSocketServer = WebSocketServer;
138
+ exports.cleanup = cleanup;
139
+ exports.default = index;
140
+ exports.initLogger = initLogger;
141
+ exports.preload = preload;
142
+ exports.setSctpSettings = setSctpSettings;
@@ -0,0 +1,313 @@
1
+ import * as stream from 'stream';
2
+
3
+ export as namespace NodeDataChannel;
4
+
5
+ // Enum in d.ts is tricky
6
+ export type LogLevel = 'Verbose' | 'Debug' | 'Info' | 'Warning' | 'Error' | 'Fatal';
7
+
8
+ // SCTP Settings
9
+ export interface SctpSettings {
10
+ recvBufferSize?: number;
11
+ sendBufferSize?: number;
12
+ maxChunksOnQueue?: number;
13
+ initialCongestionWindow?: number;
14
+ congestionControlModule?: number;
15
+ delayedSackTime?: number;
16
+ }
17
+
18
+ // Functions
19
+ export function preload(): void;
20
+ export function initLogger(level: LogLevel, callback?: (level: LogLevel, message: string) => void): void;
21
+ export function cleanup(): void;
22
+ export function setSctpSettings(settings: SctpSettings): void;
23
+
24
+ // Proxy Server
25
+ export type ProxyServerType = 'Socks5' | 'Http';
26
+ export interface ProxyServer {
27
+ type: ProxyServerType;
28
+ ip: string;
29
+ port: number;
30
+ username?: string;
31
+ password?: string;
32
+ }
33
+
34
+ export const enum RelayType {
35
+ TurnUdp = 'TurnUdp',
36
+ TurnTcp = 'TurnTcp',
37
+ TurnTls = 'TurnTls',
38
+ }
39
+
40
+ export interface IceServer {
41
+ hostname: string;
42
+ port: number;
43
+ username?: string;
44
+ password?: string;
45
+ relayType?: RelayType;
46
+ }
47
+
48
+ export type TransportPolicy = 'all' | 'relay';
49
+
50
+ export interface RtcConfig {
51
+ iceServers: (string | IceServer)[];
52
+ proxyServer?: ProxyServer;
53
+ bindAddress?: string;
54
+ enableIceTcp?: boolean;
55
+ enableIceUdpMux?: boolean;
56
+ disableAutoNegotiation?: boolean;
57
+ forceMediaTransport?: boolean;
58
+ portRangeBegin?: number;
59
+ portRangeEnd?: number;
60
+ maxMessageSize?: number;
61
+ mtu?: number;
62
+ iceTransportPolicy?: TransportPolicy;
63
+ }
64
+
65
+ // Lowercase to match the description type string from libdatachannel
66
+ export const enum DescriptionType {
67
+ Unspec = 'unspec',
68
+ Offer = 'offer',
69
+ Answer = 'answer',
70
+ Pranswer = 'pranswer',
71
+ Rollback = 'rollback',
72
+ }
73
+
74
+ export const enum ReliabilityType {
75
+ Reliable = 0,
76
+ Rexmit = 1,
77
+ Timed = 2,
78
+ }
79
+
80
+ export interface DataChannelInitConfig {
81
+ protocol?: string;
82
+ negotiated?: boolean;
83
+ id?: number;
84
+ ordered?: boolean;
85
+ maxPacketLifeTime?: number;
86
+ maxRetransmits?: number;
87
+
88
+ // Deprecated, use ordered, maxPacketLifeTime, and maxRetransmits
89
+ reliability?: {
90
+ type?: ReliabilityType;
91
+ unordered?: boolean;
92
+ rexmit?: number;
93
+ };
94
+ }
95
+
96
+ export interface SelectedCandidateInfo {
97
+ address: string;
98
+ port: number;
99
+ type: string;
100
+ transportType: string;
101
+ candidate: string;
102
+ mid: string;
103
+ priority: number;
104
+ }
105
+
106
+ // Must be same as rtc enum class Direction
107
+ export const enum Direction {
108
+ SendOnly = 'SendOnly',
109
+ RecvOnly = 'RecvOnly',
110
+ SendRecv = 'SendRecv',
111
+ Inactive = 'Inactive',
112
+ Unknown = 'Unknown',
113
+ }
114
+
115
+ export class RtcpReceivingSession {
116
+ requestBitrate(bitRate: number): void;
117
+ requestKeyframe(): boolean;
118
+ }
119
+
120
+ export class Audio {
121
+ constructor(mid: string, dir: Direction);
122
+ addAudioCodec(payloadType: number, codec: string, profile?: string): void;
123
+ addOpusCodec(payloadType: number, profile?: string): string;
124
+
125
+ direction(): Direction;
126
+ generateSdp(eol: string, addr: string, port: number): string;
127
+ mid(): string;
128
+ setDirection(dir: Direction): void;
129
+ description(): string;
130
+ removeFormat(fmt: string): void;
131
+ addSSRC(ssrc: number, name?: string, msid?: string, trackID?: string): void;
132
+ removeSSRC(ssrc: number): void;
133
+ replaceSSRC(oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string): void;
134
+ hasSSRC(ssrc: number): boolean;
135
+ getSSRCs(): number[];
136
+ getCNameForSsrc(ssrc: number): string;
137
+ setBitrate(bitRate: number): void;
138
+ getBitrate(): number;
139
+ hasPayloadType(payloadType: number): boolean;
140
+ addRTXCodec(payloadType: number, originalPayloadType: number, clockRate: number): void;
141
+ addRTPMap(): void;
142
+ parseSdpLine(line: string): void;
143
+ }
144
+
145
+ export class Video {
146
+ constructor(mid: string, dir: Direction);
147
+ addVideoCodec(payloadType: number, codec: string, profile?: string): void;
148
+ addH264Codec(payloadType: number, profile?: string): void;
149
+ addVP8Codec(payloadType: number): void;
150
+ addVP9Codec(payloadType: number): void;
151
+
152
+ direction(): Direction;
153
+ generateSdp(eol: string, addr: string, port: number): string;
154
+ mid(): string;
155
+ setDirection(dir: Direction): void;
156
+ description(): string;
157
+ removeFormat(fmt: string): void;
158
+ addSSRC(ssrc: number, name?: string, msid?: string, trackID?: string): void;
159
+ removeSSRC(ssrc: number): void;
160
+ replaceSSRC(oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string): void;
161
+ hasSSRC(ssrc: number): boolean;
162
+ getSSRCs(): number[];
163
+ getCNameForSsrc(ssrc: number): string;
164
+ setBitrate(bitRate: number): void;
165
+ getBitrate(): number;
166
+ hasPayloadType(payloadType: number): boolean;
167
+ addRTXCodec(payloadType: number, originalPayloadType: number, clockRate: number): void;
168
+ addRTPMap(): void;
169
+ parseSdpLine(line: string): void;
170
+ }
171
+
172
+ export class Track {
173
+ direction(): Direction;
174
+ mid(): string;
175
+ type(): string;
176
+ close(): void;
177
+ sendMessage(msg: string): boolean;
178
+ sendMessageBinary(buffer: Buffer): boolean;
179
+ isOpen(): boolean;
180
+ isClosed(): boolean;
181
+ bufferedAmount(): number;
182
+ maxMessageSize(): number;
183
+ setBufferedAmountLowThreshold(newSize: number): void;
184
+ requestKeyframe(): boolean;
185
+ setMediaHandler(handler: RtcpReceivingSession): void;
186
+ onOpen(cb: () => void): void;
187
+ onClosed(cb: () => void): void;
188
+ onError(cb: (err: string) => void): void;
189
+ onMessage(cb: (msg: Buffer) => void): void;
190
+ }
191
+
192
+ export interface Channel {
193
+ close(): void;
194
+ sendMessage(msg: string): boolean;
195
+ sendMessageBinary(buffer: Uint8Array): boolean;
196
+ isOpen(): boolean;
197
+ bufferedAmount(): number;
198
+ maxMessageSize(): number;
199
+ setBufferedAmountLowThreshold(newSize: number): void;
200
+ onOpen(cb: () => void): void;
201
+ onClosed(cb: () => void): void;
202
+ onError(cb: (err: string) => void): void;
203
+ onBufferedAmountLow(cb: () => void): void;
204
+ onMessage(cb: (msg: string | Buffer) => void): void;
205
+ }
206
+ export class DataChannel implements Channel {
207
+ getLabel(): string;
208
+ getId(): number;
209
+ getProtocol(): string;
210
+
211
+ // Channel implementation
212
+ close(): void;
213
+ sendMessage(msg: string): boolean;
214
+ sendMessageBinary(buffer: Uint8Array): boolean;
215
+ isOpen(): boolean;
216
+ bufferedAmount(): number;
217
+ maxMessageSize(): number;
218
+ setBufferedAmountLowThreshold(newSize: number): void;
219
+ onOpen(cb: () => void): void;
220
+ onClosed(cb: () => void): void;
221
+ onError(cb: (err: string) => void): void;
222
+ onBufferedAmountLow(cb: () => void): void;
223
+ onMessage(cb: (msg: string | Buffer) => void): void;
224
+ }
225
+
226
+ export interface WebSocketConfiguration {
227
+ disableTlsVerification?: boolean; // default = false, if true, don't verify the TLS certificate
228
+ proxyServer?: ProxyServer; // only non-authenticated http supported for now
229
+ protocols?: string[];
230
+ connectionTimeout?: number; // miliseconds, zero to disable
231
+ pingInterval?: number; // millisecondrs, zero to disable
232
+ maxOutstandingPings?: number;
233
+ caCertificatePemFile?: string;
234
+ certificatePemFile?: string;
235
+ keyPemFile?: string;
236
+ keyPemPass?: string;
237
+ maxMessageSize: number;
238
+ }
239
+ export class WebSocket implements Channel {
240
+ constructor(config?: WebSocketConfiguration);
241
+ open(url: string): void;
242
+ forceClose(): void;
243
+ remoteAddress(): string | undefined;
244
+ path(): string | undefined;
245
+
246
+ // Channel implementation
247
+ close(): void;
248
+ sendMessage(msg: string): boolean;
249
+ sendMessageBinary(buffer: Uint8Array): boolean;
250
+ isOpen(): boolean;
251
+ bufferedAmount(): number;
252
+ maxMessageSize(): number;
253
+ setBufferedAmountLowThreshold(newSize: number): void;
254
+ onOpen(cb: () => void): void;
255
+ onClosed(cb: () => void): void;
256
+ onError(cb: (err: string) => void): void;
257
+ onBufferedAmountLow(cb: () => void): void;
258
+ onMessage(cb: (msg: string | Buffer) => void): void;
259
+ }
260
+
261
+ export interface WebSocketServerConfiguration {
262
+ port?: number; // default 8080
263
+ enableTls?: boolean; // default = false;
264
+ certificatePemFile?: string;
265
+ keyPemFile?: string;
266
+ keyPemPass?: string;
267
+ bindAddress?: string;
268
+ connectionTimeout?: number; // milliseconds
269
+ maxMessageSize?: number;
270
+ }
271
+
272
+ export class WebSocketServer {
273
+ constructor(config?: WebSocketServerConfiguration);
274
+ port(): number;
275
+ stop(): void;
276
+ onClient(cb: (ws: WebSocket) => void): void;
277
+ }
278
+
279
+ export class PeerConnection {
280
+ constructor(peerName: string, config: RtcConfig);
281
+ close(): void;
282
+ setLocalDescription(type?: DescriptionType): void;
283
+ setRemoteDescription(sdp: string, type: DescriptionType): void;
284
+ localDescription(): { type: string; sdp: string } | null;
285
+ remoteDescription(): { type: string; sdp: string } | null;
286
+ addRemoteCandidate(candidate: string, mid: string): void;
287
+ createDataChannel(label: string, config?: DataChannelInitConfig): DataChannel;
288
+ addTrack(media: Video | Audio): Track;
289
+ hasMedia(): boolean;
290
+ state(): RTCPeerConnectionState;
291
+ iceState(): RTCIceConnectionState;
292
+ signalingState(): RTCSignalingState;
293
+ gatheringState(): RTCIceGatheringState;
294
+ onLocalDescription(cb: (sdp: string, type: DescriptionType) => void): void;
295
+ onLocalCandidate(cb: (candidate: string, mid: string) => void): void;
296
+ onStateChange(cb: (state: string) => void): void;
297
+ onIceStateChange(cb: (state: string) => void): void;
298
+ onSignalingStateChange(cb: (state: string) => void): void;
299
+ onGatheringStateChange(cb: (state: string) => void): void;
300
+ onDataChannel(cb: (dc: DataChannel) => void): void;
301
+ onTrack(cb: (track: Track) => void): void;
302
+ bytesSent(): number;
303
+ bytesReceived(): number;
304
+ rtt(): number;
305
+ getSelectedCandidatePair(): { local: SelectedCandidateInfo; remote: SelectedCandidateInfo } | null;
306
+ maxDataChannelId(): number;
307
+ maxMessageSize(): number;
308
+ }
309
+
310
+ export class DataChannelStream extends stream.Duplex {
311
+ constructor(rawChannel: DataChannel, options?: Omit<stream.DuplexOptions, 'objectMode'>);
312
+ get label(): string;
313
+ }
package/lib/index.d.ts CHANGED
@@ -238,6 +238,10 @@ export interface WebSocketConfiguration {
238
238
  }
239
239
  export class WebSocket implements Channel {
240
240
  constructor(config?: WebSocketConfiguration);
241
+ open(url: string): void;
242
+ forceClose(): void;
243
+ remoteAddress(): string | undefined;
244
+ path(): string | undefined;
241
245
 
242
246
  // Channel implementation
243
247
  close(): void;
@@ -275,7 +279,6 @@ export class WebSocketServer {
275
279
  export class PeerConnection {
276
280
  constructor(peerName: string, config: RtcConfig);
277
281
  close(): void;
278
- destroy(): void;
279
282
  setLocalDescription(type?: DescriptionType): void;
280
283
  setRemoteDescription(sdp: string, type: DescriptionType): void;
281
284
  localDescription(): { type: string; sdp: string } | null;
package/package.json CHANGED
@@ -1,13 +1,30 @@
1
1
  {
2
2
  "name": "node-datachannel",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "libdatachannel node bindings",
5
5
  "type": "module",
6
6
  "exports": {
7
- ".": "./lib/index.js",
8
- "./polyfill": "./polyfill/index.js"
7
+ ".": {
8
+ "import": {
9
+ "default": "./lib/index.js",
10
+ "types": "./lib/index.d.ts"
11
+ },
12
+ "require": {
13
+ "default": "./lib/index.cjs",
14
+ "types": "./lib/index.d.cts"
15
+ }
16
+ },
17
+ "./polyfill": {
18
+ "import": {
19
+ "default": "./polyfill/index.js",
20
+ "types": "./polyfill/index.d.ts"
21
+ },
22
+ "require": {
23
+ "default": "./polyfill/index.cjs",
24
+ "types": "./polyfill/index.d.cts"
25
+ }
26
+ }
9
27
  },
10
- "typings": "lib/index.d.ts",
11
28
  "engines": {
12
29
  "node": ">=16.0.0"
13
30
  },
@@ -27,7 +44,8 @@
27
44
  "lint": "eslint lib/**/* test/**/*",
28
45
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
29
46
  "wpt-test": "node test/wpt.js",
30
- "test-types": "tsc"
47
+ "test-types": "tsc",
48
+ "prepublishOnly": "cp lib/index.d.ts lib/index.d.cts && cp polyfill/index.d.ts polyfill/index.d.cts && rollup lib/index.js --file lib/index.cjs --format cjs && rollup polyfill/index.js --file polyfill/index.cjs --format cjs"
31
49
  },
32
50
  "binary": {
33
51
  "napi_versions": [
@@ -78,6 +96,7 @@
78
96
  },
79
97
  "dependencies": {
80
98
  "node-domexception": "^2.0.1",
81
- "prebuild-install": "^7.0.1"
99
+ "prebuild-install": "^7.0.1",
100
+ "rollup": "^4.14.1"
82
101
  }
83
102
  }
@@ -222,7 +222,6 @@ export default class _RTCPeerConnection extends EventTarget {
222
222
  });
223
223
 
224
224
  this.#peerConnection.close();
225
- this.#peerConnection.destroy();
226
225
  }
227
226
 
228
227
  createAnswer() {