@magicred-1/react-native-lxmf 0.2.15 → 0.2.17

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.
@@ -66,8 +66,9 @@ class LxmfModule : Module() {
66
66
 
67
67
  AsyncFunction("start") { identityHex: String, lxmfAddressHex: String, mode: Int,
68
68
  announceIntervalMs: Double, bleMtuHint: Int,
69
- tcpInterfaces: List<Map<String, Any>>, displayName: String ->
70
- Log.d(TAG, "start() mode=$mode interfaces=$tcpInterfaces name=$displayName")
69
+ tcpInterfaces: List<Map<String, Any>>, displayName: String,
70
+ isBeacon: Boolean ->
71
+ Log.d(TAG, "start() mode=$mode interfaces=$tcpInterfaces name=$displayName beacon=$isBeacon")
71
72
  val interfacesJson = org.json.JSONArray(tcpInterfaces.map { iface ->
72
73
  org.json.JSONObject().apply {
73
74
  put("host", iface["host"] ?: "")
@@ -75,7 +76,7 @@ class LxmfModule : Module() {
75
76
  }
76
77
  }).toString()
77
78
  val rc = nativeStart(identityHex, lxmfAddressHex, mode, announceIntervalMs.toLong(),
78
- bleMtuHint.toShort(), interfacesJson, displayName)
79
+ bleMtuHint.toShort(), interfacesJson, displayName, isBeacon)
79
80
  if (rc != 0) throw RuntimeException("nativeStart returned $rc")
80
81
  true
81
82
  }
@@ -91,13 +92,13 @@ class LxmfModule : Module() {
91
92
  }
92
93
 
93
94
  // Messaging
94
- AsyncFunction("send") { destHex: String, bodyBase64: String ->
95
- nativeSend(destHex, bodyBase64).toDouble()
95
+ AsyncFunction("send") { destHex: String, bodyBase64: String, fieldsJson: String? ->
96
+ nativeSend(destHex, bodyBase64, fieldsJson).toDouble()
96
97
  }
97
98
 
98
- AsyncFunction("broadcast") { destsHex: List<String>, bodyBase64: String ->
99
+ AsyncFunction("broadcast") { destsHex: List<String>, bodyBase64: String, fieldsJson: String? ->
99
100
  val destsJson = org.json.JSONArray(destsHex).toString()
100
- nativeBroadcast(destsJson, bodyBase64).toDouble()
101
+ nativeBroadcast(destsJson, bodyBase64, fieldsJson).toDouble()
101
102
  }
102
103
 
103
104
  // Identity
@@ -195,13 +196,14 @@ class LxmfModule : Module() {
195
196
  announceIntervalMs: Long,
196
197
  bleMtuHint: Short,
197
198
  tcpInterfacesJson: String,
198
- displayName: String
199
+ displayName: String,
200
+ isBeacon: Boolean
199
201
  ): Int
200
202
  private external fun nativeStop(): Int
201
203
  private external fun nativeIsRunning(): Boolean
202
204
  private external fun nativePollEvents(): String?
203
- private external fun nativeSend(destHex: String, bodyBase64: String): Long
204
- private external fun nativeBroadcast(destsJson: String, bodyBase64: String): Long
205
+ private external fun nativeSend(destHex: String, bodyBase64: String, fieldsJson: String?): Long
206
+ private external fun nativeBroadcast(destsJson: String, bodyBase64: String, fieldsJson: String?): Long
205
207
  private external fun nativeGetIdentityHex(): String?
206
208
  private external fun nativeGetStatus(): String?
207
209
  private external fun nativeGetBeacons(): String?
@@ -3,11 +3,11 @@ export type NativeModuleType = {
3
3
  start(identityHex: string, lxmfAddressHex: string, mode: number, announceIntervalMs: number, bleMtuHint: number, tcpInterfaces: {
4
4
  host: string;
5
5
  port: number;
6
- }[], displayName: string): Promise<boolean>;
6
+ }[], displayName: string, isBeacon: boolean): Promise<boolean>;
7
7
  stop(): Promise<boolean>;
8
8
  isRunning(): boolean;
9
- send(destHex: string, bodyBase64: string): Promise<number>;
10
- broadcast(destsHex: string[], bodyBase64: string): Promise<number>;
9
+ send(destHex: string, bodyBase64: string, fieldsJson?: string | null): Promise<number>;
10
+ broadcast(destsHex: string[], bodyBase64: string, fieldsJson?: string | null): Promise<number>;
11
11
  getIdentityHex(): string | null;
12
12
  getStatus(): string | null;
13
13
  getBeacons(): string | null;
package/build/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export { LxmfModule, LxmfModuleNative, isLxmfNativeAvailable, NativeModuleType } from './LxmfModule';
2
- export { useLxmf, LxmfNodeMode, type UseLxmfOptions, type TcpInterface, type LxmfNodeStatus, type Beacon, type LxmfEvent } from './useLxmf';
2
+ export { useLxmf, LxmfNodeMode, type UseLxmfOptions, type TcpInterface, type LxmfNodeStatus, type Beacon, type LxmfEvent, type LxmfMedia } from './useLxmf';
@@ -39,6 +39,22 @@ export interface TcpInterface {
39
39
  host: string;
40
40
  port: number;
41
41
  }
42
+ /** Media attachments to include in an LXMF message.
43
+ * Encoded as LXMF standard fields: FIELD_IMAGE (0x06) and FIELD_FILE_ATTACHMENTS (0x05).
44
+ * Compatible with Sideband and other LXMF clients.
45
+ */
46
+ export interface LxmfMedia {
47
+ /** Inline image: LXMF FIELD_IMAGE — rendered by receiving clients. */
48
+ image?: {
49
+ mimeType: string;
50
+ dataBase64: string;
51
+ };
52
+ /** File attachments: LXMF FIELD_FILE_ATTACHMENTS — list of named blobs. */
53
+ files?: {
54
+ name: string;
55
+ dataBase64: string;
56
+ }[];
57
+ }
42
58
  export interface UseLxmfOptions {
43
59
  autoStart?: boolean;
44
60
  identityHex?: string;
@@ -55,6 +71,8 @@ export interface UseLxmfOptions {
55
71
  bleMtuHint?: number;
56
72
  /** Display name broadcast in LXMF announces. Default: "lxmf-mobile" */
57
73
  displayName?: string;
74
+ /** Advertise this node as an anonmesh beacon (app_data = "anonmesh::beacon::v1\0<name>"). Default: false */
75
+ isBeacon?: boolean;
58
76
  }
59
77
  export declare function useLxmf(options?: UseLxmfOptions): {
60
78
  status: LxmfNodeStatus | null;
@@ -69,10 +87,11 @@ export declare function useLxmf(options?: UseLxmfOptions): {
69
87
  mode?: LxmfNodeMode;
70
88
  tcpInterfaces?: TcpInterface[];
71
89
  displayName?: string;
90
+ isBeacon?: boolean;
72
91
  }) => Promise<boolean>;
73
92
  stop: () => Promise<void>;
74
- send: (destHex: string, bodyBase64: string) => Promise<number>;
75
- broadcast: (destsHex: string[], bodyBase64: string) => Promise<number>;
93
+ send: (destHex: string, bodyBase64: string, media?: LxmfMedia) => Promise<number>;
94
+ broadcast: (destsHex: string[], bodyBase64: string, media?: LxmfMedia) => Promise<number>;
76
95
  getStatus: () => LxmfNodeStatus | null;
77
96
  getBeacons: () => Beacon[];
78
97
  fetchMessages: (limit?: number) => any[];
package/build/useLxmf.js CHANGED
@@ -131,11 +131,12 @@ function useLxmf(options = {}) {
131
131
  const announceMs = options.announceIntervalMs ?? 5000;
132
132
  const bleMtu = options.bleMtuHint ?? 255;
133
133
  const displayName = overrides?.displayName ?? options.displayName ?? '';
134
+ const isBeacon = overrides?.isBeacon ?? options.isBeacon ?? false;
134
135
  if (mode !== LxmfNodeMode.BleOnly && tcpInterfaces.length === 0) {
135
136
  setError(`Mode ${mode} requires at least one TCP interface.`);
136
137
  return false;
137
138
  }
138
- await LxmfModule_1.LxmfModule.start(resolvedIdentityHex, resolvedLxmfAddressHex, mode, announceMs, bleMtu, tcpInterfaces, displayName);
139
+ await LxmfModule_1.LxmfModule.start(resolvedIdentityHex, resolvedLxmfAddressHex, mode, announceMs, bleMtu, tcpInterfaces, displayName, isBeacon);
139
140
  setRunning(true);
140
141
  syncStatus();
141
142
  setError(null);
@@ -153,6 +154,7 @@ function useLxmf(options = {}) {
153
154
  options.announceIntervalMs,
154
155
  options.bleMtuHint,
155
156
  options.displayName,
157
+ options.isBeacon,
156
158
  syncStatus,
157
159
  ]);
158
160
  (0, react_1.useEffect)(() => {
@@ -175,18 +177,20 @@ function useLxmf(options = {}) {
175
177
  setError(e?.message ?? 'Failed to stop');
176
178
  }
177
179
  }, []);
178
- const send = (0, react_1.useCallback)(async (destHex, bodyBase64) => {
180
+ const send = (0, react_1.useCallback)(async (destHex, bodyBase64, media) => {
179
181
  try {
180
- return await LxmfModule_1.LxmfModule.send(destHex, bodyBase64);
182
+ const fieldsJson = media ? JSON.stringify(media) : null;
183
+ return await LxmfModule_1.LxmfModule.send(destHex, bodyBase64, fieldsJson);
181
184
  }
182
185
  catch (e) {
183
186
  setError(e.message);
184
187
  return -1;
185
188
  }
186
189
  }, []);
187
- const broadcast = (0, react_1.useCallback)(async (destsHex, bodyBase64) => {
190
+ const broadcast = (0, react_1.useCallback)(async (destsHex, bodyBase64, media) => {
188
191
  try {
189
- return await LxmfModule_1.LxmfModule.broadcast(destsHex, bodyBase64);
192
+ const fieldsJson = media ? JSON.stringify(media) : null;
193
+ return await LxmfModule_1.LxmfModule.broadcast(destsHex, bodyBase64, fieldsJson);
190
194
  }
191
195
  catch (e) {
192
196
  setError(e.message);
@@ -13,7 +13,8 @@ func lxmf_start(
13
13
  _ announceIntervalMs: UInt64,
14
14
  _ bleMtuHint: UInt16,
15
15
  _ tcpInterfacesJson: UnsafePointer<CChar>?,
16
- _ displayName: UnsafePointer<CChar>?
16
+ _ displayName: UnsafePointer<CChar>?,
17
+ _ isBeacon: UInt8
17
18
  ) -> Int32
18
19
 
19
20
  @_silgen_name("lxmf_stop")
@@ -26,7 +27,8 @@ func lxmf_is_running() -> Int32
26
27
  func lxmf_send(
27
28
  _ destPtr: UnsafePointer<UInt8>?,
28
29
  _ bodyPtr: UnsafePointer<UInt8>?,
29
- _ bodyLen: Int
30
+ _ bodyLen: Int,
31
+ _ fieldsJson: UnsafePointer<CChar>?
30
32
  ) -> Int64
31
33
 
32
34
  @_silgen_name("lxmf_broadcast")
@@ -34,7 +36,8 @@ func lxmf_broadcast(
34
36
  _ destsPtr: UnsafePointer<UInt8>?,
35
37
  _ destCount: Int,
36
38
  _ bodyPtr: UnsafePointer<UInt8>?,
37
- _ bodyLen: Int
39
+ _ bodyLen: Int,
40
+ _ fieldsJson: UnsafePointer<CChar>?
38
41
  ) -> Int64
39
42
 
40
43
  @_silgen_name("lxmf_poll_events")
@@ -182,7 +185,8 @@ public class LxmfModule: Module {
182
185
  announceIntervalMs: Double,
183
186
  bleMtuHint: Int,
184
187
  tcpInterfaces: [[String: Any]],
185
- displayName: String
188
+ displayName: String,
189
+ isBeacon: Bool
186
190
  ) -> Bool in
187
191
  // Serialize TCP interfaces to JSON (matches Android pattern)
188
192
  let interfacesJson: String
@@ -200,7 +204,8 @@ public class LxmfModule: Module {
200
204
  lxmf_start(
201
205
  idPtr, addrPtr,
202
206
  UInt32(mode), UInt64(announceIntervalMs),
203
- UInt16(bleMtuHint), ifacesPtr, namePtr
207
+ UInt16(bleMtuHint), ifacesPtr, namePtr,
208
+ isBeacon ? 1 : 0
204
209
  )
205
210
  }
206
211
  }
@@ -227,22 +232,33 @@ public class LxmfModule: Module {
227
232
 
228
233
  // --- Messaging ---
229
234
 
230
- AsyncFunction("send") { (destHex: String, bodyBase64: String) -> Double in
235
+ AsyncFunction("send") { (destHex: String, bodyBase64: String, fieldsJson: String?) -> Double in
231
236
  guard let destBytes = Self.hexToBytes(destHex),
232
237
  destBytes.count == 16,
233
238
  let bodyData = Data(base64Encoded: bodyBase64) else {
234
239
  return -1
235
240
  }
236
241
 
237
- let opId = destBytes.withUnsafeBufferPointer { destBuf in
238
- [UInt8](bodyData).withUnsafeBufferPointer { bodyBuf in
239
- lxmf_send(destBuf.baseAddress, bodyBuf.baseAddress, bodyData.count)
242
+ let opId: Int64
243
+ if let json = fieldsJson {
244
+ opId = destBytes.withUnsafeBufferPointer { destBuf in
245
+ [UInt8](bodyData).withUnsafeBufferPointer { bodyBuf in
246
+ json.withCString { jsonPtr in
247
+ lxmf_send(destBuf.baseAddress, bodyBuf.baseAddress, bodyData.count, jsonPtr)
248
+ }
249
+ }
250
+ }
251
+ } else {
252
+ opId = destBytes.withUnsafeBufferPointer { destBuf in
253
+ [UInt8](bodyData).withUnsafeBufferPointer { bodyBuf in
254
+ lxmf_send(destBuf.baseAddress, bodyBuf.baseAddress, bodyData.count, nil)
255
+ }
240
256
  }
241
257
  }
242
258
  return Double(opId)
243
259
  }
244
260
 
245
- AsyncFunction("broadcast") { (destsHex: [String], bodyBase64: String) -> Double in
261
+ AsyncFunction("broadcast") { (destsHex: [String], bodyBase64: String, fieldsJson: String?) -> Double in
246
262
  guard let bodyData = Data(base64Encoded: bodyBase64) else { return -1 }
247
263
 
248
264
  var flatDests = [UInt8]()
@@ -251,9 +267,20 @@ public class LxmfModule: Module {
251
267
  flatDests.append(contentsOf: bytes)
252
268
  }
253
269
 
254
- let opId = flatDests.withUnsafeBufferPointer { destBuf in
255
- [UInt8](bodyData).withUnsafeBufferPointer { bodyBuf in
256
- lxmf_broadcast(destBuf.baseAddress, destsHex.count, bodyBuf.baseAddress, bodyData.count)
270
+ let opId: Int64
271
+ if let json = fieldsJson {
272
+ opId = flatDests.withUnsafeBufferPointer { destBuf in
273
+ [UInt8](bodyData).withUnsafeBufferPointer { bodyBuf in
274
+ json.withCString { jsonPtr in
275
+ lxmf_broadcast(destBuf.baseAddress, destsHex.count, bodyBuf.baseAddress, bodyData.count, jsonPtr)
276
+ }
277
+ }
278
+ }
279
+ } else {
280
+ opId = flatDests.withUnsafeBufferPointer { destBuf in
281
+ [UInt8](bodyData).withUnsafeBufferPointer { bodyBuf in
282
+ lxmf_broadcast(destBuf.baseAddress, destsHex.count, bodyBuf.baseAddress, bodyData.count, nil)
283
+ }
257
284
  }
258
285
  }
259
286
  return Double(opId)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magicred-1/react-native-lxmf",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "LXMF Reticulum mesh networking for React Native + Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",