react-native-worklets 0.13.0-nightly-20260916-1fb70959f → 0.13.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.
- package/Common/cpp/worklets/RunLoop/AsyncQueue.h +28 -0
- package/Common/cpp/worklets/RunLoop/AsyncQueueImpl.cpp +9 -0
- package/Common/cpp/worklets/RunLoop/AsyncQueueImpl.h +6 -0
- package/Common/cpp/worklets/RunLoop/EventLoop.cpp +18 -2
- package/Common/cpp/worklets/RunLoop/EventLoop.h +3 -0
- package/Common/cpp/worklets/Tools/ScriptBuffer.h +0 -5
- package/Common/cpp/worklets/Tools/WorkletsJSIUtils.h +15 -10
- package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +24 -10
- package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +6 -0
- package/android/CMakeLists.txt +7 -23
- package/android/build.gradle.kts +4 -13
- package/apple/worklets/apple/Networking/WorkletsURLSessionDelegate.h +1 -1
- package/apple/worklets/apple/Networking/WorkletsURLSessionDelegate.mm +4 -5
- package/compatibility.json +2 -2
- package/lib/module/debug/jsVersion.js +1 -1
- package/lib/module/debug/jsVersion.js.map +1 -1
- package/lib/typescript/debug/jsVersion.d.ts +1 -1
- package/lib/typescript/debug/jsVersion.d.ts.map +1 -1
- package/package.json +13 -7
- package/plugin-oxc/babel.d.ts +7 -0
- package/plugin-oxc/babel.js +200 -0
- package/plugin-oxc/index.d.ts +33 -0
- package/plugin-oxc/index.js +36 -0
- package/plugin-oxc/worklets-oxc-plugin.darwin-arm64.node +0 -0
- package/plugin-oxc/worklets-oxc-plugin.darwin-x64.node +0 -0
- package/plugin-oxc/worklets-oxc-plugin.linux-arm64.node +0 -0
- package/plugin-oxc/worklets-oxc-plugin.linux-x64.node +0 -0
- package/plugin-oxc/worklets-oxc-plugin.win32-arm64.node +0 -0
- package/plugin-oxc/worklets-oxc-plugin.win32-x64.node +0 -0
- package/src/debug/jsVersion.ts +1 -1
- package/Common/cpp/worklets/Compat/ReactNativeVersionCompat.h +0 -7
|
@@ -2,13 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
#include <jsi/jsi.h>
|
|
4
4
|
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <utility>
|
|
7
|
+
|
|
5
8
|
namespace worklets {
|
|
6
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Identifies the owner of a job, so that a queue shared between several owners
|
|
12
|
+
* can cancel the jobs of one of them without touching the jobs of the others.
|
|
13
|
+
*
|
|
14
|
+
* Worklet Runtimes send their RuntimeId as a token.
|
|
15
|
+
*/
|
|
16
|
+
using AbortToken = uint64_t;
|
|
17
|
+
|
|
18
|
+
inline constexpr AbortToken defaultToken{0};
|
|
19
|
+
|
|
7
20
|
class AsyncQueue : public facebook::jsi::NativeState {
|
|
8
21
|
public:
|
|
9
22
|
~AsyncQueue() override = default;
|
|
10
23
|
|
|
11
24
|
virtual void push(std::function<void()> &&job) = 0;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Pushes a job on behalf of the owner the token belongs to. The default
|
|
28
|
+
* implementation discards the token.
|
|
29
|
+
*/
|
|
30
|
+
virtual void push(std::function<void()> &&job, AbortToken /* abortToken */) {
|
|
31
|
+
push(std::move(job));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Drops the jobs that are still pending, destroying them on the calling
|
|
36
|
+
* thread. A queue shared between several owners drops only the jobs pushed
|
|
37
|
+
* with this token. The default implementation keeps every job.
|
|
38
|
+
*/
|
|
39
|
+
virtual void abortPending(AbortToken /* abortToken */) {}
|
|
12
40
|
};
|
|
13
41
|
|
|
14
42
|
} // namespace worklets
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#endif // ANDROID
|
|
6
6
|
|
|
7
7
|
#include <memory>
|
|
8
|
+
#include <queue>
|
|
8
9
|
#include <string>
|
|
9
10
|
#include <thread>
|
|
10
11
|
#include <utility>
|
|
@@ -92,6 +93,14 @@ void AsyncQueueImpl::push(std::function<void()> &&job) {
|
|
|
92
93
|
state_->cv.notify_one();
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
void AsyncQueueImpl::abortPending(AbortToken /* abortToken */) {
|
|
97
|
+
std::queue<std::function<void()>> pendingJobs;
|
|
98
|
+
{
|
|
99
|
+
std::unique_lock<std::mutex> lock(state_->mutex);
|
|
100
|
+
std::swap(pendingJobs, state_->queue);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
95
104
|
AsyncQueueUI::AsyncQueueUI(const std::shared_ptr<UIScheduler> &uiScheduler) : uiScheduler_(uiScheduler) {}
|
|
96
105
|
|
|
97
106
|
void AsyncQueueUI::push(std::function<void()> &&job) {
|
|
@@ -25,8 +25,12 @@ class AsyncQueueImpl : public AsyncQueue {
|
|
|
25
25
|
|
|
26
26
|
~AsyncQueueImpl() override;
|
|
27
27
|
|
|
28
|
+
using AsyncQueue::push;
|
|
29
|
+
|
|
28
30
|
void push(std::function<void()> &&job) override;
|
|
29
31
|
|
|
32
|
+
void abortPending(AbortToken abortToken) override;
|
|
33
|
+
|
|
30
34
|
private:
|
|
31
35
|
static void runLoop(const std::shared_ptr<AsyncQueueState> &state);
|
|
32
36
|
|
|
@@ -39,6 +43,8 @@ class AsyncQueueUI : public AsyncQueue {
|
|
|
39
43
|
|
|
40
44
|
~AsyncQueueUI() override = default;
|
|
41
45
|
|
|
46
|
+
using AsyncQueue::push;
|
|
47
|
+
|
|
42
48
|
void push(std::function<void()> &&job) override;
|
|
43
49
|
|
|
44
50
|
private:
|
|
@@ -10,10 +10,12 @@ namespace worklets {
|
|
|
10
10
|
|
|
11
11
|
EventLoop::EventLoop(
|
|
12
12
|
const std::string &name,
|
|
13
|
+
const AbortToken abortToken,
|
|
13
14
|
const std::shared_ptr<jsi::Runtime> &runtime,
|
|
14
15
|
const std::shared_ptr<AsyncQueue> &queue,
|
|
15
16
|
const std::shared_ptr<std::recursive_mutex> &runtimeMutex)
|
|
16
|
-
:
|
|
17
|
+
: abortToken_(abortToken),
|
|
18
|
+
runtime_(runtime),
|
|
17
19
|
queue_(queue),
|
|
18
20
|
runtimeMutex_(runtimeMutex),
|
|
19
21
|
timeoutsQueueState_(std::make_shared<TimeoutsQueueState>()),
|
|
@@ -88,12 +90,26 @@ void EventLoop::pushTask(std::function<void(jsi::Runtime &rt)> &&job) {
|
|
|
88
90
|
job(*runtime);
|
|
89
91
|
runtime->drainMicrotasks();
|
|
90
92
|
}
|
|
91
|
-
}
|
|
93
|
+
},
|
|
94
|
+
abortToken_);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void EventLoop::abortPending() {
|
|
98
|
+
std::vector<Timeout> pendingTimeouts;
|
|
99
|
+
{
|
|
100
|
+
std::unique_lock<std::mutex> lock(timeoutsQueueState_->mutex);
|
|
101
|
+
timeoutsQueueState_->running = false;
|
|
102
|
+
std::swap(pendingTimeouts, timeoutsQueueState_->queue);
|
|
103
|
+
}
|
|
104
|
+
timeoutsQueueState_->cv.notify_all();
|
|
92
105
|
}
|
|
93
106
|
|
|
94
107
|
void EventLoop::pushTimeout(std::function<void(jsi::Runtime &rt)> &&job, int64_t delay) {
|
|
95
108
|
{
|
|
96
109
|
std::unique_lock<std::mutex> lock(timeoutsQueueState_->mutex);
|
|
110
|
+
if (!timeoutsQueueState_->running) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
97
113
|
const auto targetTime = getCurrentTimeInMs() + delay;
|
|
98
114
|
const auto timeout = Timeout{std::move(job), targetTime};
|
|
99
115
|
auto &queue = timeoutsQueueState_->queue;
|
|
@@ -33,6 +33,7 @@ class EventLoop : public std::enable_shared_from_this<EventLoop> {
|
|
|
33
33
|
public:
|
|
34
34
|
EventLoop(
|
|
35
35
|
const std::string &name,
|
|
36
|
+
AbortToken abortToken,
|
|
36
37
|
const std::shared_ptr<jsi::Runtime> &runtime,
|
|
37
38
|
const std::shared_ptr<AsyncQueue> &queue,
|
|
38
39
|
const std::shared_ptr<std::recursive_mutex> &runtimeMutex);
|
|
@@ -40,8 +41,10 @@ class EventLoop : public std::enable_shared_from_this<EventLoop> {
|
|
|
40
41
|
void run();
|
|
41
42
|
void pushTask(std::function<void(jsi::Runtime &rt)> &&job);
|
|
42
43
|
void pushTimeout(std::function<void(jsi::Runtime &rt)> &&job, int64_t delay);
|
|
44
|
+
void abortPending();
|
|
43
45
|
|
|
44
46
|
private:
|
|
47
|
+
const AbortToken abortToken_;
|
|
45
48
|
const std::shared_ptr<jsi::Runtime> runtime_;
|
|
46
49
|
const std::shared_ptr<AsyncQueue> queue_;
|
|
47
50
|
const std::shared_ptr<std::recursive_mutex> runtimeMutex_;
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include <jsi/jsi.h>
|
|
4
|
-
#include <worklets/Compat/ReactNativeVersionCompat.h>
|
|
5
4
|
|
|
6
|
-
#if REACT_NATIVE_VERSION_MINOR >= 84
|
|
7
5
|
#include <cxxreact/JSBigString.h>
|
|
8
|
-
#else
|
|
9
|
-
#include <jsireact/JSIExecutor.h>
|
|
10
|
-
#endif
|
|
11
6
|
|
|
12
7
|
#include <memory>
|
|
13
8
|
#include <utility>
|
|
@@ -183,21 +183,26 @@ void addMethod(jsi::Runtime &rt, jsi::Object &obj, const char *name, TFun &&func
|
|
|
183
183
|
rt,
|
|
184
184
|
jsi::PropNameID::forAscii(rt, name),
|
|
185
185
|
TLength,
|
|
186
|
-
[func = std::forward<TFun>(func)
|
|
186
|
+
[func = std::forward<TFun>(func)](
|
|
187
187
|
jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) mutable -> jsi::Value {
|
|
188
188
|
using TReturn =
|
|
189
189
|
std::invoke_result_t<TFun &, jsi::Runtime &, const jsi::Value &, const jsi::Value(&)[TLength]>;
|
|
190
|
+
auto invoke = [&](const jsi::Value(&typed)[TLength]) -> jsi::Value {
|
|
191
|
+
if constexpr (std::is_void_v<TReturn>) {
|
|
192
|
+
func(rt, thisVal, typed);
|
|
193
|
+
return jsi::Value::undefined();
|
|
194
|
+
} else {
|
|
195
|
+
return func(rt, thisVal, typed);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
190
198
|
if (count < TLength) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
func(rt, thisVal, typed);
|
|
197
|
-
return jsi::Value::undefined();
|
|
198
|
-
} else {
|
|
199
|
-
return func(rt, thisVal, typed);
|
|
199
|
+
jsi::Value padded[TLength];
|
|
200
|
+
for (size_t i = 0; i < count; ++i) {
|
|
201
|
+
padded[i] = jsi::Value(rt, args[i]);
|
|
202
|
+
}
|
|
203
|
+
return invoke(padded);
|
|
200
204
|
}
|
|
205
|
+
return invoke(*reinterpret_cast<const jsi::Value(*)[TLength]>(args));
|
|
201
206
|
}));
|
|
202
207
|
}
|
|
203
208
|
|
|
@@ -88,11 +88,23 @@ WorkletRuntime::WorkletRuntime(
|
|
|
88
88
|
jsi::Runtime &rt = *runtime_;
|
|
89
89
|
WorkletRuntimeCollector::install(rt);
|
|
90
90
|
if (enableEventLoop) {
|
|
91
|
-
eventLoop_ = std::make_shared<EventLoop>(name_, runtime_, queue_, runtimeMutex_);
|
|
91
|
+
eventLoop_ = std::make_shared<EventLoop>(name_, abortToken(), runtime_, queue_, runtimeMutex_);
|
|
92
92
|
eventLoop_->run();
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
WorkletRuntime::~WorkletRuntime() {
|
|
97
|
+
auto lock = acquireRuntimeLock();
|
|
98
|
+
if (eventLoop_) {
|
|
99
|
+
eventLoop_->abortPending();
|
|
100
|
+
eventLoop_.reset();
|
|
101
|
+
}
|
|
102
|
+
if (queue_) {
|
|
103
|
+
queue_->abortPending(abortToken());
|
|
104
|
+
queue_.reset();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
96
108
|
void WorkletRuntime::init(const std::shared_ptr<JSIWorkletsModuleProxy> &jsiWorkletsModuleProxy) {
|
|
97
109
|
jsi::Runtime &rt = *runtime_;
|
|
98
110
|
|
|
@@ -244,15 +256,17 @@ void WorkletRuntime::scheduleImpl(ScheduledJob job) const {
|
|
|
244
256
|
"[Worklets] Tried to invoke `schedule` on a Worklet Runtime but the "
|
|
245
257
|
"async queue is not set. Recreate the runtime with a valid async queue.");
|
|
246
258
|
|
|
247
|
-
queue_->push(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
259
|
+
queue_->push(
|
|
260
|
+
[job = std::move(job), weakThis = weak_from_this()] {
|
|
261
|
+
const auto strongThis = weakThis.lock();
|
|
262
|
+
if (!strongThis) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
auto lock = strongThis->acquireRuntimeLock();
|
|
267
|
+
job(*strongThis);
|
|
268
|
+
},
|
|
269
|
+
abortToken());
|
|
256
270
|
}
|
|
257
271
|
|
|
258
272
|
/* #endregion */
|
|
@@ -261,6 +261,8 @@ class WorkletRuntime : public jsi::HostObject, public std::enable_shared_from_th
|
|
|
261
261
|
bool enableLocking = true,
|
|
262
262
|
bool enableNetworking = true);
|
|
263
263
|
|
|
264
|
+
~WorkletRuntime() override;
|
|
265
|
+
|
|
264
266
|
void init(const std::shared_ptr<JSIWorkletsModuleProxy> &jsiWorkletsModuleProxy);
|
|
265
267
|
|
|
266
268
|
/**
|
|
@@ -439,6 +441,10 @@ class WorkletRuntime : public jsi::HostObject, public std::enable_shared_from_th
|
|
|
439
441
|
|
|
440
442
|
void legacyModeInit(const std::shared_ptr<UnpackerLoader> &unpackerLoader);
|
|
441
443
|
|
|
444
|
+
[[nodiscard]] AbortToken abortToken() const noexcept {
|
|
445
|
+
return static_cast<AbortToken>(runtimeId_);
|
|
446
|
+
}
|
|
447
|
+
|
|
442
448
|
[[nodiscard]] std::unique_lock<std::recursive_mutex> acquireRuntimeLock() const {
|
|
443
449
|
if (enableLocking_) {
|
|
444
450
|
return std::unique_lock<std::recursive_mutex>(*runtimeMutex_);
|
package/android/CMakeLists.txt
CHANGED
|
@@ -19,16 +19,10 @@ add_compile_options(${folly_FLAGS})
|
|
|
19
19
|
string(APPEND CMAKE_CXX_FLAGS " -DWORKLETS_VERSION=${WORKLETS_VERSION}\
|
|
20
20
|
-DWORKLETS_FEATURE_FLAGS=\"${WORKLETS_FEATURE_FLAGS}\"")
|
|
21
21
|
|
|
22
|
-
# HERMES_V1_ENABLED is centralized in react-native-flags.cmake
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
else()
|
|
27
|
-
# Reference the value so CMake records it as used, otherwise it warns:
|
|
28
|
-
# "Manually-specified variables were not used by the project:
|
|
29
|
-
# HERMES_V1_ENABLED"
|
|
30
|
-
set(HERMES_V1_ENABLED "${HERMES_V1_ENABLED}")
|
|
31
|
-
endif()
|
|
22
|
+
# HERMES_V1_ENABLED is centralized in react-native-flags.cmake. Reference the
|
|
23
|
+
# value so CMake records it as used, otherwise it warns: "Manually-specified
|
|
24
|
+
# variables were not used by the project: HERMES_V1_ENABLED"
|
|
25
|
+
set(HERMES_V1_ENABLED "${HERMES_V1_ENABLED}")
|
|
32
26
|
|
|
33
27
|
string(APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer -fstack-protector-all")
|
|
34
28
|
|
|
@@ -63,14 +57,8 @@ target_precompile_headers(worklets PRIVATE "${ANDROID_CPP_DIR}/WorkletsPCH.h")
|
|
|
63
57
|
target_compile_options(
|
|
64
58
|
worklets PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-Xclang;-fno-pch-timestamp>")
|
|
65
59
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"${REACT_NATIVE_DIR}/ReactCommon/cmake-utils/react-native-flags.cmake")
|
|
69
|
-
target_compile_reactnative_options(worklets PUBLIC)
|
|
70
|
-
else()
|
|
71
|
-
string(APPEND CMAKE_CXX_FLAGS
|
|
72
|
-
" -fexceptions -frtti -std=c++${CMAKE_CXX_STANDARD} -Wall -Werror")
|
|
73
|
-
endif()
|
|
60
|
+
include("${REACT_NATIVE_DIR}/ReactCommon/cmake-utils/react-native-flags.cmake")
|
|
61
|
+
target_compile_reactnative_options(worklets PUBLIC)
|
|
74
62
|
|
|
75
63
|
# includes
|
|
76
64
|
target_include_directories(worklets PUBLIC "${COMMON_CPP_DIR}"
|
|
@@ -94,11 +82,7 @@ set_target_properties(worklets PROPERTIES LINKER_LANGUAGE CXX)
|
|
|
94
82
|
target_link_libraries(worklets android log ReactAndroid::reactnative
|
|
95
83
|
ReactAndroid::jsi fbjni::fbjni)
|
|
96
84
|
|
|
97
|
-
|
|
98
|
-
target_link_libraries(worklets hermes-engine::hermesvm)
|
|
99
|
-
else()
|
|
100
|
-
target_link_libraries(worklets hermes-engine::libhermes)
|
|
101
|
-
endif()
|
|
85
|
+
target_link_libraries(worklets hermes-engine::hermesvm)
|
|
102
86
|
|
|
103
87
|
if(${HERMES_ENABLE_DEBUGGER})
|
|
104
88
|
string(APPEND CMAKE_CXX_FLAGS " -DHERMES_ENABLE_DEBUGGER=1")
|
package/android/build.gradle.kts
CHANGED
|
@@ -69,22 +69,13 @@ fun getReactNativeVersion(): String {
|
|
|
69
69
|
return reactProperties.getProperty("VERSION_NAME")
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
fun getReactNativeMinorVersion(): Int {
|
|
73
|
-
val reactNativeVersion = getReactNativeVersion()
|
|
74
|
-
return if (reactNativeVersion.startsWith("0.0.0-")) 1000 else reactNativeVersion.split(".")[1].toInt()
|
|
75
|
-
}
|
|
76
|
-
|
|
77
72
|
fun getHermesV1Enabled(): Boolean {
|
|
78
73
|
// Even though `HERMES_V1_ENABLED` is now centralized
|
|
79
|
-
// in `react-native-flags.cmake
|
|
80
|
-
//
|
|
81
|
-
//
|
|
74
|
+
// in `react-native-flags.cmake`, that CMake file depends
|
|
75
|
+
// on definitions provided in local `externalNativeBuild`
|
|
76
|
+
// configuration of the LIBRARY.
|
|
82
77
|
// I hope this is only a temporary workaround.
|
|
83
|
-
return
|
|
84
|
-
safeAppExtGet("hermesV1Enabled", true)?.toString()?.toBoolean() ?: true
|
|
85
|
-
} else {
|
|
86
|
-
safeAppExtGet("hermesV1Enabled", false)?.toString()?.toBoolean() ?: false
|
|
87
|
-
}
|
|
78
|
+
return safeAppExtGet("hermesV1Enabled", true)?.toString()?.toBoolean() ?: true
|
|
88
79
|
}
|
|
89
80
|
|
|
90
81
|
fun getWorkletsVersion(): String {
|
|
@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
26
26
|
|
|
27
27
|
- (void)sendRequest:(worklets::RequestConfig &&)config
|
|
28
28
|
requestId:(uint64_t)requestId
|
|
29
|
-
listener:(
|
|
29
|
+
listener:(std::shared_ptr<worklets::NetworkRequestListener>)listener;
|
|
30
30
|
- (void)abortRequest:(uint64_t)requestId;
|
|
31
31
|
- (void)invalidate;
|
|
32
32
|
|
|
@@ -248,7 +248,7 @@ static BOOL isSameOrigin(NSURL *lhs, NSURL *rhs)
|
|
|
248
248
|
|
|
249
249
|
- (void)sendRequest:(RequestConfig &&)config
|
|
250
250
|
requestId:(uint64_t)requestId
|
|
251
|
-
listener:(
|
|
251
|
+
listener:(std::shared_ptr<NetworkRequestListener>)listener
|
|
252
252
|
{
|
|
253
253
|
NSString *urlString = [NSString stringWithUTF8String:config.url.c_str()];
|
|
254
254
|
NSURL *url = urlString != nil ? [NSURL URLWithString:urlString] : nil;
|
|
@@ -287,22 +287,21 @@ static BOOL isSameOrigin(NSURL *lhs, NSURL *rhs)
|
|
|
287
287
|
request.HTTPShouldHandleCookies = config.withCredentials;
|
|
288
288
|
request.timeoutInterval = config.timeoutMs > 0 ? config.timeoutMs / 1000.0 : kNoTimeoutInterval;
|
|
289
289
|
|
|
290
|
-
const auto sharedListener = listener;
|
|
291
290
|
const auto timeoutMs = config.timeoutMs;
|
|
292
291
|
const auto withCredentials = config.withCredentials;
|
|
293
292
|
|
|
294
293
|
[_delegateQueue addOperationWithBlock:^{
|
|
295
294
|
if (atomic_load(&self->_invalidated)) {
|
|
296
|
-
|
|
295
|
+
listener->onError(RequestError::Aborted, "The networking session was invalidated.");
|
|
297
296
|
return;
|
|
298
297
|
}
|
|
299
298
|
NSURLSessionDataTask *task = [[self sessionWithCredentials:withCredentials] dataTaskWithRequest:request];
|
|
300
299
|
if (task == nil) {
|
|
301
|
-
|
|
300
|
+
listener->onError(RequestError::Network, "Failed to create a data task for the request.");
|
|
302
301
|
return;
|
|
303
302
|
}
|
|
304
303
|
WorkletsRequestState *state = [WorkletsRequestState new];
|
|
305
|
-
state->listener =
|
|
304
|
+
state->listener = listener;
|
|
306
305
|
state->data = [NSMutableData new];
|
|
307
306
|
state->requestId = requestId;
|
|
308
307
|
state->expectedContentLength = -1;
|
package/compatibility.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"nightly": {
|
|
3
|
-
"react-native": ["0.
|
|
3
|
+
"react-native": ["0.86", "0.87", "0.88"]
|
|
4
4
|
},
|
|
5
5
|
"0.13.x": {
|
|
6
|
-
"react-native": ["0.
|
|
6
|
+
"react-native": ["0.86", "0.87", "0.88"]
|
|
7
7
|
},
|
|
8
8
|
"0.12.x": {
|
|
9
9
|
"react-native": ["0.83", "0.84", "0.85", "0.86", "0.87"]
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* version used to build the native part of the library in runtime. Remember to
|
|
6
6
|
* keep this in sync with the version declared in `package.json`
|
|
7
7
|
*/
|
|
8
|
-
export const jsVersion = '0.13.0
|
|
8
|
+
export const jsVersion = '0.13.0';
|
|
9
9
|
//# sourceMappingURL=jsVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["jsVersion"],"sourceRoot":"../../../src","sources":["debug/jsVersion.ts"],"mappings":"AAAA,YAAY;;AAEZ;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,SAAS,GAAG,
|
|
1
|
+
{"version":3,"names":["jsVersion"],"sourceRoot":"../../../src","sources":["debug/jsVersion.ts"],"mappings":"AAAA,YAAY;;AAEZ;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,SAAS,GAAG,QAAQ","ignoreList":[]}
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* version used to build the native part of the library in runtime. Remember to
|
|
4
4
|
* keep this in sync with the version declared in `package.json`
|
|
5
5
|
*/
|
|
6
|
-
export declare const jsVersion = "0.13.0
|
|
6
|
+
export declare const jsVersion = "0.13.0";
|
|
7
7
|
//# sourceMappingURL=jsVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsVersion.d.ts","sourceRoot":"","sources":["../../../src/debug/jsVersion.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"jsVersion.d.ts","sourceRoot":"","sources":["../../../src/debug/jsVersion.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,SAAS,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-worklets",
|
|
3
|
-
"version": "0.13.0
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "The React Native multithreading library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"worklets"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "yarn workspace babel-plugin-worklets build && yarn set-version && yarn run --top-level bob build",
|
|
12
|
+
"build": "yarn workspace babel-plugin-worklets build && yarn workspace worklets-oxc-plugin build && yarn set-version && yarn run --top-level bob build",
|
|
13
13
|
"circular-dependency-check": "yarn madge --extensions js,jsx --circular lib",
|
|
14
14
|
"find-unused-code:js": "knip",
|
|
15
15
|
"format": "yarn format:js && yarn format:plugin && yarn format:common && yarn format:android && yarn format:apple",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@babel/core": "*",
|
|
63
63
|
"@react-native/metro-config": "*",
|
|
64
64
|
"react": "*",
|
|
65
|
-
"react-native": "0.
|
|
65
|
+
"react-native": "0.86 - 0.88"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@babel/generator": "^7.27.1",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"@babel/preset-typescript": "^7.28.5",
|
|
78
78
|
"@babel/traverse": "^7.27.1",
|
|
79
79
|
"@babel/types": "^7.27.1",
|
|
80
|
+
"@jridgewell/remapping": "^2.3.5",
|
|
80
81
|
"convert-source-map": "^2.0.0",
|
|
81
82
|
"semver": "^7.7.4",
|
|
82
83
|
"whatwg-fetch": "^3.6.20"
|
|
@@ -85,8 +86,8 @@
|
|
|
85
86
|
"@babel/cli": "7.28.3",
|
|
86
87
|
"@babel/core": "7.29.6",
|
|
87
88
|
"@react-native-community/cli": "20.2.0",
|
|
88
|
-
"@react-native/eslint-config": "0.
|
|
89
|
-
"@react-native/jest-preset": "0.
|
|
89
|
+
"@react-native/eslint-config": "0.88.0-rc.1",
|
|
90
|
+
"@react-native/jest-preset": "0.88.0-rc.1",
|
|
90
91
|
"@types/node": "24.7.0",
|
|
91
92
|
"@types/react": "19.2.18",
|
|
92
93
|
"clang-format-node": "1.3.5",
|
|
@@ -94,8 +95,8 @@
|
|
|
94
95
|
"is-tree-shakable": "0.5.0",
|
|
95
96
|
"knip": "5.61.3",
|
|
96
97
|
"madge": "8.0.0",
|
|
97
|
-
"react": "19.
|
|
98
|
-
"react-native": "0.
|
|
98
|
+
"react": "19.3.0",
|
|
99
|
+
"react-native": "0.88.0-rc.1",
|
|
99
100
|
"typescript": "5.9.3"
|
|
100
101
|
},
|
|
101
102
|
"main": "./lib/module/index",
|
|
@@ -119,6 +120,11 @@
|
|
|
119
120
|
"jest",
|
|
120
121
|
"plugin/index.js",
|
|
121
122
|
"plugin/index.d.ts",
|
|
123
|
+
"plugin-oxc/index.js",
|
|
124
|
+
"plugin-oxc/index.d.ts",
|
|
125
|
+
"plugin-oxc/babel.js",
|
|
126
|
+
"plugin-oxc/babel.d.ts",
|
|
127
|
+
"plugin-oxc/*.node",
|
|
122
128
|
"Package.swift",
|
|
123
129
|
"*.podspec",
|
|
124
130
|
"react-native.config.js",
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const oxc = require('./index.js');
|
|
6
|
+
|
|
7
|
+
// Previous steps can pass their output sourcemap
|
|
8
|
+
// it needs to be merged with this plugin's one
|
|
9
|
+
// to preserve correct mappings
|
|
10
|
+
const remapping = require('@jridgewell/remapping');
|
|
11
|
+
|
|
12
|
+
const PARSE_ERROR_CODE = 'WORKLETS_ERR_PARSE';
|
|
13
|
+
const FLOW_ERROR_CODE = 'WORKLETS_ERR_FLOW';
|
|
14
|
+
|
|
15
|
+
let warnedAboutIgnoredOptions = false;
|
|
16
|
+
let cachedWorkletsPkgDir;
|
|
17
|
+
let cachedSyntaxJsx;
|
|
18
|
+
let cachedSyntaxTypescript;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {typeof import('@babel/core')} babelApi
|
|
22
|
+
* @returns {import('@babel/core').PluginObj}
|
|
23
|
+
*/
|
|
24
|
+
function workletsPluginOxcBabelShim(babelApi) {
|
|
25
|
+
return {
|
|
26
|
+
name: 'worklets-oxc-plugin',
|
|
27
|
+
visitor: {
|
|
28
|
+
Program: {
|
|
29
|
+
enter(programPath, state) {
|
|
30
|
+
if (state.file.__workletsOxcRan) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
state.file.__workletsOxcRan = true;
|
|
34
|
+
|
|
35
|
+
const filename = state.filename;
|
|
36
|
+
if (filename == null) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
'[Worklets] the OXC transform needs a filename to name worklets ' +
|
|
39
|
+
'and to place their generated files, but Babel was given none.'
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result = transform(state.file.code, filename, state);
|
|
44
|
+
if (!result.changed) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
adoptSourceMap(result, state);
|
|
49
|
+
programPath.replaceWith(
|
|
50
|
+
reparse(babelApi, result.code, filename, state)
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {string} sourceText
|
|
60
|
+
* @param {string} filename
|
|
61
|
+
* @param {import('@babel/core').PluginPass} state
|
|
62
|
+
* @returns {import('./index').TransformResult}
|
|
63
|
+
*/
|
|
64
|
+
function transform(sourceText, filename, state) {
|
|
65
|
+
warnAboutIgnoredOptions(state.opts);
|
|
66
|
+
try {
|
|
67
|
+
return oxc.transform(sourceText, filename, {
|
|
68
|
+
...state.opts,
|
|
69
|
+
envName: state.file.opts.envName,
|
|
70
|
+
workletsPackageDir: resolveWorkletsPkgDir(),
|
|
71
|
+
});
|
|
72
|
+
} catch (error) {
|
|
73
|
+
const message = (error && error.message) || '';
|
|
74
|
+
if (message.includes(FLOW_ERROR_CODE)) {
|
|
75
|
+
return { code: sourceText, files: [], changed: false };
|
|
76
|
+
}
|
|
77
|
+
if (message.includes(PARSE_ERROR_CODE)) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`[Worklets] ${filename} could not be parsed, so no worklets in it ` +
|
|
80
|
+
`were compiled.\n${message}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {import('./index').PluginOptions} options
|
|
89
|
+
* @returns {void}
|
|
90
|
+
*/
|
|
91
|
+
function warnAboutIgnoredOptions(options) {
|
|
92
|
+
if (warnedAboutIgnoredOptions) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const hasExtras =
|
|
96
|
+
(options?.extraPlugins?.length ?? 0) > 0 ||
|
|
97
|
+
(options?.extraPresets?.length ?? 0) > 0;
|
|
98
|
+
if (!hasExtras) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
warnedAboutIgnoredOptions = true;
|
|
102
|
+
console.warn(
|
|
103
|
+
'[Worklets] `extraPlugins`/`extraPresets` are accepted for option-surface ' +
|
|
104
|
+
'compatibility with `react-native-worklets/plugin` but ignored — the OXC transform ' +
|
|
105
|
+
'cannot dispatch arbitrary Babel plugins. Compose them around this plugin in ' +
|
|
106
|
+
'babel.config.js instead.'
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** @returns {string} */
|
|
111
|
+
function resolveWorkletsPkgDir() {
|
|
112
|
+
if (cachedWorkletsPkgDir === undefined) {
|
|
113
|
+
try {
|
|
114
|
+
cachedWorkletsPkgDir = path.dirname(
|
|
115
|
+
require.resolve('react-native-worklets/package.json')
|
|
116
|
+
);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
"[Worklets] couldn't find the react-native-worklets package on disk, " +
|
|
120
|
+
'so the generated worklet files have nowhere to go. ' +
|
|
121
|
+
`Make sure it's installed. Cause: ${error.message}`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return cachedWorkletsPkgDir;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {import('./index').TransformResult} result
|
|
130
|
+
* @param {import('@babel/core').PluginPass} state
|
|
131
|
+
* @returns {void}
|
|
132
|
+
*/
|
|
133
|
+
function adoptSourceMap(result, state) {
|
|
134
|
+
if (!result.map) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const map = JSON.parse(result.map);
|
|
138
|
+
const sourceFileName = state.file.opts.generatorOpts?.sourceFileName;
|
|
139
|
+
if (sourceFileName) {
|
|
140
|
+
map.sources = [sourceFileName];
|
|
141
|
+
}
|
|
142
|
+
const previous = state.file.inputMap;
|
|
143
|
+
if (previous) {
|
|
144
|
+
const previousMap = previous.toObject();
|
|
145
|
+
const composed = remapping([map, previousMap], () => null, true);
|
|
146
|
+
state.file.inputMap = { toObject: () => composed };
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
state.file.inputMap = { toObject: () => map };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @param {typeof import('@babel/core')} babelApi
|
|
154
|
+
* @param {string} code
|
|
155
|
+
* @param {string} filename
|
|
156
|
+
* @param {import('@babel/core').PluginPass} state
|
|
157
|
+
* @returns {import('@babel/types').Program}
|
|
158
|
+
*/
|
|
159
|
+
function reparse(babelApi, code, filename, state) {
|
|
160
|
+
const parse = (babelApi && babelApi.parse) || require('@babel/core').parse;
|
|
161
|
+
const parserOpts = state.file.opts.parserOpts ?? {};
|
|
162
|
+
const ast = parse(code, {
|
|
163
|
+
sourceType:
|
|
164
|
+
parserOpts.sourceType ?? state.file.opts.sourceType ?? 'unambiguous',
|
|
165
|
+
parserOpts: { ...parserOpts },
|
|
166
|
+
babelrc: false,
|
|
167
|
+
configFile: false,
|
|
168
|
+
plugins: reparseSyntaxPlugins(filename),
|
|
169
|
+
});
|
|
170
|
+
return ast.program;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {string} filename
|
|
175
|
+
* @returns {import('@babel/core').PluginItem[]}
|
|
176
|
+
*/
|
|
177
|
+
function reparseSyntaxPlugins(filename) {
|
|
178
|
+
if (filename.endsWith('.tsx')) {
|
|
179
|
+
return [[syntaxTypescript(), { isTSX: true }]];
|
|
180
|
+
}
|
|
181
|
+
if (/\.(ts|mts|cts)$/.test(filename)) {
|
|
182
|
+
return [[syntaxTypescript(), { isTSX: false }]];
|
|
183
|
+
}
|
|
184
|
+
return [[syntaxJsx()]];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** @returns {string} */
|
|
188
|
+
function syntaxTypescript() {
|
|
189
|
+
cachedSyntaxTypescript ??= require.resolve('@babel/plugin-syntax-typescript');
|
|
190
|
+
return cachedSyntaxTypescript;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** @returns {string} */
|
|
194
|
+
function syntaxJsx() {
|
|
195
|
+
cachedSyntaxJsx ??= require.resolve('@babel/plugin-syntax-jsx');
|
|
196
|
+
return cachedSyntaxJsx;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
module.exports = workletsPluginOxcBabelShim;
|
|
200
|
+
module.exports.default = workletsPluginOxcBabelShim;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface PluginOptions {
|
|
2
|
+
extraPlugins?: string[];
|
|
3
|
+
extraPresets?: string[];
|
|
4
|
+
importForwarding?: {
|
|
5
|
+
moduleNames?: string[];
|
|
6
|
+
relativePaths?: string[];
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TransformOptions extends PluginOptions {
|
|
11
|
+
envName?: string;
|
|
12
|
+
pluginVersion?: string;
|
|
13
|
+
workletsPackageDir?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface EmittedFile {
|
|
17
|
+
path: string;
|
|
18
|
+
content: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TransformResult {
|
|
22
|
+
code: string;
|
|
23
|
+
map?: string;
|
|
24
|
+
files: EmittedFile[];
|
|
25
|
+
/** Whether the transform rewrote anything; if not, the input AST still stands. */
|
|
26
|
+
changed: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function transform(
|
|
30
|
+
sourceText: string,
|
|
31
|
+
filename: string,
|
|
32
|
+
options?: TransformOptions
|
|
33
|
+
): TransformResult;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { existsSync } = require('fs');
|
|
4
|
+
const { join } = require('path');
|
|
5
|
+
|
|
6
|
+
const platform = process.platform;
|
|
7
|
+
const arch = process.arch;
|
|
8
|
+
|
|
9
|
+
function candidates() {
|
|
10
|
+
return [
|
|
11
|
+
join(__dirname, `worklets-oxc-plugin.${platform}-${arch}.node`),
|
|
12
|
+
join(__dirname, 'worklets-oxc-plugin.node'),
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let binding = null;
|
|
17
|
+
let lastError = null;
|
|
18
|
+
for (const p of candidates()) {
|
|
19
|
+
if (existsSync(p)) {
|
|
20
|
+
try {
|
|
21
|
+
binding = require(p);
|
|
22
|
+
break;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
lastError = e;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!binding) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`[Worklets] Could not load native binding. Run \`yarn build\` (or \`cargo build --release\`) in ${__dirname}. Last error: ${lastError && lastError.message}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = binding;
|
|
36
|
+
module.exports.default = binding;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/debug/jsVersion.ts
CHANGED