rclnodejs 1.7.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 (65) hide show
  1. package/binding.gyp +2 -0
  2. package/index.js +93 -0
  3. package/lib/action/client.js +54 -1
  4. package/lib/client.js +66 -1
  5. package/lib/clock.js +178 -0
  6. package/lib/clock_change.js +49 -0
  7. package/lib/clock_event.js +88 -0
  8. package/lib/errors.js +50 -0
  9. package/lib/logging.js +78 -0
  10. package/lib/message_introspector.js +123 -0
  11. package/lib/message_validation.js +512 -0
  12. package/lib/node.js +133 -1
  13. package/lib/node_options.js +40 -1
  14. package/lib/observable_subscription.js +105 -0
  15. package/lib/publisher.js +56 -1
  16. package/lib/qos.js +57 -0
  17. package/lib/subscription.js +8 -0
  18. package/lib/timer.js +42 -0
  19. package/lib/validator.js +63 -7
  20. package/package.json +4 -2
  21. package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
  22. package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
  23. package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
  24. package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
  25. package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
  26. package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
  27. package/rosidl_gen/message_translator.js +0 -61
  28. package/scripts/config.js +1 -0
  29. package/src/addon.cpp +2 -0
  30. package/src/clock_event.cpp +268 -0
  31. package/src/clock_event.hpp +62 -0
  32. package/src/macros.h +2 -4
  33. package/src/rcl_action_server_bindings.cpp +21 -3
  34. package/src/rcl_bindings.cpp +59 -0
  35. package/src/rcl_context_bindings.cpp +5 -0
  36. package/src/rcl_graph_bindings.cpp +73 -0
  37. package/src/rcl_logging_bindings.cpp +158 -0
  38. package/src/rcl_node_bindings.cpp +14 -2
  39. package/src/rcl_publisher_bindings.cpp +12 -0
  40. package/src/rcl_service_bindings.cpp +7 -6
  41. package/src/rcl_subscription_bindings.cpp +51 -14
  42. package/src/rcl_time_point_bindings.cpp +135 -0
  43. package/src/rcl_timer_bindings.cpp +140 -0
  44. package/src/rcl_utilities.cpp +103 -2
  45. package/src/rcl_utilities.h +7 -1
  46. package/types/action_client.d.ts +27 -2
  47. package/types/base.d.ts +3 -0
  48. package/types/client.d.ts +29 -1
  49. package/types/clock.d.ts +86 -0
  50. package/types/clock_change.d.ts +27 -0
  51. package/types/clock_event.d.ts +51 -0
  52. package/types/errors.d.ts +49 -0
  53. package/types/index.d.ts +10 -0
  54. package/types/interfaces.d.ts +1 -1910
  55. package/types/logging.d.ts +32 -0
  56. package/types/message_introspector.d.ts +75 -0
  57. package/types/message_validation.d.ts +183 -0
  58. package/types/node.d.ts +67 -0
  59. package/types/node_options.d.ts +13 -0
  60. package/types/observable_subscription.d.ts +39 -0
  61. package/types/publisher.d.ts +28 -1
  62. package/types/qos.d.ts +18 -0
  63. package/types/subscription.d.ts +6 -0
  64. package/types/timer.d.ts +18 -0
  65. package/types/validator.d.ts +86 -0
