@neurodevs/node-lsl 23.1.0 → 23.1.2

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 (38) hide show
  1. package/build/__tests__/AbstractPackageTest.js +0 -1
  2. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  3. package/build/__tests__/impl/BleGattController.test.d.ts +4 -0
  4. package/build/__tests__/impl/BleGattController.test.js +27 -5
  5. package/build/__tests__/impl/BleGattController.test.js.map +1 -1
  6. package/build/__tests__/impl/LslStreamInlet.test.d.ts +4 -5
  7. package/build/__tests__/impl/LslStreamInlet.test.js +37 -58
  8. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  9. package/build/impl/LslStreamInfo.d.ts +3 -3
  10. package/build/impl/LslStreamInfo.js.map +1 -1
  11. package/build/impl/LslStreamInlet.d.ts +9 -39
  12. package/build/impl/LslStreamInlet.js +23 -151
  13. package/build/impl/LslStreamInlet.js.map +1 -1
  14. package/build/impl/LslStreamOutlet.d.ts +3 -3
  15. package/build/impl/LslStreamOutlet.js.map +1 -1
  16. package/build/impl/clocks/WindowedClockRegressor.d.ts +2 -2
  17. package/build/impl/clocks/WindowedClockRegressor.js.map +1 -1
  18. package/build/impl/controllers/BleGattController.d.ts +21 -12
  19. package/build/impl/controllers/BleGattController.js +22 -30
  20. package/build/impl/controllers/BleGattController.js.map +1 -1
  21. package/build/testDoubles/BleGatt/FakeBleGatt.d.ts +3 -2
  22. package/build/testDoubles/BleGatt/FakeBleGatt.js +6 -4
  23. package/build/testDoubles/BleGatt/FakeBleGatt.js.map +1 -1
  24. package/build/testDoubles/BleGatt/SpyBleGatt.d.ts +1 -1
  25. package/build/testDoubles/BleGatt/SpyBleGatt.js +2 -2
  26. package/build/testDoubles/BleGatt/SpyBleGatt.js.map +1 -1
  27. package/build/testDoubles/LslOutlet/FakeLslOutlet.d.ts +1 -1
  28. package/package.json +3 -4
  29. package/src/__tests__/AbstractPackageTest.ts +0 -2
  30. package/src/__tests__/impl/BleGattController.test.ts +48 -6
  31. package/src/__tests__/impl/LslStreamInlet.test.ts +45 -86
  32. package/src/impl/LslStreamInfo.ts +3 -3
  33. package/src/impl/LslStreamInlet.ts +38 -218
  34. package/src/impl/LslStreamOutlet.ts +3 -3
  35. package/src/impl/clocks/WindowedClockRegressor.ts +1 -1
  36. package/src/impl/controllers/BleGattController.ts +35 -37
  37. package/src/testDoubles/BleGatt/FakeBleGatt.ts +9 -6
  38. package/src/testDoubles/BleGatt/SpyBleGatt.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"SpyBleGatt.js","sourceRoot":"","sources":["../../../src/testDoubles/BleGatt/SpyBleGatt.ts"],"names":[],"mappings":"AAAA,OAAO,iBAEN,MAAM,6CAA6C,CAAA;AAEpD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,iBAAiB;IAC9C,QAAQ,GAAa,EAAE,CAAA;IACvB,QAAQ,GAAa,EAAE,CAAA;IACvB,SAAS,GAAa,EAAE,CAAA;IAE/B,YAAmB,OAAuB;QACtC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;IAEM,0BAA0B;QAC7B,OAAO,IAAI,CAAC,aAAa,CAAA;IAC7B,CAAC;IAEM,iBAAiB;QACpB,OAAO,IAAI,CAAC,cAAc,CAAA;IAC9B,CAAC;IAEM,YAAY;QACf,OAAO,IAAI,CAAC,SAAS,CAAA;IACzB,CAAC;IAEM,aAAa;QAChB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAElB,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC3B,OAAO,OAAO,CAAA;QAClB,CAAC,CAAA;IACL,CAAC;IAEM,aAAa;QAChB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAElB,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC3B,OAAO,OAAO,CAAA;QAClB,CAAC,CAAA;IACL,CAAC;IAEM,cAAc;QACjB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;QAEnB,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC5B,OAAO,OAAO,CAAA;QAClB,CAAC,CAAA;IACL,CAAC;IAEM,eAAe;QAClB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAClB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IACvB,CAAC;CACJ"}
