rclnodejs 1.8.2 → 1.9.0-alpha.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 (112) hide show
  1. package/README.md +46 -37
  2. package/index.js +62 -23
  3. package/lib/action/client.js +67 -3
  4. package/lib/action/server.js +1 -3
  5. package/lib/distro.js +2 -1
  6. package/lib/lifecycle_publisher.js +2 -2
  7. package/lib/message_info.js +94 -0
  8. package/lib/node.js +90 -14
  9. package/lib/parameter.js +5 -9
  10. package/lib/parameter_event_handler.js +468 -0
  11. package/lib/parameter_watcher.js +12 -12
  12. package/lib/service.js +8 -4
  13. package/lib/subscription.js +38 -5
  14. package/lib/time_source.js +3 -20
  15. package/lib/timer.js +2 -1
  16. package/lib/wait_for_message.js +111 -0
  17. package/package.json +7 -4
  18. package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
  19. package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
  20. package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
  21. package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
  22. package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
  23. package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
  24. package/rosidl_gen/generate_worker.js +3 -13
  25. package/rosidl_gen/idl_generator.js +210 -0
  26. package/rosidl_gen/index.js +3 -12
  27. package/rosidl_gen/packages.js +1 -3
  28. package/rosidl_gen/primitive_types.js +2 -2
  29. package/rosidl_parser/idl_parser.py +437 -0
  30. package/rosidl_parser/parser.py +2 -4
  31. package/rosidl_parser/rosidl_parser.js +27 -0
  32. package/scripts/run_asan_test.sh +118 -0
  33. package/src/executor.cpp +37 -2
  34. package/src/executor.h +11 -0
  35. package/src/macros.h +2 -2
  36. package/src/rcl_action_client_bindings.cpp +88 -12
  37. package/src/rcl_action_server_bindings.cpp +24 -13
  38. package/src/rcl_client_bindings.cpp +13 -5
  39. package/src/rcl_context_bindings.cpp +10 -11
  40. package/src/rcl_graph_bindings.cpp +2 -2
  41. package/src/rcl_guard_condition_bindings.cpp +12 -3
  42. package/src/rcl_lifecycle_bindings.cpp +34 -15
  43. package/src/rcl_node_bindings.cpp +11 -4
  44. package/src/rcl_publisher_bindings.cpp +12 -3
  45. package/src/rcl_service_bindings.cpp +12 -3
  46. package/src/rcl_subscription_bindings.cpp +92 -21
  47. package/src/rcl_timer_bindings.cpp +24 -9
  48. package/src/rcl_type_description_service_bindings.cpp +9 -1
  49. package/src/rcl_utilities.cpp +2 -2
  50. package/tools/jsdoc/Makefile +5 -0
  51. package/tools/jsdoc/README.md +96 -0
  52. package/tools/jsdoc/build-index.js +610 -0
  53. package/tools/jsdoc/publish.js +854 -0
  54. package/tools/jsdoc/regenerate-published-docs.js +605 -0
  55. package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.eot +0 -0
  56. package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.svg +1830 -0
  57. package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.woff +0 -0
  58. package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  59. package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
  60. package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  61. package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.eot +0 -0
  62. package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.svg +1830 -0
  63. package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.woff +0 -0
  64. package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.eot +0 -0
  65. package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.svg +1831 -0
  66. package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.woff +0 -0
  67. package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  68. package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
  69. package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  70. package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.eot +0 -0
  71. package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.svg +1831 -0
  72. package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.woff +0 -0
  73. package/tools/jsdoc/static/scripts/linenumber.js +25 -0
  74. package/tools/jsdoc/static/scripts/prettify/Apache-License-2.0.txt +202 -0
  75. package/tools/jsdoc/static/scripts/prettify/lang-css.js +36 -0
  76. package/tools/jsdoc/static/scripts/prettify/prettify.js +738 -0
  77. package/tools/jsdoc/static/styles/jsdoc-default.css +1012 -0
  78. package/tools/jsdoc/static/styles/prettify-jsdoc.css +111 -0
  79. package/tools/jsdoc/static/styles/prettify-tomorrow.css +132 -0
  80. package/tools/jsdoc/tmpl/augments.tmpl +10 -0
  81. package/tools/jsdoc/tmpl/container.tmpl +193 -0
  82. package/tools/jsdoc/tmpl/details.tmpl +143 -0
  83. package/tools/jsdoc/tmpl/example.tmpl +2 -0
  84. package/tools/jsdoc/tmpl/examples.tmpl +13 -0
  85. package/tools/jsdoc/tmpl/exceptions.tmpl +17 -0
  86. package/tools/jsdoc/tmpl/layout.tmpl +83 -0
  87. package/tools/jsdoc/tmpl/mainpage.tmpl +163 -0
  88. package/tools/jsdoc/tmpl/members.tmpl +43 -0
  89. package/tools/jsdoc/tmpl/method.tmpl +124 -0
  90. package/tools/jsdoc/tmpl/params.tmpl +133 -0
  91. package/tools/jsdoc/tmpl/properties.tmpl +110 -0
  92. package/tools/jsdoc/tmpl/returns.tmpl +12 -0
  93. package/tools/jsdoc/tmpl/source.tmpl +8 -0
  94. package/tools/jsdoc/tmpl/tutorial.tmpl +19 -0
  95. package/tools/jsdoc/tmpl/type.tmpl +7 -0
  96. package/types/action_client.d.ts +8 -0
  97. package/types/index.d.ts +34 -0
  98. package/types/message_info.d.ts +72 -0
  99. package/types/node.d.ts +21 -0
  100. package/types/parameter_event_handler.d.ts +139 -0
  101. package/types/subscription.d.ts +14 -2
  102. package/rosidl_convertor/README.md +0 -298
  103. package/rosidl_convertor/idl_convertor.js +0 -50
  104. package/rosidl_convertor/idl_convertor.py +0 -1250
  105. package/test_data_integrity.js +0 -108
  106. package/test_repro_exact.js +0 -57
  107. package/test_repro_hz.js +0 -86
  108. package/test_repro_pub.js +0 -36
  109. package/test_repro_stress.js +0 -83
  110. package/test_repro_sub.js +0 -64
  111. package/test_xproc_data.js +0 -64
  112. package/types/interfaces.d.ts +0 -8895
