@callstack/brownie 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.
Files changed (41) hide show
  1. package/Brownie.podspec +30 -0
  2. package/ios/BrownieFollyConvert.h +17 -0
  3. package/ios/BrownieModule.h +9 -0
  4. package/ios/BrownieModule.mm +55 -0
  5. package/ios/BrownieStore.swift +221 -0
  6. package/ios/BrownieStoreBridge.h +17 -0
  7. package/ios/BrownieStoreBridge.mm +72 -0
  8. package/ios/Generated/BrownfieldStore.swift +42 -0
  9. package/ios/Generated/SettingsStore.swift +33 -0
  10. package/lib/commonjs/NativeBrownieModule.js +2 -0
  11. package/lib/commonjs/NativeBrownieModule.js.map +1 -0
  12. package/lib/commonjs/index.js +2 -0
  13. package/lib/commonjs/index.js.map +1 -0
  14. package/lib/commonjs/package.json +1 -0
  15. package/lib/commonjs/scripts/brownfield.js +3 -0
  16. package/lib/commonjs/scripts/brownfield.js.map +1 -0
  17. package/lib/module/NativeBrownieModule.js +2 -0
  18. package/lib/module/NativeBrownieModule.js.map +1 -0
  19. package/lib/module/index.js +2 -0
  20. package/lib/module/index.js.map +1 -0
  21. package/lib/module/package.json +1 -0
  22. package/lib/module/scripts/brownfield.js +3 -0
  23. package/lib/module/scripts/brownfield.js.map +1 -0
  24. package/lib/typescript/commonjs/package.json +1 -0
  25. package/lib/typescript/commonjs/src/NativeBrownieModule.d.ts +10 -0
  26. package/lib/typescript/commonjs/src/NativeBrownieModule.d.ts.map +1 -0
  27. package/lib/typescript/commonjs/src/index.d.ts +33 -0
  28. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  29. package/lib/typescript/commonjs/src/scripts/brownfield.d.ts +3 -0
  30. package/lib/typescript/commonjs/src/scripts/brownfield.d.ts.map +1 -0
  31. package/lib/typescript/module/package.json +1 -0
  32. package/lib/typescript/module/src/NativeBrownieModule.d.ts +10 -0
  33. package/lib/typescript/module/src/NativeBrownieModule.d.ts.map +1 -0
  34. package/lib/typescript/module/src/index.d.ts +33 -0
  35. package/lib/typescript/module/src/index.d.ts.map +1 -0
  36. package/lib/typescript/module/src/scripts/brownfield.d.ts +3 -0
  37. package/lib/typescript/module/src/scripts/brownfield.d.ts.map +1 -0
  38. package/package.json +101 -0
  39. package/src/NativeBrownieModule.ts +11 -0
  40. package/src/index.ts +127 -0
  41. package/src/scripts/brownfield.ts +5 -0
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |spec|
6
+ spec.name = "Brownie"
7
+ spec.version = package['version']
8
+ spec.summary = package['description']
9
+ spec.license = package['license']
10
+
11
+ spec.authors = package['author']
12
+ spec.homepage = package['homepage']
13
+ spec.platform = :ios, "14.0"
14
+
15
+ spec.module_name = "Brownie"
16
+ spec.source = { :git => "git@github.com:callstack/react-native-brownfield.git", :tag => "#{spec.version}" }
17
+ spec.source_files = [
18
+ "ios/**/*.{h,m,mm,swift}",
19
+ "cpp/**/*.{h,cpp}"
20
+ ]
21
+ spec.private_header_files = "cpp/**/*.h"
22
+
23
+ spec.pod_target_xcconfig = {
24
+ 'DEFINES_MODULE' => 'YES',
25
+ 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20',
26
+ 'HEADER_SEARCH_PATHS' => '$(inherited) "${PODS_ROOT}/boost" "${PODS_ROOT}/RCT-Folly" "${PODS_TARGET_SRCROOT}/cpp"'
27
+ }
28
+
29
+ install_modules_dependencies(spec)
30
+ end
@@ -0,0 +1,17 @@
1
+ #pragma once
2
+
3
+ #ifdef __cplusplus
4
+
5
+ #if __has_include(<react/utils/FollyConvert.h>)
6
+ // static libs / header maps (no use_frameworks!)
7
+ #import <react/utils/FollyConvert.h>
8
+ #elif __has_include("FollyConvert.h")
9
+ /// `use_frameworks! :linkage => :static` users will need to import FollyConvert this way
10
+ #import "FollyConvert.h"
11
+ #elif __has_include("RCTFollyConvert.h")
12
+ #import "RCTFollyConvert.h"
13
+ #else
14
+ #error "FollyConvert.h not found. Ensure React-utils & RCT-Folly pods are installed."
15
+ #endif
16
+
17
+ #endif
@@ -0,0 +1,9 @@
1
+ #ifdef __cplusplus
2
+
3
+ #import <Brownie/Brownie.h>
4
+ #import <ReactCommon/RCTTurboModuleWithJSIBindings.h>
5
+
6
+ @interface BrownieModule : NativeBrownieModuleSpecBase <NativeBrownieModuleSpec>
7
+ @end
8
+
9
+ #endif
@@ -0,0 +1,55 @@
1
+ #import "BrownieModule.h"
2
+ #import <jsi/jsi.h>
3
+
4
+ #if __has_include("Brownie/Brownie-Swift.h")
5
+ #import "Brownie/Brownie-Swift.h"
6
+ #else
7
+ #import "Brownie-Swift.h"
8
+ #endif
9
+
10
+ #import "BrownieInstaller.h"
11
+
12
+ using namespace facebook;
13
+
14
+ @interface BrownieModule (JSIBindings) <RCTTurboModuleWithJSIBindings>
15
+ @end
16
+
17
+ @implementation BrownieModule {
18
+ NSMutableDictionary<NSString *, NSObject *> *_notificationObservers;
19
+ }
20
+
21
+ RCT_EXPORT_MODULE(Brownie);
22
+
23
+ - (instancetype)init {
24
+ self = [super init];
25
+ if (self) {
26
+ _notificationObservers = [NSMutableDictionary new];
27
+ [[NSNotificationCenter defaultCenter]
28
+ addObserver:self
29
+ selector:@selector(handleNotification:)
30
+ name:@"BrownieStoreUpdated"
31
+ object:nil];
32
+ }
33
+ return self;
34
+ }
35
+
36
+ - (void)dealloc {
37
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
38
+ }
39
+
40
+ - (void)handleNotification:(NSNotification *)notification {
41
+ NSDictionary *userInfo = notification.userInfo ?: @{};
42
+ [self emitNativeStoreDidChange:userInfo];
43
+ }
44
+
45
+ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
46
+ callInvoker:(const std::shared_ptr<facebook::react::CallInvoker> &)callinvoker {
47
+ brownie::BrownieInstaller::install(runtime);
48
+ }
49
+
50
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
51
+ (const facebook::react::ObjCTurboModule::InitParams &)params {
52
+ return std::make_shared<facebook::react::NativeBrownieModuleSpecJSI>(params);
53
+ }
54
+
55
+ @end
@@ -0,0 +1,221 @@
1
+ import Foundation
2
+ import Combine
3
+ import SwiftUI
4
+
5
+ extension Notification.Name {
6
+ public static let BrownieStoreUpdated = Notification.Name("BrownieStoreUpdated")
7
+ }
8
+
9
+ public protocol BrownieStoreProtocol: Codable {
10
+ static var storeName: String { get }
11
+ }
12
+
13
+ public extension BrownieStoreProtocol {
14
+ /// Registers the store with the given initial state.
15
+ static func register(_ initialState: Self) {
16
+ _ = Store(initialState, key: Self.storeName)
17
+ }
18
+ }
19
+
20
+ public struct StoreKey<State: Codable>: EnvironmentKey {
21
+ public static var defaultValue: Store<State> { fatalError("Store not provided") }
22
+ }
23
+
24
+ public extension EnvironmentValues {
25
+ func store<State>(_ type: State.Type) -> Store<State> {
26
+ self[StoreKey<State>.self]
27
+ }
28
+ }
29
+
30
+ public extension Binding {
31
+ /// Set value using closure that receives current value
32
+ func set(_ updater: (Value) -> Value) {
33
+ wrappedValue = updater(wrappedValue)
34
+ }
35
+ }
36
+
37
+ @MainActor
38
+ @propertyWrapper
39
+ public struct UseStore<State: BrownieStoreProtocol, Value: Equatable>: DynamicProperty {
40
+ @StateObject private var observer: SelectorObserver<State, Value>
41
+ private let keyPath: WritableKeyPath<State, Value>
42
+
43
+ public init(_ keyPath: WritableKeyPath<State, Value>) {
44
+ self.keyPath = keyPath
45
+ let key = State.storeName
46
+ guard let foundStore = StoreManager.shared.store(key: key, as: State.self) else {
47
+ fatalError("Store not found for key: \(key)")
48
+ }
49
+ self._observer = StateObject(wrappedValue: SelectorObserver(store: foundStore, keyPath: keyPath))
50
+ }
51
+
52
+ public var wrappedValue: Value {
53
+ observer.value
54
+ }
55
+
56
+ public var projectedValue: Binding<Value> {
57
+ Binding(
58
+ get: { observer.store.get(keyPath) },
59
+ set: { observer.store.set(keyPath, to: $0) }
60
+ )
61
+ }
62
+ }
63
+
64
+ /// Internal observer that only publishes when selected value changes.
65
+ @MainActor
66
+ class SelectorObserver<State: Codable, Value: Equatable>: ObservableObject {
67
+ let store: Store<State>
68
+ private let keyPath: KeyPath<State, Value>
69
+ @Published private(set) var value: Value
70
+ private var cancellable: AnyCancellable?
71
+
72
+ init(store: Store<State>, keyPath: KeyPath<State, Value>) {
73
+ self.store = store
74
+ self.keyPath = keyPath
75
+ self.value = store.state[keyPath: keyPath]
76
+
77
+ self.cancellable = store.$state
78
+ .map { $0[keyPath: keyPath] }
79
+ .removeDuplicates()
80
+ .sink { [weak self] newValue in
81
+ self?.value = newValue
82
+ }
83
+ }
84
+ }
85
+
86
+ @objc public class StoreManager: NSObject {
87
+ @objc public static let shared = StoreManager()
88
+
89
+ private var stores: [String: Any] = [:]
90
+ private let lock = NSLock()
91
+
92
+ public func register<State: Codable>(store: Store<State>, key: String) {
93
+ lock.lock()
94
+ defer { lock.unlock() }
95
+ stores[key] = store
96
+ }
97
+
98
+ public func store<State>(key: String, as type: State.Type) -> Store<State>? {
99
+ lock.lock()
100
+ defer { lock.unlock() }
101
+ return stores[key] as? Store<State>
102
+ }
103
+
104
+ public func removeStore(key: String) {
105
+ lock.lock()
106
+ defer { lock.unlock() }
107
+ stores.removeValue(forKey: key)
108
+ BrownieStoreBridge.removeStore(withKey: key)
109
+ }
110
+
111
+ @objc public func snapshot(key: String) -> [String: Any]? {
112
+ return BrownieStoreBridge.getSnapshot(forStore: key) as? [String: Any]
113
+ }
114
+
115
+ @objc public func setValue(key: String, property: String, value: Any) {
116
+ BrownieStoreBridge.setValue(value, forKey: property, inStore: key)
117
+ }
118
+ }
119
+
120
+ public extension StoreManager {
121
+ static func get<State>(key: String, as type: State.Type) -> Store<State>? {
122
+ shared.store(key: key, as: type)
123
+ }
124
+ }
125
+
126
+ public class Store<State: Codable>: ObservableObject {
127
+ private let storeKey: String
128
+ @Published public private(set) var state: State
129
+ private var notificationObserver: NSObjectProtocol?
130
+
131
+ public init(_ initialState: State, key: String) {
132
+ self.storeKey = key
133
+ self.state = initialState
134
+
135
+ BrownieStoreBridge.registerStore(withKey: key)
136
+ pushStateToCxx()
137
+
138
+ notificationObserver = NotificationCenter.default.addObserver(
139
+ forName: .BrownieStoreUpdated,
140
+ object: nil,
141
+ queue: .main
142
+ ) { [weak self] notification in
143
+ self?.handleStoreUpdate(notification)
144
+ }
145
+
146
+ StoreManager.shared.register(store: self, key: key)
147
+ }
148
+
149
+ deinit {
150
+ if let observer = notificationObserver {
151
+ NotificationCenter.default.removeObserver(observer)
152
+ }
153
+ }
154
+
155
+ private func pushStateToCxx() {
156
+ guard let data = try? JSONEncoder().encode(state),
157
+ let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return }
158
+
159
+ BrownieStoreBridge.setState(from: dict, forStore: storeKey)
160
+ }
161
+
162
+ private func handleStoreUpdate(_ notification: Notification) {
163
+ guard let updatedKey = notification.userInfo?["storeKey"] as? String,
164
+ updatedKey == storeKey else { return }
165
+ rebuildState()
166
+ }
167
+
168
+ private func rebuildState() {
169
+ guard let snapshot = BrownieStoreBridge.getSnapshot(forStore: storeKey),
170
+ let data = try? JSONSerialization.data(withJSONObject: snapshot),
171
+ let newState = try? JSONDecoder().decode(State.self, from: data) else { return }
172
+
173
+ state = newState
174
+ }
175
+
176
+ /// Update state using a closure
177
+ public func set(_ updater: (inout State) -> Void) {
178
+ updater(&state)
179
+ pushStateToCxx()
180
+ }
181
+
182
+ /// Set property using type-safe keypath
183
+ public func set<Value>(_ keyPath: WritableKeyPath<State, Value>, to value: Value) {
184
+ state[keyPath: keyPath] = value
185
+ pushStateToCxx()
186
+ }
187
+
188
+ /// Get property using type-safe keypath
189
+ public func get<Value>(_ keyPath: KeyPath<State, Value>) -> Value {
190
+ state[keyPath: keyPath]
191
+ }
192
+
193
+ /// Convenience subscript for property access
194
+ public subscript<Value>(_ keyPath: KeyPath<State, Value>) -> Value {
195
+ state[keyPath: keyPath]
196
+ }
197
+
198
+ // MARK: - UIKit Support
199
+
200
+ /// Subscribe to state changes with a closure. Returns a cancellation function.
201
+ public func subscribe(onChange: @escaping (State) -> Void) -> () -> Void {
202
+ let cancellable = $state.sink { state in
203
+ onChange(state)
204
+ }
205
+ return { cancellable.cancel() }
206
+ }
207
+
208
+ /// Subscribe to specific property changes. Returns a cancellation function.
209
+ public func subscribe<Value: Equatable>(
210
+ _ keyPath: KeyPath<State, Value>,
211
+ onChange: @escaping (Value) -> Void
212
+ ) -> () -> Void {
213
+ let cancellable = $state
214
+ .map { $0[keyPath: keyPath] }
215
+ .removeDuplicates()
216
+ .sink { value in
217
+ onChange(value)
218
+ }
219
+ return { cancellable.cancel() }
220
+ }
221
+ }
@@ -0,0 +1,17 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface BrownieStoreBridge : NSObject
6
+
7
+ + (void)registerStoreWithKey:(NSString *)key NS_SWIFT_NAME(registerStore(withKey:));
8
+ + (void)removeStoreWithKey:(NSString *)key NS_SWIFT_NAME(removeStore(withKey:));
9
+
10
+ + (void)setValue:(id)value forKey:(NSString *)propKey inStore:(NSString *)storeKey NS_SWIFT_NAME(setValue(_:forKey:inStore:));
11
+ + (nullable id)getValueForKey:(NSString *)propKey inStore:(NSString *)storeKey NS_SWIFT_NAME(getValue(forKey:inStore:));
12
+ + (nullable NSDictionary *)getSnapshotForStore:(NSString *)storeKey NS_SWIFT_NAME(getSnapshot(forStore:));
13
+ + (void)setStateFromDictionary:(NSDictionary *)dict forStore:(NSString *)storeKey NS_SWIFT_NAME(setState(from:forStore:));
14
+
15
+ @end
16
+
17
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,72 @@
1
+ #import "BrownieStoreBridge.h"
2
+ #import "BrownieStoreManager.h"
3
+ #import "BrownieStore.h"
4
+ #import "BrownieFollyConvert.h"
5
+
6
+ using namespace facebook::react;
7
+
8
+ @implementation BrownieStoreBridge
9
+
10
+ + (void)registerStoreWithKey:(NSString *)key {
11
+ auto store = std::make_shared<brownie::BrownieStore>();
12
+ NSString *keyCopy = [key copy];
13
+
14
+ store->setChangeCallback([keyCopy]() {
15
+ dispatch_async(dispatch_get_main_queue(), ^{
16
+ [[NSNotificationCenter defaultCenter]
17
+ postNotificationName:@"BrownieStoreUpdated"
18
+ object:nil
19
+ userInfo:@{@"storeKey" : keyCopy}];
20
+ });
21
+ });
22
+
23
+ brownie::BrownieStoreManager::shared().registerStore(std::string([key UTF8String]),
24
+ store);
25
+ }
26
+
27
+ + (void)removeStoreWithKey:(NSString *)key {
28
+ brownie::BrownieStoreManager::shared().removeStore(std::string([key UTF8String]));
29
+ }
30
+
31
+ + (void)setValue:(id)value forKey:(NSString *)propKey inStore:(NSString *)storeKey {
32
+ auto store =
33
+ brownie::BrownieStoreManager::shared().getStore(std::string([storeKey UTF8String]));
34
+ if (!store) {
35
+ return;
36
+ }
37
+
38
+ store->set(std::string([propKey UTF8String]), convertIdToFollyDynamic(value));
39
+ }
40
+
41
+ + (nullable id)getValueForKey:(NSString *)propKey inStore:(NSString *)storeKey {
42
+ auto store =
43
+ brownie::BrownieStoreManager::shared().getStore(std::string([storeKey UTF8String]));
44
+ if (!store) {
45
+ return nil;
46
+ }
47
+
48
+ return convertFollyDynamicToId(store->get(std::string([propKey UTF8String])));
49
+ }
50
+
51
+ + (nullable NSDictionary *)getSnapshotForStore:(NSString *)storeKey {
52
+ auto store =
53
+ brownie::BrownieStoreManager::shared().getStore(std::string([storeKey UTF8String]));
54
+ if (!store) {
55
+ return nil;
56
+ }
57
+
58
+ id result = convertFollyDynamicToId(store->getSnapshot());
59
+ return [result isKindOfClass:[NSDictionary class]] ? result : nil;
60
+ }
61
+
62
+ + (void)setStateFromDictionary:(NSDictionary *)dict forStore:(NSString *)storeKey {
63
+ auto store =
64
+ brownie::BrownieStoreManager::shared().getStore(std::string([storeKey UTF8String]));
65
+ if (!store) {
66
+ return;
67
+ }
68
+
69
+ store->setState(convertIdToFollyDynamic(dict));
70
+ }
71
+
72
+ @end
@@ -0,0 +1,42 @@
1
+ // This file was generated from JSON Schema using quicktype, do not modify it directly.
2
+ // To parse the JSON, add this file to your project and do:
3
+ //
4
+ // let brownfieldStore = try? JSONDecoder().decode(BrownfieldStore.self, from: jsonData)
5
+
6
+ //
7
+ // Hashable or Equatable:
8
+ // The compiler will not be able to synthesize the implementation of Hashable or Equatable
9
+ // for types that require the use of JSONAny, nor will the implementation of Hashable be
10
+ // synthesized for types that have collections (such as arrays or dictionaries).
11
+
12
+ import Foundation
13
+
14
+ // MARK: - BrownfieldStore
15
+ public struct BrownfieldStore: Codable, Equatable {
16
+ public var counter: Double
17
+ public var user: User
18
+
19
+ public init(counter: Double, user: User) {
20
+ self.counter = counter
21
+ self.user = user
22
+ }
23
+ }
24
+
25
+ //
26
+ // Hashable or Equatable:
27
+ // The compiler will not be able to synthesize the implementation of Hashable or Equatable
28
+ // for types that require the use of JSONAny, nor will the implementation of Hashable be
29
+ // synthesized for types that have collections (such as arrays or dictionaries).
30
+
31
+ // MARK: - User
32
+ public struct User: Codable, Equatable {
33
+ public var name: String
34
+
35
+ public init(name: String) {
36
+ self.name = name
37
+ }
38
+ }
39
+
40
+ extension BrownfieldStore: BrownieStoreProtocol {
41
+ public static let storeName = "BrownfieldStore"
42
+ }
@@ -0,0 +1,33 @@
1
+ // This file was generated from JSON Schema using quicktype, do not modify it directly.
2
+ // To parse the JSON, add this file to your project and do:
3
+ //
4
+ // let settingsStore = try? JSONDecoder().decode(SettingsStore.self, from: jsonData)
5
+
6
+ //
7
+ // Hashable or Equatable:
8
+ // The compiler will not be able to synthesize the implementation of Hashable or Equatable
9
+ // for types that require the use of JSONAny, nor will the implementation of Hashable be
10
+ // synthesized for types that have collections (such as arrays or dictionaries).
11
+
12
+ import Foundation
13
+
14
+ // MARK: - SettingsStore
15
+ public struct SettingsStore: Codable, Equatable {
16
+ public var notificationsEnabled, privacyMode: Bool
17
+ public var theme: Theme
18
+
19
+ public init(notificationsEnabled: Bool, privacyMode: Bool, theme: Theme) {
20
+ self.notificationsEnabled = notificationsEnabled
21
+ self.privacyMode = privacyMode
22
+ self.theme = theme
23
+ }
24
+ }
25
+
26
+ public enum Theme: String, Codable, Equatable {
27
+ case dark = "dark"
28
+ case light = "light"
29
+ }
30
+
31
+ extension SettingsStore: BrownieStoreProtocol {
32
+ public static let storeName = "SettingsStore"
33
+ }
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _reactNative=require("react-native");var _default=exports.default=_reactNative.TurboModuleRegistry.getEnforcing('Brownie');
2
+ //# sourceMappingURL=NativeBrownieModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeBrownieModule.ts"],"mappings":"gFACA,IAAAA,YAAA,CAAAC,OAAA,iBAAmD,IAAAC,QAAA,CAAAC,OAAA,CAAAC,OAAA,CASpCC,gCAAmB,CAACC,YAAY,CAAO,SAAS,CAAC","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.getSnapshot=getSnapshot;exports.setState=setState;exports.subscribe=subscribe;exports.useStore=useStore;var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));var _react=require("react");var _NativeBrownieModule=_interopRequireDefault(require("./NativeBrownieModule"));var stores=new Map();function getHostObject(key){return global.__brownieGetStore==null?void 0:global.__brownieGetStore(key);}function getOrCreateStore(key){var store=stores.get(key);if(!store){var _hostObject$unbox;var hostObject=getHostObject(key);store={hostObject:hostObject,snapshot:(_hostObject$unbox=hostObject==null||hostObject.unbox==null?void 0:hostObject.unbox())!=null?_hostObject$unbox:{},listeners:new Set()};stores.set(key,store);}return store;}function refreshSnapshot(key){var store=stores.get(key);if(store){var _store$hostObject$unb,_store$hostObject;store.snapshot=(_store$hostObject$unb=(_store$hostObject=store.hostObject)==null||_store$hostObject.unbox==null?void 0:_store$hostObject.unbox())!=null?_store$hostObject$unb:{};store.listeners.forEach(function(listener){return listener();});}}_NativeBrownieModule.default.nativeStoreDidChange(function(){stores.forEach(function(_,key){return refreshSnapshot(key);});});function subscribe(key,listener){var store=getOrCreateStore(key);store.listeners.add(listener);return function(){return store.listeners.delete(listener);};}function getSnapshot(key){var store=getOrCreateStore(key);return store.snapshot;}function setState(key,action){var store=getOrCreateStore(key);if(!store.hostObject)return;var partial=typeof action==='function'?action(store.snapshot):action;for(var _ref of Object.entries(partial)){var _ref2=(0,_slicedToArray2.default)(_ref,2);var prop=_ref2[0];var value=_ref2[1];store.hostObject[prop]=value;}}function useStore(key,selector){var sub=(0,_react.useCallback)(function(listener){return subscribe(key,listener);},[key]);var snap=(0,_react.useCallback)(function(){return selector(getSnapshot(key));},[key,selector]);var slice=(0,_react.useSyncExternalStore)(sub,snap,snap);(0,_react.useDebugValue)(slice);var boundSetState=(0,_react.useCallback)(function(action){return setState(key,action);},[key]);return[slice,boundSetState];}
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","require","_NativeBrownieModule","_interopRequireDefault","stores","Map","getHostObject","key","global","__brownieGetStore","getOrCreateStore","store","get","_hostObject$unbox","hostObject","snapshot","unbox","listeners","Set","set","refreshSnapshot","_store$hostObject$unb","_store$hostObject","forEach","listener","BrownieModule","nativeStoreDidChange","_","subscribe","add","delete","getSnapshot","setState","action","partial","_ref","Object","entries","_ref2","_slicedToArray2","default","prop","value","useStore","selector","sub","useCallback","snap","slice","useSyncExternalStore","useDebugValue","boundSetState"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ var _brownfieldCli=require("@callstack/brownfield-cli");(0,_brownfieldCli.runCLI)(process.argv);
3
+ //# sourceMappingURL=brownfield.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_brownfieldCli","require","runCLI","process","argv"],"sourceRoot":"../../../src","sources":["scripts/brownfield.ts"],"mappings":"AAAA;AAEA,IAAAA,cAAA,CAAAC,OAAA,8BAEA,GAAAC,qBAAM,EAACC,OAAO,CAACC,IAAI,CAAC","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _reactNative=require("react-native");var _default=exports.default=_reactNative.TurboModuleRegistry.getEnforcing('Brownie');
2
+ //# sourceMappingURL=NativeBrownieModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeBrownieModule.ts"],"mappings":"gFACA,IAAAA,YAAA,CAAAC,OAAA,iBAAmD,IAAAC,QAAA,CAAAC,OAAA,CAAAC,OAAA,CASpCC,gCAAmB,CAACC,YAAY,CAAO,SAAS,CAAC","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.getSnapshot=getSnapshot;exports.setState=setState;exports.subscribe=subscribe;exports.useStore=useStore;var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));var _react=require("react");var _NativeBrownieModule=_interopRequireDefault(require("./NativeBrownieModule"));var stores=new Map();function getHostObject(key){return global.__brownieGetStore==null?void 0:global.__brownieGetStore(key);}function getOrCreateStore(key){var store=stores.get(key);if(!store){var _hostObject$unbox;var hostObject=getHostObject(key);store={hostObject:hostObject,snapshot:(_hostObject$unbox=hostObject==null||hostObject.unbox==null?void 0:hostObject.unbox())!=null?_hostObject$unbox:{},listeners:new Set()};stores.set(key,store);}return store;}function refreshSnapshot(key){var store=stores.get(key);if(store){var _store$hostObject$unb,_store$hostObject;store.snapshot=(_store$hostObject$unb=(_store$hostObject=store.hostObject)==null||_store$hostObject.unbox==null?void 0:_store$hostObject.unbox())!=null?_store$hostObject$unb:{};store.listeners.forEach(function(listener){return listener();});}}_NativeBrownieModule.default.nativeStoreDidChange(function(){stores.forEach(function(_,key){return refreshSnapshot(key);});});function subscribe(key,listener){var store=getOrCreateStore(key);store.listeners.add(listener);return function(){return store.listeners.delete(listener);};}function getSnapshot(key){var store=getOrCreateStore(key);return store.snapshot;}function setState(key,action){var store=getOrCreateStore(key);if(!store.hostObject)return;var partial=typeof action==='function'?action(store.snapshot):action;for(var _ref of Object.entries(partial)){var _ref2=(0,_slicedToArray2.default)(_ref,2);var prop=_ref2[0];var value=_ref2[1];store.hostObject[prop]=value;}}function useStore(key,selector){var sub=(0,_react.useCallback)(function(listener){return subscribe(key,listener);},[key]);var snap=(0,_react.useCallback)(function(){return selector(getSnapshot(key));},[key,selector]);var slice=(0,_react.useSyncExternalStore)(sub,snap,snap);(0,_react.useDebugValue)(slice);var boundSetState=(0,_react.useCallback)(function(action){return setState(key,action);},[key]);return[slice,boundSetState];}
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","require","_NativeBrownieModule","_interopRequireDefault","stores","Map","getHostObject","key","global","__brownieGetStore","getOrCreateStore","store","get","_hostObject$unbox","hostObject","snapshot","unbox","listeners","Set","set","refreshSnapshot","_store$hostObject$unb","_store$hostObject","forEach","listener","BrownieModule","nativeStoreDidChange","_","subscribe","add","delete","getSnapshot","setState","action","partial","_ref","Object","entries","_ref2","_slicedToArray2","default","prop","value","useStore","selector","sub","useCallback","snap","slice","useSyncExternalStore","useDebugValue","boundSetState"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ var _brownfieldCli=require("@callstack/brownfield-cli");(0,_brownfieldCli.runCLI)(process.argv);
3
+ //# sourceMappingURL=brownfield.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_brownfieldCli","require","runCLI","process","argv"],"sourceRoot":"../../../src","sources":["scripts/brownfield.ts"],"mappings":"AAAA;AAEA,IAAAA,cAAA,CAAAC,OAAA,8BAEA,GAAAC,qBAAM,EAACC,OAAO,CAACC,IAAI,CAAC","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,10 @@
1
+ import type { TurboModule, CodegenTypes } from 'react-native';
2
+ export interface Spec extends TurboModule {
3
+ nativeStoreDidChange: CodegenTypes.EventEmitter<{
4
+ key: string;
5
+ value: string;
6
+ }>;
7
+ }
8
+ declare const _default: Spec;
9
+ export default _default;
10
+ //# sourceMappingURL=NativeBrownieModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeBrownieModule.d.ts","sourceRoot":"","sources":["../../../../src/NativeBrownieModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,oBAAoB,EAAE,YAAY,CAAC,YAAY,CAAC;QAC9C,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;;AAED,wBAAiE"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Empty interface for module augmentation.
3
+ * Users extend this in their *.brownie.ts files.
4
+ */
5
+ export interface BrownieStores {
6
+ }
7
+ export interface BrownieStore {
8
+ }
9
+ type StoreListener = () => void;
10
+ /**
11
+ * Subscribe to store changes from native side.
12
+ * @returns Unsubscribe function
13
+ */
14
+ export declare function subscribe<K extends keyof BrownieStores>(key: K, listener: StoreListener): () => void;
15
+ /**
16
+ * Get current store state snapshot.
17
+ */
18
+ export declare function getSnapshot<K extends keyof BrownieStores>(key: K): BrownieStores[K];
19
+ type SetStateAction<T> = Partial<T> | ((prevState: T) => Partial<T>);
20
+ /**
21
+ * Set a value in the native store.
22
+ */
23
+ export declare function setState<K extends keyof BrownieStores>(key: K, action: SetStateAction<BrownieStores[K]>): void;
24
+ /**
25
+ * React hook for subscribing to a native store with selector.
26
+ * Inspired by Zustand's useStore implementation.
27
+ * @param key Store key registered in StoreManager
28
+ * @param selector Function to select a slice of state
29
+ * @returns Tuple of [selectedState, setState] for the store
30
+ */
31
+ export declare function useStore<K extends keyof BrownieStores, U>(key: K, selector: (state: BrownieStores[K]) => U): [U, (action: SetStateAction<BrownieStores[K]>) => void];
32
+ export {};
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,aAAa;CAAG;AAEjC,MAAM,WAAW,YAAY;CAAG;AAEhC,KAAK,aAAa,GAAG,MAAM,IAAI,CAAC;AA2ChC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,aAAa,EACrD,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,aAAa,GACtB,MAAM,IAAI,CAIZ;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,aAAa,EACvD,GAAG,EAAE,CAAC,GACL,aAAa,CAAC,CAAC,CAAC,CAGlB;AAED,KAAK,cAAc,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAErE;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,aAAa,EACpD,GAAG,EAAE,CAAC,EACN,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GACvC,IAAI,CAYN;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,aAAa,EAAE,CAAC,EACvD,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GACvC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAiBzD"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=brownfield.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brownfield.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/brownfield.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,10 @@
1
+ import type { TurboModule, CodegenTypes } from 'react-native';
2
+ export interface Spec extends TurboModule {
3
+ nativeStoreDidChange: CodegenTypes.EventEmitter<{
4
+ key: string;
5
+ value: string;
6
+ }>;
7
+ }
8
+ declare const _default: Spec;
9
+ export default _default;
10
+ //# sourceMappingURL=NativeBrownieModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeBrownieModule.d.ts","sourceRoot":"","sources":["../../../../src/NativeBrownieModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,oBAAoB,EAAE,YAAY,CAAC,YAAY,CAAC;QAC9C,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;;AAED,wBAAiE"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Empty interface for module augmentation.
3
+ * Users extend this in their *.brownie.ts files.
4
+ */
5
+ export interface BrownieStores {
6
+ }
7
+ export interface BrownieStore {
8
+ }
9
+ type StoreListener = () => void;
10
+ /**
11
+ * Subscribe to store changes from native side.
12
+ * @returns Unsubscribe function
13
+ */
14
+ export declare function subscribe<K extends keyof BrownieStores>(key: K, listener: StoreListener): () => void;
15
+ /**
16
+ * Get current store state snapshot.
17
+ */
18
+ export declare function getSnapshot<K extends keyof BrownieStores>(key: K): BrownieStores[K];
19
+ type SetStateAction<T> = Partial<T> | ((prevState: T) => Partial<T>);
20
+ /**
21
+ * Set a value in the native store.
22
+ */
23
+ export declare function setState<K extends keyof BrownieStores>(key: K, action: SetStateAction<BrownieStores[K]>): void;
24
+ /**
25
+ * React hook for subscribing to a native store with selector.
26
+ * Inspired by Zustand's useStore implementation.
27
+ * @param key Store key registered in StoreManager
28
+ * @param selector Function to select a slice of state
29
+ * @returns Tuple of [selectedState, setState] for the store
30
+ */
31
+ export declare function useStore<K extends keyof BrownieStores, U>(key: K, selector: (state: BrownieStores[K]) => U): [U, (action: SetStateAction<BrownieStores[K]>) => void];
32
+ export {};
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,aAAa;CAAG;AAEjC,MAAM,WAAW,YAAY;CAAG;AAEhC,KAAK,aAAa,GAAG,MAAM,IAAI,CAAC;AA2ChC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,aAAa,EACrD,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,aAAa,GACtB,MAAM,IAAI,CAIZ;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,aAAa,EACvD,GAAG,EAAE,CAAC,GACL,aAAa,CAAC,CAAC,CAAC,CAGlB;AAED,KAAK,cAAc,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAErE;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,aAAa,EACpD,GAAG,EAAE,CAAC,EACN,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GACvC,IAAI,CAYN;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,aAAa,EAAE,CAAC,EACvD,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GACvC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAiBzD"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=brownfield.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brownfield.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/brownfield.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "@callstack/brownie",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "author": "Oskar Kwaśniewski <oskarkwasniewski@icloud.com>",
6
+ "bin": {
7
+ "brownfield": "./lib/commonjs/scripts/brownfield.js"
8
+ },
9
+ "contributors": [
10
+ "Artur Morys-Magiera <artus9033@gmail.com>",
11
+ "Oskar Kwasniewski <oskarkwasniewski@icloud.com>"
12
+ ],
13
+ "homepage": "https://github.com/callstack/react-native-brownfield",
14
+ "description": "Shared state management between React Native and Native apps",
15
+ "main": "lib/commonjs/index",
16
+ "module": "lib/module/index",
17
+ "types": "./lib/typescript/commonjs/src/index.d.ts",
18
+ "react-native": "src/index",
19
+ "exports": {
20
+ ".": {
21
+ "source": "./src/index.ts",
22
+ "import": {
23
+ "types": "./lib/typescript/module/src/index.d.ts",
24
+ "default": "./lib/module/index.js"
25
+ },
26
+ "require": {
27
+ "types": "./lib/typescript/commonjs/src/index.d.ts",
28
+ "default": "./lib/commonjs/index.js"
29
+ }
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "scripts": {
34
+ "lint": "eslint .",
35
+ "typecheck": "tsc --noEmit",
36
+ "build": "bob build",
37
+ "dev": "nodemon --watch src --ext js,ts,json --exec \"bob build\""
38
+ },
39
+ "keywords": [
40
+ "brownie",
41
+ "react-native-brownfield",
42
+ "react native brownfield",
43
+ "native",
44
+ "shared state",
45
+ "react native integration"
46
+ ],
47
+ "files": [
48
+ "src",
49
+ "lib",
50
+ "ios",
51
+ "*.podspec",
52
+ "!ios/build",
53
+ "!**/__tests__",
54
+ "!**/__fixtures__",
55
+ "!**/__mocks__",
56
+ "!**/.*"
57
+ ],
58
+ "publishConfig": {
59
+ "access": "public",
60
+ "tag": "alpha"
61
+ },
62
+ "peerDependencies": {
63
+ "react": "*",
64
+ "react-native": "*"
65
+ },
66
+ "dependencies": {
67
+ "@callstack/brownfield-cli": "^1.0.0",
68
+ "quicktype-core": "^23.2.6",
69
+ "quicktype-typescript-input": "^23.2.6",
70
+ "ts-morph": "^27.0.2"
71
+ },
72
+ "devDependencies": {
73
+ "@babel/core": "^7.25.2",
74
+ "@babel/preset-env": "^7.25.3",
75
+ "@babel/preset-typescript": "^7.27.1",
76
+ "@babel/runtime": "^7.25.0",
77
+ "@react-native/babel-preset": "0.82.1",
78
+ "@react-native/eslint-config": "0.82.1",
79
+ "@types/node": "^25.0.8",
80
+ "@types/react": "^19.1.1",
81
+ "eslint": "^9.28.0",
82
+ "globals": "^16.2.0",
83
+ "import": "^0.0.6",
84
+ "nodemon": "^3.1.11",
85
+ "react": "19.1.1",
86
+ "react-native": "0.82.1",
87
+ "react-native-builder-bob": "^0.40.17",
88
+ "typescript": "5.9.3"
89
+ },
90
+ "codegenConfig": {
91
+ "name": "Brownie",
92
+ "type": "modules",
93
+ "jsSrcsDir": "./src",
94
+ "android": {
95
+ "javaPackageName": "com.callstack.brownie"
96
+ }
97
+ },
98
+ "engines": {
99
+ "node": ">=20"
100
+ }
101
+ }
@@ -0,0 +1,11 @@
1
+ import type { TurboModule, CodegenTypes } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export interface Spec extends TurboModule {
5
+ nativeStoreDidChange: CodegenTypes.EventEmitter<{
6
+ key: string;
7
+ value: string;
8
+ }>;
9
+ }
10
+
11
+ export default TurboModuleRegistry.getEnforcing<Spec>('Brownie');
package/src/index.ts ADDED
@@ -0,0 +1,127 @@
1
+ import { useCallback, useDebugValue, useSyncExternalStore } from 'react';
2
+ import BrownieModule from './NativeBrownieModule';
3
+
4
+ /**
5
+ * Empty interface for module augmentation.
6
+ * Users extend this in their *.brownie.ts files.
7
+ */
8
+ export interface BrownieStores {}
9
+
10
+ export interface BrownieStore {}
11
+
12
+ type StoreListener = () => void;
13
+
14
+ type HostObject = any;
15
+
16
+ interface StoreCache {
17
+ hostObject: HostObject;
18
+ snapshot: Record<string, unknown>;
19
+ listeners: Set<StoreListener>;
20
+ }
21
+
22
+ const stores = new Map<string, StoreCache>();
23
+
24
+ function getHostObject(key: string): HostObject {
25
+ // @ts-expect-error - untyped global prop set by BrownieInstaller.cpp
26
+ return global.__brownieGetStore?.(key);
27
+ }
28
+
29
+ function getOrCreateStore(key: string): StoreCache {
30
+ let store = stores.get(key);
31
+ if (!store) {
32
+ const hostObject = getHostObject(key);
33
+ store = {
34
+ hostObject,
35
+ snapshot: hostObject?.unbox?.() ?? {},
36
+ listeners: new Set(),
37
+ };
38
+ stores.set(key, store);
39
+ }
40
+ return store;
41
+ }
42
+
43
+ function refreshSnapshot(key: string): void {
44
+ const store = stores.get(key);
45
+ if (store) {
46
+ store.snapshot = store.hostObject?.unbox?.() ?? {};
47
+ store.listeners.forEach((listener) => listener());
48
+ }
49
+ }
50
+
51
+ BrownieModule.nativeStoreDidChange(() => {
52
+ stores.forEach((_, key) => refreshSnapshot(key));
53
+ });
54
+
55
+ /**
56
+ * Subscribe to store changes from native side.
57
+ * @returns Unsubscribe function
58
+ */
59
+ export function subscribe<K extends keyof BrownieStores>(
60
+ key: K,
61
+ listener: StoreListener
62
+ ): () => void {
63
+ const store = getOrCreateStore(key as string);
64
+ store.listeners.add(listener);
65
+ return () => store.listeners.delete(listener);
66
+ }
67
+
68
+ /**
69
+ * Get current store state snapshot.
70
+ */
71
+ export function getSnapshot<K extends keyof BrownieStores>(
72
+ key: K
73
+ ): BrownieStores[K] {
74
+ const store = getOrCreateStore(key as string);
75
+ return store.snapshot as BrownieStores[K];
76
+ }
77
+
78
+ type SetStateAction<T> = Partial<T> | ((prevState: T) => Partial<T>);
79
+
80
+ /**
81
+ * Set a value in the native store.
82
+ */
83
+ export function setState<K extends keyof BrownieStores>(
84
+ key: K,
85
+ action: SetStateAction<BrownieStores[K]>
86
+ ): void {
87
+ const store = getOrCreateStore(key as string);
88
+ if (!store.hostObject) return;
89
+
90
+ const partial =
91
+ typeof action === 'function'
92
+ ? action(store.snapshot as BrownieStores[K])
93
+ : action;
94
+
95
+ for (const [prop, value] of Object.entries(partial)) {
96
+ store.hostObject[prop] = value;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * React hook for subscribing to a native store with selector.
102
+ * Inspired by Zustand's useStore implementation.
103
+ * @param key Store key registered in StoreManager
104
+ * @param selector Function to select a slice of state
105
+ * @returns Tuple of [selectedState, setState] for the store
106
+ */
107
+ export function useStore<K extends keyof BrownieStores, U>(
108
+ key: K,
109
+ selector: (state: BrownieStores[K]) => U
110
+ ): [U, (action: SetStateAction<BrownieStores[K]>) => void] {
111
+ const sub = useCallback(
112
+ (listener: () => void) => subscribe(key, listener),
113
+ [key]
114
+ );
115
+ const snap = useCallback(() => selector(getSnapshot(key)), [key, selector]);
116
+
117
+ const slice = useSyncExternalStore(sub, snap, snap);
118
+
119
+ useDebugValue(slice);
120
+
121
+ const boundSetState = useCallback(
122
+ (action: SetStateAction<BrownieStores[K]>) => setState(key, action),
123
+ [key]
124
+ );
125
+
126
+ return [slice, boundSetState];
127
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { runCLI } from '@callstack/brownfield-cli';
4
+
5
+ runCLI(process.argv);