rclnodejs 1.6.0 → 1.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.
Files changed (84) hide show
  1. package/binding.gyp +2 -0
  2. package/index.js +152 -0
  3. package/lib/action/client.js +109 -10
  4. package/lib/action/deferred.js +8 -2
  5. package/lib/action/server.js +10 -1
  6. package/lib/action/uuid.js +4 -1
  7. package/lib/client.js +218 -4
  8. package/lib/clock.js +182 -1
  9. package/lib/clock_change.js +49 -0
  10. package/lib/clock_event.js +88 -0
  11. package/lib/context.js +12 -2
  12. package/lib/duration.js +37 -12
  13. package/lib/errors.js +621 -0
  14. package/lib/event_handler.js +21 -4
  15. package/lib/interface_loader.js +52 -12
  16. package/lib/lifecycle.js +8 -2
  17. package/lib/logging.js +90 -3
  18. package/lib/message_introspector.js +123 -0
  19. package/lib/message_serialization.js +10 -2
  20. package/lib/message_validation.js +512 -0
  21. package/lib/native_loader.js +9 -4
  22. package/lib/node.js +403 -50
  23. package/lib/node_options.js +40 -1
  24. package/lib/observable_subscription.js +105 -0
  25. package/lib/parameter.js +172 -35
  26. package/lib/parameter_client.js +506 -0
  27. package/lib/parameter_watcher.js +309 -0
  28. package/lib/publisher.js +56 -1
  29. package/lib/qos.js +79 -5
  30. package/lib/rate.js +6 -1
  31. package/lib/serialization.js +7 -2
  32. package/lib/subscription.js +8 -0
  33. package/lib/time.js +136 -21
  34. package/lib/time_source.js +13 -4
  35. package/lib/timer.js +42 -0
  36. package/lib/utils.js +27 -1
  37. package/lib/validator.js +74 -19
  38. package/package.json +4 -2
  39. package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
  40. package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
  41. package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
  42. package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
  43. package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
  44. package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
  45. package/rosidl_gen/message_translator.js +0 -61
  46. package/scripts/config.js +1 -0
  47. package/src/addon.cpp +2 -0
  48. package/src/clock_event.cpp +268 -0
  49. package/src/clock_event.hpp +62 -0
  50. package/src/macros.h +2 -4
  51. package/src/rcl_action_server_bindings.cpp +21 -3
  52. package/src/rcl_bindings.cpp +59 -0
  53. package/src/rcl_context_bindings.cpp +5 -0
  54. package/src/rcl_graph_bindings.cpp +73 -0
  55. package/src/rcl_logging_bindings.cpp +158 -0
  56. package/src/rcl_node_bindings.cpp +14 -2
  57. package/src/rcl_publisher_bindings.cpp +12 -0
  58. package/src/rcl_service_bindings.cpp +7 -6
  59. package/src/rcl_subscription_bindings.cpp +51 -14
  60. package/src/rcl_time_point_bindings.cpp +135 -0
  61. package/src/rcl_timer_bindings.cpp +140 -0
  62. package/src/rcl_utilities.cpp +103 -2
  63. package/src/rcl_utilities.h +7 -1
  64. package/types/action_client.d.ts +27 -2
  65. package/types/base.d.ts +6 -0
  66. package/types/client.d.ts +65 -1
  67. package/types/clock.d.ts +86 -0
  68. package/types/clock_change.d.ts +27 -0
  69. package/types/clock_event.d.ts +51 -0
  70. package/types/errors.d.ts +496 -0
  71. package/types/index.d.ts +10 -0
  72. package/types/logging.d.ts +32 -0
  73. package/types/message_introspector.d.ts +75 -0
  74. package/types/message_validation.d.ts +183 -0
  75. package/types/node.d.ts +107 -0
  76. package/types/node_options.d.ts +13 -0
  77. package/types/observable_subscription.d.ts +39 -0
  78. package/types/parameter_client.d.ts +252 -0
  79. package/types/parameter_watcher.d.ts +104 -0
  80. package/types/publisher.d.ts +28 -1
  81. package/types/qos.d.ts +18 -0
  82. package/types/subscription.d.ts +6 -0
  83. package/types/timer.d.ts +18 -0
  84. package/types/validator.d.ts +86 -0