@@ -16,11 +16,15 @@
16
16
 
17
17
  #include <rcl/error_handling.h>
18
18
  #include <rcl/rcl.h>
19
+ #include <rcl/subscription.h>
20
+ #include <rmw/types.h>
19
21
 
20
22
  #include <cstdio>
21
23
  #include <memory>
22
24
  #include <string>
23
25
 
26
+ #include <rcpputils/scope_exit.hpp>
27
+
24
28
  #include "macros.h"
25
29
  #include "rcl_handle.h"
26
30
  #include "rcl_utilities.h"
@@ -51,6 +55,53 @@ Napi::Value RclTake(const Napi::CallbackInfo& info) {
51
55
  return env.Undefined();
52
56
  }
53
57
 
58
+ Napi::Value RclTakeWithInfo(const Napi::CallbackInfo& info) {
59
+ Napi::Env env = info.Env();
60
+
61
+ RclHandle* subscription_handle =
62
+ RclHandle::Unwrap(info[0].As<Napi::Object>());
63
+ rcl_subscription_t* subscription =
64
+ reinterpret_cast<rcl_subscription_t*>(subscription_handle->ptr());
65
+ void* msg_taken = info[1].As<Napi::Buffer<char>>().Data();
66
+
67
+ rmw_message_info_t message_info = rmw_get_zero_initialized_message_info();
68
+ rcl_ret_t ret = rcl_take(subscription, msg_taken, &message_info, nullptr);
69
+
70
+ if (ret != RCL_RET_OK && ret != RCL_RET_SUBSCRIPTION_TAKE_FAILED) {
71
+ std::string error_string = rcl_get_error_string().str;
72
+ rcl_reset_error();
73
+ Napi::Error::New(env, error_string).ThrowAsJavaScriptException();
74
+ return env.Undefined();
75
+ }
76
+
77
+ if (ret == RCL_RET_SUBSCRIPTION_TAKE_FAILED) {
78
+ return env.Undefined();
79
+ }
80
+
81
+ // Build JS object with message info fields
82
+ Napi::Object js_info = Napi::Object::New(env);
83
+ js_info.Set("source_timestamp",
84
+ Napi::BigInt::New(env, message_info.source_timestamp));
85
+ js_info.Set("received_timestamp",
86
+ Napi::BigInt::New(env, message_info.received_timestamp));
87
+ js_info.Set(
88
+ "publication_sequence_number",
89
+ Napi::BigInt::New(
90
+ env, static_cast<int64_t>(message_info.publication_sequence_number)));
91
+ js_info.Set(
92
+ "reception_sequence_number",
93
+ Napi::BigInt::New(
94
+ env, static_cast<int64_t>(message_info.reception_sequence_number)));
95
+
96
+ // Publisher GID as Buffer
97
+ auto gid_buf =
98
+ Napi::Buffer<uint8_t>::Copy(env, message_info.publisher_gid.data,
99
+ sizeof(message_info.publisher_gid.data));
100
+ js_info.Set("publisher_gid", gid_buf);
101
+
102
+ return js_info;
103
+ }
104
+
54
105
  Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