@@ -27,18 +27,24 @@ class NodeOptions {
27
27
  * @param {array} [parameterOverrides=[]]
28
28
  * @param {boolean} [automaticallyDeclareParametersFromOverrides=false]
29
29
  * @param {boolean} [startTypeDescriptionService=true]
30
+ * @param {boolean} [enableRosout=true]
31
+ * @param {QoS} [rosoutQos=QoS.profileDefault]
30
32
  */
31
33
  constructor(
32
34
  startParameterServices = true,
33
35
  parameterOverrides = [],
34
36
  automaticallyDeclareParametersFromOverrides = false,
35
- startTypeDescriptionService = true
37
+ startTypeDescriptionService = true,
38
+ enableRosout = true,
39
+ rosoutQos = null
36
40
  ) {
37
41
  this._startParameterServices = startParameterServices;
38
42
  this._parameterOverrides = parameterOverrides;
39
43
  this._automaticallyDeclareParametersFromOverrides =
40
44
  automaticallyDeclareParametersFromOverrides;
41
45
  this._startTypeDescriptionService = startTypeDescriptionService;
46
+ this._enableRosout = enableRosout;
47
+ this._rosoutQos = rosoutQos;
42
48
  }
43
49
 
44
50
  /**
@@ -125,6 +131,39 @@ class NodeOptions {
125
131
  this._startTypeDescriptionService = willStartTypeDescriptionService;
126
132
  }
127
133
 
134
+ /**
135
+ * Get the enableRosout option.
136
+ * Default value = true;
137
+ * @returns {boolean} - true if the rosout logging is enabled.
138
+ */
139
+ get enableRosout() {
140
+ return this._enableRosout;
141
+ }
142
+
143
+ /**
144
+ * Set enableRosout.
145
+ * @param {boolean} enableRosout
146
+ */
147
+ set enableRosout(enableRosout) {
148
+ this._enableRosout = enableRosout;
149
+ }
150
+
151
+ /**
152
+ * Get the rosoutQos option.
153
+ * @returns {QoS} - The QoS profile for rosout.
154
+ */
155
+ get rosoutQos() {
156
+ return this._rosoutQos;
157
+ }
158
+
159
+ /**
160
+ * Set rosoutQos.
161
+ * @param {QoS} rosoutQos
162
+ */
163
+ set rosoutQos(rosoutQos) {
164
+ this._rosoutQos = rosoutQos;
165
+ }
166
+
128
167
  /**
129
168
  * Return an instance configured with default options.
130
169
  * @returns {NodeOptions} - An instance with default values.
@@ -0,0 +1,105 @@
1
+ // Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ 'use strict';
16
+
17
+ const { Subject } = require('rxjs');
18
+
19
+ /**
20
+ * A wrapper that provides RxJS Observable support for ROS 2 subscriptions.
21
+ * This class wraps a standard Subscription and emits messages through an Observable.
22
+ *
23
+ * @class ObservableSubscription
24
+ * @hideconstructor
25
+ */
26
+ class ObservableSubscription {
27
+ #subscription;
28
+ #subject;
29
+ #destroyed;
30
+
31
+ /**
32
+ * Create an ObservableSubscription wrapper.
33
+ * @param {Subscription} subscription - The underlying ROS 2 subscription
34
+ */
35
+ constructor(subscription) {
36
+ this.#subscription = subscription;
37
+ this.#subject = new Subject();
38
+ this.#destroyed = false;
39
+ }
40
+
41
+ /**
42
+ * Get the RxJS Observable for this subscription.
43
+ * Use this to pipe operators and subscribe to messages.
44
+ * @type {Observable}
45
+ */
46
+ get observable() {
47
+ return this.#subject.asObservable();
48
+ }
49
+
50
+ /**
51
+ * Get the underlying ROS 2 subscription.
52
+ * @type {Subscription}
53
+ */
54
+ get subscription() {
55
+ return this.#subscription;
56
+ }
57
+
58
+ /**
59
+ * Get the topic name.
60
+ * @type {string}
61
+ */
62
+ get topic() {
63
+ return this.#subscription.topic;
64
+ }
65
+
66
+ /**
67
+ * Check if this observable subscription has been destroyed.
68
+ * @type {boolean}
69
+ */
70
+ get isDestroyed() {
71
+ return this.#destroyed;
72
+ }
73
+
74
+ /**
75
+ * Internal method to emit a message to subscribers.
76
+ * Called by the subscription's processResponse.
77
+ * @private
78
+ * @param {any} message - The message to emit
79
+ */
80
+ _emit(message) {
81
+ if (!this.#destroyed) {
82
+ this.#subject.next(message);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Complete the observable and clean up resources.
88
+ * After calling this, no more messages will be emitted.
89
+ */
90
+ complete() {
91
+ if (!this.#destroyed) {
92
+ this.#destroyed = true;
93
+ this.#subject.complete();
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Alias for complete() for consistency with RxJS naming.
99
+ */
100
+ destroy() {
101
+ this.complete();
102
+ }
103
+ }
104
+
105
+ module.exports = ObservableSubscription;
package/lib/publisher.js CHANGED
@@ -17,6 +17,7 @@
17
17
  const rclnodejs = require('./native_loader.js');
18
18
  const debug = require('debug')('rclnodejs:publisher');
19
19
  const Entity = require('./entity.js');
20
+ const { assertValidMessage } = require('./message_validation.js');
20
21
 
21
22
  /**
22
23
  * @class - Class representing a Publisher in ROS
@@ -27,6 +28,11 @@ class Publisher extends Entity {
27
28
  constructor(handle, typeClass, topic, options, node, eventCallbacks) {
28
29
  super(handle, typeClass, options);
29
30
  this._node = node;
31
+ this._validateMessages = options.validateMessages || false;
32
+ this._validationOptions = options.validationOptions || {
33
+ strict: true,
34
+ checkTypes: true,
35
+ };
30
36
  if (node && eventCallbacks) {
31
37
  this._events = eventCallbacks.createEventHandlers(this.handle);
32
38
  node._events.push(...this._events);
@@ -44,12 +50,24 @@ class Publisher extends Entity {
44
50
  * Publish a message
45
51
  * @param {object|Buffer} message - The message to be sent, could be kind of JavaScript message generated from .msg
46
52
  * or be a Buffer for a raw message.
53
+ * @param {object} [options] - Publish options
54
+ * @param {boolean} [options.validate] - Override validateMessages setting for this publish call
47
55
  * @return {undefined}
56
+ * @throws {MessageValidationError} If validation is enabled and message is invalid
48
57
  */
49
- publish(message) {
58
+ publish(message, options = {}) {
50
59
  if (message instanceof Buffer) {
51
60
  rclnodejs.publishRawMessage(this._handle, message);
52
61
  } else {
62
+ const shouldValidate =
63
+ options.validate !== undefined
64
+ ? options.validate
65
+ : this._validateMessages;
66
+
67
+ if (shouldValidate && !(message instanceof this._typeClass)) {
68
+ assertValidMessage(message, this._typeClass, this._validationOptions);
69
+ }
70
+
53
71
  // Enables call by plain object/number/string argument
54
72
  // e.g. publisher.publish(3.14);
55
73
  // publisher.publish('The quick brown fox...');
@@ -65,6 +83,35 @@ class Publisher extends Entity {
65
83
  debug(`Message of topic ${this.topic} has been published.`);
66
84
  }
67
85
 
86
+ /**
87
+ * Whether messages will be validated before publishing.
88
+ * @type {boolean}
89
+ */
90
+ get willValidateMessage() {
91
+ return this._validateMessages;
92
+ }
93
+
94
+ /**
95
+ * Enable or disable message validation for this publisher.
96
+ * @param {boolean} value - Whether to validate messages before publishing
97
+ */
98
+ set willValidateMessage(value) {
99
+ this._validateMessages = value;
100
+ }
101
+
102
+ /**
103
+ * Set validation options for this publisher.
104
+ * @param {object} options - Validation options
105
+ * @param {boolean} [options.strict=true] - Throw on unknown fields
106
+ * @param {boolean} [options.checkTypes=true] - Validate field types
107
+ * @param {boolean} [options.checkRequired=false] - Check for missing fields
108
+ */
109
+ setValidation(options) {
110
+ if (options && Object.keys(options).length > 0) {
111
+ this._validationOptions = { ...this._validationOptions, ...options };
112
+ }
113
+ }
114
+
68
115
  static createPublisher(node, typeClass, topic, options, eventCallbacks) {
69
116
  let type = typeClass.type();
70
117
  let handle = rclnodejs.createPublisher(
@@ -112,6 +159,14 @@ class Publisher extends Entity {
112
159
  return rclnodejs.waitForAllAcked(this._handle, timeout);
113
160
  }
114
161
 
162
+ /**
163
+ * Manually assert that this Publisher is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC).
164
+ * @return {undefined}
165
+ */
166
+ assertLiveliness() {
167
+ rclnodejs.assertLiveliness(this._handle);
168
+ }
169
+
115
170
  /**
116
171
  * Get the event handlers for this publisher.
117
172
  * @returns {Array} The array of event handlers for this publisher.
package/lib/qos.js CHANGED
@@ -58,6 +58,24 @@ let DurabilityPolicy = {
58
58
  RMW_QOS_POLICY_DURABILITY_VOLATILE: 2,
59
59
  };
60
60
 
61
+ /**
62
+ * Enum for LivelinessPolicy
63
+ * @readonly
64
+ * @enum {number}
65
+ */
66
+ let LivelinessPolicy = {
67
+ /** @member {number} */
68
+ RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT: 0,
69
+ /** @member {number} */
70
+ RMW_QOS_POLICY_LIVELINESS_AUTOMATIC: 1,
71
+ /** @member {number} */
72
+ RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC: 3,
73
+ /** @member {number} */
74
+ RMW_QOS_POLICY_LIVELINESS_UNKNOWN: 4,
75
+ /** @member {number} */
76
+ RMW_QOS_POLICY_LIVELINESS_BEST_AVAILABLE: 5,
77
+ };
78
+
61
79
  /** Class representing middleware quality of service */
62
80
  class QoS {
63
81
  /**
@@ -73,12 +91,14 @@ class QoS {
73
91
  depth = 0,
74
92
  reliability = ReliabilityPolicy.RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
75
93
  durability = DurabilityPolicy.RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
94
+ liveliness = LivelinessPolicy.RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
76
95
  avoidRosNameSpaceConventions = false
77
96
  ) {
78
97
  this._history = history;
79
98
  this._depth = depth;
80
99
  this._reliability = reliability;
81
100
  this._durability = durability;
101
+ this._liveliness = liveliness;
82
102
  this._avoidRosNameSpaceConventions = avoidRosNameSpaceConventions;
83
103
  }
84
104
 
@@ -112,6 +132,16 @@ class QoS {
112
132
  return DurabilityPolicy;
113
133
  }
114
134
 
135
+ /**
136
+ * Get LivelinessPolicy enum.
137
+ * @name QoS#static get:LivelinessPolicy
138
+ * @function
139
+ * @return {LivelinessPolicy}
140
+ */
141
+ static get LivelinessPolicy() {
142
+ return LivelinessPolicy;
143
+ }
144
+
115
145
  /**
116
146
  * Get the history value.
117
147
  * @name QoS#get:history
@@ -220,6 +250,33 @@ class QoS {
220
250
  this._durability = durability;
221
251
  }
222
252
 
253
+ /**
254
+ * Get the liveliness value.
255
+ * @name QoS#get:liveliness
256
+ * @function
257
+ * @return {number}
258
+ */
259
+ get liveliness() {
260
+ return this._liveliness;
261
+ }
262
+
263
+ /**
264
+ * Set the liveliness value.
265
+ * @param {number} liveliness - value to be set.
266
+ * @name QoS#set:liveliness
267
+ * @function
268
+ * @return {undefined}
269
+ */
270
+ set liveliness(liveliness) {
271
+ if (typeof liveliness !== 'number') {
272
+ throw new TypeValidationError('liveliness', liveliness, 'number', {
273
+ entityType: 'qos',
274
+ });
275
+ }
276
+
277
+ this._liveliness = liveliness;
278
+ }
279
+
223
280
  /**
224
281
  * Get the avoidRosNameSpaceConventions value.
225
282
  * @name QoS#get:avoidRosNameSpaceConventions
@@ -151,6 +151,14 @@ class Subscription extends Entity {
151
151
  : this.clearContentFilter();
152
152
  }
153
153
 
154
+ /**
155
+ * Get the current content-filter.
156
+ * @returns {object} - The content-filter description {expression: string, parameters: string[]} or undefined if not set/supported.
157
+ */
158
+ getContentFilter() {
159
+ return rclnodejs.getContentFilter(this.handle);
160
+ }
161
+
154
162
  /**
155
163
  * Clear the current content-filter. No filtering is to be applied.
156
164
  * @returns {boolean} - True if successful; false otherwise
package/lib/timer.js CHANGED
@@ -88,6 +88,19 @@ class Timer {
88
88
  return rclnodejs.timerGetTimeUntilNextCall(this._handle);
89
89
  }
90
90
 
91
+ /**
92
+ * Get the absolute time in nanoseconds when the next callback is due.
93
+ * Note: Only available on ROS2 distributions after Humble.
94
+ * @return {bigint | null} - The next call time in nanoseconds, or null if the timer is canceled.
95
+ * Returns undefined if not supported on current ROS2 distribution.
96
+ */
97
+ getNextCallTime() {
98
+ if (typeof rclnodejs.getTimerNextCallTime !== 'function') {
99
+ return undefined;
100
+ }
101
+ return rclnodejs.getTimerNextCallTime(this._handle);
102
+ }
103
+
91
104
  /**
92
105
  * Change the timer period.
93
106
  * @param {bigint} period - The new period in nanoseconds.
@@ -105,6 +118,35 @@ class Timer {
105
118
  return rclnodejs.getTimerPeriod(this._handle);
106
119
  }
107
120
 
121
+ /**
122
+ * Set the on reset callback.
123
+ * @param {function} callback - The callback to be called when the timer is reset.
124
+ * @return {undefined}
125
+ */
126
+ setOnResetCallback(callback) {
127
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
128
+ console.warn(
129
+ 'setOnResetCallback is not supported by this version of ROS 2'
130
+ );
131
+ return;
132
+ }
133
+ rclnodejs.setTimerOnResetCallback(this._handle, callback);
134
+ }
135
+
136
+ /**
137
+ * Clear the on reset callback.
138
+ * @return {undefined}
139
+ */
140
+ clearOnResetCallback() {
141
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
142
+ console.warn(
143
+ 'clearOnResetCallback is not supported by this version of ROS 2'
144
+ );
145
+ return;
146
+ }
147
+ rclnodejs.clearTimerOnResetCallback(this._handle);
148
+ }
149
+
108
150
  /**
109
151
  * Call a timer and starts counting again, retrieves actual and expected call time.
110
152
  * @return {object} - The timer information.
package/lib/validator.js CHANGED
@@ -28,8 +28,10 @@ let validator = {
28
28
 
29
29
  /**
30
30
  * Validate a given topic or service name, and throw an error if invalid.
31
- * @param {string} topic - The name of topic/service. and it must be fully-qualified and already expanded.
32
- * @return {boolean} - True if it is valid.
31
+ * @param {string} topic - The name of topic/service. Must be fully-qualified and already expanded.
32
+ * @returns {true} Always returns true if valid.
33
+ * @throws {TypeValidationError} If topic is not a string.
34
+ * @throws {NameValidationError} If the topic name is invalid.
33
35
  */
34
36
  validateFullTopicName(topic) {
35
37
  if (typeof topic !== 'string') {
@@ -43,10 +45,24 @@ let validator = {
43
45
  throw this._createErrorFromValidation(result, topic, 'topic');
44
46
  },
45
47
 
48
+ /**
49
+ * Check if a fully-qualified topic name is valid without throwing.
50
+ * @param {string} topic - The name of topic/service. Must be fully-qualified and already expanded.
51
+ * @returns {boolean} True if valid, false otherwise.
52
+ */
53
+ isValidFullTopicName(topic) {
54
+ if (typeof topic !== 'string') {
55
+ return false;
56
+ }
57
+ return rclnodejs.validateFullTopicName(topic) === null;
58
+ },
59
+
46
60
  /**
47
61
  * Validate a given node name, and throw an error if invalid.
48
62
  * @param {string} name - The name of node.
49
- * @return {boolean} - True if it is valid.
63
+ * @returns {true} Always returns true if valid.
64
+ * @throws {TypeValidationError} If name is not a string.
65
+ * @throws {NameValidationError} If the node name is invalid.
50
66
  */
51
67
  validateNodeName(name) {
52
68
  if (typeof name !== 'string') {
@@ -60,10 +76,24 @@ let validator = {
60
76
  throw this._createErrorFromValidation(result, name, 'node');
61
77
  },
62
78
 
79
+ /**
80
+ * Check if a node name is valid without throwing.
81
+ * @param {string} name - The name of node.
82
+ * @returns {boolean} True if valid, false otherwise.
83
+ */
84
+ isValidNodeName(name) {
85
+ if (typeof name !== 'string') {
86
+ return false;
87
+ }
88
+ return rclnodejs.validateNodeName(name) === null;
89
+ },
90
+
63
91
  /**
64
92
  * Validate a given topic or service name, and throw an error if invalid.
65
- * @param {string} topic - The name of topic/service and does not have to be fully-qualified and is not expanded.
66
- * @return {boolean} - True if it is valid.
93
+ * @param {string} topic - The name of topic/service. Does not have to be fully-qualified.
94
+ * @returns {true} Always returns true if valid.
95
+ * @throws {TypeValidationError} If topic is not a string.
96
+ * @throws {NameValidationError} If the topic name is invalid.
67
97
  */
68
98
  validateTopicName(topic) {
69
99
  if (typeof topic !== 'string') {
@@ -77,10 +107,24 @@ let validator = {
77
107
  throw this._createErrorFromValidation(result, topic, 'topic');
78
108
  },
79
109
 
110
+ /**
111
+ * Check if a topic name is valid without throwing.
112
+ * @param {string} topic - The name of topic/service. Does not have to be fully-qualified.
113
+ * @returns {boolean} True if valid, false otherwise.
114
+ */
115
+ isValidTopicName(topic) {
116
+ if (typeof topic !== 'string') {
117
+ return false;
118
+ }
119
+ return rclnodejs.validateTopicName(topic) === null;
120
+ },
121
+
80
122
  /**
81
123
  * Validate a given namespace, and throw an error if invalid.
82
- * @param {string} namespace - The namespace to be validated
83
- * @return {boolean} - True if it is valid.
124
+ * @param {string} namespace - The namespace to be validated.
125
+ * @returns {true} Always returns true if valid.
126
+ * @throws {TypeValidationError} If namespace is not a string.
127
+ * @throws {NameValidationError} If the namespace is invalid.
84
128
  */
85
129
  validateNamespace(namespace) {
86
130
  if (typeof namespace !== 'string') {
@@ -93,6 +137,18 @@ let validator = {
93
137
  }
94
138
  throw this._createErrorFromValidation(result, namespace, 'namespace');
95
139
  },
140
+
141
+ /**
142
+ * Check if a namespace is valid without throwing.
143
+ * @param {string} namespace - The namespace to be validated.
144
+ * @returns {boolean} True if valid, false otherwise.
145
+ */
146
+ isValidNamespace(namespace) {
147
+ if (typeof namespace !== 'string') {
148
+ return false;
149
+ }
150
+ return rclnodejs.validateNamespace(namespace) === null;
151
+ },
96
152
  };
97
153
 
98
154
  module.exports = validator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rclnodejs",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "ROS2.0 JavaScript client with Node.js",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@eslint/js": "^9.36.0",
52
- "@types/node": "^24.5.2",
52
+ "@types/node": "^25.0.2",
53
53
  "@typescript-eslint/eslint-plugin": "^8.18.0",
54
54
  "@typescript-eslint/parser": "^8.18.0",
55
55
  "clang-format": "^1.8.0",
@@ -64,6 +64,7 @@
64
64
  "jsdoc": "^4.0.4",
65
65
  "lint-staged": "^16.2.0",
66
66
  "mocha": "^11.0.2",
67
+ "node-gyp": "^12.1.0",
67
68
  "nyc": "^17.1.0",
68
69
  "prebuildify": "^6.0.1",
69
70
  "rimraf": "^6.0.1",
@@ -79,6 +80,7 @@
79
80
  "debug": "^4.4.0",
80
81
  "json-bigint": "^1.0.0",
81
82
  "node-addon-api": "^8.3.1",
83
+ "rxjs": "^7.8.1",
82
84
  "walk": "^2.3.15"
83
85
  },
84
86
  "husky": {
@@ -58,66 +58,6 @@ function copyMsgObject(msg, obj) {
58
58
  }
59
59
  }
60
60
 
61
- function verifyMessage(message, obj) {
62
- if (message.constructor.isROSArray) {
63
- // It's a ROS message array
64
- // Note: there won't be any JavaScript array in message.
65
- if (!Array.isArray(obj)) {
66
- return false;
67
- }
68
- // TODO(Kenny): deal with TypedArray in the future
69
- // TODO(Kenny): if the elements are objects, check the objects
70
- } else {
71
- // It's a ROS message
72
- const def = message.constructor.ROSMessageDef;
73
- let obj = {};
74
- for (let i in def.fields) {
75
- const name = def.fields[i].name;
76
- if (def.fields[i].type.isPrimitiveType) {
77
- // check type/existence
78
- switch (def.fields[i].type) {
79
- case 'char':
80
- case 'int16':
81
- case 'int32':
82
- case 'byte':
83
- case 'uint16':
84
- case 'uint32':
85
- case 'float32':
86
- case 'float64':
87
- if (typeof obj[name] != 'number') {
88
- return false;
89
- }
90
- break;
91
- case 'int64':
92
- case 'uint64':
93
- if (typeof obj[name] != 'bigint') {
94
- return false;
95
- }
96
- case 'bool':
97
- if (typeof obj[name] != 'boolean') {
98
- return false;
99
- }
100
- break;
101
- case 'string':
102
- if (typeof obj[name] != 'string') {
103
- return false;
104
- }
105
- break;
106
- }
107
- } else if (!verifyMessage(message[name], obj[name])) {
108
- // Proceed further on this member
109
- return false;
110
- }
111
- }
112
- }
113
- return true;
114
- }
115
-
116
- function verifyMessageStruct(MessageType, obj) {
117
- const msg = new MessageType();
118
- return verifyMessage(msg, obj);
119
- }
120
-
121
61
  function toPlainObject(message, enableTypedArray = true) {
122
62
  if (!message) return undefined;
123
63
 
@@ -186,7 +126,6 @@ function constructFromPlanObject(msg, obj) {
186
126
  }
187
127
 
188
128
  module.exports = {
189
- verifyMessageStruct: verifyMessageStruct,
190
129
  toROSMessage: toROSMessage,
191
130
  toPlainObject: toPlainObject,
192
131
  constructFromPlanObject: constructFromPlanObject,
package/scripts/config.js CHANGED
@@ -33,6 +33,7 @@ const dependencies = [
33
33
  'rosidl_runtime_c',
34
34
  'rosidl_dynamic_typesupport',
35
35
  'type_description_interfaces',
36
+ 'rcl_logging_interface',
36
37
  ];
37
38
 
38
39
  const command = os.type() === 'Windows_NT' ? 'where ros2' : 'which ros2';
package/src/addon.cpp CHANGED
@@ -15,6 +15,7 @@
15
15
  #include <node_api.h>
16
16
  #include <rcutils/logging.h>
17
17
 
18
+ #include "clock_event.hpp"
18
19
  #include "macros.h"
19
20
  #include "rcl_action_client_bindings.h"
20
21
  #include "rcl_action_goal_bindings.h"
@@ -74,6 +75,7 @@ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
74
75
  rclnodejs::InitActionGoalBindings(env, exports);
75
76
  rclnodejs::InitActionServerBindings(env, exports);
76
77
  rclnodejs::InitClientBindings(env, exports);
78
+ rclnodejs::InitClockEventBindings(env, exports);
77
79
  rclnodejs::InitContextBindings(env, exports);
78
80
  rclnodejs::InitGraphBindings(env, exports);
79
81
  rclnodejs::InitGuardConditionBindings(env, exports);