13 if (cb_info.Length() > 0) {
14 if (cb_info[0].IsString()) {
15 return cb_info[0].As<Napi::String>().Utf8Value();
17 if (cb_info[0].IsObject()) {
18 auto err_obj = cb_info[0].As<Napi::Object>();
19 auto msg = err_obj.Get(
"message");
21 return msg.As<Napi::String>().Utf8Value();
25 return "Unknown error from TypeScript";
32 return Napi::Function::New(
34 [cb_results](
const Napi::CallbackInfo& cb_info) -> Napi::Value {
35 Napi::Env env = cb_info.Env();
38 if (cb_info.Length() > 0 && !cb_info[0].IsUndefined() && !cb_info[0].IsNull()) {
40 if (cb_info[0].IsBuffer()) {
41 auto buffer = cb_info[0].As<Napi::Buffer<uint8_t>>();
42 std::vector<uint8_t> vec(buffer.Data(), buffer.Data() + buffer.Length());
43 cb_results->result_promise.set_value(std::move(vec));
45 cb_results->error_message =
"Callback returned non-Buffer value";
46 cb_results->result_promise.set_value(std::nullopt);
52 }
catch (
const std::exception& e) {
53 cb_results->error_message = std::string(
"Exception in resolve handler: ") + e.what();
56 return env.Undefined();
64 return Napi::Function::New(
66 [cb_results](
const Napi::CallbackInfo& cb_info) -> Napi::Value {
67 Napi::Env env = cb_info.Env();
70 if (cb_info.Length() > 0 && !cb_info[0].IsUndefined() && !cb_info[0].IsNull()) {
72 if (cb_info[0].IsString()) {
73 std::string name = cb_info[0].As<Napi::String>().Utf8Value();
74 std::vector<uint8_t> vec(name.begin(), name.end());
75 cb_results->result_promise.set_value(std::move(vec));
77 cb_results->error_message =
"Callback returned non-string value";
78 cb_results->result_promise.set_value(std::nullopt);
84 }
catch (
const std::exception& e) {
85 cb_results->error_message = std::string(
"Exception in resolve handler: ") + e.what();
88 return env.Undefined();
96 return Napi::Function::New(
98 [cb_results](
const Napi::CallbackInfo& cb_info) -> Napi::Value {
100 return cb_info.Env().Undefined();
108 return Napi::Function::New(
110 [cb_results](
const Napi::CallbackInfo& cb_info) -> Napi::Value {
113 return cb_info.Env().Undefined();
120 auto then_prop = promise.Get(
"then");
121 if (!then_prop.IsFunction()) {
122 throw std::runtime_error(
"Promise does not have .then() method");
125 auto then_fn = then_prop.As<Napi::Function>();
126 then_fn.Call(promise, { resolve_handler, reject_handler });
140 msgpack::object_handle obj_handle = msgpack::unpack(
reinterpret_cast<const char*
>(
data.data()),
data.size());
141 msgpack::object obj = obj_handle.get();
144 }
catch (
const std::exception& e) {
145 throw std::runtime_error(std::string(
"Failed to deserialize ") + type_name +
": " + e.what());
150 const Napi::ThreadSafeFunction& callback,
151 const std::string& operation_name,
153 std::chrono::seconds timeout)
159 auto future = callback_data->result_promise.get_future();
163 auto status = callback.BlockingCall(
165 [call_js_function, callback_data](Napi::Env env, Napi::Function js_callback,
CallbackResults* ) {
169 call_js_function(env, js_callback, callback_data);
171 } catch (
const std::exception& e) {
172 callback_data->error_message = std::string(
"Exception calling TypeScript: ") + e.what();
177 if (status != napi_ok) {
178 throw std::runtime_error(
"Failed to invoke TypeScript callback for " + operation_name);
183 auto wait_status = future.wait_for(timeout);
184 if (wait_status == std::future_status::timeout) {
185 throw std::runtime_error(
"Timeout waiting for TypeScript callback for " + operation_name);
189 auto result_data = future.get();
192 if (!callback_data->error_message.empty()) {
193 throw std::runtime_error(
"Error from TypeScript callback: " + callback_data->error_message);
200 const std::string& input_str,
201 const std::string& operation_name)
207 auto js_input = Napi::String::New(env, input_str);
208 auto js_result = js_callback.Call({ js_input });
210 if (!js_result.IsPromise()) {
211 cb_results->error_message =
"TypeScript callback did not return a Promise";
216 auto promise = js_result.As<Napi::Promise>();
225 const std::string& input_str1,
226 const std::string& input_str2,
227 const std::string& operation_name)
234 auto js_input1 = Napi::String::New(env, input_str1);
235 auto js_input2 = Napi::String::New(env, input_str2);
236 auto js_result = js_callback.Call({ js_input1, js_input2 });
238 if (!js_result.IsPromise()) {
239 cb_results->error_message =
"TypeScript callback did not return a Promise";
244 auto promise = js_result.As<Napi::Promise>();
253 std::vector<uint8_t> buffer_data,
254 const std::string& operation_name)
261 auto js_buffer = Napi::Buffer<uint8_t>::Copy(env, buffer_data.data(), buffer_data.size());
262 auto js_result = js_callback.Call({ js_buffer });
264 if (!js_result.IsPromise()) {
265 cb_results->error_message =
"TypeScript callback did not return a Promise";
270 auto promise = js_result.As<Napi::Promise>();
284 const std::string& type_name);
286 const std::string& type_name);
const std::vector< MemoryValue > data
uint8_t buffer[RANDOM_BUFFER_SIZE]
std::vector< uint8_t > serialize_to_msgpack(const T &data)
Serializes data to msgpack format.
void attach_promise_handlers(Napi::Promise promise, Napi::Function resolve_handler, Napi::Function reject_handler)
Attaches resolve and reject handlers to a promise.
T deserialize_from_msgpack(const std::vector< uint8_t > &data, const std::string &type_name)
Deserializes msgpack data to a specific type.
Napi::Function create_reject_handler(Napi::Env env, std::shared_ptr< CallbackResults > cb_results)
Creates a reject handler for promises.
Napi::Function create_void_resolve_handler(Napi::Env env, std::shared_ptr< CallbackResults > cb_results)
Creates a resolve handler for promises that return void.
std::optional< std::vector< uint8_t > > invoke_single_string_callback(const Napi::ThreadSafeFunction &callback, const std::string &input_str, const std::string &operation_name)
Helper for callbacks that take a single string argument and return Buffer | undefined.
std::optional< std::vector< uint8_t > > invoke_ts_callback_with_promise(const Napi::ThreadSafeFunction &callback, const std::string &operation_name, std::function< void(Napi::Env, Napi::Function, std::shared_ptr< CallbackResults >)> call_js_function, std::chrono::seconds timeout)
Generic callback invoker that handles the full BlockingCall pattern.
Napi::Function create_buffer_resolve_handler(Napi::Env env, std::shared_ptr< CallbackResults > cb_results)
Creates a resolve handler for promises that return Buffer | undefined.
std::optional< std::vector< uint8_t > > invoke_double_string_callback(const Napi::ThreadSafeFunction &callback, const std::string &input_str1, const std::string &input_str2, const std::string &operation_name)
Helper for callbacks that take two string arguments and return string | undefined.
std::string extract_error_from_napi_value(const Napi::CallbackInfo &cb_info)
Extracts error message from a Napi value (string or Error object)
Napi::Function create_string_resolve_handler(Napi::Env env, std::shared_ptr< CallbackResults > cb_results)
Creates a resolve handler for promises that return string | undefined.
void invoke_buffer_void_callback(const Napi::ThreadSafeFunction &callback, std::vector< uint8_t > buffer_data, const std::string &operation_name)
Helper for callbacks that take a buffer and return void.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Helper struct to pass data between C++ worker thread and JS main thread.