ping-openmls-sdk-react-native-macos 0.2.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/Frameworks/.gitkeep +0 -0
- package/Frameworks/libping_ffi.a +0 -0
- package/README.md +64 -0
- package/ios/.gitkeep +0 -0
- package/ios/Generated.swift +3239 -0
- package/ios/JSObserverBridge.swift +35 -0
- package/ios/JSStorageBridge.swift +135 -0
- package/ios/JSTransportBridge.swift +126 -0
- package/ios/PingNativeModule.m +143 -0
- package/ios/PingNativeModule.swift +656 -0
- package/ios/TypeBridge.swift +297 -0
- package/ios/module.modulemap +4 -0
- package/ios/pingFFI.h +990 -0
- package/package.json +34 -0
- package/ping-openmls-sdk-react-native-macos.podspec +54 -0
- package/src/MessagingClient.ts +488 -0
- package/src/NativePing.ts +162 -0
- package/src/WebSocketTransport.ts +118 -0
- package/src/clipboard.ts +37 -0
- package/src/index.ts +112 -0
- package/src/storage-bridge.ts +124 -0
- package/src/transport-bridge.ts +89 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Bridge that implements UniFFI's `MessageObserver` protocol by emitting RN events. The
|
|
2
|
+
// Rust core invokes `onApplicationMessage` / `onConversationUpdated` synchronously from
|
|
3
|
+
// its async tasks; we just forward to JS via the event emitter — no continuations needed
|
|
4
|
+
// because the Rust side doesn't wait for a return value.
|
|
5
|
+
//
|
|
6
|
+
// Same direction as Storage/Transport (Rust → JS) but simpler: fire-and-forget instead
|
|
7
|
+
// of round-trip.
|
|
8
|
+
//
|
|
9
|
+
// Spec: docs/RN_NATIVE_BINDINGS.md (stage 4e).
|
|
10
|
+
|
|
11
|
+
import Foundation
|
|
12
|
+
|
|
13
|
+
public typealias ObserverEventEmitter = (_ name: String, _ body: [String: Any]) -> Void
|
|
14
|
+
|
|
15
|
+
public final class JSObserverBridge: MessageObserver, @unchecked Sendable {
|
|
16
|
+
|
|
17
|
+
private let emit: ObserverEventEmitter
|
|
18
|
+
|
|
19
|
+
public init(emit: @escaping ObserverEventEmitter) {
|
|
20
|
+
self.emit = emit
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// MARK: - UniFFI MessageObserver protocol conformance
|
|
24
|
+
|
|
25
|
+
public func onApplicationMessage(msg: IncomingMessage) {
|
|
26
|
+
emit("PingApplicationMessage", TypeBridge.encodeIncomingMessage(msg))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public func onConversationUpdated(id: ConversationId, newEpoch: UInt64) {
|
|
30
|
+
emit("PingConversationUpdated", [
|
|
31
|
+
"conversation_id": TypeBridge.encodeConversationId(id),
|
|
32
|
+
"new_epoch": Int(newEpoch),
|
|
33
|
+
])
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Bridge that implements UniFFI's `Storage` protocol by marshalling each call across
|
|
2
|
+
// the Swift→JS→Swift boundary via RN's RCTEventEmitter. The Rust core (via UniFFI)
|
|
3
|
+
// invokes our methods asynchronously; we suspend on a CheckedContinuation, fire an
|
|
4
|
+
// event to JS, and the JS-side handler calls `PingNative.resolveStorageCall(id, value)`
|
|
5
|
+
// to wake us up.
|
|
6
|
+
//
|
|
7
|
+
// Stage 4a wires this class to the actual UniFFI `Storage` protocol — it can now be
|
|
8
|
+
// passed to `MessagingClient.init(storage: ...)` once stage 4b lands.
|
|
9
|
+
//
|
|
10
|
+
// Spec: docs/RN_NATIVE_BINDINGS.md (stage 4a).
|
|
11
|
+
|
|
12
|
+
import Foundation
|
|
13
|
+
|
|
14
|
+
/// Callback emitted by the bridge when it needs JS to handle a storage call. The
|
|
15
|
+
/// implementation is expected to dispatch an RN event with `body = {id, method, args}`.
|
|
16
|
+
public typealias StorageEventEmitter = (_ id: String, _ method: String, _ args: [String: Any]) -> Void
|
|
17
|
+
|
|
18
|
+
/// JS-backed implementation of UniFFI's `Storage` protocol. Each call is a JS event
|
|
19
|
+
/// round-trip; the Swift-side continuation is resumed from `PingNative` when the JS
|
|
20
|
+
/// handler reports back.
|
|
21
|
+
public final class JSStorageBridge: Storage, @unchecked Sendable {
|
|
22
|
+
|
|
23
|
+
private let emit: StorageEventEmitter
|
|
24
|
+
|
|
25
|
+
/// Pending Swift continuations keyed by call id. Mutations guarded by `lock`.
|
|
26
|
+
private var pending: [String: PendingCall] = [:]
|
|
27
|
+
private let lock = NSLock()
|
|
28
|
+
|
|
29
|
+
public init(emit: @escaping StorageEventEmitter) {
|
|
30
|
+
self.emit = emit
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// MARK: - UniFFI Storage protocol conformance
|
|
34
|
+
|
|
35
|
+
public func get(namespace: String, key: String) async throws -> Data? {
|
|
36
|
+
return try await call(method: "get",
|
|
37
|
+
args: ["namespace": namespace, "key": key],
|
|
38
|
+
decode: { TypeBridge.decodeBytes($0) })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public func put(namespace: String, key: String, value: Data) async throws {
|
|
42
|
+
let _: Bool = try await call(method: "put",
|
|
43
|
+
args: ["namespace": namespace,
|
|
44
|
+
"key": key,
|
|
45
|
+
"value": TypeBridge.encodeBytes(value)],
|
|
46
|
+
decode: { _ in true })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public func delete(namespace: String, key: String) async throws {
|
|
50
|
+
let _: Bool = try await call(method: "delete",
|
|
51
|
+
args: ["namespace": namespace, "key": key],
|
|
52
|
+
decode: { _ in true })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public func listKeys(namespace: String, prefix: String) async throws -> [String] {
|
|
56
|
+
return try await call(method: "listKeys",
|
|
57
|
+
args: ["namespace": namespace, "prefix": prefix],
|
|
58
|
+
decode: { value in (value as? [String]) ?? [] })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// MARK: - JS → Swift resumption hooks (called from PingNative)
|
|
62
|
+
|
|
63
|
+
public func resolve(id: String, value: Any?) {
|
|
64
|
+
lock.lock()
|
|
65
|
+
let call = pending.removeValue(forKey: id)
|
|
66
|
+
lock.unlock()
|
|
67
|
+
call?.resume(.success(value as Any))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public func reject(id: String, message: String) {
|
|
71
|
+
lock.lock()
|
|
72
|
+
let call = pending.removeValue(forKey: id)
|
|
73
|
+
lock.unlock()
|
|
74
|
+
// Rust expects a `PingError` for storage failures. UniFFI 0.28 generates flat
|
|
75
|
+
// error variants with a labeled `message: String` associated value; we forward
|
|
76
|
+
// the JS-side message verbatim so it shows up in Rust-side logs.
|
|
77
|
+
call?.resume(.failure(PingError.Storage(message: message)))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MARK: - Internals
|
|
81
|
+
|
|
82
|
+
private func call<T>(method: String,
|
|
83
|
+
args: [String: Any],
|
|
84
|
+
decode: @escaping (Any?) -> T) async throws -> T {
|
|
85
|
+
let id = UUID().uuidString
|
|
86
|
+
return try await withCheckedThrowingContinuation { continuation in
|
|
87
|
+
lock.lock()
|
|
88
|
+
pending[id] = PendingCall(continuation: ContinuationBox(decode: decode,
|
|
89
|
+
inner: continuation))
|
|
90
|
+
lock.unlock()
|
|
91
|
+
// Fire the event AFTER storing the continuation so a synchronously-resolving
|
|
92
|
+
// JS handler (unlikely but possible) doesn't race us.
|
|
93
|
+
emit(id, method, args)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// Erased pending call — the bridge must hold heterogeneously-typed continuations.
|
|
98
|
+
private struct PendingCall {
|
|
99
|
+
let continuation: AnyContinuation
|
|
100
|
+
func resume(_ result: Result<Any?, Error>) {
|
|
101
|
+
continuation.resume(result)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private protocol AnyContinuation {
|
|
106
|
+
func resume(_ result: Result<Any?, Error>)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private struct ContinuationBox<T>: AnyContinuation {
|
|
110
|
+
let decode: (Any?) -> T
|
|
111
|
+
let inner: CheckedContinuation<T, Error>
|
|
112
|
+
|
|
113
|
+
func resume(_ result: Result<Any?, Error>) {
|
|
114
|
+
switch result {
|
|
115
|
+
case .success(let value):
|
|
116
|
+
inner.resume(returning: decode(value))
|
|
117
|
+
case .failure(let error):
|
|
118
|
+
inner.resume(throwing: error)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// Bridge-internal errors. Rust expects `PingError` from Storage/Transport methods;
|
|
125
|
+
/// `BridgeError` is used for cases the bridge itself produces (decode failures) before
|
|
126
|
+
/// converting to `PingError.Codec`.
|
|
127
|
+
public enum BridgeError: Error, CustomStringConvertible {
|
|
128
|
+
case decodeFailure(String)
|
|
129
|
+
|
|
130
|
+
public var description: String {
|
|
131
|
+
switch self {
|
|
132
|
+
case .decodeFailure(let m): return "bridge decode failure: \(m)"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Bridge that implements UniFFI's `Transport` protocol by marshalling each call across
|
|
2
|
+
// the Swift→JS→Swift boundary. Same pattern as `JSStorageBridge`; isolated in its own
|
|
3
|
+
// class so the two bridges' pending-call tables don't collide on UUIDs.
|
|
4
|
+
//
|
|
5
|
+
// Stage 4a wires this to the real UniFFI `Transport` protocol. Stage 4b will pass an
|
|
6
|
+
// instance to `MessagingClient.init(transport: ...)`.
|
|
7
|
+
//
|
|
8
|
+
// Spec: docs/RN_NATIVE_BINDINGS.md (stage 4a).
|
|
9
|
+
|
|
10
|
+
import Foundation
|
|
11
|
+
|
|
12
|
+
public typealias TransportEventEmitter = (_ id: String, _ method: String, _ args: [String: Any]) -> Void
|
|
13
|
+
|
|
14
|
+
/// JS-backed implementation of UniFFI's `Transport` protocol.
|
|
15
|
+
public final class JSTransportBridge: Transport, @unchecked Sendable {
|
|
16
|
+
|
|
17
|
+
private let emit: TransportEventEmitter
|
|
18
|
+
|
|
19
|
+
private var pending: [String: PendingCall] = [:]
|
|
20
|
+
private let lock = NSLock()
|
|
21
|
+
|
|
22
|
+
public init(emit: @escaping TransportEventEmitter) {
|
|
23
|
+
self.emit = emit
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// MARK: - UniFFI Transport protocol conformance
|
|
27
|
+
|
|
28
|
+
public func send(envelope: MessageEnvelope) async throws {
|
|
29
|
+
let _: Bool = try await call(method: "send",
|
|
30
|
+
args: ["envelope": TypeBridge.encodeEnvelope(envelope)],
|
|
31
|
+
decode: { _ in true })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public func fetchSince(conversationId: ConversationId,
|
|
35
|
+
cursorToken: Data,
|
|
36
|
+
limit: UInt32) async throws -> [MessageEnvelope] {
|
|
37
|
+
// Args match the JS-side `Transport.fetchSince(conversationIdHex, cursorBase64, limit)`
|
|
38
|
+
// signature exactly — hex + base64 strings are smaller across the bridge than byte
|
|
39
|
+
// arrays and align with what the relay's `/sync` endpoint already speaks.
|
|
40
|
+
let convHex = conversationId.value.map { String(format: "%02x", $0) }.joined()
|
|
41
|
+
let cursorB64 = cursorToken.base64EncodedString()
|
|
42
|
+
return try await call(method: "fetchSince",
|
|
43
|
+
args: [
|
|
44
|
+
"conversationIdHex": convHex,
|
|
45
|
+
"cursorBase64": cursorB64,
|
|
46
|
+
"limit": Int(limit),
|
|
47
|
+
],
|
|
48
|
+
decode: { value in
|
|
49
|
+
// Best-effort decode; if JS returns malformed envelopes we return empty
|
|
50
|
+
// and let the SDK retry rather than throwing (resync is cheaper than crash).
|
|
51
|
+
guard let arr = value as? [[String: Any]] else { return [] }
|
|
52
|
+
return arr.compactMap { dict in
|
|
53
|
+
try? TypeBridge.decodeEnvelope(dict)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public func discoverDevices(userId: UserId) async throws -> [DiscoveredDevice] {
|
|
59
|
+
let userHex = userId.value.map { String(format: "%02x", $0) }.joined()
|
|
60
|
+
return try await call(method: "discoverDevices",
|
|
61
|
+
args: ["userIdHex": userHex],
|
|
62
|
+
decode: { value in
|
|
63
|
+
guard let arr = value as? [[String: Any]] else { return [] }
|
|
64
|
+
return arr.compactMap { dict in
|
|
65
|
+
try? TypeBridge.decodeDiscoveredDevice(dict)
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// MARK: - JS → Swift resumption hooks
|
|
71
|
+
|
|
72
|
+
public func resolve(id: String, value: Any?) {
|
|
73
|
+
lock.lock()
|
|
74
|
+
let call = pending.removeValue(forKey: id)
|
|
75
|
+
lock.unlock()
|
|
76
|
+
call?.resume(.success(value as Any))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public func reject(id: String, message: String) {
|
|
80
|
+
lock.lock()
|
|
81
|
+
let call = pending.removeValue(forKey: id)
|
|
82
|
+
lock.unlock()
|
|
83
|
+
// See JSStorageBridge.reject — UniFFI 0.28 cases carry a labeled `message: String`.
|
|
84
|
+
call?.resume(.failure(PingError.Transport(message: message)))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// MARK: - Internals (mirror of JSStorageBridge — kept inlined for clarity over DRY)
|
|
88
|
+
|
|
89
|
+
private func call<T>(method: String,
|
|
90
|
+
args: [String: Any],
|
|
91
|
+
decode: @escaping (Any?) -> T) async throws -> T {
|
|
92
|
+
let id = UUID().uuidString
|
|
93
|
+
return try await withCheckedThrowingContinuation { continuation in
|
|
94
|
+
lock.lock()
|
|
95
|
+
pending[id] = PendingCall(continuation: ContinuationBox(decode: decode,
|
|
96
|
+
inner: continuation))
|
|
97
|
+
lock.unlock()
|
|
98
|
+
emit(id, method, args)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private struct PendingCall {
|
|
103
|
+
let continuation: AnyContinuation
|
|
104
|
+
func resume(_ result: Result<Any?, Error>) {
|
|
105
|
+
continuation.resume(result)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private protocol AnyContinuation {
|
|
110
|
+
func resume(_ result: Result<Any?, Error>)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private struct ContinuationBox<T>: AnyContinuation {
|
|
114
|
+
let decode: (Any?) -> T
|
|
115
|
+
let inner: CheckedContinuation<T, Error>
|
|
116
|
+
|
|
117
|
+
func resume(_ result: Result<Any?, Error>) {
|
|
118
|
+
switch result {
|
|
119
|
+
case .success(let value):
|
|
120
|
+
inner.resume(returning: decode(value))
|
|
121
|
+
case .failure(let error):
|
|
122
|
+
inner.resume(throwing: error)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Objective-C bridge that registers the `PingNative` Swift class with React Native's
|
|
2
|
+
// module dispatcher. Required because RCT_EXTERN_MODULE / RCT_EXTERN_METHOD are
|
|
3
|
+
// Objective-C macros — the Swift side stays pure Swift via @objc declarations.
|
|
4
|
+
//
|
|
5
|
+
// Adding a new method: declare it with RCT_EXTERN_METHOD here AND with @objc
|
|
6
|
+
// (`@objc(name:resolver:rejecter:)`) on the Swift side.
|
|
7
|
+
//
|
|
8
|
+
// Spec: docs/RN_NATIVE_BINDINGS.md (stage 2).
|
|
9
|
+
|
|
10
|
+
#import <React/RCTBridgeModule.h>
|
|
11
|
+
#import <React/RCTEventEmitter.h>
|
|
12
|
+
|
|
13
|
+
// PingNative inherits from RCTEventEmitter (stage 3) so it can dispatch
|
|
14
|
+
// "PingStorageCall" / "PingTransportCall" events to JS for the bridge marshalling.
|
|
15
|
+
@interface RCT_EXTERN_MODULE(PingNative, RCTEventEmitter)
|
|
16
|
+
|
|
17
|
+
// Stage 2 smoke test.
|
|
18
|
+
RCT_EXTERN_METHOD(getWireContractVersion: (RCTPromiseResolveBlock)resolve
|
|
19
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
20
|
+
|
|
21
|
+
// Stage 3: storage round-trip self-test.
|
|
22
|
+
RCT_EXTERN_METHOD(testStorageRoundtrip: (RCTPromiseResolveBlock)resolve
|
|
23
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
24
|
+
|
|
25
|
+
// Stage 3: JS-side resume hooks for the storage bridge.
|
|
26
|
+
RCT_EXTERN_METHOD(resolveStorageCall: (NSString *)id
|
|
27
|
+
value: (id)value
|
|
28
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
29
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
30
|
+
|
|
31
|
+
RCT_EXTERN_METHOD(rejectStorageCall: (NSString *)id
|
|
32
|
+
message: (NSString *)message
|
|
33
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
34
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
35
|
+
|
|
36
|
+
// Stage 3: JS-side resume hooks for the transport bridge.
|
|
37
|
+
RCT_EXTERN_METHOD(resolveTransportCall: (NSString *)id
|
|
38
|
+
value: (id)value
|
|
39
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
40
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
41
|
+
|
|
42
|
+
RCT_EXTERN_METHOD(rejectTransportCall: (NSString *)id
|
|
43
|
+
message: (NSString *)message
|
|
44
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
45
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
46
|
+
|
|
47
|
+
// Stage 4b: identity helper (UDL addition).
|
|
48
|
+
RCT_EXTERN_METHOD(generateIdentityExport: (RCTPromiseResolveBlock)resolve
|
|
49
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
50
|
+
|
|
51
|
+
// Stage 4b: MessagingClient lifecycle.
|
|
52
|
+
RCT_EXTERN_METHOD(initClient: (NSString *)identityB64
|
|
53
|
+
deviceLabel: (NSString *)deviceLabel
|
|
54
|
+
nowMs: (double)nowMs
|
|
55
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
56
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
57
|
+
|
|
58
|
+
RCT_EXTERN_METHOD(getUserId: (RCTPromiseResolveBlock)resolve
|
|
59
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
60
|
+
|
|
61
|
+
RCT_EXTERN_METHOD(getDeviceId: (RCTPromiseResolveBlock)resolve
|
|
62
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
63
|
+
|
|
64
|
+
// Stage 4c: messaging methods.
|
|
65
|
+
RCT_EXTERN_METHOD(freshKeyPackage: (RCTPromiseResolveBlock)resolve
|
|
66
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
67
|
+
|
|
68
|
+
RCT_EXTERN_METHOD(createConversation: (NSString *)name
|
|
69
|
+
nowMs: (double)nowMs
|
|
70
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
71
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
72
|
+
|
|
73
|
+
RCT_EXTERN_METHOD(joinConversation: (NSDictionary *)welcome
|
|
74
|
+
nowMs: (double)nowMs
|
|
75
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
76
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
77
|
+
|
|
78
|
+
RCT_EXTERN_METHOD(sendMessage: (NSArray *)conversationId
|
|
79
|
+
plaintext: (NSArray *)plaintext
|
|
80
|
+
nowMs: (double)nowMs
|
|
81
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
82
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
83
|
+
|
|
84
|
+
RCT_EXTERN_METHOD(addMembers: (NSArray *)conversationId
|
|
85
|
+
keyPackages: (NSArray *)keyPackages
|
|
86
|
+
nowMs: (double)nowMs
|
|
87
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
88
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
89
|
+
|
|
90
|
+
RCT_EXTERN_METHOD(removeMembers: (NSArray *)conversationId
|
|
91
|
+
leafIndexes: (NSArray *)leafIndexes
|
|
92
|
+
nowMs: (double)nowMs
|
|
93
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
94
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
95
|
+
|
|
96
|
+
// Stage 4d: sync methods.
|
|
97
|
+
RCT_EXTERN_METHOD(processEnvelope: (NSDictionary *)envelope
|
|
98
|
+
nowMs: (double)nowMs
|
|
99
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
100
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
101
|
+
|
|
102
|
+
RCT_EXTERN_METHOD(syncConversations: (double)nowMs
|
|
103
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
104
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
105
|
+
|
|
106
|
+
// Stage 4e: discovery + observer.
|
|
107
|
+
RCT_EXTERN_METHOD(listConversations: (RCTPromiseResolveBlock)resolve
|
|
108
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
109
|
+
|
|
110
|
+
RCT_EXTERN_METHOD(listDevices: (RCTPromiseResolveBlock)resolve
|
|
111
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
112
|
+
|
|
113
|
+
RCT_EXTERN_METHOD(setObserver: (RCTPromiseResolveBlock)resolve
|
|
114
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
115
|
+
|
|
116
|
+
// Stage 4f: linking + revocation.
|
|
117
|
+
RCT_EXTERN_METHOD(buildLinkingTicket: (NSArray *)newDeviceId
|
|
118
|
+
newDeviceKp: (NSArray *)newDeviceKp
|
|
119
|
+
nowMs: (double)nowMs
|
|
120
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
121
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
122
|
+
|
|
123
|
+
RCT_EXTERN_METHOD(consumeLinkingTicket: (NSDictionary *)ticket
|
|
124
|
+
nowMs: (double)nowMs
|
|
125
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
126
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
127
|
+
|
|
128
|
+
RCT_EXTERN_METHOD(revokeDevice: (NSArray *)deviceId
|
|
129
|
+
nowMs: (double)nowMs
|
|
130
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
131
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
132
|
+
|
|
133
|
+
// Stage 5 polish: macOS clipboard helper.
|
|
134
|
+
RCT_EXTERN_METHOD(setClipboard: (NSString *)text
|
|
135
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
136
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
137
|
+
|
|
138
|
+
+ (BOOL)requiresMainQueueSetup
|
|
139
|
+
{
|
|
140
|
+
return NO;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@end
|