expo-modules-jsi 56.0.8 → 56.0.10
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/CHANGELOG.md +13 -0
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift +11 -0
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptObject.swift +24 -0
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptPromise.swift +10 -8
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptUnownedValue.swift +137 -0
- package/apple/Tests/JavaScriptObjectTests.swift +23 -0
- package/apple/Tests/JavaScriptPromiseTests.swift +17 -0
- package/apple/Tests/JavaScriptUnownedValueTests.swift +78 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 56.0.10 — 2026-06-15
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Ignore already-settled promises. ([#46765](https://github.com/expo/expo/pull/46765) by [@jakex7](https://github.com/jakex7))
|
|
18
|
+
|
|
19
|
+
## 56.0.9 — 2026-06-10
|
|
20
|
+
|
|
21
|
+
### 🎉 New features
|
|
22
|
+
|
|
23
|
+
- [iOS] Add closure-taking `JavaScriptObject.setProperty(_:function:)` overloads that create a sync or async host function from the given closure. ([#46622](https://github.com/expo/expo/pull/46622) by [@tsapeta](https://github.com/tsapeta))
|
|
24
|
+
- [iOS] Add `JavaScriptUnownedValue`, a non-owning, non-copyable value that borrows a `jsi::Value` for the zero-copy argument-decode fast path. ([#46616](https://github.com/expo/expo/pull/46616) by [@tsapeta](https://github.com/tsapeta))
|
|
25
|
+
|
|
13
26
|
## 56.0.8 — 2026-06-05
|
|
14
27
|
|
|
15
28
|
### 🐛 Bug fixes
|
|
@@ -61,6 +61,17 @@ public struct JavaScriptValuesBuffer: JavaScriptType, ~Copyable {
|
|
|
61
61
|
return JavaScriptValue(runtime, bufferPointer[index])
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/// Returns a non-owning, non-copyable value borrowing the element at `index` for the zero-copy decode
|
|
65
|
+
/// path. It borrows the `jsi::Value` this buffer owns, so it is valid only while the buffer is alive
|
|
66
|
+
/// and must not be stored or escaped — see ``JavaScriptUnownedValue``.
|
|
67
|
+
///
|
|
68
|
+
/// Unlike `subscript(_:)`, this is unchecked: `index` must be in `0..<count`. The accessor force-unwraps
|
|
69
|
+
/// `baseAddress`, so passing any index into an empty buffer crashes, and an out-of-range index reads past
|
|
70
|
+
/// the buffer. The caller is responsible for the bounds check.
|
|
71
|
+
public func unownedValue(at index: Int) -> JavaScriptUnownedValue {
|
|
72
|
+
return JavaScriptUnownedValue(runtime, bufferPointer.baseAddress! + index)
|
|
73
|
+
}
|
|
74
|
+
|
|
64
75
|
@discardableResult
|
|
65
76
|
internal consuming func set<T: JSIRepresentable>(value: borrowing T, atIndex index: Int) -> JavaScriptValuesBuffer
|
|
66
77
|
where T: ~Copyable {
|
|
@@ -256,6 +256,30 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
256
256
|
expo.setProperty(runtime.pointee, pointee, name, facebook.jsi.Value(runtime.pointee, object.pointee))
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
/// Sets a property to a synchronous host function created from the given closure. The function
|
|
260
|
+
/// is named after the property and runs the closure when called from JavaScript, returning its
|
|
261
|
+
/// result synchronously. Equivalent to `setProperty(name, runtime.createFunction(name) { … })`.
|
|
262
|
+
@JavaScriptActor
|
|
263
|
+
public func setProperty(_ name: String, function: sending @escaping JavaScriptRuntime.SyncFunctionClosure) {
|
|
264
|
+
guard let runtime else {
|
|
265
|
+
FatalError.runtimeLost()
|
|
266
|
+
}
|
|
267
|
+
setProperty(name, value: runtime.createFunction(name, function))
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/// Sets a property to an asynchronous host function created from the given closure. The function
|
|
271
|
+
/// is named after the property and runs the closure when called from JavaScript, returning a
|
|
272
|
+
/// promise that resolves with its result. Equivalent to
|
|
273
|
+
/// `setProperty(name, runtime.createAsyncFunction(name) { … })`. The `async` closure body
|
|
274
|
+
/// selects this overload over the synchronous `setProperty(_:_:)`.
|
|
275
|
+
@JavaScriptActor
|
|
276
|
+
public func setProperty(_ name: String, function: sending @escaping JavaScriptRuntime.AsyncFunctionClosure) {
|
|
277
|
+
guard let runtime else {
|
|
278
|
+
FatalError.runtimeLost()
|
|
279
|
+
}
|
|
280
|
+
setProperty(name, value: runtime.createAsyncFunction(name, function))
|
|
281
|
+
}
|
|
282
|
+
|
|
259
283
|
/// Deletes a property with the given name. After calling this function,
|
|
260
284
|
/// `hasProperty` will return `false`, and `getProperty` will return `undefined` value.
|
|
261
285
|
#if !os(macOS)
|
|
@@ -75,15 +75,16 @@ public struct JavaScriptPromise: JavaScriptType, ~Copyable {
|
|
|
75
75
|
guard let runtime else {
|
|
76
76
|
return
|
|
77
77
|
}
|
|
78
|
-
guard !resolveFunction.isEmpty else {
|
|
79
|
-
preconditionFailure("Cannot settle a promise more than once")
|
|
80
|
-
}
|
|
81
78
|
|
|
82
79
|
// `resolve` is not isolated, so make sure to jump to JS thread.
|
|
83
80
|
runtime.schedule(priority: .immediate) { [resolveFunction, rejectFunction] in
|
|
81
|
+
// If the promise is already settled, do nothing.
|
|
82
|
+
guard let resolver = resolveFunction.take() else {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
84
85
|
// Call the actual resolver given in the Promise setup.
|
|
85
86
|
// This will also call `deferredPromise.resolve` in the `then` handler.
|
|
86
|
-
_ = try!
|
|
87
|
+
_ = try! resolver.getFunction().call(arguments: value)
|
|
87
88
|
|
|
88
89
|
// Release the rejecter, we cannot call it anymore.
|
|
89
90
|
rejectFunction.release()
|
|
@@ -94,19 +95,20 @@ public struct JavaScriptPromise: JavaScriptType, ~Copyable {
|
|
|
94
95
|
guard let runtime else {
|
|
95
96
|
return
|
|
96
97
|
}
|
|
97
|
-
guard !rejectFunction.isEmpty else {
|
|
98
|
-
preconditionFailure("Cannot settle a promise more than once")
|
|
99
|
-
}
|
|
100
98
|
|
|
101
99
|
// `reject` is not isolated, so make sure to jump to JS thread.
|
|
102
100
|
runtime.schedule(priority: .immediate) { [resolveFunction, rejectFunction] in
|
|
101
|
+
// If the promise is already settled, do nothing.
|
|
102
|
+
guard let rejecter = rejectFunction.take() else {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
103
105
|
// Create a JS error from any (native) error.
|
|
104
106
|
let errorMessage = String(describing: error)
|
|
105
107
|
let errorValue = JavaScriptError(runtime, message: errorMessage).asValue()
|
|
106
108
|
|
|
107
109
|
// Call the actual rejecter given in the Promise setup.
|
|
108
110
|
// This will also call `deferredPromise.reject` in the `then` handler.
|
|
109
|
-
_ = try!
|
|
111
|
+
_ = try! rejecter.getFunction().call(arguments: errorValue)
|
|
110
112
|
|
|
111
113
|
// Release the resolver, we cannot call it anymore.
|
|
112
114
|
resolveFunction.release()
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// Copyright 2025-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
internal import ExpoModulesJSI_Cxx
|
|
4
|
+
import Foundation
|
|
5
|
+
internal import jsi
|
|
6
|
+
|
|
7
|
+
/// A non-owning, non-copyable `JavaScriptValue` that borrows a `facebook.jsi.Value` owned elsewhere —
|
|
8
|
+
/// typically an argument still living in the `JavaScriptValuesBuffer` for the duration of a host
|
|
9
|
+
/// function call.
|
|
10
|
+
///
|
|
11
|
+
/// Unlike ``JavaScriptValue`` (a `final class` that owns its `jsi::Value`) and ``JavaScriptRef``
|
|
12
|
+
/// (an owning reference that promotes a value to reference semantics so it *can* escape), an unowned
|
|
13
|
+
/// value owns nothing: it borrows a `jsi::Value` whose lifetime is guaranteed by someone else. It
|
|
14
|
+
/// exists to feed the argument-decode fast path, where wrapping each argument in a heap-allocated
|
|
15
|
+
/// owning `JavaScriptValue` (ARC plus a real `jsi::Value` copy, per argument, per call) is pure
|
|
16
|
+
/// overhead — `decode` only needs to *read* the argument long enough to extract a `Double`/`String`/etc.
|
|
17
|
+
///
|
|
18
|
+
/// > Warning: Lifetime safety rests on convention, not the compiler. `~Copyable` prevents *aliasing*
|
|
19
|
+
/// > the value but does not enforce that the owning buffer outlives it. Unlike Swift's `unowned(safe)`
|
|
20
|
+
/// > class refs, there is no trap on use-after-free. The contract is "valid only within the synchronous
|
|
21
|
+
/// > decode call, while the owner is alive" — which the buffer-driven decode path honors because it
|
|
22
|
+
/// > reads the value inline on the JS thread before the buffer is torn down. Do not store, capture, or
|
|
23
|
+
/// > escape it; call ``copied()`` to materialize an owning value when escape is needed.
|
|
24
|
+
public struct JavaScriptUnownedValue: ~Copyable {
|
|
25
|
+
// Borrows the `jsi::Value` at this address; it does not own it and must not outlive the owner.
|
|
26
|
+
internal let pointer: UnsafePointer<facebook.jsi.Value>
|
|
27
|
+
|
|
28
|
+
// Non-optional `unowned`, matching `JavaScriptValuesBuffer.runtime`: it is strictly call-scoped and
|
|
29
|
+
// cannot outlive the runtime executing the call, so we skip both the ARC traffic and the optional unwrap
|
|
30
|
+
// that the owning `JavaScriptValue` pays.
|
|
31
|
+
internal unowned let runtime: JavaScriptRuntime
|
|
32
|
+
|
|
33
|
+
internal init(_ runtime: JavaScriptRuntime, _ pointer: UnsafePointer<facebook.jsi.Value>) {
|
|
34
|
+
self.runtime = runtime
|
|
35
|
+
self.pointer = pointer
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Materializes an owning ``JavaScriptValue`` by copying the borrowed `jsi::Value`. Use it when the
|
|
39
|
+
/// value must outlive the decode call (stored, captured, handed to a `Promise`).
|
|
40
|
+
public func copied() -> JavaScriptValue {
|
|
41
|
+
return JavaScriptValue(runtime, pointer.pointee)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// MARK: - Type checks
|
|
45
|
+
|
|
46
|
+
public func isUndefined() -> Bool {
|
|
47
|
+
return pointer.pointee.isUndefined()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public func isNull() -> Bool {
|
|
51
|
+
return pointer.pointee.isNull()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public func isBool() -> Bool {
|
|
55
|
+
return pointer.pointee.isBool()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public func isNumber() -> Bool {
|
|
59
|
+
return pointer.pointee.isNumber()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public func isString() -> Bool {
|
|
63
|
+
return pointer.pointee.isString()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public func isSymbol() -> Bool {
|
|
67
|
+
return pointer.pointee.isSymbol()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public func isBigInt() -> Bool {
|
|
71
|
+
return pointer.pointee.isBigInt()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public func isObject() -> Bool {
|
|
75
|
+
return pointer.pointee.isObject()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// MARK: - Primitive accessors
|
|
79
|
+
|
|
80
|
+
/// Returns the value as a boolean, or asserts if not a boolean.
|
|
81
|
+
public func getBool() -> Bool {
|
|
82
|
+
assert(isBool(), "Value is not a boolean")
|
|
83
|
+
return pointer.pointee.getBool()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// Returns the value as an integer, or asserts if not a number.
|
|
87
|
+
public func getInt() -> Int {
|
|
88
|
+
assert(isNumber(), "Value is not a number")
|
|
89
|
+
return Int(pointer.pointee.getNumber())
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Returns the value as a double, or asserts if not a number.
|
|
93
|
+
public func getDouble() -> Double {
|
|
94
|
+
assert(isNumber(), "Value is not a number")
|
|
95
|
+
return pointer.pointee.getNumber()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// Returns the value as a string, or asserts if not a string.
|
|
99
|
+
public func getString() -> String {
|
|
100
|
+
assert(isString(), "Value is not a string")
|
|
101
|
+
return String(pointer.pointee.getString(runtime.pointee).utf8(runtime.pointee))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// MARK: - Throwing conversions ("as functions")
|
|
105
|
+
|
|
106
|
+
/// Returns the value as a boolean, or throws `TypeError` if it is not a boolean.
|
|
107
|
+
public func asBool() throws(JavaScriptValue.TypeError) -> Bool {
|
|
108
|
+
guard isBool() else {
|
|
109
|
+
throw JavaScriptValue.TypeError(type: Bool.self)
|
|
110
|
+
}
|
|
111
|
+
return getBool()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Returns the value as an integer, or throws `TypeError` if it is not a number.
|
|
115
|
+
public func asInt() throws(JavaScriptValue.TypeError) -> Int {
|
|
116
|
+
guard isNumber() else {
|
|
117
|
+
throw JavaScriptValue.TypeError(type: Int.self)
|
|
118
|
+
}
|
|
119
|
+
return getInt()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// Returns the value as a double, or throws `TypeError` if it is not a number.
|
|
123
|
+
public func asDouble() throws(JavaScriptValue.TypeError) -> Double {
|
|
124
|
+
guard isNumber() else {
|
|
125
|
+
throw JavaScriptValue.TypeError(type: Double.self)
|
|
126
|
+
}
|
|
127
|
+
return getDouble()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Returns the value as a string, or throws `TypeError` if it is not a string.
|
|
131
|
+
public func asString() throws(JavaScriptValue.TypeError) -> String {
|
|
132
|
+
guard isString() else {
|
|
133
|
+
throw JavaScriptValue.TypeError(type: String.self)
|
|
134
|
+
}
|
|
135
|
+
return getString()
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -223,6 +223,29 @@ struct JavaScriptObjectTests {
|
|
|
223
223
|
#expect(try object.getPropertyAsObject("nested").getProperty("value").getInt() == 42)
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
@Test
|
|
227
|
+
@JavaScriptActor
|
|
228
|
+
func `set property with sync function closure`() throws {
|
|
229
|
+
let object = JavaScriptObject(runtime)
|
|
230
|
+
object.setProperty("double") { this, arguments in
|
|
231
|
+
return JavaScriptValue(self.runtime, arguments[0].getInt() * 2)
|
|
232
|
+
}
|
|
233
|
+
let fn = try object.getPropertyAsFunction("double")
|
|
234
|
+
#expect(try fn.call(arguments: 21).getInt() == 42)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@Test
|
|
238
|
+
@JavaScriptActor
|
|
239
|
+
func `set property with async function closure`() async throws {
|
|
240
|
+
let object = JavaScriptObject(runtime)
|
|
241
|
+
object.setProperty("addAsync") { this, arguments async throws in
|
|
242
|
+
return JavaScriptValue(self.runtime, arguments[0].getInt() + arguments[1].getInt())
|
|
243
|
+
}
|
|
244
|
+
let fn = try object.getPropertyAsFunction("addAsync")
|
|
245
|
+
let result = try await fn.call(arguments: 20, 22).getPromise().await()
|
|
246
|
+
#expect(result.getInt() == 42)
|
|
247
|
+
}
|
|
248
|
+
|
|
226
249
|
@Test
|
|
227
250
|
func `delete property`() {
|
|
228
251
|
let object = JavaScriptObject(runtime)
|
|
@@ -279,6 +279,23 @@ struct JavaScriptPromiseTests {
|
|
|
279
279
|
#expect(result.getInt() == 99)
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
@Test
|
|
283
|
+
func `settling promise more than once is ignored`() async throws {
|
|
284
|
+
struct TestError: Error, Sendable {}
|
|
285
|
+
|
|
286
|
+
let runtime = JavaScriptRuntime()
|
|
287
|
+
let promise = try JavaScriptPromise(runtime)
|
|
288
|
+
|
|
289
|
+
runtime.global().setProperty("testPromise", value: promise.asValue())
|
|
290
|
+
promise.resolve(42)
|
|
291
|
+
promise.reject(TestError())
|
|
292
|
+
promise.resolve(100)
|
|
293
|
+
|
|
294
|
+
let result = try await promise.await()
|
|
295
|
+
|
|
296
|
+
#expect(result.getInt() == 42)
|
|
297
|
+
}
|
|
298
|
+
|
|
282
299
|
@Test
|
|
283
300
|
func `promise all`() async throws {
|
|
284
301
|
let runtime = JavaScriptRuntime()
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import ExpoModulesJSI
|
|
2
|
+
import Testing
|
|
3
|
+
|
|
4
|
+
@Suite
|
|
5
|
+
@JavaScriptActor
|
|
6
|
+
struct JavaScriptUnownedValueTests {
|
|
7
|
+
let runtime = JavaScriptRuntime()
|
|
8
|
+
|
|
9
|
+
@Test
|
|
10
|
+
func `reads primitives without copying`() {
|
|
11
|
+
let buffer = JavaScriptValuesBuffer.allocate(in: runtime, with: 42, "hello", true)
|
|
12
|
+
|
|
13
|
+
// The view is `~Copyable`, so compare accessor results against literals rather than passing the
|
|
14
|
+
// view into `#expect` — the macro captures its operand and would otherwise require `Copyable`.
|
|
15
|
+
let number = buffer.unownedValue(at: 0)
|
|
16
|
+
#expect(number.isNumber() == true)
|
|
17
|
+
#expect(number.getInt() == 42)
|
|
18
|
+
#expect(number.getDouble() == 42)
|
|
19
|
+
|
|
20
|
+
let string = buffer.unownedValue(at: 1)
|
|
21
|
+
#expect(string.isString() == true)
|
|
22
|
+
#expect(string.getString() == "hello")
|
|
23
|
+
|
|
24
|
+
let bool = buffer.unownedValue(at: 2)
|
|
25
|
+
#expect(bool.isBool() == true)
|
|
26
|
+
#expect(bool.getBool() == true)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Test
|
|
30
|
+
func `recognizes null and undefined`() {
|
|
31
|
+
let buffer = JavaScriptValuesBuffer.allocate(in: runtime, with: JavaScriptValue.null, JavaScriptValue.undefined)
|
|
32
|
+
|
|
33
|
+
let null = buffer.unownedValue(at: 0)
|
|
34
|
+
#expect(null.isNull() == true)
|
|
35
|
+
#expect(null.isUndefined() == false)
|
|
36
|
+
|
|
37
|
+
let undefined = buffer.unownedValue(at: 1)
|
|
38
|
+
#expect(undefined.isUndefined() == true)
|
|
39
|
+
#expect(undefined.isNull() == false)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Test
|
|
43
|
+
func `throwing accessors validate the type`() throws {
|
|
44
|
+
let buffer = JavaScriptValuesBuffer.allocate(in: runtime, with: 42, "hello")
|
|
45
|
+
|
|
46
|
+
#expect(try buffer.unownedValue(at: 0).asInt() == 42)
|
|
47
|
+
#expect(try buffer.unownedValue(at: 0).asDouble() == 42)
|
|
48
|
+
#expect(try buffer.unownedValue(at: 1).asString() == "hello")
|
|
49
|
+
|
|
50
|
+
#expect(throws: JavaScriptValue.TypeError.self) {
|
|
51
|
+
try buffer.unownedValue(at: 0).asString()
|
|
52
|
+
}
|
|
53
|
+
#expect(throws: JavaScriptValue.TypeError.self) {
|
|
54
|
+
try buffer.unownedValue(at: 1).asInt()
|
|
55
|
+
}
|
|
56
|
+
#expect(throws: JavaScriptValue.TypeError.self) {
|
|
57
|
+
try buffer.unownedValue(at: 1).asBool()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Test
|
|
62
|
+
func `copied materializes an owning value`() throws {
|
|
63
|
+
let buffer = JavaScriptValuesBuffer.allocate(in: runtime, with: "owned")
|
|
64
|
+
let owning = buffer.unownedValue(at: 0).copied()
|
|
65
|
+
|
|
66
|
+
#expect(try owning.asString() == "owned")
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@Test
|
|
70
|
+
func `recognizes objects`() {
|
|
71
|
+
let object = runtime.createObject()
|
|
72
|
+
let buffer = JavaScriptValuesBuffer.allocate(in: runtime, with: object.asValue())
|
|
73
|
+
|
|
74
|
+
let view = buffer.unownedValue(at: 0)
|
|
75
|
+
#expect(view.isObject() == true)
|
|
76
|
+
#expect(view.isNumber() == false)
|
|
77
|
+
}
|
|
78
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-jsi",
|
|
3
|
-
"version": "56.0.
|
|
3
|
+
"version": "56.0.10",
|
|
4
4
|
"description": "The JavaScript Interface for Expo Modules",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"sideEffects": [],
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"./apple/scripts/test.sh"
|
|
42
42
|
]
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "812dc007aefed0c432c0439fdfe05ee2f4f21da2",
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "apple/scripts/build-xcframework.sh",
|
|
47
47
|
"swift:format": "../../scripts/swift-format.sh",
|