55
106
  Napi::Env env = info.Env();
56
107
 
@@ -108,12 +159,6 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
108
159
  rcl_ret_t ret = rcl_subscription_options_set_content_filter_options(
109
160
  expression.c_str(), argc, (const char**)argv, &subscription_ops);
110
161
 
111
- if (ret != RCL_RET_OK) {
112
- std::string error_string = rcl_get_error_string().str;
113
- rcl_reset_error();
114
- Napi::Error::New(env, error_string).ThrowAsJavaScriptException();
115
- }
116
-
117
162
  if (argc) {
118
163
  for (int i = 0; i < argc; i++) {
119
164
  free(argv[i]);
@@ -122,7 +167,10 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
122
167
  }
123
168
 
124
169
  if (ret != RCL_RET_OK) {
170
+ std::string error_string = rcl_get_error_string().str;
171
+ rcl_reset_error();
125
172
  free(subscription);
173
+ Napi::Error::New(env, error_string).ThrowAsJavaScriptException();
126
174
  return env.Undefined();
127
175
  }
128
176
  }
@@ -137,8 +185,8 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
137
185
  if (ret != RCL_RET_OK) {
138
186
  std::string error_msg = rcl_get_error_string().str;
139
187
  rcl_reset_error();
140
- Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
141
188
  free(subscription);
189
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
142
190
  return env.Undefined();
143
191
  }
144
192
 
@@ -157,9 +205,9 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
157
205
 
158
206
  return js_obj;
159
207
  } else {
160
- Napi::Error::New(env, GetErrorMessageAndClear())
161
- .ThrowAsJavaScriptException();
208
+ std::string error_msg = GetErrorMessageAndClear();
162
209
  free(subscription);
210
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
163
211
  return env.Undefined();
164
212
  }
165
213
  }
@@ -194,10 +242,16 @@ Napi::Value RclTakeRaw(const Napi::CallbackInfo& info) {
194
242
  return env.Undefined();
195
243
  }
196
244
 
245
+ RCPPUTILS_SCOPE_EXIT({
246
+ rcl_ret_t fini_ret = rmw_serialized_message_fini(&msg);
247
+ if (fini_ret != RCL_RET_OK) {
248
+ rcl_reset_error();
249
+ }
250
+ });
251
+
197
252
  Napi::Buffer<char> buffer = Napi::Buffer<char>::Copy(
198
253
  env, reinterpret_cast<char*>(msg.buffer), msg.buffer_length);
