@mentra/bluetooth-sdk 0.1.17 → 0.1.19

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 (57) hide show
  1. package/README.md +1 -1
  2. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +52 -4
  3. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +119 -16
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +0 -6
  5. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +22 -21
  6. package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +1 -1
  7. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +488 -15
  8. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +457 -31
  9. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
  10. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +361 -67
  11. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +7501 -3704
  12. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +134 -0
  13. package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +0 -6
  14. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleJsonCompact.java +493 -0
  15. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +4 -1
  16. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleWireProtocol.java +108 -0
  17. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +4 -3
  18. package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900LengthCodec.java +115 -0
  19. package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +103 -68
  20. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +106 -0
  21. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +93 -0
  22. package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +111 -11
  23. package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +7 -9
  24. package/android/src/test/java/com/mentra/bluetoothsdk/utils/AvifExifStripperTest.java +17 -1
  25. package/android/src/test/java/com/mentra/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
  26. package/android/src/test/java/com/mentra/bluetoothsdk/utils/BleJsonCompactTest.java +158 -0
  27. package/android/src/test/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
  28. package/android/src/test/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
  29. package/build/BluetoothSdk.types.d.ts +12 -1
  30. package/build/BluetoothSdk.types.d.ts.map +1 -1
  31. package/build/BluetoothSdk.types.js.map +1 -1
  32. package/build/types/index.d.ts +3 -0
  33. package/build/types/index.d.ts.map +1 -0
  34. package/build/types/index.js +2 -0
  35. package/build/types/index.js.map +1 -0
  36. package/ios/LocalPhotoUploadServer.swift +78 -0
  37. package/ios/MentraPhotoReceiverModule.swift +10 -0
  38. package/ios/Source/BluetoothSdkDefaults.swift +1 -1
  39. package/ios/Source/Bridge.swift +63 -0
  40. package/ios/Source/DeviceManager.swift +134 -29
  41. package/ios/Source/DeviceStore.swift +0 -5
  42. package/ios/Source/MentraBluetoothSDK.swift +26 -23
  43. package/ios/Source/OtaManifest.swift +1 -1
  44. package/ios/Source/internal/BleTraceLogger.swift +192 -0
  45. package/ios/Source/sgcs/G2.swift +518 -11
  46. package/ios/Source/sgcs/MentraLive.swift +607 -39
  47. package/ios/Source/sgcs/MentraNex.swift +416 -32
  48. package/ios/Source/sgcs/SGCManager.swift +155 -0
  49. package/ios/Source/sgcs/mentraos_ble.pb.swift +726 -122
  50. package/ios/Source/status/DeviceStatus.swift +0 -8
  51. package/ios/Source/utils/BleJsonCompact.swift +395 -0
  52. package/ios/Source/utils/BleWireProtocol.swift +92 -0
  53. package/ios/Source/utils/MessageChunkReassembler.swift +82 -0
  54. package/ios/Source/utils/MessageChunker.swift +73 -0
  55. package/package.json +14 -7
  56. package/src/BluetoothSdk.types.ts +13 -1
  57. package/src/types/index.ts +7 -0
