@neurodevs/node-lsl 14.1.5 → 16.0.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.
Files changed (44) hide show
  1. package/build/__tests__/AbstractPackageTest.d.ts +1 -0
  2. package/build/__tests__/AbstractPackageTest.js +7 -0
  3. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  4. package/build/__tests__/impl/LslStreamInfo.test.d.ts +1 -0
  5. package/build/__tests__/impl/LslStreamInfo.test.js +33 -6
  6. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  7. package/build/__tests__/impl/LslWebSocketBridge.test.d.ts +10 -2
  8. package/build/__tests__/impl/LslWebSocketBridge.test.js +78 -12
  9. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  10. package/build/impl/LslStreamInfo.d.ts +17 -8
  11. package/build/impl/LslStreamInfo.js +12 -6
  12. package/build/impl/LslStreamInfo.js.map +1 -1
  13. package/build/impl/LslStreamInlet.js +2 -1
  14. package/build/impl/LslStreamInlet.js.map +1 -1
  15. package/build/impl/LslStreamOutlet.d.ts +3 -2
  16. package/build/impl/LslStreamOutlet.js +4 -4
  17. package/build/impl/LslStreamOutlet.js.map +1 -1
  18. package/build/impl/LslWebSocketBridge.d.ts +18 -6
  19. package/build/impl/LslWebSocketBridge.js +69 -27
  20. package/build/impl/LslWebSocketBridge.js.map +1 -1
  21. package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +8 -0
  22. package/build/testDoubles/StreamInfo/FakeStreamInfo.js +11 -0
  23. package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
  24. package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +2 -0
  25. package/build/testDoubles/StreamInfo/SpyStreamInfo.js +5 -0
  26. package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +1 -1
  27. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.d.ts +2 -0
  28. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js +18 -4
  29. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js.map +1 -1
  30. package/build/testDoubles/WebSockets/FakeWebSocket.d.ts +4 -0
  31. package/build/testDoubles/WebSockets/FakeWebSocket.js +12 -1
  32. package/build/testDoubles/WebSockets/FakeWebSocket.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/__tests__/AbstractPackageTest.ts +10 -0
  35. package/src/__tests__/impl/LslStreamInfo.test.ts +40 -6
  36. package/src/__tests__/impl/LslWebSocketBridge.test.ts +111 -13
  37. package/src/impl/LslStreamInfo.ts +28 -12
  38. package/src/impl/LslStreamInlet.ts +4 -1
  39. package/src/impl/LslStreamOutlet.ts +6 -5
  40. package/src/impl/LslWebSocketBridge.ts +104 -38
  41. package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +14 -0
  42. package/src/testDoubles/StreamInfo/SpyStreamInfo.ts +7 -0
  43. package/src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts +24 -5
  44. package/src/testDoubles/WebSockets/FakeWebSocket.ts +14 -1
@@ -1,26 +1,36 @@
1
- import { WebSocketServer } from 'ws';
1
+ import WebSocket, { WebSocketServer } from 'ws';
2
2
  import { ChannelFormat } from './LiblslAdapter.js';
3
3
  import { StreamInlet } from './LslStreamInlet.js';
4
4
  export default class LslWebSocketBridge implements WebSocketBridge {
5
5
  static Class?: WebSocketBridgeConstructor;
6
+ static WS: typeof WebSocket;
6
7
  static WSS: typeof import("ws").Server;
7
8
  private inlet;
8
- private wss;
9
+ private localServer?;
10
+ private remoteSockets?;
9
11
  private isDestroyed;
10
12
  protected constructor(options: WebSocketBridgeConstructorOptions);
11
13
  static Create(options: WebSocketBridgeOptions): WebSocketBridge;
14
+ private throwIfNoLocalServerOrRemoteSockets;
15
+ private readonly insufficientOptionsError;
12
16
  activate(): void;
13
17
  private throwIfBridgeIsDestroyed;
18
+ private readonly cannotActivateMessage;
14
19
  private startPullingData;
15
20
  deactivate(): void;
21
+ private readonly cannotDeactivateMessage;
16
22
  private stopPullingData;
17
23
  destroy(): void;
18
24
  private destroyBoundInlet;
19
- private closeWebSocketServer;
25
+ private closeLocalServerIfExists;
26
+ private closeRemoteSocketsIfExists;
20
27
  private static createOnDataCallback;
21
28
  private static broadcastToClients;
22
- private static LslStreamInlet;
29
+ private static sendToSockets;
30
+ private static createSocketsFrom;
31
+ private static WebSocket;
23
32
  private static WebSocketServer;
33
+ private static LslStreamInlet;
24
34
  }
