@temporalio/core-bridge 1.11.8 → 1.12.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 (205) hide show
  1. package/Cargo.lock +219 -193
  2. package/Cargo.toml +27 -8
  3. package/README.md +5 -0
  4. package/index.js +72 -12
  5. package/lib/errors.d.ts +25 -0
  6. package/lib/errors.js +76 -1
  7. package/lib/errors.js.map +1 -1
  8. package/lib/index.d.ts +11 -478
  9. package/lib/index.js +28 -5
  10. package/lib/index.js.map +1 -1
  11. package/lib/native.d.ts +330 -0
  12. package/lib/{worker-tuner.js → native.js} +1 -1
  13. package/lib/native.js.map +1 -0
  14. package/package.json +7 -3
  15. package/releases/aarch64-apple-darwin/index.node +0 -0
  16. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  17. package/releases/x86_64-apple-darwin/index.node +0 -0
  18. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  19. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  20. package/sdk-core/.cargo/config.toml +8 -2
  21. package/sdk-core/.cargo/multi-worker-manual-test +15 -0
  22. package/sdk-core/.github/workflows/per-pr.yml +40 -11
  23. package/sdk-core/AGENTS.md +73 -0
  24. package/sdk-core/ARCHITECTURE.md +71 -23
  25. package/sdk-core/Cargo.toml +1 -1
  26. package/sdk-core/README.md +4 -4
  27. package/sdk-core/arch_docs/workflow_task_chunking.md +51 -0
  28. package/sdk-core/client/Cargo.toml +1 -1
  29. package/sdk-core/client/src/lib.rs +49 -13
  30. package/sdk-core/client/src/metrics.rs +15 -16
  31. package/sdk-core/client/src/proxy.rs +2 -2
  32. package/sdk-core/client/src/raw.rs +54 -8
  33. package/sdk-core/client/src/retry.rs +109 -13
  34. package/sdk-core/client/src/worker_registry/mod.rs +4 -4
  35. package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
  36. package/sdk-core/core/Cargo.toml +28 -8
  37. package/sdk-core/core/src/abstractions.rs +62 -10
  38. package/sdk-core/core/src/core_tests/activity_tasks.rs +180 -8
  39. package/sdk-core/core/src/core_tests/mod.rs +4 -4
  40. package/sdk-core/core/src/core_tests/queries.rs +18 -4
  41. package/sdk-core/core/src/core_tests/workers.rs +3 -3
  42. package/sdk-core/core/src/core_tests/workflow_tasks.rs +191 -25
  43. package/sdk-core/core/src/ephemeral_server/mod.rs +10 -3
  44. package/sdk-core/core/src/internal_flags.rs +14 -14
  45. package/sdk-core/core/src/lib.rs +5 -2
  46. package/sdk-core/core/src/pollers/mod.rs +1 -1
  47. package/sdk-core/core/src/pollers/poll_buffer.rs +495 -164
  48. package/sdk-core/core/src/protosext/mod.rs +3 -3
  49. package/sdk-core/core/src/replay/mod.rs +3 -3
  50. package/sdk-core/core/src/telemetry/metrics.rs +13 -4
  51. package/sdk-core/core/src/telemetry/mod.rs +72 -70
  52. package/sdk-core/core/src/telemetry/otel.rs +51 -54
  53. package/sdk-core/core/src/test_help/mod.rs +9 -3
  54. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +31 -11
  55. package/sdk-core/core/src/worker/activities/local_activities.rs +35 -28
  56. package/sdk-core/core/src/worker/activities.rs +58 -30
  57. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  58. package/sdk-core/core/src/worker/client.rs +155 -53
  59. package/sdk-core/core/src/worker/mod.rs +103 -95
  60. package/sdk-core/core/src/worker/nexus.rs +100 -73
  61. package/sdk-core/core/src/worker/tuner/resource_based.rs +14 -6
  62. package/sdk-core/core/src/worker/tuner.rs +4 -13
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +47 -51
  64. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -4
  65. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +127 -32
  66. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +1 -2
  67. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +1 -1
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +55 -42
  69. package/sdk-core/core/src/worker/workflow/managed_run.rs +45 -35
  70. package/sdk-core/core/src/worker/workflow/mod.rs +200 -97
  71. package/sdk-core/core/src/worker/workflow/wft_poller.rs +175 -4
  72. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +38 -36
  73. package/sdk-core/core-api/Cargo.toml +8 -0
  74. package/sdk-core/core-api/src/envconfig.rs +1544 -0
  75. package/sdk-core/core-api/src/lib.rs +2 -0
  76. package/sdk-core/core-api/src/telemetry/metrics.rs +8 -0
  77. package/sdk-core/core-api/src/telemetry.rs +36 -3
  78. package/sdk-core/core-api/src/worker.rs +301 -75
  79. package/sdk-core/docker/docker-compose-telem.yaml +1 -0
  80. package/sdk-core/etc/prometheus.yaml +6 -2
  81. package/sdk-core/histories/long_local_activity_with_update-0_history.bin +0 -0
  82. package/sdk-core/histories/long_local_activity_with_update-1_history.bin +0 -0
  83. package/sdk-core/histories/long_local_activity_with_update-2_history.bin +0 -0
  84. package/sdk-core/histories/long_local_activity_with_update-3_history.bin +0 -0
  85. package/sdk-core/sdk/src/activity_context.rs +5 -0
  86. package/sdk-core/sdk/src/interceptors.rs +73 -3
  87. package/sdk-core/sdk/src/lib.rs +15 -16
  88. package/sdk-core/sdk/src/workflow_context/options.rs +10 -0
  89. package/sdk-core/sdk/src/workflow_context.rs +48 -29
  90. package/sdk-core/sdk/src/workflow_future.rs +5 -6
  91. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/.github/workflows/push-to-buf.yml +20 -0
  92. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/CODEOWNERS +6 -0
  93. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +17 -6
  94. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -1
  95. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.lock +7 -2
  96. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +2 -0
  97. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +78 -0
  98. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +29 -0
  99. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +74 -32
  100. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +45 -15
  101. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/nexus/v1/message.proto +7 -1
  102. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +3 -3
  103. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +3 -3
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/LICENSE +1 -1
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +2 -0
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +1103 -88
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +1233 -151
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/activity/v1/message.proto +0 -22
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +19 -24
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +0 -22
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +12 -22
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +45 -45
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -22
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/command_type.proto +0 -22
  115. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +15 -22
  116. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +0 -22
  117. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +4 -22
  118. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +0 -22
  119. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/namespace.proto +0 -22
  120. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/nexus.proto +0 -20
  121. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/query.proto +0 -22
  122. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +0 -22
  123. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/schedule.proto +0 -22
  124. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -22
  125. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +0 -22
  126. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -22
  127. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +0 -22
  128. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto +0 -22
  129. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -22
  130. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/filter/v1/message.proto +0 -22
  131. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +75 -49
  132. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +0 -22
  133. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +0 -20
  134. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +0 -22
  135. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +0 -22
  136. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/protocol/v1/message.proto +0 -22
  137. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/query/v1/message.proto +0 -22
  138. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/replication/v1/message.proto +0 -22
  139. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/rules/v1/message.proto +90 -0
  140. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +0 -22
  141. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/enhanced_stack_trace.proto +0 -22
  142. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +0 -22
  143. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/user_metadata.proto +0 -22
  144. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +0 -22
  145. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +17 -38
  146. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/update/v1/message.proto +0 -22
  147. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/version/v1/message.proto +0 -22
  148. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +151 -44
  149. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -65
  150. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +69 -28
  151. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/activity_task/activity_task.proto +18 -0
  152. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/common/common.proto +5 -0
  153. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/nexus/nexus.proto +16 -1
  154. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +21 -15
  155. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +3 -0
  156. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -0
  157. package/sdk-core/sdk-core-protos/src/lib.rs +60 -16
  158. package/sdk-core/test-utils/src/lib.rs +157 -39
  159. package/sdk-core/tests/cloud_tests.rs +86 -0
  160. package/sdk-core/tests/fuzzy_workflow.rs +23 -26
  161. package/sdk-core/tests/global_metric_tests.rs +116 -0
  162. package/sdk-core/tests/heavy_tests.rs +127 -7
  163. package/sdk-core/tests/integ_tests/client_tests.rs +2 -8
  164. package/sdk-core/tests/integ_tests/metrics_tests.rs +100 -106
  165. package/sdk-core/tests/integ_tests/polling_tests.rs +94 -8
  166. package/sdk-core/tests/integ_tests/update_tests.rs +75 -6
  167. package/sdk-core/tests/integ_tests/worker_tests.rs +54 -5
  168. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +240 -0
  169. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +41 -3
  170. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +168 -8
  171. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +285 -15
  172. package/sdk-core/tests/integ_tests/workflow_tests/priority.rs +12 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -2
  174. package/sdk-core/tests/integ_tests/workflow_tests.rs +124 -74
  175. package/sdk-core/tests/main.rs +3 -51
  176. package/sdk-core/tests/manual_tests.rs +430 -0
  177. package/sdk-core/tests/runner.rs +28 -2
  178. package/src/client.rs +565 -0
  179. package/src/helpers/abort_controller.rs +204 -0
  180. package/src/helpers/callbacks.rs +299 -0
  181. package/src/helpers/errors.rs +302 -0
  182. package/src/helpers/future.rs +44 -0
  183. package/src/helpers/handles.rs +191 -0
  184. package/src/helpers/inspect.rs +18 -0
  185. package/src/helpers/json_string.rs +58 -0
  186. package/src/helpers/mod.rs +20 -0
  187. package/src/helpers/properties.rs +71 -0
  188. package/src/helpers/try_from_js.rs +213 -0
  189. package/src/helpers/try_into_js.rs +129 -0
  190. package/src/lib.rs +28 -40
  191. package/src/logs.rs +111 -0
  192. package/src/metrics.rs +325 -0
  193. package/src/runtime.rs +409 -498
  194. package/src/testing.rs +315 -57
  195. package/src/worker.rs +907 -378
  196. package/ts/errors.ts +57 -0
  197. package/ts/index.ts +10 -596
  198. package/ts/native.ts +496 -0
  199. package/lib/worker-tuner.d.ts +0 -167
  200. package/lib/worker-tuner.js.map +0 -1
  201. package/src/conversions/slot_supplier_bridge.rs +0 -291
  202. package/src/conversions.rs +0 -618
  203. package/src/errors.rs +0 -38
  204. package/src/helpers.rs +0 -297
  205. package/ts/worker-tuner.ts +0 -193