package/binding.gyp CHANGED
@@ -26,6 +26,7 @@
26
26
  './src/rcl_action_server_bindings.cpp',
27
27
  './src/rcl_bindings.cpp',
28
28
  './src/rcl_client_bindings.cpp',
29
+ './src/clock_event.cpp',
29
30
  './src/rcl_context_bindings.cpp',
30
31
  './src/rcl_graph_bindings.cpp',
31
32
  './src/rcl_guard_condition_bindings.cpp',
@@ -67,6 +68,7 @@
67
68
  '-lrcl_action',
68
69
  '-lrcl_lifecycle',
69
70
  '-lrcutils',
71
+ '-lrcl_logging_interface',
70
72
  '-lrcl_yaml_param_parser',
71
73
  '-lrcpputils',
72
74
  '-lrmw',
package/index.js CHANGED
@@ -17,7 +17,9 @@
17
17
  const DistroUtils = require('./lib/distro.js');
18
18
  const RMWUtils = require('./lib/rmw.js');
19
19
  const { Clock, ROSClock } = require('./lib/clock.js');
20
+ const ClockEvent = require('./lib/clock_event.js');
20
21
  const ClockType = require('./lib/clock_type.js');
22
+ const ClockChange = require('./lib/clock_change.js');
21
23
  const { compareVersions } = require('./lib/utils.js');
22
24
  const Context = require('./lib/context.js');
23
25
  const debug = require('debug')('rclnodejs');
@@ -58,7 +60,21 @@ const {
58
60
  serializeMessage,
59
61
  deserializeMessage,
60
62
  } = require('./lib/serialization.js');
63
+ const ParameterClient = require('./lib/parameter_client.js');
64
+ const errors = require('./lib/errors.js');
65
+ const ParameterWatcher = require('./lib/parameter_watcher.js');
66
+ const MessageIntrospector = require('./lib/message_introspector.js');
67
+ const ObservableSubscription = require('./lib/observable_subscription.js');
61
68
  const { spawn } = require('child_process');
69
+ const {
70
+ ValidationProblem,
71
+ getMessageSchema,
72
+ getFieldNames,
73
+ getFieldType,
74
+ validateMessage,
75
+ assertValidMessage,
76
+ createMessageValidator,
77
+ } = require('./lib/message_validation.js');
62
78
 
63
79
  /**
64
80
  * Get the version of the generator that was used for the currently present interfaces.
@@ -175,9 +191,15 @@ let rcl = {
175
191
  /** {@link Clock} class */
176
192
  Clock: Clock,
177
193
 
194
+ /** {@link ClockEvent} class */
195
+ ClockEvent: ClockEvent,
196
+
178
197
  /** {@link ClockType} enum */
179
198
  ClockType: ClockType,
180
199
 
200
+ /** {@link ClockChange} enum */
201
+ ClockChange: ClockChange,
202
+
181
203
  /** {@link Context} class */
182
204
  Context: Context,
183
205
 