25
35
  export interface WebSocketBridge {
26
36
  activate(): void;
@@ -36,9 +46,11 @@ export interface WebSocketBridgeOptions {
36
46
  name?: string;
37
47
  type?: string;
38
48
  sourceId?: string;
39
- wssPort?: number;
49
+ listenPort?: number;
50
+ connectUrls?: string | string[];
40
51
  }
41
52
  export interface WebSocketBridgeConstructorOptions extends WebSocketBridgeOptions {
42
53
  inlet: StreamInlet;
43
- wss: WebSocketServer;
54
+ localServer?: WebSocketServer;
55
+ remoteSockets?: WebSocket[];
44
56
  }
@@ -1,72 +1,114 @@
1
- import { WebSocketServer } from 'ws';
1
+ import WebSocket, { WebSocketServer } from 'ws';
2
2
  import LslStreamInlet from './LslStreamInlet.js';
3
3
  export default class LslWebSocketBridge {
4
4
  static Class;
5
+ static WS = WebSocket;
5
6
  static WSS = WebSocketServer;
6
7
  inlet;
7
- wss;
8
+ localServer;
9
+ remoteSockets;
8
10
  isDestroyed = false;
9
11
  constructor(options) {
10
- const { inlet, wss } = options;
12
+ const { inlet, localServer, remoteSockets } = options;
11
13
  this.inlet = inlet;
12
- this.wss = wss;
14
+ this.localServer = localServer;
15
+ this.remoteSockets = remoteSockets;
16
+ this.throwIfNoLocalServerOrRemoteSockets();
13
17
  }
14
18
  static Create(options) {
15
- const { wssPort = 8080 } = options ?? {};
16
- const wss = this.WebSocketServer(wssPort);
17
- const inlet = this.LslStreamInlet(options, wss);
18
- return new (this.Class ?? this)({ ...options, inlet, wss });
19
+ const { listenPort, connectUrls, ...rest } = options;
20
+ const inletOptions = rest;
21
+ const localServer = this.WebSocketServer(listenPort);
22
+ const remoteSockets = this.createSocketsFrom(connectUrls);
23
+ const inlet = this.LslStreamInlet(inletOptions, localServer, remoteSockets);
24
+ return new (this.Class ?? this)({
25
+ ...options,
26
+ inlet,
27
+ localServer,
28
+ remoteSockets,
29
+ });
19
30
  }
31
+ throwIfNoLocalServerOrRemoteSockets() {
32
+ if (!(this.localServer || this.remoteSockets)) {
33
+ throw new Error(this.insufficientOptionsError);
34
+ }
35
+ }
36
+ insufficientOptionsError = `At least one of listenPort or connectUrls must be provided!`;
20
37
  activate() {
21
- this.throwIfBridgeIsDestroyed();
38
+ this.throwIfBridgeIsDestroyed(this.cannotActivateMessage);
22
39
  this.startPullingData();
23
40
  }
24
- throwIfBridgeIsDestroyed() {
41
+ throwIfBridgeIsDestroyed(err) {
25
42
  if (this.isDestroyed) {
26
- throw new Error(`\n\n Cannot re-activate bridge after destroying it! \n\n Please create and activate a new instance. \n`);
43
+ throw new Error(err);
27
44
  }
28
45
  }
46
+ cannotActivateMessage = `\n\n Cannot activate bridge after destroying it! \n\n Please create and activate a new instance. \n`;
29
47
  startPullingData() {
30
48
  this.inlet.startPulling();
31
49
  }
32
50
  deactivate() {
51
+ this.throwIfBridgeIsDestroyed(this.cannotDeactivateMessage);
33
52
  this.stopPullingData();
34
53
  }
54
+ cannotDeactivateMessage = `\n\n Cannot deactivate bridge after destroying it! \n\n Please create and activate a new instance. \n`;
35
55
  stopPullingData() {
36
56
  this.inlet.stopPulling();
37
57
  }
38
58
  destroy() {
39
59
  this.destroyBoundInlet();
40
- this.closeWebSocketServer();
60
+ this.closeLocalServerIfExists();
61
+ this.closeRemoteSocketsIfExists();
41
62
  this.isDestroyed = true;
42
63
  }
43
64
  destroyBoundInlet() {
44
65
  this.inlet.destroy();
45
66
  }
46
- closeWebSocketServer() {
47
- this.wss.close();
67
+ closeLocalServerIfExists() {
68
+ this.localServer?.close();
69
+ }
70
+ closeRemoteSocketsIfExists() {
71
+ this.remoteSockets?.forEach((socket) => socket.close());
48
72
  }
49
- static createOnDataCallback(wss) {
73
+ static createOnDataCallback(localServer, remoteSockets) {
50
74
  return (samples, timestamps) => {
51
- this.broadcastToClients(wss, samples, timestamps);
75
+ const payload = JSON.stringify({ samples, timestamps });
76
+ if (localServer) {
77
+ this.broadcastToClients(localServer, payload);
78
+ }
79
+ if (remoteSockets) {
80
+ this.sendToSockets(remoteSockets, payload);
81
+ }
52
82
  };
53
83
  }
54
- static broadcastToClients(wss, samples, timestamps) {
55
- for (const client of wss.clients) {
84
+ static broadcastToClients(localServer, payload) {
85
+ for (const client of localServer.clients) {
56
86
  if (client.readyState === WebSocket.OPEN) {
57
- client.send(JSON.stringify({
58
- samples,
59
- timestamps,
60
- }));
87
+ client.send(payload);
61
88
  }
62
89
  }
63
90
  }
64
- static LslStreamInlet(options, wss) {
65
- const onData = this.createOnDataCallback(wss);
66
- return LslStreamInlet.Create(options, onData);
91
+ static sendToSockets(remoteSockets, payload) {
92
+ for (const socket of remoteSockets) {
93
+ if (socket.readyState === WebSocket.OPEN) {
94
+ socket.send(payload);
95
+ }
96
+ }
97
+ }
98
+ static createSocketsFrom(connectUrls) {
99
+ return connectUrls
100
+ ? (Array.isArray(connectUrls) ? connectUrls : [connectUrls]).map((url) => this.WebSocket(url))
101
+ : undefined;
67
102
  }
68
- static WebSocketServer(wssPort) {
69
- return new this.WSS({ port: wssPort });
103
+ static WebSocket(url) {
104
+ return new this.WS(url);
105
+ }
106
+ static WebSocketServer(listenPort) {
107
+ return listenPort ? new this.WSS({ port: listenPort }) : undefined;
108
+ }
109
+ static LslStreamInlet(options, localServer, remoteSockets) {
110
+ const onData = this.createOnDataCallback(localServer, remoteSockets);
111
+ return LslStreamInlet.Create(options, onData);
70
112
  }
71
113
  }
72
114
  //# sourceMappingURL=LslWebSocketBridge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LslWebSocketBridge.js","sourceRoot":"","sources":["../../src/impl/LslWebSocketBridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LslWebSocketBridge.js","sourceRoot":"","sources":["../../src/impl/LslWebSocketBridge.ts"],"names":[],"mappings":"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"}
@@ -4,8 +4,16 @@ export default class FakeStreamInfo implements StreamInfo {
4
4
  static callsToConstructor: StreamInfoOptions[];
5
5
  static numCallsToDestroy: number;
6
6
  static boundStreamInfo: BoundStreamInfo;
7
+ name: string;
8
+ type: string;
9
+ sourceId: string;
10
+ channelNames: string[];
11
+ channelFormat: "float32";
12
+ sampleRateHz: number;
13
+ units: string;
7
14
  constructor(options: StreamInfoOptions);
8
15
  destroy(): void;
16
+ get channelCount(): number;
9
17
  get boundStreamInfo(): BoundStreamInfo;
10
18
  static resetTestDouble(): void;
11
19
  }
@@ -1,13 +1,24 @@
1
+ import generateId from '@neurodevs/generate-id';
1
2
  export default class FakeStreamInfo {
2
3
  static callsToConstructor = [];
3
4
  static numCallsToDestroy = 0;
4
5
  static boundStreamInfo = {};
6
+ name = generateId();
7
+ type = generateId();
8
+ sourceId = generateId();
9
+ channelNames = [generateId(), generateId()];
10
+ channelFormat = 'float32';
11
+ sampleRateHz = 0;
12
+ units = 'N/A';
5
13
  constructor(options) {
6
14
  FakeStreamInfo.callsToConstructor.push(options);
7
15
  }
8
16
  destroy() {
9
17
  FakeStreamInfo.numCallsToDestroy++;
10
18
  }
19
+ get channelCount() {
20
+ return this.channelNames.length;
21
+ }
11
22
  get boundStreamInfo() {
12
23
  return FakeStreamInfo.boundStreamInfo;
13
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FakeStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/FakeStreamInfo.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,OAAO,cAAc;IACxB,MAAM,CAAC,kBAAkB,GAAwB,EAAE,CAAA;IACnD,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,GAAG,EAAqB,CAAA;IAErD,YAAmB,OAA0B;QACzC,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAEM,OAAO;QACV,cAAc,CAAC,iBAAiB,EAAE,CAAA;IACtC,CAAC;IAED,IAAW,eAAe;QACtB,OAAO,cAAc,CAAC,eAAe,CAAA;IACzC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,cAAc,CAAC,kBAAkB,GAAG,EAAE,CAAA;QACtC,cAAc,CAAC,iBAAiB,GAAG,CAAC,CAAA;IACxC,CAAC"}
1
+ {"version":3,"file":"FakeStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/FakeStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAK/C,MAAM,CAAC,OAAO,OAAO,cAAc;IACxB,MAAM,CAAC,kBAAkB,GAAwB,EAAE,CAAA;IACnD,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,GAAG,EAAqB,CAAA;IAE9C,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,QAAQ,GAAG,UAAU,EAAE,CAAA;IACvB,YAAY,GAAa,CAAC,UAAU,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IACrD,aAAa,GAAG,SAAkB,CAAA;IAClC,YAAY,GAAG,CAAC,CAAA;IAChB,KAAK,GAAG,KAAK,CAAA;IAEpB,YAAmB,OAA0B;QACzC,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAEM,OAAO;QACV,cAAc,CAAC,iBAAiB,EAAE,CAAA;IACtC,CAAC;IAED,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAA;IACnC,CAAC;IAED,IAAW,eAAe;QACtB,OAAO,cAAc,CAAC,eAAe,CAAA;IACzC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,cAAc,CAAC,kBAAkB,GAAG,EAAE,CAAA;QACtC,cAAc,CAAC,iBAAiB,GAAG,CAAC,CAAA;IACxC,CAAC"}
@@ -1,9 +1,11 @@
1
1
  import LslStreamInfo, { StreamInfoOptions } from '../../impl/LslStreamInfo.js';
2
2
  export default class SpyStreamInfo extends LslStreamInfo {
3
+ static numCallsToConstructor: number;
3
4
  constructor(options: StreamInfoOptions);
4
5
  getBoundInfo(): import("../../index.js").BoundStreamInfo;
5
6
  getName(): string;
6
7
  getType(): string;
7
8
  getSourceId(): string;
8
9
  getUnits(): string;
10
+ static resetTestDouble(): void;
9
11
  }
@@ -1,7 +1,9 @@
1
1
  import LslStreamInfo from '../../impl/LslStreamInfo.js';
2
2
  export default class SpyStreamInfo extends LslStreamInfo {
3
+ static numCallsToConstructor = 0;
3
4
  constructor(options) {
4
5
  super(options);
6
+ SpyStreamInfo.numCallsToConstructor++;
5
7
  }
6
8
  getBoundInfo() {
7
9
  return this.boundInfo;
@@ -18,5 +20,8 @@ export default class SpyStreamInfo extends LslStreamInfo {
18
20
  getUnits() {
19
21
  return this.units;
20
22
  }
23
+ static resetTestDouble() {
24
+ SpyStreamInfo.numCallsToConstructor = 0;
25
+ }
21
26
  }
22
27
  //# sourceMappingURL=SpyStreamInfo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpyStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/SpyStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,aAAoC,MAAM,6BAA6B,CAAA;AAE9E,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAAa;IACpD,YAAmB,OAA0B;QACzC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;IAEM,YAAY;QACf,OAAO,IAAI,CAAC,SAAS,CAAA;IACzB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAA;IACxB,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;CACJ"}
1
+ {"version":3,"file":"SpyStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/SpyStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,aAAoC,MAAM,6BAA6B,CAAA;AAE9E,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAAa;IAC7C,MAAM,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAEvC,YAAmB,OAA0B;QACzC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,aAAa,CAAC,qBAAqB,EAAE,CAAA;IACzC,CAAC;IAEM,YAAY;QACf,OAAO,IAAI,CAAC,SAAS,CAAA;IACzB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAA;IACxB,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,aAAa,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAC3C,CAAC"}
@@ -9,4 +9,6 @@ export default class FakeWebSocketBridge implements WebSocketBridge {
9
9
  deactivate(): void;
10
10
  destroy(): void;
11
11
  static resetTestDouble(): void;
12
+ private static setFakeWebSocket;
13
+ private static setFakeWebSocketServer;
12
14
  }
@@ -1,3 +1,6 @@
1
+ import LslWebSocketBridge from '../../impl/LslWebSocketBridge.js';
2
+ import FakeWebSocket from '../WebSockets/FakeWebSocket.js';
3
+ import FakeWebSocketServer from '../WebSockets/FakeWebSocketServer.js';
1
4
  export default class FakeWebSocketBridge {
2
5
  static numCallsToConstructor = 0;
3
6
  static numCallsToActivate = 0;
@@ -16,10 +19,21 @@ export default class FakeWebSocketBridge {
16
19
  FakeWebSocketBridge.numCallsToDestroy++;
17
20
  }
18
21
  static resetTestDouble() {
19
- FakeWebSocketBridge.numCallsToConstructor = 0;
20
- FakeWebSocketBridge.numCallsToActivate = 0;
21
- FakeWebSocketBridge.numCallsToDeactivate = 0;
22
- FakeWebSocketBridge.numCallsToDestroy = 0;
22
+ this.numCallsToConstructor = 0;
23
+ this.numCallsToActivate = 0;
24
+ this.numCallsToDeactivate = 0;
25
+ this.numCallsToDestroy = 0;
26
+ this.setFakeWebSocket();
27
+ this.setFakeWebSocketServer();
28
+ }
29
+ static setFakeWebSocket() {
30
+ LslWebSocketBridge.WS = FakeWebSocket;
31
+ FakeWebSocket.resetTestDouble();
32
+ }
33
+ static setFakeWebSocketServer() {
34
+ LslWebSocketBridge.WSS =
35
+ FakeWebSocketServer;
36
+ FakeWebSocketServer.resetTestDouble();
23
37
  }
24
38
  }
25
39
  //# sourceMappingURL=FakeWebSocketBridge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FakeWebSocketBridge.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAC7B,MAAM,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAChC,MAAM,CAAC,kBAAkB,GAAG,CAAC,CAAA;IAC7B,MAAM,CAAC,oBAAoB,GAAG,CAAC,CAAA;IAC/B,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAEnC;QACI,mBAAmB,CAAC,qBAAqB,EAAE,CAAA;IAC/C,CAAC;IAEM,QAAQ;QACX,mBAAmB,CAAC,kBAAkB,EAAE,CAAA;IAC5C,CAAC;IAEM,UAAU;QACb,mBAAmB,CAAC,oBAAoB,EAAE,CAAA;IAC9C,CAAC;IAEM,OAAO;QACV,mBAAmB,CAAC,iBAAiB,EAAE,CAAA;IAC3C,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,mBAAmB,CAAC,qBAAqB,GAAG,CAAC,CAAA;QAC7C,mBAAmB,CAAC,kBAAkB,GAAG,CAAC,CAAA;QAC1C,mBAAmB,CAAC,oBAAoB,GAAG,CAAC,CAAA;QAC5C,mBAAmB,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAC7C,CAAC"}
1
+ {"version":3,"file":"FakeWebSocketBridge.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts"],"names":[],"mappings":"AACA,OAAO,kBAEN,MAAM,kCAAkC,CAAA;AACzC,OAAO,aAAa,MAAM,gCAAgC,CAAA;AAC1D,OAAO,mBAAmB,MAAM,sCAAsC,CAAA;AAEtE,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAC7B,MAAM,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAChC,MAAM,CAAC,kBAAkB,GAAG,CAAC,CAAA;IAC7B,MAAM,CAAC,oBAAoB,GAAG,CAAC,CAAA;IAC/B,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAEnC;QACI,mBAAmB,CAAC,qBAAqB,EAAE,CAAA;IAC/C,CAAC;IAEM,QAAQ;QACX,mBAAmB,CAAC,kBAAkB,EAAE,CAAA;IAC5C,CAAC;IAEM,UAAU;QACb,mBAAmB,CAAC,oBAAoB,EAAE,CAAA;IAC9C,CAAC;IAEM,OAAO;QACV,mBAAmB,CAAC,iBAAiB,EAAE,CAAA;IAC3C,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,IAAI,CAAC,qBAAqB,GAAG,CAAC,CAAA;QAC9B,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAA;QAC3B,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAA;QAC7B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAA;QAE1B,IAAI,CAAC,gBAAgB,EAAE,CAAA;QACvB,IAAI,CAAC,sBAAsB,EAAE,CAAA;IACjC,CAAC;IAEO,MAAM,CAAC,gBAAgB;QAC3B,kBAAkB,CAAC,EAAE,GAAG,aAA4C,CAAA;QACpE,aAAa,CAAC,eAAe,EAAE,CAAA;IACnC,CAAC;IAEO,MAAM,CAAC,sBAAsB;QACjC,kBAAkB,CAAC,GAAG;YAClB,mBAAwD,CAAA;QAC5D,mBAAmB,CAAC,eAAe,EAAE,CAAA;IACzC,CAAC"}
@@ -1,10 +1,14 @@
1
1
  export default class FakeWebSocket {
2
+ static callsToConstructor: (string | undefined)[];
2
3
  static callsToSend: {
3
4
  id: string;
4
5
  data: unknown;
5
6
  }[];
7
+ static numCallsToClose: number;
6
8
  readyState: number;
7
9
  id: string;
10
+ constructor(url?: string);
8
11
  send(data: unknown): void;
12
+ close(): void;
9
13
  static resetTestDouble(): void;
10
14
  }
@@ -1,14 +1,25 @@
1
1
  import generateId from '@neurodevs/generate-id';
2
2
  import WebSocket from 'ws';
3
3
  export default class FakeWebSocket {
4
+ static callsToConstructor = [];
4
5
  static callsToSend = [];
6
+ static numCallsToClose = 0;
5
7
  readyState = WebSocket.OPEN;
6
8
  id = generateId();
9
+ constructor(url) {
10
+ FakeWebSocket.callsToConstructor.push(url);
11
+ }
7
12
  send(data) {
8
13
  FakeWebSocket.callsToSend.push({ id: this.id, data });
9
14
  }
15
+ close() {
16
+ FakeWebSocket.numCallsToClose++;
17
+ this.readyState = WebSocket.CLOSED;
18
+ }
10
19
  static resetTestDouble() {
11
- FakeWebSocket.callsToSend = [];
20
+ this.callsToConstructor = [];
21
+ this.callsToSend = [];
22
+ this.numCallsToClose = 0;
12
23
  }
13
24
  }
14
25
  //# sourceMappingURL=FakeWebSocket.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FakeWebSocket.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSockets/FakeWebSocket.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAC/C,OAAO,SAAS,MAAM,IAAI,CAAA;AAE1B,MAAM,CAAC,OAAO,OAAO,aAAa;IACvB,MAAM,CAAC,WAAW,GAAoC,EAAE,CAAA;IAExD,UAAU,GAAW,SAAS,CAAC,IAAI,CAAA;IACnC,EAAE,GAAG,UAAU,EAAE,CAAA;IAEjB,IAAI,CAAC,IAAa;QACrB,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,aAAa,CAAC,WAAW,GAAG,EAAE,CAAA;IAClC,CAAC"}
1
+ {"version":3,"file":"FakeWebSocket.js","sourceRoot":"","sources":["../../../src/testDoubles/WebSockets/FakeWebSocket.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAC/C,OAAO,SAAS,MAAM,IAAI,CAAA;AAE1B,MAAM,CAAC,OAAO,OAAO,aAAa;IACvB,MAAM,CAAC,kBAAkB,GAA2B,EAAE,CAAA;IACtD,MAAM,CAAC,WAAW,GAAoC,EAAE,CAAA;IACxD,MAAM,CAAC,eAAe,GAAG,CAAC,CAAA;IAE1B,UAAU,GAAW,SAAS,CAAC,IAAI,CAAA;IACnC,EAAE,GAAG,UAAU,EAAE,CAAA;IAExB,YAAmB,GAAY;QAC3B,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC9C,CAAC;IAEM,IAAI,CAAC,IAAa;QACrB,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC;IAEM,KAAK;QACR,aAAa,CAAC,eAAe,EAAE,CAAA;QAC/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,MAAM,CAAA;IACtC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAA;QAC5B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;QACrB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;IAC5B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurodevs/node-lsl",
3
- "version": "14.1.5",
3
+ "version": "16.0.0",
4
4
  "description": "Lab Streaming Layer (LSL) bindings for Node",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -1,4 +1,5 @@
1
1
  import AbstractModuleTest from '@neurodevs/node-tdd'
2
+ import WebSocket from 'ws'
2
3
 
3
4
  import { Server } from 'ws'
4
5
  import LiblslAdapter from '../impl/LiblslAdapter.js'
@@ -18,6 +19,7 @@ import FakeStreamInlet from '../testDoubles/StreamInlet/FakeStreamInlet.js'
18
19
  import { SpyStreamInlet } from '../testDoubles/StreamInlet/SpyStreamInlet.js'
19
20
  import FakeStreamOutlet from '../testDoubles/StreamOutlet/FakeStreamOutlet.js'
20
21
  import SpyLslWebSocketBridge from '../testDoubles/WebSocketBridge/SpyLslWebSocketBridge.js'
22
+ import FakeWebSocket from '../testDoubles/WebSockets/FakeWebSocket.js'
21
23
  import FakeWebSocketServer from '../testDoubles/WebSockets/FakeWebSocketServer.js'
22
24
 
23
25
  export default class AbstractPackageTest extends AbstractModuleTest {
@@ -38,11 +40,14 @@ export default class AbstractPackageTest extends AbstractModuleTest {
38
40
 
39
41
  protected static setSpyStreamInfo() {
40
42
  LslStreamInfo.Class = SpyStreamInfo
43
+ SpyStreamInfo.resetTestDouble()
41
44
  }
42
45
 
43
46
  protected static setFakeStreamInfo() {
44
47
  LslStreamInfo.Class = FakeStreamInfo
45
48
  FakeStreamInfo.resetTestDouble()
49
+
50
+ LslStreamInfo['instanceCache'] = {}
46
51
  }
47
52
 
48
53
  protected static setSpyStreamInlet() {
@@ -67,6 +72,11 @@ export default class AbstractPackageTest extends AbstractModuleTest {
67
72
  LslWebSocketBridge.Class = SpyLslWebSocketBridge
68
73
  }
69
74
 
75
+ protected static setFakeWebSocket() {
76
+ LslWebSocketBridge.WS = FakeWebSocket as unknown as typeof WebSocket
77
+ FakeWebSocket.resetTestDouble()
78
+ }
79
+
70
80
  protected static setFakeWebSocketServer() {
71
81
  LslWebSocketBridge.WSS = FakeWebSocketServer as unknown as typeof Server
72
82
  FakeWebSocketServer.resetTestDouble()
@@ -13,6 +13,8 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
13
13
 
14
14
  this.setSpyStreamInfo()
15
15
 
16
+ LslStreamInfo['instanceCache'] = {}
17
+
16
18
  this.instance = this.LslStreamInfo()
17
19
  }
18
20
 
@@ -23,8 +25,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
23
25
 
24
26
  @test()
25
27
  protected static async generatesUniqueNameIfNotProvided() {
26
- const instance1 = this.LslStreamInfo({ name: undefined })
27
- const instance2 = this.LslStreamInfo({ name: undefined })
28
+ const instance1 = this.LslStreamInfo({
29
+ name: undefined,
30
+ type: this.generateId(),
31
+ })
32
+
33
+ const instance2 = this.LslStreamInfo({
34
+ name: undefined,
35
+ type: this.generateId(),
36
+ })
28
37
 
29
38
  assert.isNotEqual(
30
39
  instance1.getName(),
@@ -58,8 +67,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
58
67
 
59
68
  @test()
60
69
  protected static async generatesUniqueTypeIfNotProvided() {
61
- const instance1 = this.LslStreamInfo({ type: undefined })
62
- const instance2 = this.LslStreamInfo({ type: undefined })
70
+ const instance1 = this.LslStreamInfo({
71
+ type: undefined,
72
+ name: this.generateId(),
73
+ })
74
+
75
+ const instance2 = this.LslStreamInfo({
76
+ type: undefined,
77
+ name: this.generateId(),
78
+ })
63
79
 
64
80
  assert.isNotEqual(
65
81
  instance1.getType(),
@@ -82,8 +98,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
82
98
 
83
99
  @test()
84
100
  protected static async generatesUniqueSourceIdIfNotProvided() {
85
- const instance1 = this.LslStreamInfo({ sourceId: undefined })
86
- const instance2 = this.LslStreamInfo({ sourceId: undefined })
101
+ const instance1 = this.LslStreamInfo({
102
+ sourceId: undefined,
103
+ name: this.generateId(),
104
+ })
105
+
106
+ const instance2 = this.LslStreamInfo({
107
+ sourceId: undefined,
108
+ name: this.generateId(),
109
+ })
87
110
 
88
111
  assert.isNotEqual(
89
112
  instance1.getSourceId(),
@@ -192,6 +215,17 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
192
215
  )
193
216
  }
194
217
 
218
+ @test()
219
+ protected static async cachesInfoIfPassedSameOptions() {
220
+ this.LslStreamInfo()
221
+
222
+ assert.isEqual(
223
+ SpyStreamInfo.numCallsToConstructor,
224
+ 1,
225
+ 'Did not cache stream info!'
226
+ )
227
+ }
228
+
195
229
  private static readonly defaultOptions = {
196
230
  name: this.generateId(),
197
231
  type: this.generateId(),