199
- THROW_ERROR_IF_NOT_EQUAL(rmw_serialized_message_fini(&msg), RCL_RET_OK,
200
- "Failed to deallocate message buffer");
254
+
201
255
  return buffer;
202
256
  }
203
257
 
@@ -211,6 +265,20 @@ Napi::Value GetSubscriptionTopic(const Napi::CallbackInfo& info) {
211
265
  return Napi::String::New(env, topic);
212
266
  }
213
267
 
268
+ #if ROS_VERSION > 2505 // Rolling only
269
+ Napi::Value IsContentFilterSupported(const Napi::CallbackInfo& info) {
270
+ Napi::Env env = info.Env();
271
+
272
+ RclHandle* subscription_handle =
273
+ RclHandle::Unwrap(info[0].As<Napi::Object>());
274
+ rcl_subscription_t* subscription =
275
+ reinterpret_cast<rcl_subscription_t*>(subscription_handle->ptr());
276
+
277
+ bool is_supported = rcl_subscription_is_cft_supported(subscription);
278
+ return Napi::Boolean::New(env, is_supported);
279
+ }
280
+ #endif
281
+
214
282
  Napi::Value HasContentFilter(const Napi::CallbackInfo& info) {
215
283
  Napi::Env env = info.Env();
216
284
 
@@ -369,6 +437,14 @@ Napi::Value GetContentFilter(const Napi::CallbackInfo& info) {
369
437
  return env.Undefined();
370
438
  }
371
439
 
440
+ RCPPUTILS_SCOPE_EXIT({
441
+ rcl_ret_t fini_ret =
442
+ rcl_subscription_content_filter_options_fini(subscription, &options);
443
+ if (fini_ret != RCL_RET_OK) {
444
+ rcl_reset_error();
445
+ }
446
+ });
447
+
372
448
  // Create result object
373
449
  Napi::Object result = Napi::Object::New(env);
374
450
  result.Set(
@@ -387,16 +463,6 @@ Napi::Value GetContentFilter(const Napi::CallbackInfo& info) {
387
463
  }
388
464
  result.Set("parameters", parameters);
389
465
 
390
- // Cleanup
391
- rcl_ret_t fini_ret =
392
- rcl_subscription_content_filter_options_fini(subscription, &options);
393
- if (fini_ret != RCL_RET_OK) {
394
- std::string error_msg = rcl_get_error_string().str;
395
- rcl_reset_error();
396
- Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
397
- return env.Undefined();
398
- }
399
-
400
466
  return result;
401
467
  }
402
468
 
@@ -419,11 +485,16 @@ Napi::Value GetPublisherCount(const Napi::CallbackInfo& info) {
419
485
 
420
486
  Napi::Object InitSubscriptionBindings(Napi::Env env, Napi::Object exports) {
421
487
  exports.Set("rclTake", Napi::Function::New(env, RclTake));
488
+ exports.Set("rclTakeWithInfo", Napi::Function::New(env, RclTakeWithInfo));
422
489
  exports.Set("createSubscription",
423
490
  Napi::Function::New(env, CreateSubscription));
424
491
  exports.Set("rclTakeRaw", Napi::Function::New(env, RclTakeRaw));
425
492
  exports.Set("getSubscriptionTopic",
426
493
  Napi::Function::New(env, GetSubscriptionTopic));
494
+ #if ROS_VERSION > 2505 // Rolling only
495
+ exports.Set("isContentFilterSupported",
496
+ Napi::Function::New(env, IsContentFilterSupported));
497
+ #endif
427
498
  exports.Set("hasContentFilter", Napi::Function::New(env, HasContentFilter));
428
499
  exports.Set("setContentFilter", Napi::Function::New(env, SetContentFilter));
429
500
  exports.Set("getContentFilter", Napi::Function::New(env, GetContentFilter));
@@ -19,6 +19,7 @@
19
19
 
20
20
  #include <memory>
21
21
  #include <mutex>
22
+ #include <string>
22
23
  #include <unordered_map>
23
24
 
24
25
  #include "macros.h"
@@ -82,16 +83,30 @@ Napi::Value CreateTimer(const Napi::CallbackInfo& info) {
82
83
  *timer = rcl_get_zero_initialized_timer();
83
84
 
84
85
  #if ROS_VERSION > 2305 // After Iron.
85
- THROW_ERROR_IF_NOT_EQUAL(
86
- RCL_RET_OK,
87
- rcl_timer_init2(timer, clock, context, period_nsec, nullptr,
88
- rcl_get_default_allocator(), /*autostart=*/true),
89
- rcl_get_error_string().str);
86
+ {
87
+ rcl_ret_t ret = rcl_timer_init2(timer, clock, context, period_nsec, nullptr,
88
+ rcl_get_default_allocator(),
89
+ /*autostart=*/true);
90
+ if (RCL_RET_OK != ret) {
91
+ std::string error_msg = rcl_get_error_string().str;
92
+ rcl_reset_error();
93
+ free(timer);
94
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
95
+ return env.Undefined();
96
+ }
97
+ }
90
98
  #else
91
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
92
- rcl_timer_init(timer, clock, context, period_nsec,
93
- nullptr, rcl_get_default_allocator()),
94
- rcl_get_error_string().str);
99
+ {
100
+ rcl_ret_t ret = rcl_timer_init(timer, clock, context, period_nsec, nullptr,
101
+ rcl_get_default_allocator());
102
+ if (RCL_RET_OK != ret) {
103
+ std::string error_msg = rcl_get_error_string().str;
104
+ rcl_reset_error();
105
+ free(timer);
106
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
107
+ return env.Undefined();
108
+ }
109
+ }
95
110
  #endif
96
111
 
97
112
  auto js_obj =
@@ -15,9 +15,12 @@
15
15
  #include "rcl_type_description_service_bindings.h"
16
16
 
17
17
  #include <napi.h>
18
+ #include <rcl/error_handling.h>
18
19
  #include <rcl/rcl.h>
19
20
  #include <rmw/types.h>
20
21
 
22
+ #include <string>
23
+
21
24
  #include "rcl_handle.h"
22
25
 
23
26
  namespace rclnodejs {
@@ -31,8 +34,13 @@ Napi::Value InitTypeDescriptionService(const Napi::CallbackInfo& info) {
31
34
  *service = rcl_get_zero_initialized_service();
32
35
  rcl_ret_t ret = rcl_node_type_description_service_init(service, node);
33
36
  if (RCL_RET_OK != ret) {
34
- Napi::Error::New(env, "Failed to initialize type description service")
37
+ std::string error_msg = rcl_get_error_string().str;
38
+ rcl_reset_error();
39
+ free(service);
40
+ Napi::Error::New(
41
+ env, "Failed to initialize type description service: " + error_msg)
35
42
  .ThrowAsJavaScriptException();
43
+ return env.Undefined();
36
44
  }
37
45
 
38
46
  auto service_handle =
@@ -21,10 +21,10 @@
21
21
 
22
22
  #include <cstdio>
23
23
  #include <memory>
24
- #include <rcpputils/scope_exit.hpp>
25
- // NOLINTNEXTLINE
26
24
  #include <string>
27
25
 
26
+ #include <rcpputils/scope_exit.hpp>
27
+
28
28
  namespace {
29
29
 
30
30
  const rmw_qos_profile_t* GetQoSProfileFromString(const std::string& profile) {
@@ -0,0 +1,5 @@
1
+ .PHONY: docs
2
+
3
+ docs:
4
+ npx jsdoc --package ../../package.json ../../index.js ../../lib/*.js ../../lib/action/*.js -t . -d ../../docs
5
+ node ./build-index.js
@@ -0,0 +1,96 @@
1
+ # JSDoc Workflow
2
+
3
+ This directory contains the custom JSDoc template, the landing-page generator,
4
+ and the staging script used to prepare the docs content that is published to the
5
+ `gh-pages` branch.
6
+
7
+ ## Commands
8
+
9
+ ### `npm run docs`
10
+
11
+ Build local docs for the current workspace version.
12
+
13
+ Output:
14
+
15
+ - `docs/<current-version>/`
16
+ - `docs/index.html`
17
+
18
+ Use this to verify the docs for the version currently declared in
19
+ `package.json`.
20
+
21
+ ### `npm run docs:gh-pages`
22
+
23
+ Stage the publishable docs tree under `build/gh-pages-docs/`.
24
+
25
+ Behavior:
26
+
27
+ - reads the currently published version set from `origin/gh-pages`
28
+ - preserves that published history
29
+ - regenerates docs for the current workspace version
30
+ - rebuilds the staged landing page index
31
+
32
+ This is the normal command to use for a new release.
33
+
34
+ If you delete `build/` and rerun `npm run docs:gh-pages`, the staged tree will
35
+ still contain all currently published versions. That command recreates
36
+ `build/gh-pages-docs/` by copying the published docs snapshot from
37
+ `origin/gh-pages`, then regenerating only the current workspace version.
38
+
39
+ ### `npm run docs:gh-pages:full`
40
+
41
+ Fully rebuild the currently published docs history under
42
+ `build/gh-pages-docs/`.
43
+
44
+ Behavior:
45
+
46
+ - reads the published version set from `origin/gh-pages`
47
+ - rebuilds only those published versions from tags
48
+ - regenerates docs for the current workspace version
49
+ - rebuilds the staged landing page index
50
+
51
+ This does **not** rebuild docs for every historical `rclnodejs` tag. It only
52
+ rebuilds the subset that is actually published online.
53
+
54
+ ## New Release Example
55
+
56
+ For a new release such as `1.9.0`:
57
+
58
+ 1. Update `package.json` to `1.9.0`.
59
+ 2. Run `npm run docs`.
60
+ 3. Verify the local output in `docs/1.9.0/` and `docs/index.html`.
61
+ 4. Run `npm run docs:gh-pages`.
62
+ 5. Verify the staged output in:
63
+ - `build/gh-pages-docs/docs/1.9.0/`
64
+ - `build/gh-pages-docs/docs/index.html`
65
+ - `build/gh-pages-docs/.nojekyll`
66
+ 6. Publish the contents of `build/gh-pages-docs/` to the `gh-pages` branch.
67
+
68
+ ## Manual Landing Page Rebuild
69
+
70
+ If the staged docs tree already exists and you only want to rebuild
71
+ `build/gh-pages-docs/docs/index.html`, run `tools/jsdoc/build-index.js` against
72
+ that docs root and point it at the package metadata for the latest published
73
+ version.
74
+
75
+ Example for published version `1.8.0`:
76
+
77
+ ```bash
78
+ mkdir -p build/gh-pages-docs/.tmp
79
+ git show 1.8.0:package.json > build/gh-pages-docs/.tmp/package-1.8.0.json
80
+
81
+ export RCLNODEJS_DOCS_ROOT="$PWD/build/gh-pages-docs/docs"
82
+ export RCLNODEJS_DOCS_INDEX_PATH="$PWD/build/gh-pages-docs/docs/index.html"
83
+ export RCLNODEJS_LOCAL_INDEX_PATH=''
84
+ export RCLNODEJS_PACKAGE_JSON_PATH="$PWD/build/gh-pages-docs/.tmp/package-1.8.0.json"
85
+
86
+ node tools/jsdoc/build-index.js
87
+ rm -rf build/gh-pages-docs/.tmp
88
+ ```
89
+
90
+ ## Notes
91
+
92
+ - The staged publish output keeps shared assets in `build/gh-pages-docs/docs/_static/`.
93
+ - `.nojekyll` must remain in the staged output because the published docs tree
94
+ uses an underscore-prefixed directory.
95
+ - The live docs index is the source of truth for which versions should remain
96
+ published.