@@ -217,6 +239,15 @@ let rcl = {
217
239
  /** {@link ParameterType} */
218
240
  ParameterType: ParameterType,
219
241
 
242
+ /** {@link ParameterClient} class */
243
+ ParameterClient: ParameterClient,
244
+
245
+ /** {@link ParameterWatcher} class */
246
+ ParameterWatcher: ParameterWatcher,
247
+
248
+ /** {@link ObservableSubscription} class */
249
+ ObservableSubscription: ObservableSubscription,
250
+
220
251
  /** {@link QoS} class */
221
252
  QoS: QoS,
222
253
 
@@ -377,6 +408,21 @@ let rcl = {
377
408
  _rosVersionChecked = true;
378
409
  },
379
410
 
411
+ /**
412
+ * Remove ROS-specific arguments from the given argument list.
413
+ * @param {string[]} argv - The argument list to process.
414
+ * @return {string[]} The argument list with ROS arguments removed.
415
+ */
416
+ removeROSArgs(argv) {
417
+ if (!Array.isArray(argv)) {
418
+ throw new TypeError('argv must be an array.');
419
+ }
420
+ if (!argv.every((argument) => typeof argument === 'string')) {
421
+ throw new TypeError('argv elements must be strings (and not null).');
422
+ }
423
+ return rclnodejs.removeROSArgs(argv);
424
+ },
425
+
380
426
  /**
381
427
  * Start detection and processing of units of work.
382
428
  * @param {Node} node - The node to be spun up.
@@ -556,6 +602,109 @@ let rcl = {
556
602
  * @returns {string} The JSON string representation
557
603
  */
558
604
  toJSONString: toJSONString,
605
+
606
+ /** {@link ValidationProblem} - Enum of validation problem types */
607
+ ValidationProblem: ValidationProblem,
608
+
609
+ /**
610
+ * Get the schema definition for a message type
611
+ * @param {function|string|object} typeClass - Message type class or identifier
612
+ * @returns {object|null} Schema definition with fields and constants
613
+ */
614
+ getMessageSchema: getMessageSchema,
615
+
616
+ /**
617
+ * Get field names for a message type
618
+ * @param {function|string|object} typeClass - Message type class or identifier
619
+ * @returns {string[]} Array of field names
620
+ */
621
+ getFieldNames: getFieldNames,
622
+
623
+ /**
624
+ * Get type information for a specific field
625
+ * @param {function|string|object} typeClass - Message type class or identifier
626
+ * @param {string} fieldName - Name of the field
627
+ * @returns {object|null} Field type information or null if not found
628
+ */
629
+ getFieldType: getFieldType,
630
+
631
+ /**
632
+ * Validate a message object against its schema
633
+ * @param {object} obj - Plain object to validate
634
+ * @param {function|string|object} typeClass - Message type class or identifier
635
+ * @param {object} [options] - Validation options
636
+ * @returns {{valid: boolean, issues: Array<object>}} Validation result
637
+ */
638
+ validateMessage: validateMessage,
639
+
640
+ /**
641
+ * Validate a message and throw if invalid
642
+ * @param {object} obj - Plain object to validate
643
+ * @param {function|string|object} typeClass - Message type class or identifier
644
+ * @param {object} [options] - Validation options
645
+ * @throws {MessageValidationError} If validation fails
646
+ */
647
+ assertValidMessage: assertValidMessage,
648
+
649
+ /**
650
+ * Create a validator function for a specific message type
651
+ * @param {function|string|object} typeClass - Message type class or identifier
652
+ * @param {object} [defaultOptions] - Default validation options
653
+ * @returns {function} Validator function
654
+ */
655
+ createMessageValidator: createMessageValidator,
656
+
657
+ // Error classes for structured error handling
658
+ /** {@link RclNodeError} - Base error class for all rclnodejs errors */
659
+ RclNodeError: errors.RclNodeError,
660
+
661
+ /** {@link ValidationError} - Error thrown when validation fails */
662
+ ValidationError: errors.ValidationError,
663
+ /** {@link TypeValidationError} - Type validation error */
664
+ TypeValidationError: errors.TypeValidationError,
665
+ /** {@link RangeValidationError} - Range/value validation error */
666
+ RangeValidationError: errors.RangeValidationError,
667
+ /** {@link MessageValidationError} - Message structure/type validation error */
668
+ MessageValidationError: errors.MessageValidationError,
669
+ /** {@link NameValidationError} - ROS name validation error */
670
+ NameValidationError: errors.NameValidationError,
671
+
672
+ /** {@link OperationError} - Base class for operation/runtime errors */
673
+ OperationError: errors.OperationError,
674
+ /** {@link TimeoutError} - Request timeout error */
675
+ TimeoutError: errors.TimeoutError,
676
+ /** {@link AbortError} - Request abortion error */
677
+ AbortError: errors.AbortError,
678
+ /** {@link ServiceNotFoundError} - Service not available error */
679
+ ServiceNotFoundError: errors.ServiceNotFoundError,
680
+ /** {@link NodeNotFoundError} - Remote node not found error */
681
+ NodeNotFoundError: errors.NodeNotFoundError,
682
+
683
+ /** {@link ParameterError} - Base error for parameter operations */
684
+ ParameterError: errors.ParameterError,
685
+ /** {@link ParameterNotFoundError} - Parameter not found error */
686
+ ParameterNotFoundError: errors.ParameterNotFoundError,
687
+ /** {@link ParameterTypeError} - Parameter type mismatch error */
688
+ ParameterTypeError: errors.ParameterTypeError,
689
+ /** {@link ReadOnlyParameterError} - Read-only parameter modification error */
690
+ ReadOnlyParameterError: errors.ReadOnlyParameterError,
691
+
692
+ /** {@link TopicError} - Base error for topic operations */
693
+ TopicError: errors.TopicError,
694
+ /** {@link PublisherError} - Publisher-specific error */
695
+ PublisherError: errors.PublisherError,
696
+ /** {@link SubscriptionError} - Subscription-specific error */
697
+ SubscriptionError: errors.SubscriptionError,
698
+
699
+ /** {@link ActionError} - Base error for action operations */
700
+ ActionError: errors.ActionError,
701
+ /** {@link GoalRejectedError} - Goal rejected by action server */
702
+ GoalRejectedError: errors.GoalRejectedError,
703
+ /** {@link ActionServerNotFoundError} - Action server not found */
704
+ ActionServerNotFoundError: errors.ActionServerNotFoundError,
705
+
706
+ /** {@link NativeError} - Wraps errors from native C++ layer */
707
+ NativeError: errors.NativeError,
559
708
  };