1
+ {"version":3,"file":"SpyBleGatt.js","sourceRoot":"","sources":["../../../src/testDoubles/BleGatt/SpyBleGatt.ts"],"names":[],"mappings":"AAAA,OAAO,iBAEN,MAAM,6CAA6C,CAAA;AAEpD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,iBAAiB;IAC9C,QAAQ,GAAa,EAAE,CAAA;IACvB,QAAQ,GAAa,EAAE,CAAA;IACvB,SAAS,GAAa,EAAE,CAAA;IAE/B,YAAmB,OAAuB;QACtC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;IAEM,0BAA0B;QAC7B,OAAO,IAAI,CAAC,aAAa,CAAA;IAC7B,CAAC;IAEM,iBAAiB;QACpB,OAAO,IAAI,CAAC,cAAc,CAAA;IAC9B,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;IAEM,aAAa;QAChB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAElB,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC3B,OAAO,OAAO,CAAA;QAClB,CAAC,CAAA;IACL,CAAC;IAEM,aAAa;QAChB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAElB,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC3B,OAAO,OAAO,CAAA;QAClB,CAAC,CAAA;IACL,CAAC;IAEM,cAAc;QACjB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;QAEnB,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC9B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC5B,OAAO,OAAO,CAAA;QAClB,CAAC,CAAA;IACL,CAAC;IAEM,eAAe;QAClB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAClB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IACvB,CAAC;CACJ"}
@@ -14,7 +14,7 @@ export default class FakeLslOutlet implements LslOutlet {
14
14
  get name(): string;
15
15
  get type(): string;
16
16
  get sourceId(): string;
17
- get channelNames(): string[];
17
+ get channelNames(): readonly string[];
18
18
  get channelCount(): number;
19
19
  get channelFormat(): "string" | "undefined" | "float32" | "double64" | "int32" | "int16" | "int8" | "int64";
20
20
  get sampleRateHz(): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurodevs/node-lsl",
3
- "version": "23.1.0",
3
+ "version": "23.1.2",
4
4
  "description": "Lab Streaming Layer (LSL) bindings for Node",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -42,12 +42,11 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@neurodevs/generate-id": "^1.1.3",
45
- "@neurodevs/ndx-native": "^9.0.0",
46
- "ffi-rs": "^1.3.1",
45
+ "@neurodevs/ndx-native": "^10.0.0",
47
46
  "ws": "^8.18.3"
48
47
  },
