@derec-alliance/react-native 0.0.1
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/DeRec.podspec +25 -0
- package/LICENSE +201 -0
- package/README.md +222 -0
- package/android/CMakeLists.txt +38 -0
- package/android/build.gradle +79 -0
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/java/org/derec/DeRecModule.kt +56 -0
- package/android/src/main/java/org/derec/DeRecPackage.kt +24 -0
- package/android/src/main/jni/OnLoad.cpp +39 -0
- package/android/src/main/jniLibs/arm64-v8a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/x86_64/libderec_library.a +0 -0
- package/cpp/Convert.cpp +50 -0
- package/cpp/Convert.h +38 -0
- package/cpp/DeRecInstaller.cpp +186 -0
- package/cpp/DeRecInstaller.h +28 -0
- package/cpp/Invoker.h +20 -0
- package/cpp/JsCallbackBridge.cpp +144 -0
- package/cpp/JsCallbackBridge.h +148 -0
- package/cpp/Primitives.cpp +1193 -0
- package/cpp/Primitives.h +39 -0
- package/cpp/ProtocolHost.cpp +613 -0
- package/cpp/ProtocolHost.h +88 -0
- package/cpp/RuntimeInvoker.h +29 -0
- package/cpp/StoreCallbacks.cpp +1293 -0
- package/cpp/StoreCallbacks.h +111 -0
- package/cpp/WorkerThread.cpp +74 -0
- package/cpp/WorkerThread.h +54 -0
- package/cpp/derec_ffi.h +2145 -0
- package/ios/DeRec.h +23 -0
- package/ios/DeRec.mm +39 -0
- package/ios/DeRecFFI.xcframework/Info.plist +48 -0
- package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +2145 -0
- package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +2145 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +0 -0
- package/lib/binary.d.ts +19 -0
- package/lib/binary.js +164 -0
- package/lib/codec.d.ts +16 -0
- package/lib/codec.js +80 -0
- package/lib/errors.d.ts +23 -0
- package/lib/errors.js +35 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +27 -0
- package/lib/messages.d.ts +41 -0
- package/lib/messages.js +192 -0
- package/lib/native.d.ts +11 -0
- package/lib/native.js +40 -0
- package/lib/primitives.d.ts +137 -0
- package/lib/primitives.js +329 -0
- package/lib/protocol.d.ts +188 -0
- package/lib/protocol.js +514 -0
- package/lib/types.d.ts +1014 -0
- package/lib/types.js +63 -0
- package/package.json +55 -0
- package/react-native.config.js +19 -0
- package/src/binary.ts +182 -0
- package/src/codec.ts +79 -0
- package/src/errors.ts +45 -0
- package/src/index.ts +7 -0
- package/src/messages.ts +192 -0
- package/src/native.ts +52 -0
- package/src/primitives.ts +770 -0
- package/src/protocol.ts +621 -0
- package/src/types.ts +1040 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 DeRec Alliance. All rights reserved.
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <jsi/jsi.h>
|
|
7
|
+
|
|
8
|
+
#include <functional>
|
|
9
|
+
#include <memory>
|
|
10
|
+
|
|
11
|
+
#include "JsCallbackBridge.h"
|
|
12
|
+
|
|
13
|
+
extern "C" {
|
|
14
|
+
#include "derec_ffi.h"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
namespace derec {
|
|
18
|
+
|
|
19
|
+
/// Converts a settled callback's resolved value (or a plain, non-thenable
|
|
20
|
+
/// return) into the opaque payload the blocked protocol worker decodes once
|
|
21
|
+
/// `JsCallbackBridge::callSync` returns. Each callback defines its own
|
|
22
|
+
/// encoding for this payload — raw bytes for a byte-returning store method,
|
|
23
|
+
/// a single flag byte for a boolean, four little-endian bytes for a version
|
|
24
|
+
/// — since `CallResult` itself has no opinion on what "bytes" means.
|
|
25
|
+
using ResultConverter =
|
|
26
|
+
std::function<CallResult(facebook::jsi::Runtime&, const facebook::jsi::Value&)>;
|
|
27
|
+
|
|
28
|
+
/// Owns the six `#[repr(C)]` store/transport callback structs the protocol
|
|
29
|
+
/// invokes synchronously, and retains the JavaScript objects those callbacks
|
|
30
|
+
/// dispatch to so they outlive the protocol handle.
|
|
31
|
+
///
|
|
32
|
+
/// Every function-pointer field across the six structs is `user_data ==
|
|
33
|
+
/// this`; every struct that has a `free_buffer` field points it at
|
|
34
|
+
/// `storeFreeBuffer`, the sole releaser for buffers this binding allocates
|
|
35
|
+
/// via `allocBytes`.
|
|
36
|
+
///
|
|
37
|
+
/// Inherits `enable_shared_from_this` because a store callback's body is
|
|
38
|
+
/// captured by value into `JsCallbackBridge::callSync`'s argument, which in
|
|
39
|
+
/// turn is captured into the JavaScript `CallInvoker`'s own queue — a queue
|
|
40
|
+
/// this binding does not control and that can still hold a scheduled task
|
|
41
|
+
/// after `ProtocolHost::teardown` has drained its own worker and destroyed
|
|
42
|
+
/// its `StoreBindings`. Each trampoline captures `shared_from_this()` rather
|
|
43
|
+
/// than the raw `this` recovered from `user_data`, so the queued task keeps
|
|
44
|
+
/// this object (and the `shared_ptr<jsi::Object>` stores it holds) alive
|
|
45
|
+
/// until the task actually runs and releases its own copy — on the
|
|
46
|
+
/// JavaScript thread, which is where those references need to be dropped.
|
|
47
|
+
class StoreBindings : public std::enable_shared_from_this<StoreBindings> {
|
|
48
|
+
public:
|
|
49
|
+
/// `stores` must carry one property per store — `channelStore`,
|
|
50
|
+
/// `shareStore`, `secretStore`, `userSecretStore`, `stateStore`,
|
|
51
|
+
/// `transport` — each a JS object implementing the corresponding
|
|
52
|
+
/// interface from `src/types.ts`. Throws a `jsi::JSError` naming the first
|
|
53
|
+
/// missing store, and again if any callback struct ends up with an unset
|
|
54
|
+
/// member (a build-time contract violation, not a caller error, but
|
|
55
|
+
/// reported the same way since both are equally fatal to the handle).
|
|
56
|
+
static std::shared_ptr<StoreBindings> create(facebook::jsi::Runtime& rt,
|
|
57
|
+
facebook::jsi::Object& stores,
|
|
58
|
+
JsCallbackBridge& bridge,
|
|
59
|
+
std::shared_ptr<InstanceState> state);
|
|
60
|
+
|
|
61
|
+
const ChannelStoreCallbacks* channel() const { return &channelCallbacks_; }
|
|
62
|
+
const SecretStoreCallbacks* secret() const { return &secretCallbacks_; }
|
|
63
|
+
const ShareStoreCallbacks* share() const { return &shareCallbacks_; }
|
|
64
|
+
const UserSecretStoreCallbacks* userSecret() const { return &userSecretCallbacks_; }
|
|
65
|
+
const StateStoreCallbacks* state() const { return &stateCallbacks_; }
|
|
66
|
+
const TransportCallbacks* transport() const { return &transportCallbacks_; }
|
|
67
|
+
|
|
68
|
+
facebook::jsi::Runtime& runtime() const { return rt_; }
|
|
69
|
+
JsCallbackBridge& bridge() const { return bridge_; }
|
|
70
|
+
const std::shared_ptr<InstanceState>& instanceState() const { return instanceState_; }
|
|
71
|
+
|
|
72
|
+
const std::shared_ptr<facebook::jsi::Object>& channelStore() const { return channelStore_; }
|
|
73
|
+
const std::shared_ptr<facebook::jsi::Object>& secretStore() const { return secretStore_; }
|
|
74
|
+
const std::shared_ptr<facebook::jsi::Object>& shareStore() const { return shareStore_; }
|
|
75
|
+
const std::shared_ptr<facebook::jsi::Object>& userSecretStore() const {
|
|
76
|
+
return userSecretStore_;
|
|
77
|
+
}
|
|
78
|
+
const std::shared_ptr<facebook::jsi::Object>& stateStore() const { return stateStore_; }
|
|
79
|
+
const std::shared_ptr<facebook::jsi::Object>& transportStore() const { return transport_; }
|
|
80
|
+
|
|
81
|
+
/// Settle a callback body's promise (or plain, non-thenable return value)
|
|
82
|
+
/// through `convert`, dispatching via `then` only when the value is
|
|
83
|
+
/// actually thenable. `convert` runs on the JavaScript thread, with `rt`
|
|
84
|
+
/// live, before `settle` is invoked — never after.
|
|
85
|
+
void settleFromPromise(facebook::jsi::Runtime& rt, facebook::jsi::Value value,
|
|
86
|
+
std::function<void(CallResult)> settle, ResultConverter convert);
|
|
87
|
+
|
|
88
|
+
private:
|
|
89
|
+
StoreBindings(facebook::jsi::Runtime& rt, JsCallbackBridge& bridge,
|
|
90
|
+
std::shared_ptr<InstanceState> state);
|
|
91
|
+
|
|
92
|
+
facebook::jsi::Runtime& rt_;
|
|
93
|
+
JsCallbackBridge& bridge_;
|
|
94
|
+
std::shared_ptr<InstanceState> instanceState_;
|
|
95
|
+
|
|
96
|
+
std::shared_ptr<facebook::jsi::Object> channelStore_;
|
|
97
|
+
std::shared_ptr<facebook::jsi::Object> secretStore_;
|
|
98
|
+
std::shared_ptr<facebook::jsi::Object> shareStore_;
|
|
99
|
+
std::shared_ptr<facebook::jsi::Object> userSecretStore_;
|
|
100
|
+
std::shared_ptr<facebook::jsi::Object> stateStore_;
|
|
101
|
+
std::shared_ptr<facebook::jsi::Object> transport_;
|
|
102
|
+
|
|
103
|
+
ChannelStoreCallbacks channelCallbacks_{};
|
|
104
|
+
SecretStoreCallbacks secretCallbacks_{};
|
|
105
|
+
ShareStoreCallbacks shareCallbacks_{};
|
|
106
|
+
UserSecretStoreCallbacks userSecretCallbacks_{};
|
|
107
|
+
StateStoreCallbacks stateCallbacks_{};
|
|
108
|
+
TransportCallbacks transportCallbacks_{};
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
} // namespace derec
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 DeRec Alliance. All rights reserved.
|
|
3
|
+
|
|
4
|
+
#include "WorkerThread.h"
|
|
5
|
+
|
|
6
|
+
namespace derec {
|
|
7
|
+
|
|
8
|
+
WorkerThread::WorkerThread(std::string name) : name_(std::move(name)) {
|
|
9
|
+
thread_ = std::thread([this] { loop(); });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
WorkerThread::~WorkerThread() { drainAndJoin(); }
|
|
13
|
+
|
|
14
|
+
bool WorkerThread::post(std::function<void()> work) {
|
|
15
|
+
{
|
|
16
|
+
std::lock_guard<std::mutex> lock(m_);
|
|
17
|
+
if (!accepting_) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
queue_.push_back(std::move(work));
|
|
21
|
+
}
|
|
22
|
+
cv_.notify_one();
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
void WorkerThread::drainAndJoin() {
|
|
27
|
+
{
|
|
28
|
+
std::lock_guard<std::mutex> lock(m_);
|
|
29
|
+
if (joined_) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
accepting_ = false;
|
|
33
|
+
joined_ = true;
|
|
34
|
+
}
|
|
35
|
+
cv_.notify_all();
|
|
36
|
+
if (thread_.joinable()) {
|
|
37
|
+
thread_.join();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
bool WorkerThread::isCurrentThread() const {
|
|
42
|
+
return std::this_thread::get_id() == thread_.get_id();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void WorkerThread::loop() {
|
|
46
|
+
for (;;) {
|
|
47
|
+
std::function<void()> work;
|
|
48
|
+
{
|
|
49
|
+
std::unique_lock<std::mutex> lock(m_);
|
|
50
|
+
cv_.wait(lock, [this] { return !queue_.empty() || !accepting_; });
|
|
51
|
+
if (queue_.empty()) {
|
|
52
|
+
// Only exit once the queue is drained, so shutdown never discards
|
|
53
|
+
// work that was accepted before `drainAndJoin`.
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
work = std::move(queue_.front());
|
|
57
|
+
queue_.pop_front();
|
|
58
|
+
}
|
|
59
|
+
// An exception escaping the thread function would call std::terminate and
|
|
60
|
+
// take the whole application down, so nothing may propagate past here.
|
|
61
|
+
// Posted work reaches into JSI, where a `jsi::JSError` is a live
|
|
62
|
+
// possibility. There is no channel to report on at this point: the caller
|
|
63
|
+
// that posted the task has already moved on, and any result the task was
|
|
64
|
+
// meant to settle is settled by the callback bridge's own timeout as a
|
|
65
|
+
// backend failure. Dropping the exception and continuing to service the
|
|
66
|
+
// queue is therefore the only behaviour that keeps the instance usable.
|
|
67
|
+
try {
|
|
68
|
+
work();
|
|
69
|
+
} catch (...) {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
} // namespace derec
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 DeRec Alliance. All rights reserved.
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <condition_variable>
|
|
7
|
+
#include <deque>
|
|
8
|
+
#include <functional>
|
|
9
|
+
#include <mutex>
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <thread>
|
|
12
|
+
|
|
13
|
+
namespace derec {
|
|
14
|
+
|
|
15
|
+
/// A single serial thread owning all `derec_protocol_*` calls for one
|
|
16
|
+
/// protocol instance.
|
|
17
|
+
///
|
|
18
|
+
/// Serialization is required by the protocol: `tick` mutates the same round
|
|
19
|
+
/// state an inbound `process` does, so the two must not interleave for a given
|
|
20
|
+
/// `secret_id`. Running them on one serial queue satisfies that structurally.
|
|
21
|
+
class WorkerThread {
|
|
22
|
+
public:
|
|
23
|
+
explicit WorkerThread(std::string name);
|
|
24
|
+
~WorkerThread();
|
|
25
|
+
|
|
26
|
+
WorkerThread(const WorkerThread&) = delete;
|
|
27
|
+
WorkerThread& operator=(const WorkerThread&) = delete;
|
|
28
|
+
|
|
29
|
+
/// Enqueue work. Returns `true` if it was accepted, `false` if
|
|
30
|
+
/// `drainAndJoin` has already been called — in which case `work` is
|
|
31
|
+
/// dropped rather than run. Callers that need the caller to learn about a
|
|
32
|
+
/// refused task (rather than silently never hearing from it again, as a
|
|
33
|
+
/// dropped store-callback task would) must check this.
|
|
34
|
+
bool post(std::function<void()> work);
|
|
35
|
+
|
|
36
|
+
/// Run everything already queued, then stop and join. Idempotent.
|
|
37
|
+
void drainAndJoin();
|
|
38
|
+
|
|
39
|
+
/// True when called from this worker's own thread.
|
|
40
|
+
bool isCurrentThread() const;
|
|
41
|
+
|
|
42
|
+
private:
|
|
43
|
+
void loop();
|
|
44
|
+
|
|
45
|
+
std::string name_;
|
|
46
|
+
mutable std::mutex m_;
|
|
47
|
+
std::condition_variable cv_;
|
|
48
|
+
std::deque<std::function<void()>> queue_;
|
|
49
|
+
bool accepting_ = true;
|
|
50
|
+
bool joined_ = false;
|
|
51
|
+
std::thread thread_;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
} // namespace derec
|