objc-js 0.0.12 → 0.0.13
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.
|
Binary file
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"format": "prettier --write \"**/*.{ts,js,json,md}\"",
|
|
40
40
|
"preinstall-disabled": "npm run build-scripts && npm run make-clangd-config"
|
|
41
41
|
},
|
|
42
|
-
"version": "0.0.
|
|
42
|
+
"version": "0.0.13",
|
|
43
43
|
"description": "Objective-C bridge for Node.js",
|
|
44
44
|
"main": "dist/index.js",
|
|
45
45
|
"dependencies": {
|
|
@@ -57,19 +57,27 @@ void CallJSCallback(Napi::Env env, Napi::Function jsCallback,
|
|
|
57
57
|
jsArgs.push_back(ExtractInvocationArgumentToJS(env, invocation, i, argType[0]));
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
NSLog(@"[DEBUG] About to call JS callback for %s with %zu arguments",
|
|
61
|
+
data->selectorName.c_str(), jsArgs.size());
|
|
62
|
+
|
|
60
63
|
// Call the JavaScript callback
|
|
61
64
|
try {
|
|
62
65
|
Napi::Value result = jsCallback.Call(jsArgs);
|
|
63
66
|
|
|
67
|
+
NSLog(@"[DEBUG] JS callback for %s returned, result type: %d",
|
|
68
|
+
data->selectorName.c_str(), result.Type());
|
|
69
|
+
|
|
64
70
|
// Handle return value if the method expects one
|
|
65
71
|
const char *returnType = [sig methodReturnType];
|
|
66
72
|
SimplifiedTypeEncoding retType(returnType);
|
|
67
73
|
|
|
68
74
|
if (retType[0] != 'v') { // Not void
|
|
69
|
-
NSLog(@"Setting return value for %s, return type: %c",
|
|
70
|
-
data->selectorName.c_str(), retType[0]
|
|
75
|
+
NSLog(@"[DEBUG] Setting return value for %s, return type: %c, JS result is %s",
|
|
76
|
+
data->selectorName.c_str(), retType[0],
|
|
77
|
+
result.IsNull() ? "null" : result.IsUndefined() ? "undefined" : "value");
|
|
71
78
|
SetInvocationReturnFromJS(invocation, result, retType[0],
|
|
72
79
|
data->selectorName.c_str());
|
|
80
|
+
NSLog(@"[DEBUG] Return value set for %s", data->selectorName.c_str());
|
|
73
81
|
}
|
|
74
82
|
} catch (const Napi::Error &e) {
|
|
75
83
|
NSLog(@"Error calling JavaScript callback for %s: %s",
|
|
@@ -165,6 +173,7 @@ void ForwardInvocation(id self, SEL _cmd, NSInvocation *invocation) {
|
|
|
165
173
|
Napi::ThreadSafeFunction tsfn;
|
|
166
174
|
std::string typeEncoding;
|
|
167
175
|
pthread_t js_thread;
|
|
176
|
+
bool isElectron;
|
|
168
177
|
{
|
|
169
178
|
std::lock_guard<std::mutex> lock(g_implementations_mutex);
|
|
170
179
|
auto it = g_implementations.find(ptr);
|
|
@@ -201,13 +210,19 @@ void ForwardInvocation(id self, SEL _cmd, NSInvocation *invocation) {
|
|
|
201
210
|
|
|
202
211
|
// Get the JS thread ID to check if we're on the same thread
|
|
203
212
|
js_thread = it->second.js_thread;
|
|
213
|
+
isElectron = it->second.isElectron;
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
// Check if we're on the JS thread
|
|
207
217
|
bool is_js_thread = pthread_equal(pthread_self(), js_thread);
|
|
208
218
|
|
|
219
|
+
NSLog(@"[DEBUG] ForwardInvocation for %s: is_js_thread=%d, isElectron=%d, current_thread=%p, js_thread=%p",
|
|
220
|
+
selectorName.c_str(), is_js_thread, isElectron, pthread_self(), js_thread);
|
|
221
|
+
|
|
209
222
|
// IMPORTANT: We call directly on the JS thread so return values are set
|
|
210
223
|
// synchronously; otherwise we use a ThreadSafeFunction to marshal work.
|
|
224
|
+
// EXCEPTION: In Electron, we ALWAYS use TSFN even on the JS thread because
|
|
225
|
+
// Electron's V8 context isn't properly set up for direct handle creation.
|
|
211
226
|
|
|
212
227
|
// Create invocation data
|
|
213
228
|
auto data = new InvocationData();
|
|
@@ -217,9 +232,10 @@ void ForwardInvocation(id self, SEL _cmd, NSInvocation *invocation) {
|
|
|
217
232
|
|
|
218
233
|
napi_status status;
|
|
219
234
|
|
|
220
|
-
if (is_js_thread) {
|
|
221
|
-
// We're on the JS thread
|
|
235
|
+
if (is_js_thread && !isElectron) {
|
|
236
|
+
// We're on the JS thread in Node/Bun (NOT Electron)
|
|
222
237
|
// Call directly to ensure return values are set synchronously.
|
|
238
|
+
NSLog(@"[DEBUG] Taking JS thread direct call path for %s", selectorName.c_str());
|
|
223
239
|
data->completionMutex = nullptr;
|
|
224
240
|
data->completionCv = nullptr;
|
|
225
241
|
data->isComplete = nullptr;
|
|
@@ -258,13 +274,17 @@ void ForwardInvocation(id self, SEL _cmd, NSInvocation *invocation) {
|
|
|
258
274
|
// Wrap in try-catch to handle invalid env (e.g., in Electron when context
|
|
259
275
|
// is destroyed)
|
|
260
276
|
try {
|
|
277
|
+
NSLog(@"[DEBUG] Creating Napi::Env from stored_env for %s", selectorName.c_str());
|
|
261
278
|
Napi::Env callEnv(stored_env);
|
|
262
279
|
|
|
263
280
|
// Create a HandleScope to properly manage V8 handles
|
|
264
281
|
// This is critical for Electron which may have multiple V8 contexts
|
|
282
|
+
NSLog(@"[DEBUG] Creating HandleScope for %s", selectorName.c_str());
|
|
265
283
|
Napi::HandleScope scope(callEnv);
|
|
266
284
|
|
|
285
|
+
NSLog(@"[DEBUG] Calling CallJSCallback directly for %s", selectorName.c_str());
|
|
267
286
|
CallJSCallback(callEnv, jsFn, data);
|
|
287
|
+
NSLog(@"[DEBUG] CallJSCallback completed for %s", selectorName.c_str());
|
|
268
288
|
// CallJSCallback releases invocation and deletes data.
|
|
269
289
|
} catch (const std::exception &e) {
|
|
270
290
|
NSLog(@"Error calling JS callback directly (likely invalid env in "
|
|
@@ -323,6 +343,7 @@ void ForwardInvocation(id self, SEL _cmd, NSInvocation *invocation) {
|
|
|
323
343
|
// We're on a different thread (e.g., Cocoa callback from
|
|
324
344
|
// ASAuthorizationController) Use NonBlockingCall + runloop pumping to avoid
|
|
325
345
|
// deadlocks
|
|
346
|
+
NSLog(@"[DEBUG] Taking non-JS thread path for %s", selectorName.c_str());
|
|
326
347
|
std::mutex completionMutex;
|
|
327
348
|
std::condition_variable completionCv;
|
|
328
349
|
bool isComplete = false;
|
|
@@ -130,13 +130,33 @@ Napi::Value CreateProtocolImplementation(const Napi::CallbackInfo &info) {
|
|
|
130
130
|
// Get the method implementations object's property names
|
|
131
131
|
Napi::Array propertyNames = methodImplementations.GetPropertyNames();
|
|
132
132
|
|
|
133
|
+
// Detect if we're running in Electron by checking process.versions.electron
|
|
134
|
+
bool isElectron = false;
|
|
135
|
+
try {
|
|
136
|
+
Napi::Object global = env.Global();
|
|
137
|
+
if (global.Has("process")) {
|
|
138
|
+
Napi::Object process = global.Get("process").As<Napi::Object>();
|
|
139
|
+
if (process.Has("versions")) {
|
|
140
|
+
Napi::Object versions = process.Get("versions").As<Napi::Object>();
|
|
141
|
+
isElectron = versions.Has("electron");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch (...) {
|
|
145
|
+
// If detection fails, assume not Electron
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (isElectron) {
|
|
149
|
+
NSLog(@"[DEBUG] Detected Electron runtime, will always use TSFN path");
|
|
150
|
+
}
|
|
151
|
+
|
|
133
152
|
// Store callbacks for this instance (we'll set the instance pointer later)
|
|
134
153
|
ProtocolImplementation impl{
|
|
135
154
|
.callbacks = {},
|
|
136
155
|
.typeEncodings = {},
|
|
137
156
|
.className = className,
|
|
138
157
|
.env = env,
|
|
139
|
-
.js_thread = pthread_self() // Store the current (JS) thread ID
|
|
158
|
+
.js_thread = pthread_self(), // Store the current (JS) thread ID
|
|
159
|
+
.isElectron = isElectron
|
|
140
160
|
};
|
|
141
161
|
|
|
142
162
|
// Store default type encodings to keep them alive
|