49
48
  "devDependencies": {
50
- "@neurodevs/eslint-config-ndx": "2.0.0",
49
+ "@neurodevs/eslint-config-ndx": "2.0.3",
51
50
  "@neurodevs/node-tdd": "^3.0.3",
52
51
  "@neurodevs/prettier-config-ndx": "^1.0.2",
53
52
  "@types/ws": "^8.18.1",
@@ -100,8 +100,6 @@ export default class AbstractPackageTest extends AbstractModuleTest {
100
100
 
101
101
  FakeLibndx.resetTestDouble()
102
102
  FakeLibndx.fakeResult = { status: 200 }
103
-
104
- BleGattController.ndx = this.fakeLibndx
105
103
  }
106
104
 
107
105
  protected static setSpyLslInfo() {
@@ -21,6 +21,8 @@ export default class BleGattControllerTest extends AbstractPackageTest {
21
21
  private static readonly fakeError = this.generateId()
22
22
  private static readonly fake400Error = `400 error: ${this.fakeError}`
23
23
  private static readonly fake500Error = `500 error: ${this.fakeError}`
24
+ private static readonly uuidNotResolvedError =
25
+ 'Device uuid is not resolved yet! Must either pass as option to Create or call connect() first.'
24
26
 
25
27
  private static readonly charCallbacks = [
26
28
  {
@@ -93,7 +95,7 @@ export default class BleGattControllerTest extends AbstractPackageTest {
93
95
 
94
96
  @test()
95
97
  protected static async discoversUuidWhenDeviceUuidNotProvided() {
96
- const instance = await this.BleGattControllerWithPrefix()
98
+ const instance = this.BleGattControllerWithPrefix()
97
99
 
98
100
  await this.connectWithDiscovery(instance)
99
101
 
@@ -124,7 +126,7 @@ export default class BleGattControllerTest extends AbstractPackageTest {
124
126
 
125
127
  @test()
126
128
  protected static async usesDiscoveredUuidToCreateBleBackend() {
127
- const instance = await this.BleGattControllerWithPrefix()
129
+ const instance = this.BleGattControllerWithPrefix()
128
130
 
129
131
  await this.connectWithDiscovery(instance)
130
132
 
@@ -139,7 +141,7 @@ export default class BleGattControllerTest extends AbstractPackageTest {
139
141
 
140
142
  @test()
141
143
  protected static async usesDiscoveredUuidToStartBleBackend() {
142
- const instance = await this.BleGattControllerWithPrefix()
144
+ const instance = this.BleGattControllerWithPrefix()
143
145
 
144
146
  await this.connectWithDiscovery(instance)
145
147
 
@@ -152,7 +154,7 @@ export default class BleGattControllerTest extends AbstractPackageTest {
152
154
 
153
155
  @test()
154
156
  protected static async exposesDiscoveredUuid() {
155
- const instance = await this.BleGattControllerWithPrefix()
157
+ const instance = this.BleGattControllerWithPrefix()
156
158
 
157
159
  await this.connectWithDiscovery(instance)
158
160
 
@@ -406,8 +408,8 @@ export default class BleGattControllerTest extends AbstractPackageTest {
406
408
  await this.connect()
407
409
  await this.disconnect()
408
410
 
409
- assert.isFalse(
410
- this.instance.getConnected(),
411
+ assert.isTrue(
412
+ this.instance.getState().status === 'disconnected',
411
413
  'Did not reset connected flag on disconnect!'
412
414
  )
413
415
  }
@@ -432,6 +434,46 @@ export default class BleGattControllerTest extends AbstractPackageTest {
432
434
  )
433
435
  }
434
436
 
437
+ @test()
438
+ protected static async writeCharacteristicThrowsIfUuidNotResolved() {
439
+ const instance = this.BleGattControllerWithPrefix()
440
+
441
+ await assert.doesThrowAsync(
442
+ async () =>
443
+ await instance.writeCharacteristic(
444
+ this.charUuid,
445
+ this.charValueToWrite
446
+ ),
447
+ this.uuidNotResolvedError,
448
+ 'Should not write to a device whose uuid is not resolved!'
449
+ )
450
+ }
451
+
452
+ @test()
453
+ protected static async subscribeCharacteristicsThrowsIfUuidNotResolved() {
454
+ const instance = this.BleGattControllerWithPrefix()
455
+
456
+ await assert.doesThrowAsync(
457
+ async () =>
458
+ await instance.subscribeCharacteristics(
459
+ this.extraCharCallbacks
460
+ ),
461
+ this.uuidNotResolvedError,
462
+ 'Should not subscribe to a device whose uuid is not resolved!'
463
+ )
464
+ }
465
+
466
+ @test()
467
+ protected static async disconnectThrowsIfUuidNotResolved() {
468
+ const instance = this.BleGattControllerWithPrefix()
469
+
470
+ await assert.doesThrowAsync(
471
+ async () => await instance.disconnect(),
472
+ this.uuidNotResolvedError,
473
+ 'Should not disconnect a device whose uuid is not resolved!'
474
+ )
475
+ }
476
+
435
477
  @test()
436
478
  protected static async throwsWithUnknownErrorIfNoError() {
437
479
  this.setFake500ErrorWithoutError()
@@ -1,13 +1,5 @@
1
1
  import { FakeLiblsl } from '@neurodevs/ndx-native'
2
2
  import { test, assert } from '@neurodevs/node-tdd'
3
- import {
4
- createPointer,
5
- DataType,
6
- FieldType,
7
- JsExternal,
8
- PointerType,
9
- unwrapPointer,
10
- } from 'ffi-rs'
11
3
 
12
4
  import LslStreamInlet, { LslInletOptions } from '../../impl/LslStreamInlet.js'
13
5
  import SpyLslInlet from '../../testDoubles/LslInlet/SpyLslInlet.js'
@@ -21,27 +13,6 @@ export default class LslStreamInletTest extends AbstractPackageTest {
21
13
  timestamps: number[]
22
14
  }[]
23
15
 
24
- private static readonly sampleBufferPtr = unwrapPointer(
25
- createPointer({
26
- paramsType: [DataType.U8Array],
27
- paramsValue: [new Float32Array(this.channelCount * this.chunkSize)],
28
- })
29
- )[0]
30
-
31
- private static readonly timestampBufferPtr = unwrapPointer(
32
- createPointer({
33
- paramsType: [DataType.U8Array],
34
- paramsValue: [new Float64Array(this.chunkSize)],
35
- })
36
- )[0]
37
-
38
- private static readonly errorCodePtr = unwrapPointer(
39
- createPointer({
40
- paramsType: [DataType.U8Array],
41
- paramsValue: [new Int32Array(1)],
42
- })
43
- )[0]
44
-
45
16
  protected static async beforeAll() {
46
17
  assert.isEqual(
47
18
  LslStreamInlet.waitAfterOpenStreamMs,
@@ -60,7 +31,6 @@ export default class LslStreamInletTest extends AbstractPackageTest {
60
31
 
61
32
  LslStreamInlet.waitAfterOpenStreamMs = 0
62
33
  LslStreamInlet.lsl = this.fakeLiblsl
63
- LslStreamInlet.freePointer = () => {}
64
34
 
65
35
  this.instance = await this.LslStreamInlet()
66
36
  }
@@ -81,6 +51,7 @@ export default class LslStreamInletTest extends AbstractPackageTest {
81
51
  {
82
52
  infoHandle: this.inletHandle,
83
53
  maxBufferedMs: this.maxBufferedMs,
54
+ chunkSize: this.chunkSize,
84
55
  },
85
56
  'Should have called createInlet!'
86
57
  )
@@ -101,46 +72,39 @@ export default class LslStreamInletTest extends AbstractPackageTest {
101
72
 
102
73
  @test()
103
74
  protected static async destroyCallsLslBinding() {
104
- await this.startPullingThenDestroy()
75
+ await this.startPulling()
76
+ const inletHandle = this.inletHandle
105
77
 
106
- assert.isEqualDeep(
107
- this.fakeLiblsl.lastDestroyInletOptions,
108
- { inletHandle: this.inletHandle },
78
+ this.destroy()
79
+
80
+ assert.isTrue(
81
+ inletHandle !== undefined &&
82
+ this.fakeLiblsl.lastDestroyInletOptions?.inletHandle ===
83
+ inletHandle,
109
84
  'Did not destroy inlet!'
110
85
  )
111
86
  }
112
87
 
113
88
  @test()
114
- protected static async destroyFreesAllPointers() {
115
- interface FreePointerParams {
116
- paramsType: FieldType[]
117
- paramsValue: JsExternal[]
118
- pointerType: PointerType
119
- }
120
-
121
- let calls: FreePointerParams[] = []
89
+ protected static async destroyDoesNotDestroyInletThatWasNeverCreated() {
90
+ this.destroy()
122
91
 
123
- LslStreamInlet.freePointer = (params: FreePointerParams) => {
124
- calls.push(params)
125
- }
92
+ assert.isEqual(
93
+ this.fakeLiblsl.destroyInletHitCount,
94
+ 0,
95
+ 'Should not have destroyed an inlet that was never created!'
96
+ )
97
+ }
126
98
 
99
+ @test()
100
+ protected static async destroyingTwiceDestroysInletOnce() {
127
101
  await this.startPullingThenDestroy()
102
+ this.destroy()
128
103
 
129
- const { paramsType, pointerType } = calls[0]
130
-
131
- assert.isEqualDeep(
132
- { paramsType, pointerType },
133
- {
134
- paramsType: [
135
- DataType.U8Array,
136
- DataType.U8Array,
137
- DataType.U8Array,
138
- DataType.U8Array,
139
- ],
140
- pointerType: PointerType.CPointer,
141
- },
142
-
143
- 'Destroy did not free all pointers!'
104
+ assert.isEqual(
105
+ this.fakeLiblsl.destroyInletHitCount,
106
+ 1,
107
+ 'Should have destroyed inlet only once!'
144
108
  )
145
109
  }
146
110
 
@@ -207,7 +171,6 @@ export default class LslStreamInletTest extends AbstractPackageTest {
207
171
  {
208
172
  inletHandle: this.inletHandle,
209
173
  timeoutMs: aboutOneYearInMs,
210
- errorCodePtr: this.errorCodePtr,
211
174
  },
212
175
  'Did not open inlet stream!'
213
176
  )
@@ -230,7 +193,6 @@ export default class LslStreamInletTest extends AbstractPackageTest {
230
193
  {
231
194
  inletHandle: instance['inletHandle'],
232
195
  timeoutMs: openStreamTimeoutMs,
233
- errorCodePtr: this.errorCodePtr,
234
196
  },
235
197
  'Did not open inlet stream with passed timeout!'
236
198
  )
@@ -316,13 +278,7 @@ export default class LslStreamInletTest extends AbstractPackageTest {
316
278
 
317
279
  assert.isEqualDeep(
318
280
  this.fakeLiblsl.lastPullSampleOptions,
319
- {
320
- inletHandle: this.inletHandle,
321
- sampleBufferPtr: this.sampleBufferPtr,
322
- sampleBufferElements: this.channelCount,
323
- timeoutMs: 0,
324
- errorCodePtr: this.errorCodePtr,
325
- },
281
+ { inletHandle: this.inletHandle, timeoutMs: 0 },
326
282
  'Should have called pullSample!'
327
283
  )
328
284
  }
@@ -333,33 +289,36 @@ export default class LslStreamInletTest extends AbstractPackageTest {
333
289
 
334
290
  assert.isEqualDeep(
335
291
  this.fakeLiblsl.lastPullChunkOptions,
336
- {
337
- inletHandle: this.inletHandle,
338
- sampleBufferPtr: this.sampleBufferPtr,
339
- timestampBufferPtr: this.timestampBufferPtr,
340
- sampleBufferElements: this.chunkSize * this.channelCount,
341
- timestampBufferElements: this.chunkSize,
342
- timeoutMs: 0,
343
- errorCodePtr: this.errorCodePtr,
344
- },
292
+ { inletHandle: this.inletHandle, timeoutMs: 0 },
345
293
  'Should have called pullChunk!'
346
294
  )
347
295
  }
348
296
 
349
297
  @test()
350
- protected static async pushSampleHandlesErrorCode() {
351
- let passedErrorCode: number | undefined
298
+ protected static async passesEachPulledSampleToOnData() {
299
+ await this.runChunkSizeOne()
352
300
 
353
- LslStreamInlet.handleLslError = (errorCode: number) => {
354
- passedErrorCode = errorCode
355
- }
301
+ assert.isEqualDeep(
302
+ this.callsToOnData,
303
+ FakeLiblsl.fakeSamples.map((sample) => ({
304
+ samples: Array.from(sample),
305
+ timestamps: [FakeLiblsl.fakeSampleTimestampSec],
306
+ })),
307
+ 'Did not pass each pulled sample to onData!'
308
+ )
309
+ }
356
310
 
311
+ @test()
312
+ protected static async passesEachPulledChunkToOnData() {
357
313
  await this.startThenStop()
358
314
 
359
315
  assert.isEqualDeep(
360
- passedErrorCode,
361
- FakeLiblsl.fakeErrorCode,
362
- 'Did not pass the expected error code to handleLslError!'
316
+ this.callsToOnData,
317
+ FakeLiblsl.fakeChunks.map((chunk, i) => ({
318
+ samples: Array.from(chunk),
319
+ timestamps: Array.from(FakeLiblsl.fakeTimestamps[i]),
320
+ })),
321
+ 'Did not pass each pulled chunk to onData!'
363
322
  )
364
323
  }
365
324
 
@@ -12,7 +12,7 @@ export default class LslStreamInfo implements LslInfo {
12
12
  public readonly name: string
13
13
  public readonly type: string
14
14
  public readonly sourceId: string
15
- public readonly channelNames: string[]
15
+ public readonly channelNames: readonly string[]
16
16
  public readonly channelCount: number
17
17
  public readonly channelFormat: ChannelFormat
18
18
  public readonly sampleRateHz: number
@@ -87,7 +87,7 @@ export interface LslInfo {
87
87
  readonly type: string
88
88
  readonly sourceId: string
89
89
  readonly units: string
90
- readonly channelNames: string[]
90
+ readonly channelNames: readonly string[]
91
91
  readonly channelCount: number
92
92
  readonly channelFormat: ChannelFormat
93
93
  readonly sampleRateHz: number
@@ -97,7 +97,7 @@ export interface LslInfo {
97
97
  export type LslInfoConstructor = new (options: LslInfoOptions) => LslInfo
98
98
 
99
99
  export interface LslInfoOptions {
100
- channelNames: string[]
100
+ channelNames: readonly string[]
101
101
  channelFormat: ChannelFormat
102
102
  sampleRateHz: number
103
103
  name?: string