@@ -0,0 +1,71 @@
1
+ use neon::prelude::*;
2
+
3
+ use super::{AppendFieldContext as _, BridgeError, BridgeResult, TryFromJs, TryIntoJs};
4
+
5
+ /// Extension trait for `JsObject`.
6
+ pub trait ObjectExt: Object {
7
+ /// Get a property from a JS Object, converting it to a Rust value using `TryFromJs`.
8
+ ///
9
+ /// Type errors will be reported with `field` set to the name of the property being
10
+ /// accessed; it is expected that caller will prepend any additional path components
11
+ /// that led to this object, to help identify the object that failed.
12
+ fn get_property_into<'cx, C: Context<'cx>, T: TryFromJs>(
13
+ &self,
14
+ cx: &mut C,
15
+ key: &str,
16
+ ) -> BridgeResult<T> {
17
+ let value = self.get_value(cx, key)?;
18
+ if value.is_a::<JsUndefined, _>(cx) {
19
+ return Err(BridgeError::TypeError {
20
+ message: format!("Missing property '{key}'"),
21
+ field: Some(key.to_string()),
22
+ });
23
+ }
24
+ <T>::try_from_js(cx, value).field(key)
25
+ }
26
+
27
+ /// Set a property on a JS Object, converting it from a Rust value using `TryIntoJs`.
28
+ fn set_property_from<'cx, C: Context<'cx>, T: TryIntoJs>(
29
+ &self,
30
+ cx: &mut C,
31
+ key: &str,
32
+ value: T,
33
+ ) -> NeonResult<()> {
34
+ let key = cx.string(key);
35
+ let value = value.try_into_js(cx)?;
36
+ self.set(cx, key, value)?;
37
+ Ok(())
38
+ }
39
+
40
+ /// Set a property on a JS Object, converting it from a Rust value using `TryIntoJs`.
41
+ fn set_property<'cx, C: Context<'cx>, T: Value>(
42
+ &self,
43
+ cx: &mut C,
44
+ key: &str,
45
+ value: Handle<'cx, T>,
46
+ ) -> NeonResult<()> {
47
+ let key = cx.string(key);
48
+ self.set(cx, key, value)?;
49
+ Ok(())
50
+ }
51
+ }
52
+
53
+ impl ObjectExt for JsObject {}
54
+ impl ObjectExt for JsError {}
55
+
56
+ /// Extension trait for `FunctionContext` that adds a method to get an argument and
57
+ /// convert it to a value using `TryFromJs`.
58
+ ///
59
+ /// Type errors will be reported with field name `args[index]`; it is expected that
60
+ /// caller will prepend the function name to the error message's `field` to help identify
61
+ /// the function that failed.
62
+ pub trait FunctionContextExt {
63
+ fn argument_into<T: TryFromJs>(&mut self, index: usize) -> BridgeResult<T>;
64
+ }
65
+
66
+ impl FunctionContextExt for FunctionContext<'_> {
67
+ fn argument_into<T: TryFromJs>(&mut self, index: usize) -> BridgeResult<T> {
68
+ let value = self.argument::<JsValue>(index)?;
69
+ <T>::try_from_js(self, value).field(format!("args[{index}]").as_str())
70
+ }
71
+ }
@@ -0,0 +1,213 @@
1
+ use std::{collections::HashMap, net::SocketAddr, time::Duration};
2
+
3
+ use neon::{
4
+ handle::Handle,
5
+ object::Object,
6
+ prelude::Context,
7
+ types::{
8
+ JsArray, JsBoolean, JsBuffer, JsNull, JsNumber, JsObject, JsString, JsUndefined, JsValue,
9
+ Value, buffer::TypedArray,
10
+ },
11
+ };
12
+ use temporal_sdk_core::Url;
13
+
14
+ use super::{BridgeError, BridgeResult};
15
+
16
+ /// Trait for Rust types that can be created from JavaScript values, possibly throwing an error.
17
+ pub trait TryFromJs: Sized {
18
+ fn try_from_js<'cx, 'b>(
19
+ cx: &mut impl Context<'cx>,
20
+ js_value: Handle<'b, JsValue>,
21
+ ) -> BridgeResult<Self>;
22
+ }
23
+
24
+ // TryFromJs implementations for primitives and other basic types //////////////////////////////////
25
+
26
+ impl TryFromJs for () {
27
+ fn try_from_js<'cx, 'b>(
28
+ cx: &mut impl Context<'cx>,
29
+ js_value: Handle<'b, JsValue>,
30
+ ) -> BridgeResult<Self> {
31
+ // Make sure we are not getting something where we expect nothing
32
+ let _ = js_value.downcast::<JsUndefined, _>(cx)?;
33
+ Ok(())
34
+ }
35
+ }
36
+
37
+ impl TryFromJs for String {
38
+ fn try_from_js<'cx, 'b>(
39
+ cx: &mut impl Context<'cx>,
40
+ js_value: Handle<'b, JsValue>,
41
+ ) -> BridgeResult<Self> {
42
+ Ok(js_value.downcast::<JsString, _>(cx)?.value(cx))
43
+ }
44
+ }
45
+
46
+ impl TryFromJs for bool {
47
+ fn try_from_js<'cx, 'b>(
48
+ cx: &mut impl Context<'cx>,
49
+ js_value: Handle<'b, JsValue>,
50
+ ) -> BridgeResult<Self> {
51
+ Ok(js_value.downcast::<JsBoolean, _>(cx)?.value(cx))
52
+ }
53
+ }
54
+
55
+ impl TryFromJs for u16 {
56
+ fn try_from_js<'cx, 'b>(
57
+ cx: &mut impl Context<'cx>,
58
+ js_value: Handle<'b, JsValue>,
59
+ ) -> BridgeResult<Self> {
60
+ #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
61
+ Ok(js_value.downcast::<JsNumber, _>(cx)?.value(cx) as Self)
62
+ }
63
+ }
64
+
65
+ #[allow(clippy::cast_possible_truncation)]
66
+ impl TryFromJs for i32 {
67
+ fn try_from_js<'cx, 'b>(
68
+ cx: &mut impl Context<'cx>,
69
+ js_value: Handle<'b, JsValue>,
70
+ ) -> BridgeResult<Self> {
71
+ Ok(js_value.downcast::<JsNumber, _>(cx)?.value(cx) as Self)
72
+ }
73
+ }
74
+
75
+ #[allow(clippy::cast_possible_truncation)]
76
+ impl TryFromJs for f32 {
77
+ fn try_from_js<'cx, 'b>(
78
+ cx: &mut impl Context<'cx>,
79
+ js_value: Handle<'b, JsValue>,
80
+ ) -> BridgeResult<Self> {
81
+ Ok(js_value.downcast::<JsNumber, _>(cx)?.value(cx) as Self)
82
+ }
83
+ }
84
+
85
+ #[allow(clippy::cast_possible_truncation)]
86
+ impl TryFromJs for u64 {
87
+ fn try_from_js<'cx, 'b>(
88
+ cx: &mut impl Context<'cx>,
89
+ js_value: Handle<'b, JsValue>,
90
+ ) -> BridgeResult<Self> {
91
+ #[allow(clippy::cast_sign_loss)]
92
+ Ok(js_value.downcast::<JsNumber, _>(cx)?.value(cx) as Self)
93
+ }
94
+ }
95
+
96
+ impl TryFromJs for f64 {
97
+ fn try_from_js<'cx, 'b>(
98
+ cx: &mut impl Context<'cx>,
99
+ js_value: Handle<'b, JsValue>,
100
+ ) -> BridgeResult<Self> {
101
+ Ok(js_value.downcast::<JsNumber, _>(cx)?.value(cx))
102
+ }
103
+ }
104
+
105
+ impl TryFromJs for usize {
106
+ fn try_from_js<'cx, 'b>(
107
+ cx: &mut impl Context<'cx>,
108
+ js_value: Handle<'b, JsValue>,
109
+ ) -> BridgeResult<Self> {
110
+ #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
111
+ Ok(js_value.downcast::<JsNumber, _>(cx)?.value(cx) as Self)
112
+ }
113
+ }
114
+
115
+ impl TryFromJs for Duration {
116
+ fn try_from_js<'cx, 'b>(
117
+ cx: &mut impl Context<'cx>,
118
+ js_value: Handle<'b, JsValue>,
119
+ ) -> BridgeResult<Self> {
120
+ #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
121
+ Ok(Self::from_millis(
122
+ js_value.downcast::<JsNumber, _>(cx)?.value(cx) as u64,
123
+ ))
124
+ }
125
+ }
126
+
127
+ impl<T: TryFromJs> TryFromJs for Option<T> {
128
+ fn try_from_js<'cx, 'b>(
129
+ cx: &mut impl Context<'cx>,
130
+ js_value: Handle<'b, JsValue>,
131
+ ) -> BridgeResult<Self> {
132
+ if js_value.is_a::<JsNull, _>(cx) {
133
+ Ok(None)
134
+ } else {
135
+ Ok(Some(T::try_from_js(cx, js_value)?))
136
+ }
137
+ }
138
+ }
139
+
140
+ impl TryFromJs for Vec<u8> {
141
+ fn try_from_js<'cx, 'b>(
142
+ cx: &mut impl Context<'cx>,
143
+ js_value: Handle<'b, JsValue>,
144
+ ) -> BridgeResult<Self> {
145
+ Ok(js_value.downcast::<JsBuffer, _>(cx)?.as_slice(cx).to_vec())
146
+ }
147
+ }
148
+
149
+ impl<T: TryFromJs> TryFromJs for Vec<T> {
150
+ fn try_from_js<'cx, 'b>(
151
+ cx: &mut impl Context<'cx>,
152
+ js_value: Handle<'b, JsValue>,
153
+ ) -> BridgeResult<Self> {
154
+ let array = js_value.downcast::<JsArray, _>(cx)?;
155
+ let len = array.len(cx);
156
+ let mut result = Self::with_capacity(len as usize);
157
+
158
+ for i in 0..len {
159
+ let value = array.get_value(cx, i)?;
160
+ result.push(T::try_from_js(cx, value)?);
161
+ }
162
+ Ok(result)
163
+ }
164
+ }
165
+
166
+ #[allow(clippy::implicit_hasher)]
167
+ impl<T: TryFromJs> TryFromJs for HashMap<String, T> {
168
+ fn try_from_js<'cx, 'b>(
169
+ cx: &mut impl Context<'cx>,
170
+ js_value: Handle<'b, JsValue>,
171
+ ) -> BridgeResult<Self> {
172
+ let obj = js_value.downcast::<JsObject, _>(cx)?;
173
+ let props = obj.get_own_property_names(cx)?.to_vec(cx)?;
174
+
175
+ let mut map = Self::new();
176
+ for key_handle in props {
177
+ let key = key_handle.to_string(cx)?.value(cx);
178
+ let value = obj.get_value(cx, key_handle)?;
179
+ map.insert(key, T::try_from_js(cx, value)?);
180
+ }
181
+ Ok(map)
182
+ }
183
+ }
184
+
185
+ impl TryFromJs for SocketAddr {
186
+ fn try_from_js<'cx, 'b>(
187
+ cx: &mut impl Context<'cx>,
188
+ js_value: Handle<'b, JsValue>,
189
+ ) -> BridgeResult<Self> {
190
+ let addr = js_value.downcast::<JsString, _>(cx)?;
191
+ addr.value(cx)
192
+ .parse::<Self>()
193
+ .map_err(|e| BridgeError::TypeError {
194
+ field: None,
195
+ message: e.to_string(),
196
+ })
197
+ }
198
+ }
199
+
200
+ impl TryFromJs for Url {
201
+ fn try_from_js<'cx, 'b>(
202
+ cx: &mut impl Context<'cx>,
203
+ js_value: Handle<'b, JsValue>,
204
+ ) -> BridgeResult<Self> {
205
+ let url = js_value.downcast::<JsString, _>(cx)?;
206
+ url.value(cx)
207
+ .parse::<Self>()
208
+ .map_err(|e| BridgeError::TypeError {
209
+ field: None,
210
+ message: e.to_string(),
211
+ })
212
+ }
213
+ }
@@ -0,0 +1,129 @@
1
+ use std::{
2
+ sync::Arc,
3
+ time::{Duration, SystemTime, UNIX_EPOCH},
4
+ };
5
+
6
+ use neon::{
7
+ object::Object,
8
+ prelude::Context,
9
+ result::JsResult,
10
+ types::{
11
+ JsArray, JsBigInt, JsBoolean, JsBuffer, JsNumber, JsString, JsUndefined, JsValue, Value,
12
+ },
13
+ };
14
+
15
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
16
+
17
+ /// Trait for types that can be converted to JavaScript values, possibly throwing an error.
18
+ pub trait TryIntoJs {
19
+ type Output: Value;
20
+ fn try_into_js<'cx>(self, cx: &mut impl Context<'cx>) -> JsResult<'cx, Self::Output>;
21
+ }
22
+
23
+ // TryIntoJs implementations for primitives and other basic types //////////////////////////////////
24
+
25
+ impl TryIntoJs for bool {
26
+ type Output = JsBoolean;
27
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsBoolean> {
28
+ Ok(cx.boolean(self))
29
+ }
30
+ }
31
+
32
+ impl TryIntoJs for u32 {
33
+ type Output = JsNumber;
34
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsNumber> {
35
+ Ok(cx.number(self))
36
+ }
37
+ }
38
+
39
+ impl TryIntoJs for String {
40
+ type Output = JsString;
41
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsString> {
42
+ Ok(cx.string(self.as_str()))
43
+ }
44
+ }
45
+
46
+ impl TryIntoJs for &str {
47
+ type Output = JsString;
48
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsString> {
49
+ Ok(cx.string(self))
50
+ }
51
+ }
52
+
53
+ impl<T: TryIntoJs> TryIntoJs for Vec<T> {
54
+ type Output = JsArray;
55
+
56
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsArray> {
57
+ let array = cx.empty_array();
58
+ for (i, item) in self.into_iter().enumerate() {
59
+ let item = item.try_into_js(cx)?;
60
+ #[allow(clippy::cast_possible_truncation)]
61
+ array.set(cx, i as u32, item)?;
62
+ }
63
+ Ok(array)
64
+ }
65
+ }
66
+
67
+ impl TryIntoJs for Vec<u8> {
68
+ type Output = JsBuffer;
69
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsBuffer> {
70
+ JsBuffer::from_slice(cx, &self)
71
+ }
72
+ }
73
+
74
+ impl TryIntoJs for &[u8] {
75
+ type Output = JsBuffer;
76
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsBuffer> {
77
+ JsBuffer::from_slice(cx, self)
78
+ }
79
+ }
80
+
81
+ impl TryIntoJs for SystemTime {
82
+ type Output = JsBigInt;
83
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsBigInt> {
84
+ let nanos = self
85
+ .duration_since(UNIX_EPOCH)
86
+ .unwrap_or(Duration::ZERO)
87
+ .as_nanos();
88
+ Ok(JsBigInt::from_u128(cx, nanos))
89
+ }
90
+ }
91
+
92
+ impl<T: TryIntoJs> TryIntoJs for Option<T> {
93
+ // Output really is (T::Output | JsNull), hence JsValue
94
+ type Output = JsValue;
95
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsValue> {
96
+ if let Some(value) = self {
97
+ Ok(value.try_into_js(cx)?.upcast())
98
+ } else {
99
+ Ok(cx.null().upcast())
100
+ }
101
+ }
102
+ }
103
+
104
+ impl<T: TryIntoJs + Clone> TryIntoJs for Arc<T> {
105
+ type Output = T::Output;
106
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, T::Output> {
107
+ self.as_ref().clone().try_into_js(cx)
108
+ }
109
+ }
110
+
111
+ impl TryIntoJs for () {
112
+ type Output = JsUndefined;
113
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsUndefined> {
114
+ Ok(cx.undefined())
115
+ }
116
+ }
117
+
118
+ impl<T0: TryIntoJs, T1: TryIntoJs> TryIntoJs for (T0, T1) {
119
+ type Output = JsArray;
120
+ fn try_into_js<'a>(self, cx: &mut impl Context<'a>) -> JsResult<'a, JsArray> {
121
+ let v0 = self.0.try_into_js(cx)?;
122
+ let v1 = self.1.try_into_js(cx)?;
123
+
124
+ let array = cx.empty_array();
125
+ array.set(cx, 0, v0)?;
126
+ array.set(cx, 1, v1)?;
127
+ Ok(array)
128
+ }
129
+ }
package/src/lib.rs CHANGED
@@ -1,47 +1,35 @@
1
- mod conversions;
2
- mod errors;
3
- mod helpers;
1
+ #![warn(
2
+ clippy::pedantic,
3
+ clippy::nursery,
4
+ clippy::cargo,
5
+ clippy::perf,
6
+ clippy::style
7
+ )]
8
+ #![allow(
9
+ clippy::missing_errors_doc,
10
+ clippy::too_long_first_doc_paragraph,
11
+ clippy::option_if_let_else,
12
+ clippy::multiple_crate_versions,
13
+ clippy::significant_drop_tightening
14
+ )]
15
+
16
+ pub mod helpers;
17
+
18
+ mod client;
19
+ mod logs;
20
+ mod metrics;
4
21
  mod runtime;