560
709
 
561
710
  const _sigHandler = () => {
@@ -585,3 +734,6 @@ const Lifecycle = require('./lib/lifecycle.js');
585
734
 
586
735
  /** Lifecycle namespace */
587
736
  rcl.lifecycle = Lifecycle;
737
+
738
+ /** {@link MessageIntrospector} class */
739
+ rcl.MessageIntrospector = MessageIntrospector;
@@ -23,6 +23,12 @@ const DistroUtils = require('../distro.js');
23
23
  const Entity = require('../entity.js');
24
24
  const loader = require('../interface_loader.js');
25
25
  const QoS = require('../qos.js');
26
+ const {
27
+ TypeValidationError,
28
+ ActionError,
29
+ OperationError,
30
+ } = require('../errors.js');
31
+ const { assertValidMessage } = require('../message_validation.js');
26
32
 
27
33
  /**
28
34
  * @class - ROS Action client.
@@ -75,6 +81,12 @@ class ActionClient extends Entity {
75
81
  this._options.qos.statusSubQosProfile =
76
82
  this._options.qos.statusSubQosProfile || QoS.profileActionStatusDefault;
77
83
 
84
+ this._validateGoals = this._options.validateGoals || false;
85
+ this._validationOptions = this._options.validationOptions || {
86
+ strict: true,
87
+ checkTypes: true,
88
+ };
89
+
78
90
  let type = this.typeClass.type();
79
91
 
80
92
  this._handle = rclnodejs.actionCreateClient(
@@ -103,7 +115,14 @@ class ActionClient extends Entity {
103
115
  if (goalHandle.accepted) {
104
116
  let uuid = ActionUuid.fromMessage(goalHandle.goalId).toString();
105
117
  if (this._goalHandles.has(uuid)) {
106
- throw new Error(`Two goals were accepted with the same ID (${uuid})`);
118
+ throw new ActionError(
119
+ `Two goals were accepted with the same ID (${uuid})`,
120
+ this._actionName,
121
+ {
122
+ code: 'DUPLICATE_GOAL_ID',
123
+ details: { goalId: uuid },
124
+ }
125
+ );
107
126
  }
108
127
 
109
128
  this._goalHandles.set(uuid, goalHandle);
@@ -188,6 +207,34 @@ class ActionClient extends Entity {
188
207
  }
189
208
  }
190
209
 
210
+ /**
211
+ * Whether goals will be validated before sending.
212
+ * @type {boolean}
213
+ */
214
+ get willValidateGoal() {
215
+ return this._validateGoals;
216
+ }
217
+
218
+ /**
219
+ * Enable or disable goal validation for this action client.
220
+ * @param {boolean} value - Whether to validate goals
221
+ */
222
+ set willValidateGoal(value) {
223
+ this._validateGoals = value;
224
+ }
225
+
226
+ /**
227
+ * Set validation options for this action client.
228
+ * @param {object} options - Validation options
229
+ * @param {boolean} [options.strict=true] - Throw on unknown fields
230
+ * @param {boolean} [options.checkTypes=true] - Validate field types
231
+ */
232
+ setValidation(options) {
233
+ if (options && Object.keys(options).length > 0) {
234
+ this._validationOptions = { ...this._validationOptions, ...options };
235
+ }
236
+ }
237
+
191
238
  /**
192
239
  * Send a goal and wait for the goal ACK asynchronously.
193
240
  *
@@ -197,9 +244,27 @@ class ActionClient extends Entity {
197
244
  * @param {object} goal - The goal request.
198
245
  * @param {function} feedbackCallback - Callback function for feedback associated with the goal.
199
246
  * @param {object} goalUuid - Universally unique identifier for the goal. If None, then a random UUID is generated.
247
+ * @param {object} [options] - Send options
248
+ * @param {boolean} [options.validate] - Override validateGoals setting for this call
200
249
  * @returns {Promise} - A Promise to a goal handle that resolves when the goal request has been accepted or rejected.
250
+ * @throws {MessageValidationError} If validation is enabled and goal is invalid
201
251
  */
202
- sendGoal(goal, feedbackCallback, goalUuid) {
252
+ sendGoal(goal, feedbackCallback, goalUuid, options = {}) {
253
+ const shouldValidate =
254
+ options.validate !== undefined ? options.validate : this._validateGoals;
255
+
256
+ if (shouldValidate) {
257
+ const GoalType = this._typeClass.impl.SendGoalService.Request;
258
+ const goalInstance = new GoalType();
259
+ if (goalInstance.goal && goalInstance.goal.constructor) {
260
+ assertValidMessage(
261
+ goal,
262
+ goalInstance.goal.constructor,
263
+ this._validationOptions
264
+ );
265
+ }
266
+ }
267
+
203
268
  let request = new this._typeClass.impl.SendGoalService.Request();
204
269
  request['goal_id'] = goalUuid || ActionUuid.randomMessage();
205
270
  request.goal = goal;
@@ -210,8 +275,14 @@ class ActionClient extends Entity {
210
275
  );
211
276
 
212
277
  if (this._pendingGoalRequests.has(sequenceNumber)) {
213
- throw new Error(
214
- `Sequence (${sequenceNumber}) conflicts with pending goal request`
278
+ throw new OperationError(
279
+ `Sequence (${sequenceNumber}) conflicts with pending goal request`,
280
+ {
281
+ code: 'SEQUENCE_CONFLICT',
282
+ entityType: 'action client',
283
+ entityName: this._actionName,
284
+ details: { sequenceNumber: sequenceNumber, requestType: 'goal' },
285
+ }
215
286
  );
216
287
  }
217
288
 
@@ -274,7 +345,15 @@ class ActionClient extends Entity {
274
345
  */
275
346
  _cancelGoal(goalHandle) {
276
347
  if (!(goalHandle instanceof ClientGoalHandle)) {
277
- throw new TypeError('Invalid argument, must be type of ClientGoalHandle');
348
+ throw new TypeValidationError(
349
+ 'goalHandle',
350
+ goalHandle,
351
+ 'ClientGoalHandle',
352
+ {
353
+ entityType: 'action client',
354
+ entityName: this._actionName,
355
+ }
356
+ );
278
357
  }
279
358
 
280
359
  let request = new ActionInterfaces.CancelGoal.Request();
@@ -290,8 +369,14 @@ class ActionClient extends Entity {
290
369
  request.serialize()
291
370
  );
292
371
  if (this._pendingCancelRequests.has(sequenceNumber)) {
293
- throw new Error(
294
- `Sequence (${sequenceNumber}) conflicts with pending cancel request`
372
+ throw new OperationError(
373
+ `Sequence (${sequenceNumber}) conflicts with pending cancel request`,
374
+ {
375
+ code: 'SEQUENCE_CONFLICT',
376
+ entityType: 'action client',
377
+ entityName: this._actionName,
378
+ details: { sequenceNumber: sequenceNumber, requestType: 'cancel' },
379
+ }
295
380
  );
296
381
  }
297
382
 
@@ -316,7 +401,15 @@ class ActionClient extends Entity {
316
401
  */
317
402
  _getResult(goalHandle) {
318
403
  if (!(goalHandle instanceof ClientGoalHandle)) {
319
- throw new TypeError('Invalid argument, must be type of ClientGoalHandle');
404
+ throw new TypeValidationError(
405
+ 'goalHandle',
406
+ goalHandle,
407
+ 'ClientGoalHandle',
408
+ {
409
+ entityType: 'action client',
410
+ entityName: this._actionName,
411
+ }
412
+ );
320
413
  }
321
414
 
322
415
  let request = new this.typeClass.impl.GetResultService.Request();
@@ -327,8 +420,14 @@ class ActionClient extends Entity {
327
420
  request.serialize()
328
421
  );
329
422
  if (this._pendingResultRequests.has(sequenceNumber)) {
330
- throw new Error(
331
- `Sequence (${sequenceNumber}) conflicts with pending result request`
423
+ throw new OperationError(
424
+ `Sequence (${sequenceNumber}) conflicts with pending result request`,
425
+ {
426
+ code: 'SEQUENCE_CONFLICT',
427
+ entityType: 'action client',
428
+ entityName: this._actionName,
429
+ details: { sequenceNumber: sequenceNumber, requestType: 'result' },
430
+ }
332
431
  );
333
432
  }
334
433
 
@@ -14,6 +14,8 @@
14
14
 
15
15
  'use strict';
16
16
 
17
+ const { TypeValidationError } = require('../errors.js');
18
+
17
19
  /**
18
20
  * @class - Wraps a promise allowing it to be resolved elsewhere.
19
21
  * @ignore
@@ -42,7 +44,9 @@ class Deferred {
42
44
  */
43
45
  beforeSetResultCallback(callback) {
44
46
  if (typeof callback !== 'function') {
45
- throw new TypeError('Invalid parameter');
47
+ throw new TypeValidationError('callback', callback, 'function', {
48
+ entityType: 'deferred promise',
49
+ });
46
50
  }
47
51
 
48
52
  this._beforeSetResultCallback = callback;
@@ -70,7 +74,9 @@ class Deferred {
70
74
  */
71
75
  setDoneCallback(callback) {
72
76
  if (typeof callback !== 'function') {
73
- throw new TypeError('Invalid parameter');
77
+ throw new TypeValidationError('callback', callback, 'function', {
78
+ entityType: 'deferred promise',
79
+ });
74
80
  }
75
81
 
76
82
  this._promise.finally(() => callback(this._result));
@@ -23,6 +23,7 @@ const { CancelResponse, GoalEvent, GoalResponse } = require('./response.js');
23
23
  const loader = require('../interface_loader.js');
24
24
  const QoS = require('../qos.js');
25
25
  const ServerGoalHandle = require('./server_goal_handle.js');
26
+ const { TypeValidationError } = require('../errors.js');
26
27
 
27
28
  /**
28
29
  * Execute the goal.
@@ -219,7 +220,15 @@ class ActionServer extends Entity {
219
220
  */
220
221
  registerExecuteCallback(executeCallback) {
221
222
  if (typeof executeCallback !== 'function') {
222
- throw new TypeError('Invalid argument');
223
+ throw new TypeValidationError(
224
+ 'executeCallback',
225
+ executeCallback,
226
+ 'function',
227
+ {
228
+ entityType: 'action server',
229
+ entityName: this._actionName,
230
+ }
231
+ );
223
232
  }
224
233
 
225
234
  this._callback = executeCallback;
@@ -16,6 +16,7 @@
16
16
 
17
17
  const ActionInterfaces = require('./interfaces.js');
18
18
  const { randomUUID } = require('crypto');
19
+ const { TypeValidationError } = require('../errors.js');
19
20
 
20
21
  /**
21
22
  * @class - Represents a unique identifier used by actions.
@@ -31,7 +32,9 @@ class ActionUuid {
31
32
  constructor(bytes) {
32
33
  if (bytes) {
33
34
  if (!(bytes instanceof Uint8Array)) {
34
- throw new Error('Invalid parameter');
35
+ throw new TypeValidationError('bytes', bytes, 'Uint8Array', {
36
+ entityType: 'action uuid',
37
+ });
35
38
  }
36
39
 
37
40
  this._bytes = bytes;