@@ -0,0 +1,192 @@
1
+ import Foundation
2
+ import os.log
3
+ import UIKit
4
+
5
+ enum BleTraceLogger {
6
+ private static let log = OSLog(subsystem: "com.mentra.bluetoothsdk", category: "MentraBleTrace")
7
+ private static let maxPayloadChars = 3000
8
+ private static let k900Type = "k900"
9
+ private static let sensitiveKeyParts = ["password", "pass", "token", "secret", "authorization", "auth", "email"]
10
+
11
+ static func logJson(
12
+ direction: String,
13
+ layer: String,
14
+ payload: [String: Any]?,
15
+ bytes: Int? = nil,
16
+ sourceFile: String = #fileID,
17
+ sourceFunction: String = #function,
18
+ sourceLine: Int = #line
19
+ ) {
20
+ guard let payload else {
21
+ emit(format(
22
+ direction: direction,
23
+ layer: layer,
24
+ source: source(file: sourceFile, function: sourceFunction, line: sourceLine),
25
+ type: "null",
26
+ bytes: bytes,
27
+ payload: "null"
28
+ ))
29
+ return
30
+ }
31
+
32
+ let sanitized = sanitizeDictionary(payload)
33
+ emit(format(
34
+ direction: direction,
35
+ layer: layer,
36
+ source: source(file: sourceFile, function: sourceFunction, line: sourceLine),
37
+ type: extractType(from: payload),
38
+ bytes: bytes,
39
+ payload: jsonString(sanitized)
40
+ ))
41
+ }
42
+
43
+ static func logMap(
44
+ direction: String,
45
+ layer: String,
46
+ type: String?,
47
+ payload: [String: Any],
48
+ bytes: Int? = nil,
49
+ sourceFile: String = #fileID,
50
+ sourceFunction: String = #function,
51
+ sourceLine: Int = #line
52
+ ) {
53
+ let sanitized = sanitizeDictionary(payload)
54
+ emit(format(
55
+ direction: direction,
56
+ layer: layer,
57
+ source: source(file: sourceFile, function: sourceFunction, line: sourceLine),
58
+ type: type ?? extractType(from: sanitized),
59
+ bytes: bytes,
60
+ payload: jsonString(sanitized)
61
+ ))
62
+ }
63
+
64
+ static func logLifecycle(component: String, event: String, extra: [String: Any] = [:]) {
65
+ var payload: [String: Any] = [
66
+ "event": event,
67
+ "component": component,
68
+ "pid": ProcessInfo.processInfo.processIdentifier,
69
+ "model": UIDevice.current.model,
70
+ "systemVersion": UIDevice.current.systemVersion,
71
+ ]
72
+ for (key, value) in extra {
73
+ payload[key] = value
74
+ }
75
+ logMap(direction: "phone_app", layer: "app_lifecycle", type: event, payload: payload)
76
+ }
77
+
78
+ private static func emit(_ line: String) {
79
+ os_log("%{public}@", log: log, type: .info, line)
80
+ }
81
+
82
+ private static func format(
83
+ direction: String,
84
+ layer: String,
85
+ source: String,
86
+ type: String,
87
+ bytes: Int?,
88
+ payload: String
89
+ ) -> String {
90
+ let bytesText = bytes.map { " bytes=\($0)" } ?? ""
91
+ return "BLE_TRACE direction=\(direction) layer=\(layer) source=\(source) type=\(type)\(bytesText) payload=\(truncate(payload))"
92
+ }
93
+
94
+ private static func extractType(from payload: [String: Any]) -> String {
95
+ if let type = payload["type"] as? String, !type.isEmpty {
96
+ return type
97
+ }
98
+ if let cValue = payload["C"] as? String, !cValue.isEmpty {
99
+ if let data = cValue.data(using: .utf8),
100
+ let inner = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
101
+ let type = inner["type"] as? String,
102
+ !type.isEmpty
103
+ {
104
+ return type
105
+ }
106
+ return extractK900Type(cValue)
107
+ }
108
+ return "unknown"
109
+ }
110
+
111
+ private static func extractK900Type(_ value: String) -> String {
112
+ value == "sr_log" ? "\(k900Type):sr_log" : k900Type
113
+ }
114
+
115
+ private static func sanitizeDictionary(_ value: [String: Any]) -> [String: Any] {
116
+ var output: [String: Any] = [:]
117
+ for (key, child) in value {
118
+ output[key] = sanitizeValue(key: key, value: child)
119
+ }
120
+ return output
121
+ }
122
+
123
+ private static func sanitizeArray(_ value: [Any]) -> [Any] {
124
+ value.map { sanitizeValue(key: nil, value: $0) }
125
+ }
126
+
127
+ private static func sanitizeValue(key: String?, value: Any) -> Any {
128
+ if let key, sensitiveKeyParts.contains(where: { key.localizedCaseInsensitiveContains($0) }) {
129
+ return "<redacted>"
130
+ }
131
+
132
+ if key == "C", let stringValue = value as? String {
133
+ if let data = stringValue.data(using: .utf8),
134
+ let parsed = try? JSONSerialization.jsonObject(with: data)
135
+ {
136
+ return jsonString(sanitizeJsonValue(parsed))
137
+ }
138
+ return sanitizeK900Command(stringValue)
139
+ }
140
+
141
+ return sanitizeJsonValue(value)
142
+ }
143
+
144
+ private static func sanitizeJsonValue(_ value: Any) -> Any {
145
+ switch value {
146
+ case let dictionary as [String: Any]:
147
+ return sanitizeDictionary(dictionary)
148
+ case let array as [Any]:
149
+ return sanitizeArray(array)
150
+ case let data as Data:
151
+ return "<data \(data.count) bytes>"
152
+ case let url as URL:
153
+ return url.absoluteString
154
+ case let bool as Bool:
155
+ return bool
156
+ case let number as NSNumber:
157
+ return number
158
+ case let string as String:
159
+ return string
160
+ case _ as NSNull:
161
+ return NSNull()
162
+ default:
163
+ return String(describing: value)
164
+ }
165
+ }
166
+
167
+ private static func sanitizeK900Command(_ value: String) -> String {
168
+ value == "sr_log" ? value : "<non-json C payload>"
169
+ }
170
+
171
+ private static func jsonString(_ value: Any) -> String {
172
+ guard JSONSerialization.isValidJSONObject(value),
173
+ let data = try? JSONSerialization.data(withJSONObject: value),
174
+ let string = String(data: data, encoding: .utf8)
175
+ else {
176
+ return String(describing: value)
177
+ }
178
+ return string
179
+ }
180
+
181
+ private static func source(file: String, function: String, line: Int) -> String {
182
+ "\(function)(\(file):\(line))"
183
+ }
184
+
185
+ private static func truncate(_ value: String) -> String {
186
+ guard value.count > maxPayloadChars else {
187
+ return value
188
+ }
189
+ let endIndex = value.index(value.startIndex, offsetBy: maxPayloadChars)
190
+ return "\(value[..<endIndex])...(truncated \(value.count - maxPayloadChars) chars)"
191
+ }
192
+ }