5
22
  mod testing;
6
23
  mod worker;
7
24
 
8
- use crate::runtime::*;
9
- use crate::worker::*;
10
- use neon::prelude::*;
11
- use testing::*;
12
-
13
25
  #[neon::main]
14
- fn main(mut cx: ModuleContext) -> NeonResult<()> {
15
- cx.export_function("getTimeOfDay", get_time_of_day)?;
16
- cx.export_function("newRuntime", runtime_new)?;
17
- cx.export_function("newClient", client_new)?;
18
- cx.export_function("clientUpdateHeaders", client_update_headers)?;
19
- cx.export_function("clientUpdateApiKey", client_update_api_key)?;
20
- cx.export_function("newWorker", worker_new)?;
21
- cx.export_function("newReplayWorker", replay_worker_new)?;
22
- cx.export_function("pushHistory", push_history)?;
23
- cx.export_function("closeHistoryStream", close_history_stream)?;
24
- cx.export_function("workerInitiateShutdown", worker_initiate_shutdown)?;
25
- cx.export_function("workerFinalizeShutdown", worker_finalize_shutdown)?;
26
- cx.export_function("clientClose", client_close)?;
27
- cx.export_function("runtimeShutdown", runtime_shutdown)?;
28
- cx.export_function("pollLogs", poll_logs)?;
29
- cx.export_function(
30
- "workerPollWorkflowActivation",
31
- worker_poll_workflow_activation,
32
- )?;
33
- cx.export_function("workerPollActivityTask", worker_poll_activity_task)?;
34
- cx.export_function(
35
- "workerCompleteWorkflowActivation",
36
- worker_complete_workflow_activation,
37
- )?;
38
- cx.export_function("workerCompleteActivityTask", worker_complete_activity_task)?;
39
- cx.export_function(
40
- "workerRecordActivityHeartbeat",
41
- worker_record_activity_heartbeat,
42
- )?;
43
- cx.export_function("startEphemeralServer", start_ephemeral_server)?;
44
- cx.export_function("shutdownEphemeralServer", shutdown_ephemeral_server)?;
45
- cx.export_function("getEphemeralServerTarget", get_ephemeral_server_target)?;
26
+ fn main(mut cx: neon::prelude::ModuleContext) -> neon::prelude::NeonResult<()> {
27
+ client::init(&mut cx)?;
28
+ logs::init(&mut cx)?;
29
+ metrics::init(&mut cx)?;
30
+ runtime::init(&mut cx)?;
31
+ testing::init(&mut cx)?;
32
+ worker::init(&mut cx)?;
33
+
46
34
  Ok(())
47
35
  }
package/src/logs.rs ADDED
@@ -0,0 +1,111 @@
1
+ use std::{
2
+ collections::HashMap,
3
+ time::{Duration, SystemTime, UNIX_EPOCH},
4
+ };
5
+
6
+ use neon::prelude::*;
7
+
8
+ use serde::{Serialize, ser::SerializeMap as _};
9
+ use temporal_sdk_core::api::telemetry::CoreLog;
10
+
11
+ use bridge_macros::js_function;
12
+
13
+ use crate::helpers::{BridgeError, BridgeResult, IntoThrow, JsonString, TryIntoJs};
14
+
15
+ pub fn init(cx: &mut neon::prelude::ModuleContext) -> neon::prelude::NeonResult<()> {
16
+ cx.export_function("getTimeOfDay", get_time_of_day)?;
17
+
18
+ Ok(())
19
+ }
20
+
21
+ /// Helper to get the current time in nanosecond resolution. Nano seconds timestamps are
22
+ /// used to precisely sort logs emitted from the Workflow Context, main thread, and Core.
23
+ #[js_function]
24
+ pub fn get_time_of_day() -> BridgeResult<SystemTime> {
25
+ Ok(SystemTime::now())
26
+ }
27
+
28
+ #[derive(Debug, Clone, Serialize)]
29
+ pub struct LogEntry {
30
+ pub target: String,
31
+ pub message: String,
32
+ pub timestamp: String, // u128 as a string - JSON doesn't support u128 numbers
33
+ pub level: String,
34
+
35
+ #[serde(serialize_with = "serialize_map_as_camel_case")]
36
+ pub fields: HashMap<String, serde_json::Value>,
37
+ pub span_contexts: Vec<String>,
38
+ }
39
+
40
+ impl TryFrom<CoreLog> for JsonString<LogEntry> {
41
+ type Error = BridgeError;
42
+
43
+ fn try_from(core_log: CoreLog) -> BridgeResult<Self> {
44
+ let timestamp = core_log
45
+ .timestamp
46
+ .duration_since(UNIX_EPOCH)
47
+ .unwrap_or(Duration::ZERO)
48
+ .as_nanos();
49
+
50
+ Self::try_from_value(LogEntry {
51
+ target: core_log.target,
52
+ message: core_log.message,
53
+ timestamp: timestamp.to_string(),
54
+ level: core_log.level.to_string(),
55
+ fields: core_log.fields,
56
+ span_contexts: core_log.span_contexts,
57
+ })
58
+ }
59
+ }
60
+
61
+ /// Serialize a map, converting keys to camel case.
62
+ fn serialize_map_as_camel_case<S>(
63
+ value: &HashMap<String, serde_json::Value>,
64
+ serializer: S,
65
+ ) -> Result<S::Ok, S::Error>
66
+ where
67
+ S: serde::Serializer,
68
+ {
69
+ let mut map = serializer.serialize_map(Some(value.len()))?;
70
+ for (k, v) in value {
71
+ map.serialize_entry(&snake_to_camel(k), v)?;
72
+ }
73
+ map.end()
74
+ }
75
+
76
+ /// Convert a string from snake case to camel case.
77
+ fn snake_to_camel(input: &str) -> String {
78
+ match input.find('_') {
79
+ None => input.to_string(),
80
+ Some(first) => {
81
+ let mut result = String::with_capacity(input.len());
82
+ if first > 0 {
83
+ result.push_str(&input[..first]);
84
+ }
85
+ let mut capitalize = true;
86
+ for c in input[first + 1..].chars() {
87
+ if c == '_' {
88
+ capitalize = true;
89
+ } else if capitalize {
90
+ result.push(c.to_ascii_uppercase());
91
+ capitalize = false;
92
+ } else {
93
+ result.push(c.to_ascii_lowercase());
94
+ }
95
+ }
96
+ result
97
+ }
98
+ }
99
+ }
100
+
101
+ #[cfg(test)]
102
+ mod tests {
103
+ use super::*;
104
+
105
+ #[test]
106
+ fn snake_to_camel_works() {
107
+ assert_eq!(snake_to_camel("this_is_a_test"), "thisIsATest");
108
+ assert_eq!(snake_to_camel("this___IS_a_TEST"), "thisIsATest");
109
+ assert_eq!(snake_to_camel("éàç_this_is_a_test"), "éàçThisIsATest");
110
+ }
111
+ }