sen-ether-client 0.1.7 → 0.2.1

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/API.md CHANGED
@@ -8,7 +8,7 @@ import { Sen, SenInterest, SenRemoteObject } from 'sen-ether-client';
8
8
 
9
9
  ## Compatibility
10
10
 
11
- `sen-ether-client@0.1.x` supports:
11
+ `sen-ether-client@0.1.x` and `sen-ether-client@0.2.x` support:
12
12
 
13
13
  - kernel protocol `9`
14
14
  - ether protocol `2`
@@ -39,9 +39,25 @@ Connection options:
39
39
  - `interfaceAddress`: local interface address or interface name for multicast
40
40
  discovery.
41
41
  - `tcpHub`: optional SEN TCP discovery hub as `host:port`. If omitted,
42
- multicast discovery is used.
42
+ multicast discovery is used. When combined with `session`, the client opens
43
+ a local Ether listener, sends presence beams to the hub and connects to
44
+ compatible peers announced by the hub.
43
45
  - `session`: optional SEN session name. If omitted, `Sen` can use queries for
44
- different sessions and connects to each one on demand.
46
+ different sessions and connects to each one on demand. When provided, the
47
+ client also acts as an active Ether process and announces itself through the
48
+ selected discovery transport.
49
+ - `multicastDiscovery`: enable active multicast presence beaming when no
50
+ `tcpHub` is configured. Defaults to `true`.
51
+ - `group`: multicast discovery group. Defaults to `239.255.0.44`.
52
+ - `bindAddress`: optional multicast discovery bind address.
53
+ - `listen`: enable the local Ether TCP listener. Defaults to `true` for active
54
+ hub sessions.
55
+ - `listenHost`: host/interface for the local Ether listener. Defaults to
56
+ `0.0.0.0`.
57
+ - `listenPort`: local Ether listener port. Defaults to `0` so the OS picks one.
58
+ - `advertisedHost`: host advertised in discovery beams. Defaults to the
59
+ selected interface address.
60
+ - `beamPeriodMs`: active discovery beam period. Defaults to `1000`.
45
61
  - `timeout`: discovery and operation timeout in ms.
46
62
  - `discoverySettleMs`: discovery settle time after the first process is found.
47
63
  Defaults to `100`.
@@ -86,9 +102,30 @@ const world = await sen.interest('SELECT * FROM world1.environment');
86
102
  TCP discovery hub usage:
87
103
 
88
104
  ```js
89
- const sen = await Sen.connect({ tcpHub: '127.0.0.1:65222' });
105
+ const sen = await Sen.connect({
106
+ session: 'hmi',
107
+ tcpHub: '127.0.0.1:65222'
108
+ });
109
+ ```
110
+
111
+ The TCP discovery hub forwards fixed-size presence beams only. Bus messages are
112
+ sent over direct process TCP connections between peers, so Node.js producers
113
+ and consumers must advertise reachable `listenHost`/`advertisedHost` endpoints.
114
+
115
+ Multicast discovery usage:
116
+
117
+ ```js
118
+ const sen = await Sen.connect({
119
+ session: 'hmi',
120
+ interfaceAddress: '127.0.0.1',
121
+ listenHost: '127.0.0.1',
122
+ advertisedHost: '127.0.0.1'
123
+ });
90
124
  ```
91
125
 
126
+ On multi-interface machines, set `interfaceAddress` so multicast beams are sent
127
+ and received on the intended network device.
128
+
92
129
  Explicit single-session usage is still supported:
93
130
 
94
131
  ```js
@@ -115,6 +152,8 @@ Main methods:
115
152
 
116
153
  - `await sen.connect(options)`
117
154
  - `await sen.interest(query, options)`
155
+ - `await sen.publishObjects(busName, objects, options)`
156
+ - `await sen.removePublishedObjects(busName, objects, options)`
118
157
  - `await sen.session(name)`
119
158
  - `await sen.discoverBuses(options)`
120
159
  - `sen.listSessions()`
@@ -145,6 +184,30 @@ const diagnostics = await sen.session('hmi').then(hmi => hmi.bus('diagnostics'))
145
184
  does open a lightweight process connection per discovered session, because SEN
146
185
  presence beams announce sessions/processes but not the bus list.
147
186
 
187
+ Publishing local objects:
188
+
189
+ ```js
190
+ const sen = await Sen.connect({
191
+ session: 'session',
192
+ tcpHub: '127.0.0.1:65222'
193
+ });
194
+
195
+ await sen.publishObjects('session.bus', [{
196
+ name: 'demo-counter',
197
+ className: 'demo.Counter',
198
+ properties: {
199
+ label: 'Demo Counter',
200
+ count: 1,
201
+ running: true
202
+ }
203
+ }]);
204
+ ```
205
+
206
+ When no `spec` is provided, `sen-ether-client` infers a simple ClassTypeSpec
207
+ from scalar `properties`. For objects with nested structs, sequences, enums or
208
+ aliases, pass the exact SEN `spec` and dependent `types` so consumers can decode
209
+ the state with the same model as native SEN producers.
210
+
148
211
  Main events:
149
212
 
150
213
  - `connect`
@@ -188,8 +251,8 @@ For browser gateways or high-frequency telemetry, request only the properties
188
251
  you need and emit batches instead of one JS event per property update:
189
252
 
190
253
  ```js
