@glassly/bluetooth-sdk 0.1.0-dev.98 → 0.2.8-dev.444

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 (155) hide show
  1. package/README.md +47 -6
  2. package/android/build.gradle +7 -7
  3. package/android/lc3Lib/build.gradle +2 -2
  4. package/android/src/main/assets/G2Firmware/README.md +27 -2
  5. package/android/src/main/assets/G2Firmware/{g2-stock-2.2.9.22.evenota.bin → g2-glassly-cfw-2.3.0.24.evenota.bin} +0 -0
  6. package/android/src/main/assets/G2Firmware/{g2-glassly-cfw-2.2.9.22.evenota.bin → g2-stock-2.3.0.24.evenota.bin} +0 -0
  7. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdk.kt +38 -0
  8. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkModule.kt +50 -14
  9. package/android/src/main/java/com/glassly/bluetoothsdk/Bridge.kt +18 -0
  10. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceManager.kt +139 -10
  11. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceStore.kt +28 -1
  12. package/android/src/main/java/com/glassly/bluetoothsdk/DisplayPacer.kt +199 -0
  13. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +10 -1
  14. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +4 -4
  15. package/android/src/main/java/com/glassly/bluetoothsdk/GlassesNotifications.kt +155 -0
  16. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +1075 -257
  17. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2BleLink.kt +119 -0
  18. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassification.kt +29 -28
  19. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwRenderer.kt +138 -33
  20. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwScene.kt +673 -0
  21. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCache.kt +235 -162
  22. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTransport.kt +402 -0
  23. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2DisplayDiagnostics.kt +84 -0
  24. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocol.kt +3 -3
  25. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Flasher.kt +9 -9
  26. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Keyboard.kt +689 -0
  27. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2KeyboardBridge.kt +452 -0
  28. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2KeyboardHid.kt +208 -0
  29. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2NotificationFile.kt +181 -0
  30. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2RingBattery.kt +20 -0
  31. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Sensors.kt +67 -0
  32. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2TouchInput.kt +39 -0
  33. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +5 -5
  34. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +14 -14
  35. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/{GlasslyBle.java → NexProto.java} +6462 -7618
  36. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/NotificationMessageIds.kt +58 -0
  37. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/SGCManager.kt +77 -2
  38. package/android/src/main/java/com/glassly/bluetoothsdk/speakerid/SpeakerIdEngine.kt +1 -1
  39. package/android/src/main/java/com/glassly/bluetoothsdk/status/DeviceStatus.kt +55 -0
  40. package/android/src/main/java/com/glassly/bluetoothsdk/stt/STTTools.kt +1 -1
  41. package/android/src/main/java/com/glassly/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +1 -1
  42. package/android/src/main/java/com/glassly/bluetoothsdk/tts/TTSTools.kt +1 -1
  43. package/android/src/main/java/com/glassly/bluetoothsdk/utils/NexSGCUtils.kt +24 -149
  44. package/android/src/test/java/com/glassly/bluetoothsdk/DisplayPacerTest.kt +277 -0
  45. package/android/src/test/java/com/glassly/bluetoothsdk/G2BleLinkTest.kt +70 -0
  46. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassificationTest.kt +45 -56
  47. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwRendererTest.kt +78 -5
  48. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwSceneTest.kt +489 -0
  49. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCacheTest.kt +100 -43
  50. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTransportTest.kt +252 -0
  51. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2DisplayDiagnosticsTest.kt +64 -0
  52. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2KeyboardTest.kt +271 -0
  53. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2NotificationFileTest.kt +204 -0
  54. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2RingBatteryTest.kt +56 -0
  55. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2SensorsTest.kt +56 -0
  56. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2TouchInputTest.kt +60 -0
  57. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NexProtoDescriptorTest.kt +32 -0
  58. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NotificationMessageIdsTest.kt +58 -0
  59. package/build/BluetoothSdk.types.d.ts +209 -20
  60. package/build/BluetoothSdk.types.d.ts.map +1 -1
  61. package/build/BluetoothSdk.types.js.map +1 -1
  62. package/build/_internal.d.ts +1 -1
  63. package/build/_internal.d.ts.map +1 -1
  64. package/build/_internal.js.map +1 -1
  65. package/build/_private/BluetoothSdkModule.d.ts +30 -1
  66. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  67. package/build/_private/BluetoothSdkModule.js.map +1 -1
  68. package/build/generated/changelogCatalog.d.ts +28 -1
  69. package/build/generated/changelogCatalog.d.ts.map +1 -1
  70. package/build/generated/changelogCatalog.js +37 -1
  71. package/build/generated/changelogCatalog.js.map +1 -1
  72. package/build/generated/releaseMetadata.js +4 -4
  73. package/build/generated/releaseMetadata.js.map +1 -1
  74. package/build/index.d.ts +1 -1
  75. package/build/index.d.ts.map +1 -1
  76. package/build/index.js +14 -0
  77. package/build/index.js.map +1 -1
  78. package/ios/BluetoothSdkModule.swift +102 -13
  79. package/ios/GlasslyBluetoothSDK.podspec +1 -1
  80. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +8 -3
  81. package/ios/Source/BluetoothSDK.swift +53 -0
  82. package/ios/Source/BluetoothSdkDefaults.swift +1 -1
  83. package/ios/Source/Bridge.swift +13 -0
  84. package/ios/Source/DeviceManager.swift +151 -33
  85. package/ios/Source/DeviceStore.swift +28 -14
  86. package/ios/Source/DisplayPacer.swift +180 -0
  87. package/ios/Source/GeneratedChangelogCatalog.swift +10 -1
  88. package/ios/Source/GeneratedReleaseMetadata.swift +4 -4
  89. package/ios/Source/GlassesNotifications.swift +181 -0
  90. package/ios/Source/ObservableStore.swift +14 -2
  91. package/ios/Source/Resources/G2Firmware/README.md +27 -2
  92. package/ios/Source/Resources/G2Firmware/{g2-stock-2.2.9.22.evenota.bin → g2-glassly-cfw-2.3.0.24.evenota.bin} +0 -0
  93. package/ios/Source/Resources/G2Firmware/{g2-glassly-cfw-2.2.9.22.evenota.bin → g2-stock-2.3.0.24.evenota.bin} +0 -0
  94. package/ios/Source/controllers/R1.swift +0 -1
  95. package/ios/Source/internal/BluetoothAvailability.swift +31 -0
  96. package/ios/Source/sgcs/G2.swift +1434 -504
  97. package/ios/Source/sgcs/G2AncsRelay.swift +268 -0
  98. package/ios/Source/sgcs/G2BleLink.swift +102 -0
  99. package/ios/Source/sgcs/G2CfwClassification.swift +45 -27
  100. package/ios/Source/sgcs/G2CfwRenderer.swift +166 -33
  101. package/ios/Source/sgcs/G2CfwScene.swift +779 -0
  102. package/ios/Source/sgcs/G2CfwTextureCache.swift +244 -117
  103. package/ios/Source/sgcs/G2CfwTransport.swift +485 -0
  104. package/ios/Source/sgcs/G2DisplayDiagnostics.swift +154 -0
  105. package/ios/Source/sgcs/G2FlashProtocol.swift +2 -2
  106. package/ios/Source/sgcs/G2Flasher.swift +9 -9
  107. package/ios/Source/sgcs/G2Keyboard.swift +780 -0
  108. package/ios/Source/sgcs/G2KeyboardBridge.swift +438 -0
  109. package/ios/Source/sgcs/G2KeyboardHid.swift +290 -0
  110. package/ios/Source/sgcs/G2NotificationTuning.swift +24 -0
  111. package/ios/Source/sgcs/G2RingBattery.swift +22 -0
  112. package/ios/Source/sgcs/G2Sensors.swift +75 -0
  113. package/ios/Source/sgcs/G2TouchInput.swift +51 -0
  114. package/ios/Source/sgcs/G2WritePacing.swift +18 -0
  115. package/ios/Source/sgcs/MentraNex.swift +44 -44
  116. package/ios/Source/sgcs/SGCManager.swift +120 -13
  117. package/ios/Source/sgcs/{glassly_ble.pb.swift → nex_ble.pb.swift} +405 -465
  118. package/ios/Source/speakerid/SpeakerIdEngine.swift +2 -2
  119. package/ios/Source/status/DeviceStatus.swift +27 -0
  120. package/ios/Source/stt/SherpaOnnxTranscriber.swift +15 -14
  121. package/ios/Source/utils/Enums.swift +0 -1
  122. package/ios/Source/utils/G1Text.swift +0 -1
  123. package/ios/Source/utils/G2NotifyFile.swift +20 -10
  124. package/ios/Source/utils/JSCExperiment.swift +6 -6
  125. package/ios/Source/utils/Models.swift +0 -1
  126. package/ios/Tests/BluetoothSDKTests/BluetoothAvailabilityTests.swift +29 -0
  127. package/ios/Tests/BluetoothSDKTests/DisplayPacerTests.swift +255 -0
  128. package/ios/Tests/BluetoothSDKTests/G2AncsRelayTests.swift +186 -0
  129. package/ios/Tests/BluetoothSDKTests/G2BleLinkTests.swift +52 -0
  130. package/ios/Tests/BluetoothSDKTests/G2CfwClassificationTests.swift +46 -51
  131. package/ios/Tests/BluetoothSDKTests/G2CfwRendererTests.swift +164 -5
  132. package/ios/Tests/BluetoothSDKTests/G2CfwSceneTests.swift +497 -0
  133. package/ios/Tests/BluetoothSDKTests/G2CfwTextureCacheTests.swift +108 -44
  134. package/ios/Tests/BluetoothSDKTests/G2CfwTransportTests.swift +259 -0
  135. package/ios/Tests/BluetoothSDKTests/G2DisplayDiagnosticsTests.swift +89 -0
  136. package/ios/Tests/BluetoothSDKTests/G2FlashProtocolTests.swift +3 -2
  137. package/ios/Tests/BluetoothSDKTests/G2ImageAckTests.swift +104 -0
  138. package/ios/Tests/BluetoothSDKTests/G2KeyboardTests.swift +274 -0
  139. package/ios/Tests/BluetoothSDKTests/G2NotifyFileTests.swift +21 -5
  140. package/ios/Tests/BluetoothSDKTests/G2RingBatteryTests.swift +56 -0
  141. package/ios/Tests/BluetoothSDKTests/G2SensorsTests.swift +56 -0
  142. package/ios/Tests/BluetoothSDKTests/G2TouchInputTests.swift +71 -0
  143. package/ios/Tests/BluetoothSDKTests/G2WritePacingTests.swift +35 -0
  144. package/ios/Tests/BluetoothSDKTests/GlassesNotificationTests.swift +95 -0
  145. package/package.json +1 -1
  146. package/plugin/build/withAndroid.js +2 -2
  147. package/plugin/build/withIos.js +1 -1
  148. package/scripts/gen-nex-proto.sh +12 -0
  149. package/scripts/inject-ios-sdk-version.mjs +1 -1
  150. package/src/BluetoothSdk.types.ts +214 -19
  151. package/src/_internal.ts +1 -1
  152. package/src/_private/BluetoothSdkModule.ts +40 -0
  153. package/src/generated/changelogCatalog.ts +37 -1
  154. package/src/generated/releaseMetadata.ts +4 -4
  155. package/src/index.ts +24 -0
