react-native-nitro-modules 0.9.2 → 0.10.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/README.md CHANGED
@@ -154,8 +154,8 @@ The following C++ / JS types are supported out of the box:
154
154
  <tr>
155
155
  <td><code>A | B | C | ...</code></td>
156
156
  <td><code>std::variant&lt;A, B, C, ...&gt;</code></td>
157
- <td><code>Variant_A_B_C</code> 🟡  (<a href="https://github.com/mrousavy/nitro/issues/39">#39</a>)</td>
158
- <td>❌</td>
157
+ <td><code>Variant_A_B_C</code></td>
158
+ <td><code>Variant_A_B_C</code></td>
159
159
  </tr>
160
160
  <tr>
161
161
  <td><code>Record&lt;string, T&gt;</code></td>
@@ -190,7 +190,7 @@ The following C++ / JS types are supported out of the box:
190
190
  <tr>
191
191
  <td><code>{ ... }</code></td>
192
192
  <td><code>std::shared_ptr&lt;<a href="./cpp/core/AnyMap.hpp">AnyMap</a>&gt;</code></td>
193
- <td><code><a href="./ios/core/AnyMapHolder.swift">AnyMapHolder</a></code> 🟡  (<a href="https://github.com/mrousavy/nitro/issues/57">#57</a>)</td>
193
+ <td><code><a href="./ios/core/AnyMapHolder.swift">AnyMapHolder</a></code></td>
194
194
  <td><code><a href="./android/src/main/java/com/margelo/nitro/core/AnyMap.kt">AnyMap</a></code></td>
195
195
  </tr>
196
196
  <tr>
@@ -0,0 +1,29 @@
1
+ //
2
+ // BoxedHybridObject.cpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 17.09.24.
6
+ //
7
+
8
+ #include "BoxedHybridObject.hpp"
9
+
10
+ namespace margelo::nitro {
11
+
12
+ std::vector<jsi::PropNameID> BoxedHybridObject::getPropertyNames(facebook::jsi::Runtime& runtime) {
13
+ return jsi::PropNameID::names(runtime, "unbox");
14
+ }
15
+
16
+ jsi::Value BoxedHybridObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
17
+ std::string name = propName.utf8(runtime);
18
+
19
+ if (name == "unbox") {
20
+ return jsi::Function::createFromHostFunction(
21
+ runtime, jsi::PropNameID::forUtf8(runtime, "unbox"), 0,
22
+ [hybridObject = _hybridObject](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args,
23
+ size_t count) -> jsi::Value { return hybridObject->toObject(runtime); });
24
+ }
25
+
26
+ return jsi::Value::undefined();
27
+ }
28
+
29
+ } // namespace margelo::nitro
@@ -0,0 +1,36 @@
1
+ //
2
+ // Created by Marc Rousavy on 21.02.24.
3
+ //
4
+
5
+ #pragma once
6
+
7
+ #include "HybridObject.hpp"
8
+ #include <jsi/jsi.h>
9
+ #include <memory>
10
+
11
+ namespace margelo::nitro {
12
+
13
+ using namespace facebook;
14
+
15
+ /**
16
+ * Represents a `HybridObject` that has been boxed into a `jsi::HostObject`.
17
+ *
18
+ * While `HybridObject`s are runtime agnostic, some threading/worklet libraries do not support copying over objects
19
+ * with `jsi::NativeState` and a prototype chain (which is what a `HybridObject` is), so Nitro offers support for
20
+ * boxing those `HybridObject`s into a type that those libraries support - which is a `jsi::HostObject`.
21
+ *
22
+ * Simply call `unbox()` on this `jsi::HostObject` from the new Runtime/context to get the `HybridObject` again.
23
+ */
24
+ class BoxedHybridObject : public jsi::HostObject {
25
+ public:
26
+ explicit BoxedHybridObject(const std::shared_ptr<HybridObject>& hybridObject) : _hybridObject(hybridObject) {}
27
+
28
+ public:
29
+ jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& propName) override;
30
+ std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& runtime) override;
31
+
32
+ private:
33
+ std::shared_ptr<HybridObject> _hybridObject;
34
+ };
35
+
36
+ } // namespace margelo::nitro
@@ -1,5 +1,5 @@
1
1
  //
2
- // BorrowingReference.hpp
2
+ // FutureType.hpp
3
3
  // NitroModules
4
4
  //
5
5
  // Created by Marc Rousavy on 21.06.24.
@@ -0,0 +1,29 @@
1
+ //
2
+ // TypeIndex.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 21.06.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <tuple>
11
+ #include <type_traits>
12
+
13
+ namespace margelo::nitro {
14
+
15
+ // Gets the index of `T` in a `std::tuple<...>`.
16
+ template <typename T, typename... Ts>
17
+ struct type_index;
18
+
19
+ template <typename T, typename First, typename... Rest>
20
+ struct type_index<T, First, Rest...> {
21
+ static constexpr size_t value = std::is_same_v<T, First> ? 0 : 1 + type_index<T, Rest...>::value;
22
+ };
23
+
24
+ template <typename T>
25
+ struct type_index<T> {
26
+ static constexpr size_t value = -1; // Type not found
27
+ };
28
+
29
+ } // namespace margelo::nitro
@@ -6,6 +6,7 @@
6
6
  //
7
7
 
8
8
  #include "NativeNitroModules.hpp"
9
+ #include "BoxedHybridObject.hpp"
9
10
  #include "CallInvokerDispatcher.hpp"
10
11
  #include "Dispatcher.hpp"
11
12
  #include "HybridObjectRegistry.hpp"
@@ -18,8 +19,6 @@ using namespace margelo::nitro;
18
19
  NativeNitroModules::NativeNitroModules(std::shared_ptr<CallInvoker> jsInvoker)
19
20
  : TurboModule(kModuleName, jsInvoker), _callInvoker(jsInvoker) {}
20
21
 
21
- NativeNitroModules::~NativeNitroModules() {}
22
-
23
22
  jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
24
23
  std::string name = propName.utf8(runtime);
25
24
 
@@ -33,21 +32,16 @@ jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID&
33
32
  }
34
33
  if (name == "createHybridObject") {
35
34
  return jsi::Function::createFromHostFunction(
36
- runtime, jsi::PropNameID::forUtf8(runtime, "createHybridObject"), 2,
35
+ runtime, jsi::PropNameID::forUtf8(runtime, "createHybridObject"), 1,
37
36
  [this](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value {
38
37
  #ifdef NITRO_DEBUG
39
- if (count != 1 && count != 2) [[unlikely]] {
40
- throw jsi::JSError(runtime, "NitroModules.createHybridObject(..) expects 1 or 2 arguments, but " + std::to_string(count) +
41
- " were supplied!");
38
+ if (count != 1) [[unlikely]] {
39
+ throw jsi::JSError(runtime,
40
+ "NitroModules.createHybridObject(..) expects 1 argument, but " + std::to_string(count) + " were supplied!");
42
41
  }
43
42
  #endif
44
43
  jsi::String objectName = args[0].asString(runtime);
45
- std::optional<jsi::Object> optionalArgs = std::nullopt;
46
- if (count > 1) {
47
- optionalArgs = args[1].asObject(runtime);
48
- }
49
-
50
- return createHybridObject(runtime, objectName, optionalArgs);
44
+ return createHybridObject(runtime, objectName);
51
45
  });
52
46
  }
53
47
  if (name == "hasHybridObject") {
@@ -87,6 +81,29 @@ jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID&
87
81
  return jsi::Value::undefined();
88
82
  });
89
83
  }
84
+ if (name == "box") {
85
+ return jsi::Function::createFromHostFunction(
86
+ runtime, jsi::PropNameID::forUtf8(runtime, "box"), 1,
87
+ [](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value {
88
+ jsi::Object object = args[0].asObject(runtime);
89
+ #ifdef NITRO_DEBUG
90
+ if (!object.hasNativeState(runtime)) {
91
+ std::string stringified = args[0].toString(runtime).utf8(runtime);
92
+ throw std::runtime_error("Cannot box object " + stringified + " - it does not have a NativeState!");
93
+ }
94
+ #endif
95
+
96
+ std::shared_ptr<jsi::NativeState> nativeState = object.getNativeState(runtime);
97
+ std::shared_ptr<HybridObject> maybeHybridObject = std::dynamic_pointer_cast<HybridObject>(nativeState);
98
+ if (maybeHybridObject == nullptr) {
99
+ std::string stringified = args[0].toString(runtime).utf8(runtime);
100
+ throw std::runtime_error("Cannot box object " + stringified + " - it has a NativeState, but it's not a HybridObject!");
101
+ }
102
+
103
+ auto boxed = std::make_shared<BoxedHybridObject>(maybeHybridObject);
104
+ return jsi::Object::createFromHostObject(runtime, boxed);
105
+ });
106
+ }
90
107
  if (name == "buildType") {
91
108
  #ifdef NITRO_DEBUG
92
109
  return jsi::String::createFromAscii(runtime, "debug");
@@ -105,11 +122,9 @@ void NativeNitroModules::install(jsi::Runtime& runtime) {
105
122
  Dispatcher::installRuntimeGlobalDispatcher(runtime, dispatcher);
106
123
  }
107
124
 
108
- jsi::Value NativeNitroModules::createHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName,
109
- const std::optional<jsi::Object>&) {
125
+ jsi::Value NativeNitroModules::createHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName) {
110
126
  auto name = hybridObjectName.utf8(runtime);
111
- // TODO: Pass args? Do we need that?
112
- auto hybridObject = HybridObjectRegistry::createHybridObject(name.c_str());
127
+ auto hybridObject = HybridObjectRegistry::createHybridObject(name);
113
128
  return hybridObject->toObject(runtime);
114
129
  }
115
130
 
@@ -16,8 +16,7 @@ using namespace facebook;
16
16
  // The base C++-based TurboModule. This is the entry point where all nitro modules get initialized.
17
17
  class NativeNitroModules : public TurboModule {
18
18
  public:
19
- NativeNitroModules(std::shared_ptr<CallInvoker> jsInvoker);
20
- ~NativeNitroModules();
19
+ explicit NativeNitroModules(std::shared_ptr<CallInvoker> jsInvoker);
21
20
 
22
21
  public:
23
22
  jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& propName) override;
@@ -25,7 +24,7 @@ public:
25
24
  // Setup
26
25
  void install(jsi::Runtime& runtime);
27
26
  // Hybrid Objects stuff
28
- jsi::Value createHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName, const std::optional<jsi::Object>& args);
27
+ jsi::Value createHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName);
29
28
  jsi::Value hasHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName);
30
29
  jsi::Value getAllHybridObjectNames(jsi::Runtime& runtime);
31
30
 
@@ -15,6 +15,11 @@
15
15
  #ifdef NDEBUG
16
16
  #undef NITRO_DEBUG
17
17
  #endif
18
+ #ifdef ANDROID
19
+ #ifndef NDEBUG
20
+ #define NITRO_DEBUG
21
+ #endif
22
+ #endif
18
23
 
19
24
  // Helper to find out if a C++ compiler attribute is available
20
25
  #ifdef __has_attribute
@@ -88,4 +88,12 @@ inline std::vector<std::string> getAnyObjectKeys(const AnyObject& object) {
88
88
  return keys;
89
89
  }
90
90
 
91
+ inline AnyValue getAnyObjectValue(const AnyObject& object, const std::string& key) {
92
+ auto item = object.find(key);
93
+ if (item == object.end()) {
94
+ throw std::runtime_error("Couldn't find " + key + " in AnyObject!");
95
+ }
96
+ return item->second;
97
+ }
98
+
91
99
  } // namespace margelo::nitro
@@ -11,12 +11,13 @@ import Foundation
11
11
  * Represents any value representable by the `AnyMap`.
12
12
  * Note: Arrays are currently not implemented due to a Swift compiler bug https://github.com/swiftlang/swift/issues/75994
13
13
  */
14
- public enum AnyValue {
14
+ public indirect enum AnyValue {
15
15
  case null
16
16
  case number(Double)
17
17
  case bool(Bool)
18
18
  case bigint(Int64)
19
19
  case string(String)
20
+ case array(Array<AnyValue>)
20
21
  case object(Dictionary<String, AnyValue>)
21
22
 
22
23
  static func create(_ value: margelo.nitro.AnyValue) -> AnyValue {
@@ -30,6 +31,8 @@ public enum AnyValue {
30
31
  return .bigint(margelo.nitro.get_AnyValue_bigint(value))
31
32
  } else if margelo.nitro.is_AnyValue_string(value) {
32
33
  return .string(margelo.nitro.get_AnyValue_string(value).toSwift())
34
+ } else if margelo.nitro.is_AnyValue_AnyArray(value) {
35
+ return .array(margelo.nitro.get_AnyValue_AnyArray(value).toSwift())
33
36
  } else if margelo.nitro.is_AnyValue_AnyObject(value) {
34
37
  return .object(margelo.nitro.get_AnyValue_AnyObject(value).toSwift())
35
38
  } else {
@@ -42,22 +45,18 @@ public enum AnyValue {
42
45
  * Represents an `AnyMap` that can be passed to Swift.
43
46
  */
44
47
  public class AnyMapHolder {
45
- let _cppPart: margelo.nitro.TSharedMap
46
-
47
- public var cppPart: margelo.nitro.TSharedMap {
48
- return _cppPart
49
- }
48
+ public let cppPart: margelo.nitro.TSharedMap
50
49
 
51
50
  public init() {
52
- _cppPart = margelo.nitro.AnyMap.make()
51
+ cppPart = margelo.nitro.AnyMap.make()
53
52
  }
54
53
 
55
54
  public init(withPreallocatedSize size: Int) {
56
- _cppPart = margelo.nitro.AnyMap.make(size)
55
+ cppPart = margelo.nitro.AnyMap.make(size)
57
56
  }
58
57
 
59
- public init(withCppPart cppPart: margelo.nitro.TSharedMap) {
60
- _cppPart = cppPart
58
+ public init(withCppPart otherCppPart: margelo.nitro.TSharedMap) {
59
+ cppPart = otherCppPart
61
60
  }
62
61
 
63
62
  // pragma MARK: Common Operations
@@ -66,21 +65,21 @@ public class AnyMapHolder {
66
65
  * Returns whether the given key exists in the map.
67
66
  */
68
67
  public func contains(key: String) -> Bool {
69
- return _cppPart.pointee.contains(std.string(key))
68
+ return cppPart.pointee.contains(std.string(key))
70
69
  }
71
70
 
72
71
  /**
73
72
  * Removes the given key from the map.
74
73
  */
75
74
  public func remove(key: String) {
76
- _cppPart.pointee.remove(std.string(key))
75
+ cppPart.pointee.remove(std.string(key))
77
76
  }
78
77
 
79
78
  /**
80
79
  * Removes all keys in this map.
81
80
  */
82
81
  public func clear() {
83
- _cppPart.pointee.clear()
82
+ cppPart.pointee.clear()
84
83
  }
85
84
 
86
85
  // pragma MARK: Getters
@@ -91,44 +90,54 @@ public class AnyMapHolder {
91
90
  * this function throws.
92
91
  */
93
92
  public func getDouble(key: String) -> Double {
94
- return _cppPart.pointee.getDouble(std.string(key))
93
+ return cppPart.pointee.getDouble(std.string(key))
95
94
  }
96
95
 
97
96
  /**
98
- * Gets the double value at the given key.
97
+ * Gets the boolean value at the given key.
99
98
  * If no value exists at the given key, or if it is not a double,
100
99
  * this function throws.
101
100
  */
102
101
  public func getBoolean(key: String) -> Bool {
103
- return _cppPart.pointee.getBoolean(std.string(key))
102
+ return cppPart.pointee.getBoolean(std.string(key))
104
103
  }
105
104
 
106
105
  /**
107
- * Gets the double value at the given key.
106
+ * Gets the bigint value at the given key.
108
107
  * If no value exists at the given key, or if it is not a double,
109
108
  * this function throws.
110
109
  */
111
110
  public func getBigInt(key: String) -> Int64 {
112
- return _cppPart.pointee.getBigInt(std.string(key))
111
+ return cppPart.pointee.getBigInt(std.string(key))
113
112
  }
114
113
 
115
114
  /**
116
- * Gets the double value at the given key.
115
+ * Gets the string value at the given key.
117
116
  * If no value exists at the given key, or if it is not a double,
118
117
  * this function throws.
119
118
  */
120
119
  public func getString(key: String) -> String {
121
- let value = _cppPart.pointee.getString(std.string(key))
120
+ let value = cppPart.pointee.getString(std.string(key))
122
121
  return String(value)
123
122
  }
124
-
123
+
125
124
  /**
126
- * Gets the double value at the given key.
125
+ * Gets the array value at the given key.
126
+ * If no value exists at the given key, or if it is not a double,
127
+ * this function throws.
128
+ */
129
+ public func getArray(key: String) -> [AnyValue] {
130
+ let value = cppPart.pointee.getArray(std.string(key))
131
+ return value.toSwift()
132
+ }
133
+
134
+ /**
135
+ * Gets the object value at the given key.
127
136
  * If no value exists at the given key, or if it is not a double,
128
137
  * this function throws.
129
138
  */
130
139
  public func getObject(key: String) -> Dictionary<String, AnyValue> {
131
- let value = _cppPart.pointee.getObject(std.string(key))
140
+ let value = cppPart.pointee.getObject(std.string(key))
132
141
  return value.toSwift()
133
142
  }
134
143
 
@@ -138,42 +147,49 @@ public class AnyMapHolder {
138
147
  * Set the given key to `null`.
139
148
  */
140
149
  public func setNull(key: String) {
141
- _cppPart.pointee.setNull(std.string(key))
150
+ cppPart.pointee.setNull(std.string(key))
142
151
  }
143
152
 
144
153
  /**
145
154
  * Set the given key to the given double value.
146
155
  */
147
156
  public func setDouble(key: String, value: Double) {
148
- _cppPart.pointee.setDouble(std.string(key), value)
157
+ cppPart.pointee.setDouble(std.string(key), value)
149
158
  }
150
159
 
151
160
  /**
152
161
  * Set the given key to the given boolean value.
153
162
  */
154
163
  public func setBoolean(key: String, value: Bool) {
155
- _cppPart.pointee.setBoolean(std.string(key), value)
164
+ cppPart.pointee.setBoolean(std.string(key), value)
156
165
  }
157
166
 
158
167
  /**
159
168
  * Set the given key to the given bigint value.
160
169
  */
161
170
  public func setBigInt(key: String, value: Int64) {
162
- _cppPart.pointee.setBigInt(std.string(key), value)
171
+ cppPart.pointee.setBigInt(std.string(key), value)
163
172
  }
164
173
 
165
174
  /**
166
175
  * Set the given key to the given string value.
167
176
  */
168
177
  public func setString(key: String, value: String) {
169
- _cppPart.pointee.setString(std.string(key), std.string(value))
178
+ cppPart.pointee.setString(std.string(key), std.string(value))
170
179
  }
171
-
180
+
181
+ /**
182
+ * Set the given key to the given array value.
183
+ */
184
+ public func setArray(key: String, value: [AnyValue]) {
185
+ cppPart.pointee.setArray(std.string(key), margelo.nitro.AnyArray.create(value))
186
+ }
187
+
172
188
  /**
173
189
  * Set the given key to the given object value.
174
190
  */
175
191
  public func setObject(key: String, value: Dictionary<String, AnyValue>) {
176
- _cppPart.pointee.setObject(std.string(key), margelo.nitro.AnyObject.create(value))
192
+ cppPart.pointee.setObject(std.string(key), margelo.nitro.AnyObject.create(value))
177
193
  }
178
194
 
179
195
  // pragma MARK: Is Getters
@@ -182,42 +198,49 @@ public class AnyMapHolder {
182
198
  * Gets whether the given `key` is holding a null value, or not.
183
199
  */
184
200
  public func isNull(key: String) -> Bool {
185
- return _cppPart.pointee.isNull(std.string(key))
201
+ return cppPart.pointee.isNull(std.string(key))
186
202
  }
187
203
 
188
204
  /**
189
205
  * Gets whether the given `key` is holding a double value, or not.
190
206
  */
191
207
  public func isDouble(key: String) -> Bool {
192
- return _cppPart.pointee.isDouble(std.string(key))
208
+ return cppPart.pointee.isDouble(std.string(key))
193
209
  }
194
210
 
195
211
  /**
196
212
  * Gets whether the given `key` is holding a boolean value, or not.
197
213
  */
198
214
  public func isBool(key: String) -> Bool {
199
- return _cppPart.pointee.isBoolean(std.string(key))
215
+ return cppPart.pointee.isBoolean(std.string(key))
200
216
  }
201
217
 
202
218
  /**
203
219
  * Gets whether the given `key` is holding a bigint value, or not.
204
220
  */
205
221
  public func isBigInt(key: String) -> Bool {
206
- return _cppPart.pointee.isBigInt(std.string(key))
222
+ return cppPart.pointee.isBigInt(std.string(key))
207
223
  }
208
224
 
209
225
  /**
210
226
  * Gets whether the given `key` is holding a string value, or not.
211
227
  */
212
228
  public func isString(key: String) -> Bool {
213
- return _cppPart.pointee.isString(std.string(key))
229
+ return cppPart.pointee.isString(std.string(key))
214
230
  }
215
-
231
+
216
232
  /**
217
- * Gets whether the given `key` is holding a object value, or not.
233
+ * Gets whether the given `key` is holding an array value, or not.
234
+ */
235
+ public func isArray(key: String) -> Bool {
236
+ return cppPart.pointee.isArray(std.string(key))
237
+ }
238
+
239
+ /**
240
+ * Gets whether the given `key` is holding an object value, or not.
218
241
  */
219
242
  public func isObject(key: String) -> Bool {
220
- return _cppPart.pointee.isObject(std.string(key))
243
+ return cppPart.pointee.isObject(std.string(key))
221
244
  }
222
245
  }
223
246
 
@@ -236,6 +259,8 @@ extension margelo.nitro.AnyValue {
236
259
  return create(bigint)
237
260
  case .string(let string):
238
261
  return create(string)
262
+ case .array(let array):
263
+ return create(array)
239
264
  case .object(let object):
240
265
  return create(object)
241
266
  }
@@ -309,7 +334,8 @@ extension margelo.nitro.AnyObject {
309
334
  let keys = margelo.nitro.getAnyObjectKeys(self)
310
335
  var dictionary = Dictionary<String, AnyValue>(minimumCapacity: keys.size())
311
336
  for key in keys {
312
-
337
+ let value = margelo.nitro.getAnyObjectValue(self, key)
338
+ dictionary[String(key)] = AnyValue.create(value)
313
339
  }
314
340
  return dictionary
315
341
  }
@@ -7,7 +7,6 @@ export interface Spec extends TurboModule {
7
7
  getAllHybridObjectNames(): string[];
8
8
  hasNativeState(obj: UnsafeObject): boolean;
9
9
  removeNativeState(obj: UnsafeObject): void;
10
- buildType: 'debug' | 'release';
11
10
  }
12
11
  export declare function getNativeNitroModules(): Spec;
13
12
  declare global {
@@ -1,4 +1,15 @@
1
1
  import type { HybridObject } from './HybridObject';
2
+ /**
3
+ * Represents a boxed {@linkcode HybridObject} that can later be unboxed again.
4
+ * This is implemented as a `jsi::HostObject`.
5
+ */
6
+ export interface BoxedHybridObject<T extends HybridObject> {
7
+ /**
8
+ * Unboxes the {@linkcode HybridObject}.
9
+ * This can be called from a different Runtime than the one it was boxed in.
10
+ */
11
+ unbox(): T;
12
+ }
2
13
  /**
3
14
  * A lazy proxy for initializing Nitro Modules HybridObjects.
4
15
  */
@@ -45,4 +56,28 @@ export declare const NitroModules: {
45
56
  * preprocessor flag.
46
57
  */
47
58
  readonly buildType: "debug" | "release";
59
+ /**
60
+ * Boxes the given {@linkcode hybridObject} into a {@linkcode BoxedHybridObject<T>}, which can
61
+ * later be unboxed in a separate Runtime.
62
+ *
63
+ * While Nitro is runtime-agnostic and all `HybridObject`s can be used from a any Runtime,
64
+ * some threading/worklet libraries (like [react-native-worklets-core](https://github.com/margelo/react-native-worklets-core))
65
+ * do not yet support copying over `HybridObject`s as they use newer JSI APIs like `jsi::NativeState`.
66
+ *
67
+ * While those APIs are not yet available, you can still use every Nitro Hybrid Object in a separate
68
+ * Runtime/Worklet context by just boxing it yourself:
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const something = NitroModules.createHybridObject<Something>('Something')
73
+ * const boxed = NitroModules.box(something)
74
+ * const context = Worklets.createContext('DummyContext')
75
+ * context.runAsync(() => {
76
+ * 'worklet'
77
+ * const unboxed = boxed.unbox()
78
+ * console.log(unboxed.name) // --> "Something"
79
+ * })
80
+ * ```
81
+ */
82
+ box<T extends HybridObject>(hybridObject: T): BoxedHybridObject<T>;
48
83
  };
@@ -64,4 +64,31 @@ export const NitroModules = {
64
64
  const nitro = getNativeNitroModules();
65
65
  return nitro.buildType;
66
66
  },
67
+ /**
68
+ * Boxes the given {@linkcode hybridObject} into a {@linkcode BoxedHybridObject<T>}, which can
69
+ * later be unboxed in a separate Runtime.
70
+ *
71
+ * While Nitro is runtime-agnostic and all `HybridObject`s can be used from a any Runtime,
72
+ * some threading/worklet libraries (like [react-native-worklets-core](https://github.com/margelo/react-native-worklets-core))
73
+ * do not yet support copying over `HybridObject`s as they use newer JSI APIs like `jsi::NativeState`.
74
+ *
75
+ * While those APIs are not yet available, you can still use every Nitro Hybrid Object in a separate
76
+ * Runtime/Worklet context by just boxing it yourself:
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * const something = NitroModules.createHybridObject<Something>('Something')
81
+ * const boxed = NitroModules.box(something)
82
+ * const context = Worklets.createContext('DummyContext')
83
+ * context.runAsync(() => {
84
+ * 'worklet'
85
+ * const unboxed = boxed.unbox()
86
+ * console.log(unboxed.name) // --> "Something"
87
+ * })
88
+ * ```
89
+ */
90
+ box(hybridObject) {
91
+ const nitro = getNativeNitroModules();
92
+ return nitro.box(hybridObject);
93
+ },
67
94
  };
@@ -2,12 +2,13 @@ import type { TurboModule } from 'react-native';
2
2
  import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
3
3
  export interface NativeNitroSpec extends TurboModule {
4
4
  install(): void;
5
- createHybridObject(name: string, args?: UnsafeObject): UnsafeObject;
5
+ createHybridObject(name: string): UnsafeObject;
6
6
  hasHybridObject(name: string): boolean;
7
7
  getAllHybridObjectNames(): string[];
8
8
  hasNativeState(obj: UnsafeObject): boolean;
9
9
  removeNativeState(obj: UnsafeObject): void;
10
10
  buildType: 'debug' | 'release';
11
+ box(obj: UnsafeObject): UnsafeObject;
11
12
  }
12
13
  export declare function getNativeNitroModules(): NativeNitroSpec;
13
14
  declare global {