191
- const tracks = await sen.interest('SELECT hmi.tactical.BaseTrack FROM hmi.loadtest', {
192
- properties: ['latitude', 'longitude', 'altitude', 'trackHeading'],
254
+ const tracks = await sen.interest('SELECT bus.Track FROM hmi.loadtest', {
255
+ properties: ['latitude', 'longitude', 'altitude', 'heading'],
193
256
  changeMode: 'batch',
194
257
  batchIntervalMs: 16,
195
258
  batchMaxSize: 1000,
package/README.md CHANGED
@@ -39,6 +39,7 @@ versions, not to a specific SEN release name.
39
39
  | sen-ether-client | Kernel protocol | Ether protocol |
40
40
  | --- | ---: | ---: |
41
41
  | 0.1.x | 9 | 2 |
42
+ | 0.2.x | 9 | 2 |
42
43
 
43
44
  If a remote kernel reports another kernel or ether protocol version during the
44
45
  SEN handshake, `sen-ether-client` treats it as incompatible until that protocol version
@@ -61,6 +62,10 @@ visible SEN processes:
61
62
  const sen = await Sen.connect();
62
63
  ```
63
64
 
65
+ When a `session` is provided, the client also behaves as an active Ether
66
+ process: it opens a TCP listener, announces its presence through multicast
67
+ discovery, and connects to compatible peers announced on the same session.
68
+
64
69
  If your SEN ether discovery port is configured through SEN's environment,
65
70
  `sen-ether-client` reads the same variable:
66
71
 
@@ -80,10 +85,28 @@ explicitly:
80
85
 
81
86
  ```js
82
87
  const sen = await Sen.connect({
88
+ session: 'hmi',
83
89
  tcpHub: '127.0.0.1:65222'
84
90
  });
85
91
  ```
86
92
 
93
+ With a `session` and `tcpHub`, `sen-ether-client` acts as an active Ether
94
+ process: it opens a TCP listener, announces a SEN presence beam to the hub, and
95
+ connects to compatible peers announced by the hub. This allows Node.js
96
+ producers and consumers to discover each other without a native SEN process
97
+ brokering their bus messages.
98
+
99
+ For local multicast tests, select loopback explicitly:
100
+
101
+ ```js
102
+ const sen = await Sen.connect({
103
+ session: 'hmi',
104
+ interfaceAddress: '127.0.0.1',
105
+ listenHost: '127.0.0.1',
106
+ advertisedHost: '127.0.0.1'
107
+ });
108
+ ```
109
+
87
110
  Connected sessions are monitored through SEN ether presence beams. If the
88
111
  remote process stops announcing itself for `presenceTimeoutMs` milliseconds
89
112
  (default `5000`), the client closes the stale connection and restarts the
@@ -152,8 +175,8 @@ For browser gateways or high-frequency telemetry, batch changes and decode only
152
175
  the properties needed by the UI:
153
176
 
154
177
  ```js
155
- const tracks = await sen.interest('SELECT hmi.tactical.BaseTrack FROM hmi.loadtest', {
156
- properties: ['latitude', 'longitude', 'altitude', 'trackHeading'],
178
+ const tracks = await sen.interest('SELECT bus.Track FROM hmi.loadtest', {
179
+ properties: ['latitude', 'longitude', 'altitude', 'heading'],
157
180
  changeMode: 'batch',
158
181
  coalesce: true
159
182
  });
@@ -178,6 +201,35 @@ const firstAircraft = await tracks.waitFor(
178
201
  );
179
202
  ```
180
203
 
204
+ ## Publish objects
205
+
206
+ `sen-ether-client` can also act as a lightweight producer. The producer joins
207
+ the bus, publishes local objects to remote interests, and answers type/state
208
+ requests for those objects.
209
+
210
+ ```js
211
+ import { Sen } from 'sen-ether-client';
212
+
213
+ const sen = await Sen.connect({
214
+ session: 'session',
215
+ tcpHub: '127.0.0.1:65222'
216
+ });
217
+
218
+ await sen.publishObjects('session.bus', {
219
+ name: 'demo-counter',
220
+ className: 'demo.Counter',
221
+ properties: {
222
+ label: 'Demo Counter',
223
+ count: 1,
224
+ running: true
225
+ }
226
+ });
227
+ ```
228
+
229
+ For exact SEN typing, pass a `spec` on each object and any dependent custom
230
+ types through `types`. This is required for structured values such as structs,
231
+ sequences, enums and variants.
232
+
181
233
  ## Objects
182
234
 
183
235
  Read and write properties:
package/index.js CHANGED
@@ -31,6 +31,9 @@
31
31
  * @property {string} [tcpHub] Optional SEN TCP discovery hub as `host:port`. If omitted, multicast discovery is used.
32
32
  * @property {string} [session] Optional SEN session name. Omit it to let
33
33
  * `interest(query)` connect to the session named in the query.
34
+ * @property {boolean} [multicastDiscovery=true] Enable active multicast presence beaming when no TCP hub is configured.
35
+ * @property {string} [group='239.255.0.44'] Multicast discovery group.
36
+ * @property {string} [bindAddress] Optional multicast discovery bind address.
34
37
  * @property {string} [app] Remote process appName substring filter.
35
38
  * @property {number} [timeout=3000] Discovery and operation timeout in ms.
36
39
  * @property {number} [discoverySettleMs=100] Discovery settle time after the first process is found.
@@ -45,6 +48,11 @@
45
48
  * @property {number} [presenceTimeoutMs=5000] Close and reconnect when the connected SEN process stops announcing presence beams. `0` disables it.
46
49
  * @property {number} [presenceCheckIntervalMs=1000] Presence watchdog check interval in ms.
47
50
  * @property {string} [interfaceAddress] Local interface address or interface name for multicast discovery.
51
+ * @property {boolean} [listen=true] Enable the local Ether TCP listener for active discovery.
52
+ * @property {string} [listenHost='0.0.0.0'] Local host/interface for the Ether listener.
53
+ * @property {number} [listenPort=0] Local Ether listener port. `0` lets the OS choose.
54
+ * @property {string} [advertisedHost] Host advertised in TCP discovery beams.
55
+ * @property {number} [beamPeriodMs=1000] Active discovery beam period in ms.
48
56
  * @property {object} [target] Already discovered/direct SEN target.
49
57
  */
50
58
 
@@ -62,6 +70,24 @@
62
70
  * @property {boolean} [coalesce=false] Keep only latest queued change per object/property.
63
71
  */
64
72
 
73
+ /**
74
+ * @typedef {object} SenPublishedObject
75
+ * @property {string} name SEN object name.
76
+ * @property {string} className SEN class name.
77
+ * @property {number} [id] Optional stable object id. Defaults to CRC32(name).
78
+ * @property {number} [typeHash] Optional class hash. Defaults to CRC32(className).
79
+ * @property {object} [properties] Current object property values.
80
+ * @property {object} [snapshot] Alias for properties.
81
+ * @property {object} [spec] Optional SEN ClassTypeSpec. If omitted, a simple class spec is inferred from properties.
82
+ * @property {bigint|number|string} [timestamp] Optional SEN timestamp in ns.
83
+ */
84
+
85
+ /**
86
+ * @typedef {object} SenPublishOptions
87
+ * @property {Map<string, object>|Record<string, object>|object[]} [types] Extra SEN type specs required by object properties.
88
+ * @property {number} [participantId] Optional local participant id for a newly joined bus.
89
+ */
90
+
65
91
  /**
66
92
  * @typedef {object} SenListBusesOptions
67
93
  * @property {boolean} [qualified=false] Return session-qualified bus names.
package/lib/bus.js CHANGED
@@ -67,9 +67,36 @@ function readU32List(reader) {
67
67
  }
68
68
 
69
69
  function writeU32List(writer, values = []) {
70
+ writer.writeUInt32(values.length);
71
+ for (const value of values) {
72
+ writer.writeUInt32(value);
73
+ }
74
+ }
75
+
76
+ function enumKey(values, value, label) {
77
+ const index = values.indexOf(value);
78
+ if (index < 0) {
79
+ throw new RangeError(`unknown SEN ${label} value: ${value}`);
80
+ }
81
+ return index;
82
+ }
83
+
84
+ function writeSequence(writer, values = [], writeItem) {
70
85
  writer.writeUInt32(values.length);
71
86
  for (const value of values) {
72
- writer.writeUInt32(value);
87
+ writeItem(writer, value);
88
+ }
89
+ }
90
+
91
+ function writeStringList(writer, values = []) {
92
+ writeSequence(writer, values, (itemWriter, value) => itemWriter.writeString(value));
93
+ }
94
+
95
+ function writeOptional(writer, value, writeValue) {
96
+ const present = value !== null && value !== undefined;
97
+ writer.writeBool(present);
98
+ if (present) {
99
+ writeValue(writer, value);
73
100
  }
74
101
  }
75
102
 
@@ -333,6 +360,224 @@ function readTypeSpecResponse(reader) {
333
360
  }
334
361
  }
335
362
 
363
+ function writeEnumeratorSpec(writer, item = {}) {
364
+ writer.writeString(item.name ?? '');
365
+ writer.writeUInt32(item.key ?? 0);
366
+ writer.writeString(item.description ?? '');
367
+ }
368
+
369
+ function writeEnumTypeSpec(writer, value = {}) {
370
+ writeSequence(writer, value.enums ?? [], writeEnumeratorSpec);
371
+ writer.writeUInt8(enumKey(INTEGRAL_TYPE, value.storageType ?? 'uint32Type', 'IntegralType'));
372
+ }
373
+
374
+ function writeNumericType(writer, value = {}) {
375
+ const type = value.type ?? 'RealType';
376
+ writer.writeUInt32(enumKey(NUMERIC_TYPE, type, 'NumericType'));
377
+ if (type === 'IntegralType') {
378
+ writer.writeUInt8(enumKey(INTEGRAL_TYPE, value.value ?? 'int32Type', 'IntegralType'));
379
+ return;
380
+ }
381
+ if (type === 'RealType') {
382
+ writer.writeUInt8(enumKey(REAL_TYPE, value.value ?? 'float64Type', 'RealType'));
383
+ return;
384
+ }
385
+ throw new TypeError(`unhandled SEN NumericType alternative: ${type}`);
386
+ }
387
+
388
+ function writeUnitInfo(writer, value = {}) {
389
+ writer.writeString(value.name ?? '');
390
+ writer.writeString(value.abbreviation ?? '');
391
+ writer.writeUInt8(enumKey(UNIT_CATEGORY, value.category ?? 'length', 'UnitCat'));
392
+ }
393
+
394
+ function writeQuantityTypeSpec(writer, value = {}) {
395
+ writeNumericType(writer, value.elementType ?? { type: 'RealType', value: 'float64Type' });
396
+ writeUnitInfo(writer, value.unit ?? {});
397
+ writeOptional(writer, value.minValue, (itemWriter, item) => itemWriter.writeFloat64(Number(item)));
398
+ writeOptional(writer, value.maxValue, (itemWriter, item) => itemWriter.writeFloat64(Number(item)));
399
+ }
400
+
401
+ function writeSequenceTypeSpec(writer, value = {}) {
402
+ writer.writeString(value.elementType ?? '');
403
+ writeOptional(writer, value.maxSize, (itemWriter, item) => itemWriter.writeUInt64(item));
404
+ writer.writeBool(Boolean(value.fixedSize));
405
+ }
406
+
407
+ function writeStructTypeFieldSpec(writer, item = {}) {
408
+ writer.writeString(item.name ?? '');
409
+ writer.writeString(item.description ?? '');
410
+ writer.writeString(item.type ?? '');
411
+ }
412
+
413
+ function writeStructTypeSpec(writer, value = {}) {
414
+ writeSequence(writer, value.fields ?? [], writeStructTypeFieldSpec);
415
+ writer.writeString(value.parent ?? '');
416
+ }
417
+
418
+ function writeVariantTypeFieldSpec(writer, item = {}) {
419
+ writer.writeUInt32(item.key ?? 0);
420
+ writer.writeString(item.description ?? '');
421
+ writer.writeString(item.type ?? '');
422
+ }
423
+
424
+ function writeVariantTypeSpec(writer, value = {}) {
425
+ writeSequence(writer, value.fields ?? [], writeVariantTypeFieldSpec);
426
+ }
427
+
428
+ function writeAliasTypeSpec(writer, value = {}) {
429
+ writer.writeString(value.aliasedType ?? '');
430
+ }
431
+
432
+ function writeOptionalTypeSpec(writer, value = {}) {
433
+ writer.writeString(value.type ?? '');
434
+ }
435
+
436
+ function writeArgSpec(writer, item = {}) {
437
+ writer.writeString(item.name ?? '');
438
+ writer.writeString(item.description ?? '');
439
+ writer.writeString(item.type ?? '');
440
+ }
441
+
442
+ function writeEventSpec(writer, item = {}) {
443
+ writer.writeString(item.name ?? '');
444
+ writer.writeString(item.description ?? '');
445
+ writeSequence(writer, item.args ?? [], writeArgSpec);
446
+ writer.writeUInt8(enumKey(TRANSPORT_MODE, item.transportMode ?? 'confirmed', 'TransportModeSpec'));
447
+ }
448
+
449
+ function writeMethodSpec(writer, item = {}) {
450
+ writer.writeString(item.name ?? '');
451
+ writer.writeString(item.description ?? '');
452
+ writeSequence(writer, item.args ?? [], writeArgSpec);
453
+ writer.writeUInt8(enumKey(TRANSPORT_MODE, item.transportMode ?? 'confirmed', 'TransportModeSpec'));
454
+ writer.writeUInt8(enumKey(METHOD_CONSTNESS, item.constness ?? 'nonConstant', 'MethodConstnessSpec'));
455
+ writer.writeBool(Boolean(item.deferred));
456
+ writer.writeString(item.returnType ?? '');
457
+ writer.writeUInt8(enumKey(PROPERTY_RELATION, item.propertyRelation ?? 'nonPropertyRelated', 'PropertyRelationSpec'));
458
+ writer.writeBool(Boolean(item.localOnly));
459
+ }
460
+
461
+ function writePropertySpec(writer, item = {}) {
462
+ writer.writeString(item.name ?? '');
463
+ writer.writeString(item.description ?? '');
464
+ writer.writeUInt8(enumKey(PROPERTY_CATEGORY, item.category ?? 'dynamicRO', 'PropertyCategorySpec'));
465
+ writer.writeString(item.type ?? '');
466
+ writer.writeUInt8(enumKey(TRANSPORT_MODE, item.transportMode ?? 'confirmed', 'TransportModeSpec'));
467
+ writeStringList(writer, item.tags ?? []);
468
+ writer.writeBool(Boolean(item.checkedSet));
469
+ }
470
+
471
+ function writeClassTypeSpec(writer, value = {}) {
472
+ writeSequence(writer, value.properties ?? [], writePropertySpec);
473
+ writeSequence(writer, value.methods ?? [], writeMethodSpec);
474
+ writeSequence(writer, value.events ?? [], writeEventSpec);
475
+ writeMethodSpec(writer, value.constructor ?? { name: '', returnType: '' });
476
+ writeStringList(writer, value.parents ?? []);
477
+ writer.writeBool(Boolean(value.isInterface));
478
+ }
479
+
480
+ function writeCustomTypeData(writer, data = {}) {
481
+ const type = data.type ?? 'StructTypeSpec';
482
+ const value = data.value ?? {};
483
+ writer.writeUInt32(enumKey(CUSTOM_TYPE_DATA, type, 'CustomTypeData'));
484
+
485
+ switch (type) {
486
+ case 'EnumTypeSpec':
487
+ writeEnumTypeSpec(writer, value);
488
+ break;
489
+ case 'QuantityTypeSpec':
490
+ writeQuantityTypeSpec(writer, value);
491
+ break;
492
+ case 'SequenceTypeSpec':
493
+ writeSequenceTypeSpec(writer, value);
494
+ break;
495
+ case 'StructTypeSpec':
496
+ writeStructTypeSpec(writer, value);
497
+ break;
498
+ case 'VariantTypeSpec':
499
+ writeVariantTypeSpec(writer, value);
500
+ break;
501
+ case 'AliasTypeSpec':
502
+ writeAliasTypeSpec(writer, value);
503
+ break;
504
+ case 'OptionalTypeSpec':
505
+ writeOptionalTypeSpec(writer, value);
506
+ break;
507
+ case 'ClassTypeSpec':
508
+ writeClassTypeSpec(writer, value);
509
+ break;
510
+ default:
511
+ throw new TypeError(`unhandled SEN CustomTypeData alternative: ${type}`);
512
+ }
513
+ }
514
+
515
+ function writeCustomTypeSpec(writer, spec = {}) {
516
+ writer.writeString(spec.name ?? '');
517
+ writer.writeString(spec.qualifiedName ?? spec.name ?? '');
518
+ writer.writeString(spec.description ?? '');
519
+ writeCustomTypeData(writer, spec.data);
520
+ }
521
+
522
+ function writeTypeSpecResponse(writer, item = {}) {
523
+ writer.writeUInt32(enumKey(TYPE_SPEC_RESPONSE, item.type ?? 'NonClassSpecResponse', 'TypeSpecResponse'));
524
+ if ((item.type ?? 'NonClassSpecResponse') === 'ClassSpecResponse') {
525
+ writer.writeUInt32(item.classHash ?? crc32(item.spec?.qualifiedName ?? item.spec?.name ?? ''));
526
+ writeCustomTypeSpec(writer, item.spec);
527
+ writeU32List(writer, item.dependentTypes ?? []);
528
+ return;
529
+ }
530
+ writeCustomTypeSpec(writer, item.spec);
531
+ }
532
+
533
+ function writeObjectAdded(writer, item = {}) {
534
+ writer.writeString(item.className ?? '');
535
+ writer.writeUInt32(item.typeHash ?? crc32(item.className ?? ''));
536
+ writer.writeString(item.name ?? '');
537
+ writer.writeUInt32(item.id ?? crc32(item.name ?? ''));
538
+ writer.writeBuffer(item.state ?? Buffer.alloc(0));
539
+ writer.writeInt64(item.time ?? 0n);
540
+ }
541
+
542
+ function writeInterestDiscovery(writer, item = {}) {
543
+ writer.writeUInt32(item.interestId ?? 0);
544
+ writeSequence(writer, item.objects ?? [], writeObjectAdded);
545
+ }
546
+
547
+ function writeObjectsPublished(writer, value = {}) {
548
+ writer.writeUInt32(value.ownerId ?? 0);
549
+ writeSequence(writer, value.discoveries ?? [], writeInterestDiscovery);
550
+ }
551
+
552
+ function writeObjectsRemoved(writer, value = {}) {
553
+ writeSequence(writer, value.removals ?? [], (itemWriter, item) => {
554
+ itemWriter.writeUInt32(item.interestId ?? 0);
555
+ writeU32List(itemWriter, item.ids ?? []);
556
+ });
557
+ }
558
+
559
+ function writeObjectsStateResponse(writer, value = {}) {
560
+ writer.writeUInt32(value.ownerId ?? 0);
561
+ writeSequence(writer, value.responses ?? [], (itemWriter, response) => {
562
+ itemWriter.writeUInt32(response.interestId ?? 0);
563
+ writeSequence(itemWriter, response.objectStates ?? [], (stateWriter, state) => {
564
+ stateWriter.writeUInt32(state.id ?? 0);
565
+ stateWriter.writeInt64(state.timestamp ?? 0n);
566
+ stateWriter.writeBuffer(state.state ?? Buffer.alloc(0));
567
+ });
568
+ });
569
+ }
570
+
571
+ function writeTypesInfoResponse(writer, value = {}) {
572
+ writer.writeUInt32(value.ownerId ?? 0);
573
+ writeSequence(writer, value.types ?? [], writeTypeSpecResponse);
574
+ }
575
+
576
+ function writeTypesInfoRejection(writer, value = {}) {
577
+ writer.writeUInt32(value.ownerId ?? 0);
578
+ writeStringList(writer, value.rejections ?? []);
579
+ }
580
+
336
581
  function readTypesInfoResponse(reader) {
337
582
  return {
338
583
  ownerId: reader.readUInt32(),
@@ -637,6 +882,21 @@ export function encodeKernelControlMessage(message) {
637
882
  writer.writeUInt32(value.ownerId);
638
883
  writeU32List(writer, value.requests);
639
884
  break;
885
+ case 'ObjectsPublished':
886
+ writeObjectsPublished(writer, value);
887
+ break;
888
+ case 'ObjectsRemoved':
889
+ writeObjectsRemoved(writer, value);
890
+ break;
891
+ case 'ObjectsStateResponse':
892
+ writeObjectsStateResponse(writer, value);
893
+ break;
894
+ case 'TypesInfoResponse':
895
+ writeTypesInfoResponse(writer, value);
896
+ break;
897
+ case 'TypesInfoRejection':
898
+ writeTypesInfoRejection(writer, value);
899
+ break;
640
900
  default:
641
901
  throw new TypeError(`encoding SEN kernel ControlMessage ${type} is not implemented`);
642
902
  }