@@ -0,0 +1,95 @@
1
+ @testable import BluetoothSDK
2
+ import Foundation
3
+ import XCTest
4
+
5
+ final class GlassesNotificationTests: XCTestCase {
6
+ func testConfigDictionaryRoundTrip() throws {
7
+ let source: [String: Any] = [
8
+ "enabled": true,
9
+ "popups": false,
10
+ // Bridge numbers arrive as NSNumber, not Int.
11
+ "popupSeconds": NSNumber(value: 7),
12
+ "holdDuringApps": false,
13
+ "blockedApps": ["com.example.one", "com.example.two"],
14
+ "allowedApps": [
15
+ ["id": "com.example.three", "name": "Three"],
16
+ ["id": "com.example.four"],
17
+ ],
18
+ ]
19
+
20
+ let config = try GlassesNotificationConfig(dictionary: source)
21
+ XCTAssertTrue(config.enabled)
22
+ XCTAssertFalse(config.popups)
23
+ XCTAssertEqual(config.popupSeconds, 7)
24
+ XCTAssertFalse(config.holdDuringApps)
25
+ XCTAssertEqual(config.blockedApps, ["com.example.one", "com.example.two"])
26
+ XCTAssertEqual(
27
+ config.allowedApps,
28
+ [
29
+ .init(id: "com.example.three", name: "Three"),
30
+ // A missing name falls back to the id.
31
+ .init(id: "com.example.four", name: "com.example.four"),
32
+ ]
33
+ )
34
+
35
+ let roundTripped = try GlassesNotificationConfig(dictionary: config.dictionary)
36
+ XCTAssertEqual(roundTripped, config)
37
+ }
38
+
39
+ func testConfigRejectsPopupSecondsOutOfRange() {
40
+ for seconds in [-1, 61] {
41
+ XCTAssertThrowsError(
42
+ try GlassesNotificationConfig(dictionary: ["popupSeconds": NSNumber(value: seconds)])
43
+ ) { error in
44
+ guard case GlassesNotificationError.invalidConfig = error else {
45
+ return XCTFail("expected invalidConfig for \(seconds), got \(error)")
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ func testStatusDictionaryUsesNullForMissingFields() {
52
+ let dictionary = GlassesNotificationStatus.unsupported.dictionary
53
+ XCTAssertEqual(dictionary["supported"] as? Bool, false)
54
+ XCTAssertEqual(dictionary["feed"] as? String, "none")
55
+ XCTAssertEqual(dictionary["access"] as? String, "not_needed")
56
+ XCTAssertEqual(dictionary["phase"] as? String, "idle")
57
+ XCTAssertTrue(dictionary["config"] is NSNull)
58
+ XCTAssertTrue(dictionary["error"] is NSNull)
59
+ }
60
+
61
+ func testSnapPopupSeconds() {
62
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(0), 0)
63
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(1), 5)
64
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(5), 5)
65
+ // Ties round up.
66
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(6), 7)
67
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(7), 7)
68
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(8), 7)
69
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(9), 10)
70
+ XCTAssertEqual(G2NotificationTuning.snapPopupSeconds(30), 10)
71
+ }
72
+
73
+ func testFilterEnabledOnlyWithBlockedApps() {
74
+ func config(blocked: [String], allowed: [GlassesNotificationConfig.AllowedApp]) -> GlassesNotificationConfig {
75
+ GlassesNotificationConfig(
76
+ enabled: true,
77
+ popups: true,
78
+ popupSeconds: 5,
79
+ holdDuringApps: true,
80
+ blockedApps: blocked,
81
+ allowedApps: allowed
82
+ )
83
+ }
84
+
85
+ XCTAssertFalse(G2NotificationTuning.filterEnabled(for: config(blocked: [], allowed: [])))
86
+ XCTAssertFalse(
87
+ G2NotificationTuning.filterEnabled(
88
+ for: config(blocked: [], allowed: [.init(id: "com.example.one", name: "One")])
89
+ )
90
+ )
91
+ XCTAssertTrue(
92
+ G2NotificationTuning.filterEnabled(for: config(blocked: ["com.example.one"], allowed: []))
93
+ )
94
+ }
95
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/bluetooth-sdk",
3
- "version": "0.1.0-dev.98",
3
+ "version": "0.2.8-dev.444",
4
4
  "description": "SDK for communicating with smart glasses",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -24,7 +24,7 @@ function withSettingsGradleModifications(config) {
24
24
  return (0, config_plugins_1.withSettingsGradle)(config, (config) => {
25
25
  let settingsGradle = config.modResults.contents;
26
26
  const bluetoothSdkRoot = getBluetoothSdkRoot();
27
- const bluetoothSdkRootExpression = `System.getenv("GLASSLY_BLUETOOTH_SDK_PACKAGE_PATH") ?: ${toGroovyString(bluetoothSdkRoot)}`;
27
+ const bluetoothSdkRootExpression = `System.getenv("BLUETOOTH_SDK_PACKAGE_PATH") ?: ${toGroovyString(bluetoothSdkRoot)}`;
28
28
  if (!settingsGradle.includes("project(':glassly-bluetooth-sdk').projectDir")) {
29
29
  const bluetoothSdkProjectBlock = `
30
30
  if (findProject(':glassly-bluetooth-sdk') != null) {
@@ -115,7 +115,7 @@ function withSherpaOnnxLocalMavenRepo(config) {
115
115
  }
116
116
  let contents = config.modResults.contents;
117
117
  const fallbackRoot = toGroovyString(getBluetoothSdkRoot());
118
- const repoDirExpression = `new File(System.getenv("GLASSLY_BLUETOOTH_SDK_PACKAGE_PATH") ?: ${fallbackRoot}, "android/libs/maven")`;
118
+ const repoDirExpression = `new File(System.getenv("BLUETOOTH_SDK_PACKAGE_PATH") ?: ${fallbackRoot}, "android/libs/maven")`;
119
119
  const marker = "// bluetooth-sdk: sherpa-onnx local maven repo";
120
120
  if (contents.includes(marker)) {
121
121
  return config;
@@ -9,7 +9,7 @@ const child_process_1 = require("child_process");
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const config_plugins_1 = require("expo/config-plugins");
12
- const BLUETOOTH_SDK_EXPO_ADAPTER_ENV = "GLASSLY_BLUETOOTH_SDK_INCLUDE_EXPO_ADAPTER";
12
+ const BLUETOOTH_SDK_EXPO_ADAPTER_ENV = "BLUETOOTH_SDK_INCLUDE_EXPO_ADAPTER";
13
13
  const BLUETOOTH_SDK_EXPO_ADAPTER_LINE = `ENV['${BLUETOOTH_SDK_EXPO_ADAPTER_ENV}'] ||= '1'`;
14
14
  const INFO_ANALYTICS_DISABLED = "BluetoothSdkAnalyticsDisabled";
15
15
  exports.INFO_SDK_VERSION = "BluetoothSdkVersion";
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ # Regenerate the Nex BLE protobuf bindings from proto/nex_ble.proto.
3
+ # Needs protoc and protoc-gen-swift (brew install protobuf swift-protobuf).
4
+ # Keep com.google.protobuf:protobuf-java in android/build.gradle >= the protoc
5
+ # major used here; gencode refuses to load on an older runtime.
6
+ set -euo pipefail
7
+ cd "$(dirname "$0")/.."
8
+ protoc --version
9
+ protoc -I proto \
10
+ --java_out=android/src/main/java \
11
+ --swift_out=ios/Source/sgcs \
12
+ proto/nex_ble.proto
@@ -17,7 +17,7 @@ if (typeof version !== "string" || version.trim() === "") {
17
17
  throw new Error("mobile/modules/bluetooth-sdk/package.json is missing a version")
18
18
  }
19
19
 
20
- const placeholder = 'private static let swiftPackageSdkVersion = "__GLASSLY_BLUETOOTH_SDK_VERSION__"'
20
+ const placeholder = 'private static let swiftPackageSdkVersion = "__BLUETOOTH_SDK_VERSION__"'
21
21
  const injectedVersion = `private static let swiftPackageSdkVersion = "${version}"`
22
22
 
23
23
  async function pathExists(filePath) {
@@ -45,6 +45,8 @@ export type TouchEvent = {
45
45
  deviceModel: DeviceModel
46
46
  gestureName: string
47
47
  timestamp: number
48
+ /** Native input source when supplied; G2 source 2 identifies the ring. */
49
+ source?: number
48
50
  }
49
51
 
50
52
  export type AccelEvent = {
@@ -55,6 +57,53 @@ export type AccelEvent = {
55
57
  timestamp: number
56
58
  }
57
59
 
60
+ /**
61
+ * One raw HID key transition from the keyboard bridged through G2 Glassly CFW
62
+ * (revision 39+): keyboard page 7 or consumer page 12 usage ids, no layout
63
+ * applied. Phone receipt time in ms.
64
+ */
65
+ export type KeyboardKeyEvent = {
66
+ page: number
67
+ usage: number
68
+ down: boolean
69
+ timestamp: number
70
+ }
71
+
72
+ /** One advertiser seen during a keyboard scan. `address` is MSB-first hex. */
73
+ export type KeyboardAdvertEvent = {
74
+ address: string
75
+ /** 0 public, 1 random, 2 public identity, 3 random identity. */
76
+ addressType: number
77
+ name: string
78
+ /** Advertises the HID service (0x1812). */
79
+ hid: boolean
80
+ rssi: number
81
+ }
82
+
83
+ /**
84
+ * Pairing prompt from the keyboard bridge. `passkey`: the keyboard shows a
85
+ * PIN the user must enter on the phone (answer with g2KeyboardPasskey).
86
+ * `display`: the phone chose `value`; the user types it on the keyboard and
87
+ * presses Enter. `compare`: confirm the keyboard shows `value` (g2KeyboardCompare).
88
+ */
89
+ export type KeyboardPairingEvent = {
90
+ kind: "passkey" | "display" | "compare"
91
+ value?: number
92
+ }
93
+
94
+ export type KeyboardBridgeState = "idle" | "scanning" | "connecting" | "pairing" | "configuring" | "connected" | "error"
95
+
96
+ export type KeyboardBridgeStatus = {
97
+ keyboardBridge: boolean
98
+ keyboardConnected: boolean
99
+ keyboardName: string
100
+ keyboardSaved: boolean
101
+ keyboardState: KeyboardBridgeState
102
+ keyboardError: string
103
+ /** Firmware STATUS record when the bridge answered the query. */
104
+ firmware?: {enabled: boolean; conn: number; connected: boolean; encrypted: boolean; scanning: boolean}
105
+ }
106
+
58
107
  export type HeadUpEvent = {
59
108
  up: boolean
60
109
  }
@@ -63,8 +112,39 @@ export type HeadUpEvent = {
63
112
  * Glasses magnetometer heading, streamed while the native navigation mode is
64
113
  * active (G2 service 0x08). Degrees 0…359, 0 = magnetic north.
65
114
  */
115
+ export type LightSensorEvent = {
116
+ type: "light_sensor"
117
+ reason: "query" | "started" | "poll" | "stopped"
118
+ opened: boolean
119
+ passive: boolean
120
+ autoBrightness: boolean
121
+ readSucceeded: boolean
122
+ status: number
123
+ value: number
124
+ peak: number
125
+ targetLevel: number
126
+ brightness: number
127
+ gear: number
128
+ scaleQ10: number
129
+ sampleTimestampMs: number
130
+ timestamp: number
131
+ }
132
+
133
+ export type CompassSensorDiagnostics = {
134
+ accuracy: 0 | 1 | 2 | 3 | null
135
+ anomalies: 0 | 1 | 2 | null
136
+ source: "unknown" | "grv" | "gmrv" | "rv"
137
+ sampleMatched: boolean
138
+ grvValid: boolean
139
+ gmrvValid: boolean
140
+ rvValid: boolean
141
+ magneticDataFresh: boolean
142
+ sampleTimestampMs: number
143
+ }
144
+
66
145
  export type CompassHeadingEvent = {
67
146
  type: "compass_heading"
147
+ diagnostics?: CompassSensorDiagnostics
68
148
  heading: number
69
149
  timestamp: number
70
150
  }
@@ -91,6 +171,29 @@ export type NavigationViewEvent = {
91
171
  viewIndex: number
92
172
  }
93
173
 
174
+ /**
175
+ * A scene frame (display.render()) reached — or can no longer reach — the
176
+ * glasses. `seq` is the host's frame number; a report covers every earlier
177
+ * frame too, since unsent frames fold into the next one. `presented: false`
178
+ * carries the `reason` (screen off, nav UI up, page rebuilding, …).
179
+ */
180
+ export type SceneFramePresentedEvent = {
181
+ type: "scene_frame_presented"
182
+ seq: number
183
+ appId: string
184
+ presented: boolean
185
+ reason?: string
186
+ }
187
+
188
+ /**
189
+ * The glasses finished every animation a scene frame started (Glassly CFW
190
+ * revision 27+). `tag` is the low 16 bits of the host frame number.
191
+ */
192
+ export type SceneSettledEvent = {
193
+ type: "scene_settled"
194
+ tag: number
195
+ }
196
+
94
197
  export type VoiceActivityDetectionStatusEvent = {
95
198
  type: "voice_activity_detection_status"
96
199
  voiceActivityDetectionEnabled: boolean
@@ -1001,10 +1104,13 @@ export type BluetoothSdkModuleEvents = {
1001
1104
  button_press: (event: ButtonPressEvent) => void
1002
1105
  touch_event: (event: TouchEvent) => void
1003
1106
  accel_event: (event: AccelEvent) => void
1107
+ light_sensor: (event: LightSensorEvent) => void
1004
1108
  compass_heading: (event: CompassHeadingEvent) => void
1005
1109
  compass_calibration: (event: CompassCalibrationEvent) => void
1006
1110
  navigation_mode_change: (event: NavigationModeEvent) => void
1007
1111
  navigation_view_change: (event: NavigationViewEvent) => void
1112
+ scene_frame_presented: (event: SceneFramePresentedEvent) => void
1113
+ scene_settled: (event: SceneSettledEvent) => void
1008
1114
  head_up: (event: HeadUpEvent) => void
1009
1115
  voice_activity_detection_status: (event: VoiceActivityDetectionStatusEvent) => void
1010
1116
  speaking_status: (event: SpeakingStatusEvent) => void
@@ -1016,6 +1122,8 @@ export type BluetoothSdkModuleEvents = {
1016
1122
  phone_notification: (event: PhoneNotificationEvent) => void
1017
1123
  phone_notification_dismissed: (event: PhoneNotificationDismissedEvent) => void
1018
1124
  notification_app_seen: (event: NotificationAppSeenEvent) => void
1125
+ glasses_notification_status: (event: GlassesNotificationStatus) => void
1126
+ notification_upload_result: (event: NotificationUploadResult) => void
1019
1127
  wifi_status_change: (event: WifiStatusChangeEvent) => void
1020
1128
  wifi_scan_result: (event: WifiScanResultEvent) => void
1021
1129
  hotspot_status_change: (event: HotspotStatusChangeEvent) => void
@@ -1060,6 +1168,9 @@ export type BluetoothSdkModuleEvents = {
1060
1168
  receive_command_from_ble: (event: BleCommandTraceEvent) => void
1061
1169
  miniapp_selected: (event: MiniappSelectedEvent) => void
1062
1170
  extraction_progress: (event: ExtractionProgressEvent) => void
1171
+ keyboard_key: (event: KeyboardKeyEvent) => void
1172
+ keyboard_advert: (event: KeyboardAdvertEvent) => void
1173
+ keyboard_pairing: (event: KeyboardPairingEvent) => void
1063
1174
  }
1064
1175
 
1065
1176
  export interface ExtractionProgressEvent {
@@ -1106,6 +1217,64 @@ export interface NotificationAppSeenEvent {
1106
1217
  timestamp: number
1107
1218
  }
1108
1219
 
1220
+ /** How connected glasses obtain the phone's notifications. */
1221
+ export type GlassesNotificationFeed = "phone_upload" | "ancs" | "none"
1222
+
1223
+ /**
1224
+ * Desired on-glass notification behaviour, in glasses-neutral terms. Drivers
1225
+ * map it onto their protocol and snap values their firmware cannot take.
1226
+ */
1227
+ export interface GlassesNotificationConfig {
1228
+ /** Master switch: off keeps every phone notification off the glasses. */
1229
+ enabled: boolean
1230
+ /** Show a popup when a notification arrives; off keeps history only. */
1231
+ popups: boolean
1232
+ /** Seconds a popup stays up. 0 lets the firmware choose. */
1233
+ popupSeconds: number
1234
+ /** Hold popups while another glasses feature (navigation, a miniapp) is on screen. */
1235
+ holdDuringApps: boolean
1236
+ /** Ids the wearer blocked: Android package names or iOS bundle ids. */
1237
+ blockedApps: string[]
1238
+ /**
1239
+ * Known ids minus blocked, for firmware whose filter is an allowlist.
1240
+ * Filtering is off whenever `blockedApps` is empty, whatever this holds.
1241
+ */
1242
+ allowedApps: Array<{id: string; name: string}>
1243
+ }
1244
+
1245
+ export interface GlassesNotificationStatus {
1246
+ /** The connected driver can take a config at all. */
1247
+ supported: boolean
1248
+ feed: GlassesNotificationFeed
1249
+ /**
1250
+ * Whether the glasses may read the phone's notifications. `not_needed` when
1251
+ * the phone uploads content itself.
1252
+ */
1253
+ access: "granted" | "denied" | "unknown" | "not_needed"
1254
+ /** `applied` means the last config was written to the link, not acknowledged. `stale` needs a reconnect. */
1255
+ phase: "idle" | "applying" | "applied" | "stale" | "error"
1256
+ config: GlassesNotificationConfig | null
1257
+ error: string | null
1258
+ }
1259
+
1260
+ /** One phone notification handed to glasses that present content themselves. */
1261
+ export interface PhoneNotificationUpload {
1262
+ notificationId: string
1263
+ packageName: string
1264
+ appName: string
1265
+ title: string
1266
+ subtitle: string
1267
+ body: string
1268
+ timestampMs: number
1269
+ }
1270
+
1271
+ /** Outcome of an upload, by id only; content never crosses back. */
1272
+ export interface NotificationUploadResult {
1273
+ notificationId: string
1274
+ outcome: "sent" | "failed" | "cancelled" | "dropped"
1275
+ detail: string
1276
+ }
1277
+
1109
1278
  export type PublicGlassesStatus = Omit<
1110
1279
  GlassesStatus,
1111
1280
  "otaUpdateAvailable" | "otaProgress" | "otaInProgress" | "otaVersionUrl"
@@ -1126,6 +1295,8 @@ export type PublicBluetoothStatus = Pick<
1126
1295
  >
1127
1296
 
1128
1297
  export type BluetoothSdkEventMap = {
1298
+ glasses_notification_status: GlassesNotificationStatus
1299
+ notification_upload_result: NotificationUploadResult
1129
1300
  log: LogEvent
1130
1301
  device_discovered: Device
1131
1302
  default_device_changed: {device?: Device}
@@ -1175,6 +1346,9 @@ export type BluetoothSdkEventMap = {
1175
1346
  g2_firmware_flash_progress: G2FirmwareFlashProgressEvent
1176
1347
  version_info: VersionInfoEvent
1177
1348
  extraction_progress: ExtractionProgressEvent
1349
+ keyboard_key: KeyboardKeyEvent
1350
+ keyboard_advert: KeyboardAdvertEvent
1351
+ keyboard_pairing: KeyboardPairingEvent
1178
1352
  }
1179
1353
 
1180
1354
  export type BluetoothSdkEventName = keyof BluetoothSdkEventMap
@@ -1226,6 +1400,12 @@ export interface BluetoothSdkPublicModule {
1226
1400
  * saying "Hey Even, show notifications"). G2 only; a no-op elsewhere.
1227
1401
  */
1228
1402
  showNativeNotificationPanel(): Promise<void>
1403
+ /**
1404
+ * Apply on-glass notification behaviour. Rejects when no glasses are connected
1405
+ * or the connected driver has no firmware notification surface.
1406
+ */
1407
+ setGlassesNotificationConfig(config: GlassesNotificationConfig): Promise<void>
1408
+ getGlassesNotificationStatus(): Promise<GlassesNotificationStatus>
1229
1409
  setDashboardPosition(height: number, depth: number): Promise<void>
1230
1410
  setHeadUpAngle(angleDegrees: number): Promise<void>
1231
1411
  setImuEnabled(enabled: boolean): Promise<void>
@@ -1320,6 +1500,19 @@ export interface BluetoothSdkPublicModule {
1320
1500
  requestVersionInfo(): Promise<VersionInfoResult>
1321
1501
  availableG2FirmwareArtifacts(): Promise<G2FirmwareArtifact[]>
1322
1502
  startG2FirmwareFlash(target: G2FirmwareTarget): Promise<G2FirmwareFlashResult>
1503
+ /**
1504
+ * BLE keyboard bridge (G2 Glassly CFW revision 39+): the right lens hosts one
1505
+ * HID-over-GATT keyboard. Scan for five seconds (results also arrive as
1506
+ * `keyboard_advert` events), connect and remember one, or drop it.
1507
+ */
1508
+ g2KeyboardScan(): Promise<KeyboardAdvertEvent[]>
1509
+ g2KeyboardConnect(address: string, addressType: number, name: string): Promise<void>
1510
+ g2KeyboardReconnect(): Promise<void>
1511
+ g2KeyboardDisconnect(): Promise<void>
1512
+ g2KeyboardForget(): Promise<void>
1513
+ g2KeyboardPasskey(pin: number): Promise<void>
1514
+ g2KeyboardCompare(accept: boolean): Promise<void>
1515
+ g2KeyboardStatus(): Promise<KeyboardBridgeStatus>
1323
1516
  /**
1324
1517
  * Select the OTA manifest used by subsequent update checks and installs.
1325
1518
  * The URL may point at Glassly's hosted manifest or any customer-controlled HTTP(S) server.
@@ -1467,11 +1660,20 @@ export interface GlassesStatus {
1467
1660
  */
1468
1661
  sceneCanvasWidth?: number
1469
1662
  sceneCanvasHeight?: number
1663
+ /** Connected firmware draws vector shapes and animates transitions on the glasses (G2 Glassly CFW). */
1664
+ sceneVector?: boolean
1665
+ /** Connected firmware reports when a scene frame's animations have ended (G2 Glassly CFW revision 27+). */
1666
+ sceneSettle?: boolean
1470
1667
  // wifi info
1471
1668
  wifi: WifiStatus
1472
1669
  // battery info
1473
1670
  batteryLevel: number
1474
1671
  charging: boolean
1672
+ /** R1 status relayed by the glasses; independent of the phone-connected controller. */
1673
+ ringConnected: boolean
1674
+ /** -1 until a valid connected R1 battery report is available. */
1675
+ ringBatteryLevel: number
1676
+ ringCharging: boolean
1475
1677
  caseBatteryLevel: number
1476
1678
  caseCharging: boolean
1477
1679
  caseOpen: boolean
@@ -1494,6 +1696,18 @@ export interface GlassesStatus {
1494
1696
  * on Android and for models that don't consume ANCS on-firmware.
1495
1697
  */
1496
1698
  ancsAuthorized?: boolean
1699
+ /**
1700
+ * G2 Glassly CFW keyboard bridge (revision 39+). `keyboardBridge` is true
1701
+ * only while connected glasses run a firmware that hosts a keyboard;
1702
+ * `keyboardSaved`/`keyboardName` describe the remembered keyboard, which
1703
+ * the driver reconnects on every CFW detection.
1704
+ */
1705
+ keyboardBridge?: boolean
1706
+ keyboardConnected?: boolean
1707
+ keyboardName?: string
1708
+ keyboardSaved?: boolean
1709
+ keyboardState?: KeyboardBridgeState
1710
+ keyboardError?: string
1497
1711
  }
1498
1712
 
1499
1713
  export interface CoreDashboardMenuItem {
@@ -1514,23 +1728,6 @@ export interface CoreSettings {
1514
1728
  calendar_events: CalendarEvent[]
1515
1729
  }
1516
1730
 
1517
- /** G2 on-glass notification display behavior (NotificationControl protobuf). */
1518
- export interface G2NotificationCtrlSetting {
1519
- enabled: boolean
1520
- auto_display: boolean
1521
- /** On-screen popup duration in seconds: 0 (firmware default), 5, 7, or 10. */
1522
- disp_time: number
1523
- avoid_disturb: boolean
1524
- }
1525
-
1526
- /** G2 on-glass ANCS app filter (user/notify_whitelist.json push). */
1527
- export interface G2NotificationFilterSetting {
1528
- /** false = whitelisting off on-glass (fail-open, every app shows). */
1529
- enabled: boolean
1530
- /** Allowlist entries; identifiers are iOS bundle ids. */
1531
- apps: Array<{id: string; name: string}>
1532
- }
1533
-
1534
1731
  export interface Device {
1535
1732
  /**
1536
1733
  * Stable app-facing key for this scan result, within the limits of the
@@ -1629,8 +1826,6 @@ export type BluetoothSettingsUpdate = Partial<{
1629
1826
  dashboard_depth: number
1630
1827
  menu_apps: DashboardMenuItem[] | CoreDashboardMenuItem[] | Array<Record<string, unknown>> | null
1631
1828
  calendar_events: CalendarEvent[]
1632
- notification_ctrl: G2NotificationCtrlSetting
1633
- notification_filter: G2NotificationFilterSetting
1634
1829
  metric_system: boolean
1635
1830
  twelve_hour_time: boolean
1636
1831
  gallery_mode: boolean
package/src/_internal.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * surface.
8
8
  */
9
9
  export {default} from "./_private/BluetoothSdkModule"
10
- export type {BluetoothSdkInternalModule} from "./_private/BluetoothSdkModule"
10
+ export type {BluetoothSdkInternalModule, JscSpawnAndMeasureResult} from "./_private/BluetoothSdkModule"
11
11
  export * from "./BluetoothSdk.types"
12
12
  export {default as LocalNetwork} from "./_private/LocalNetworkModule"
13
13
  export * from "./_private/LocalNetworkModule"
@@ -26,8 +26,13 @@ import type {
26
26
  G2FirmwareFlashResult,
27
27
  G2FirmwareTarget,
28
28
  HotspotStatusChangeEvent,
29
+ KeyboardAdvertEvent,
30
+ KeyboardBridgeStatus,
29
31
  MicPreference,
32
+ GlassesNotificationConfig,
33
+ GlassesNotificationStatus,
30
34
  ObservableStoreCategory,
35
+ PhoneNotificationUpload,
31
36
  OtaQueryResult,
32
37
  OtaStartAckEvent,
33
38
  PhotoRequestParams,
@@ -108,6 +113,10 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
108
113
  forget(): Promise<void>
109
114
  forgetController(): Promise<void>
110
115
  showDashboard(): Promise<void>
116
+ setGlassesNotificationConfig(config: GlassesNotificationConfig): Promise<void>
117
+ getGlassesNotificationStatus(): Promise<GlassesNotificationStatus>
118
+ /** Glasses that present phone notifications from uploaded content (G2 on Android). Rejects elsewhere. */
119
+ uploadPhoneNotification(upload: PhoneNotificationUpload): Promise<void>
111
120
  setBrightness(level: number, autoMode?: boolean | null): Promise<void>
112
121
  setAutoBrightness(enabled: boolean): Promise<void>
113
122
  setDashboardPosition(height: number, depth: number): Promise<void>
@@ -115,10 +124,13 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
115
124
  setCalendarEvents(events: CalendarEvent[]): Promise<void>
116
125
  setHeadUpAngle(angleDegrees: number): Promise<void>
117
126
  setImuEnabled(enabled: boolean): Promise<void>
127
+ glassesSensorControl(sensor: string, operation: string, options: Record<string, number>): Promise<boolean>
118
128
  setScreenDisabled(disabled: boolean): Promise<void>
119
129
  ping(): Promise<void>
120
130
  dbg1(): Promise<void>
121
131
  dbg2(): Promise<void>
132
+ dbg3(): Promise<void>
133
+ dbg4(): Promise<void>
122
134
 
123
135
  // Incident Reporting
124
136
  sendIncidentId(incidentId: string, apiBaseUrl?: string | null): Promise<void>
@@ -185,6 +197,16 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
185
197
  availableG2FirmwareArtifacts(): Promise<G2FirmwareArtifact[]>
186
198
  startG2FirmwareFlash(target: G2FirmwareTarget): Promise<G2FirmwareFlashResult>
187
199
 
200
+ // BLE keyboard bridge (G2 Glassly CFW revision 39+)
201
+ g2KeyboardScan(): Promise<KeyboardAdvertEvent[]>
202
+ g2KeyboardConnect(address: string, addressType: number, name: string): Promise<void>
203
+ g2KeyboardReconnect(): Promise<void>
204
+ g2KeyboardDisconnect(): Promise<void>
205
+ g2KeyboardForget(): Promise<void>
206
+ g2KeyboardPasskey(pin: number): Promise<void>
207
+ g2KeyboardCompare(accept: boolean): Promise<void>
208
+ g2KeyboardStatus(): Promise<KeyboardBridgeStatus>
209
+
188
210
  // Version Info Commands
189
211
  requestVersionInfo(): Promise<VersionInfoResult>
190
212
 
@@ -290,6 +312,24 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
290
312
 
291
313
  // Process resident-set-size in MB. iOS-only; Android stub returns 0.
292
314
  getMemoryMB(): number
315
+
316
+ // JSC memory-spike harness (see JSCExperiment.swift). iOS-only; not
317
+ // implemented on Android — callers must guard for its absence.
318
+ /** Spawn `count` JSContexts and report the memory delta vs `baselineMB`. */
319
+ jscSpawnAndMeasure(count: number, baselineMB: number): JscSpawnAndMeasureResult
320
+ /** Tear down every JSContext spawned by the harness. */
321
+ jscKillAll(): void
322
+ }
323
+
324
+ /** Result of {@link BluetoothSdkNativeModule.jscSpawnAndMeasure}. */
325
+ export interface JscSpawnAndMeasureResult {
326
+ spawned: number
327
+ totalAlive: number
328
+ baselineMB: number
329
+ beforeMB: number
330
+ afterMB: number
331
+ deltaMB: number
332
+ perContextMB: number
293
333
  }
294
334
 
295
335
  export type BluetoothSdkInternalModule = BluetoothSdkNativeModule
@@ -7,7 +7,43 @@ export const GENERATED_RELEASE_CHANGELOGS = Object.freeze(
7
7
  },
8
8
  {
9
9
  "version": "3.1.0",
10
- "markdown": "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- GlasslyOS, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."
10
+ "markdown": "Software updates are more reliable, with clearer progress and recovery when the glasses restart.\n\n- Glassly, Glassly Engine, the Bluetooth SDK, and the glasses client now share one coordinated release version.\n- Mentra Live updates can continue across APK, system, and firmware restarts without asking the user to start the same update again.\n- Bluetooth photo capture and transfer diagnostics are more precise and less disruptive to normal glasses traffic."
11
+ },
12
+ {
13
+ "version": "0.2.8",
14
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
15
+ },
16
+ {
17
+ "version": "0.2.7",
18
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
19
+ },
20
+ {
21
+ "version": "0.2.6",
22
+ "markdown": "- Terminal follows light and dark mode, removes the on-glasses status badge, and uses font-scaled line spacing in the glasses session picker.\n- Notifications uses the explicit 5-second popup default and prevents text selection on iOS.\n- The session.display example removes the SVG and rotation demo."
23
+ },
24
+ {
25
+ "version": "0.2.5",
26
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
27
+ },
28
+ {
29
+ "version": "0.2.4",
30
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
31
+ },
32
+ {
33
+ "version": "0.2.3",
34
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
35
+ },
36
+ {
37
+ "version": "0.2.2",
38
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
39
+ },
40
+ {
41
+ "version": "0.2.1",
42
+ "markdown": "This release is under active development. User-facing changes will be documented as they land."
43
+ },
44
+ {
45
+ "version": "0.2.0",
46
+ "markdown": "The glasses UI on Glassly CFW is now a set of pages over one overlay: the dashboard, side menu, calendar, notification viewer and debug menu each stand on their own.\n\n- A phone notification shows the viewer on its own and closes back to whatever was on the glasses; it no longer opens the dashboard first, and the ignore-while-active hold is honoured everywhere on custom firmware.\n- Double tap on any page returns to the main content; head-down closes only the dashboard.\n- A debug menu on the dashboard (Debug Settings toggle) queries phone-side state such as isPhoneActive().\n- The metric toggle moved to Appearance, and miniapps can read the host's preferences.\n- Messenger group threads show on the notification title row."
11
47
  },
12
48
  {
13
49
  "version": "0.1.0",
@@ -11,10 +11,10 @@ export interface BluetoothSdkReleaseMetadata {
11
11
 
12
12
  export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
- "familyBaseVersion": "0.1.0",
15
- "releaseIdentity": "0.1.0-dev.98",
16
- "releaseSetId": "glassly-0.1.0-dev.98",
17
- "sourceCommit": "2c7feb7c84f8161087b58ef18cf589254ad16ae8",
14
+ "familyBaseVersion": "0.2.8",
15
+ "releaseIdentity": "0.2.8-dev.444",
16
+ "releaseSetId": "glassly-0.2.8-dev.444",
17
+ "sourceCommit": "9ad99e635c0320d07373d42bb7422daf5289d49d",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })