@qafka/react-native 2.8.1 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.8.2] — 2026-11-12
11
+
12
+ ### Fixed
13
+
14
+ - Android emulator in development builds: initialization failed with `Attestation failed: 401 — Root certificate is not a Google attestation root`, because emulators report Android 8+ but have no hardware-backed keystore. In development builds (`__DEV__`) the SDK now detects the emulator and continues without attestation, the same way it already does on the iOS simulator. Use a TEST API key there; PRODUCTION keys still require an attested session. Release builds are unchanged and keep attesting on every device. Requires a native rebuild.
15
+
10
16
  ## [2.8.1] — 2026-10-06
11
17
 
12
18
  ### Added
@@ -27,9 +27,31 @@ class QafkaAttestationModule(reactContext: ReactApplicationContext) :
27
27
  "bundleId" to bundleId,
28
28
  "appVersion" to appVersion,
29
29
  "deviceModel" to deviceModel,
30
+ "isEmulator" to isEmulator(),
30
31
  )
31
32
  }
32
33
 
34
+ // Emulators have no TEE, so their attestation chain is rooted in a
35
+ // software root that the backend rejects. JS uses this only in
36
+ // development builds to fall back to the unsupported-device path.
37
+ private fun isEmulator(): Boolean {
38
+ val fingerprint = Build.FINGERPRINT ?: ""
39
+ val hardware = Build.HARDWARE ?: ""
40
+ val product = Build.PRODUCT ?: ""
41
+ val model = Build.MODEL ?: ""
42
+ return fingerprint.startsWith("generic") ||
43
+ fingerprint.startsWith("unknown") ||
44
+ fingerprint.contains("emulator") ||
45
+ hardware == "goldfish" ||
46
+ hardware == "ranchu" ||
47
+ product.startsWith("sdk") ||
48
+ product.contains("_sdk") ||
49
+ product.contains("emulator") ||
50
+ product.contains("simulator") ||
51
+ model.contains("Emulator") ||
52
+ model.contains("Android SDK built for")
53
+ }
54
+
33
55
  @ReactMethod
34
56
  fun isSupported(promise: Promise) {
35
57
  // Key Attestation requires Android 8.0+ (API 26) for hardware-backed
@@ -14,6 +14,11 @@ export interface QafkaDeviceInfo {
14
14
  */
15
15
  export declare function getDeviceInfo(): QafkaDeviceInfo;
16
16
  export declare function isAttestationAvailable(): boolean;
17
+ /**
18
+ * True when the native module reports an Android emulator. iOS simulators
19
+ * already report `isSupported() === false`, so they never need this flag.
20
+ */
21
+ export declare function isEmulator(): boolean;
17
22
  export declare function isSupported(): Promise<boolean>;
18
23
  export declare function generateKey(): Promise<string>;
19
24
  export declare function attestKey(keyId: string, challengeBase64: string): Promise<string>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Platform = void 0;
4
4
  exports.getDeviceInfo = getDeviceInfo;
5
5
  exports.isAttestationAvailable = isAttestationAvailable;
6
+ exports.isEmulator = isEmulator;
6
7
  exports.isSupported = isSupported;
7
8
  exports.generateKey = generateKey;
8
9
  exports.attestKey = attestKey;
@@ -31,6 +32,14 @@ function getDeviceInfo() {
31
32
  function isAttestationAvailable() {
32
33
  return NativeAttestation !== null;
33
34
  }
35
+ /**
36
+ * True when the native module reports an Android emulator. iOS simulators
37
+ * already report `isSupported() === false`, so they never need this flag.
38
+ */
39
+ function isEmulator() {
40
+ const mod = react_native_1.NativeModules.QafkaAttestation;
41
+ return mod?.isEmulator === true;
42
+ }
34
43
  async function isSupported() {
35
44
  if (!NativeAttestation)
36
45
  return false;
@@ -74,12 +74,18 @@ class AttestationManager {
74
74
  // is essential for diagnosing release-build failures where the JS-side
75
75
  // error overlay only shows a generic "App configuration error".
76
76
  this.log(`[Qafka:init] platform=${react_native_1.Platform.OS} moduleLinked=${moduleLinked}`, `[Qafka:init] platform=${react_native_1.Platform.OS} url=${this.config.apiUrl} moduleLinked=${moduleLinked}`);
77
- const supported = await NativeAttestation.isSupported();
78
- this.log(`[Qafka:init] isSupported=${supported}`);
77
+ // Android emulators report Android 8+ but cannot produce a Google-rooted
78
+ // attestation. Only development builds treat them as unsupported; release
79
+ // builds keep attesting so an emulator is never let through unverified.
80
+ const devEmulator = __DEV__ && react_native_1.Platform.OS === 'android' && NativeAttestation.isEmulator();
81
+ const supported = devEmulator ? false : await NativeAttestation.isSupported();
82
+ this.log(`[Qafka:init] isSupported=${supported} devEmulator=${devEmulator}`);
79
83
  if (!supported) {
80
84
  const reason = !moduleLinked
81
85
  ? `the QafkaAttestation native module is not registered (rebuild your app after installing the SDK)`
82
- : `this device does not support attestation (Android 8.0+ / iOS 14+ required)`;
86
+ : devEmulator
87
+ ? `Android emulators cannot produce hardware-backed attestation; use a TEST API key`
88
+ : `this device does not support attestation (Android 8.0+ / iOS 14+ required)`;
83
89
  if (__DEV__) {
84
90
  console.warn(`[Qafka] Attestation unavailable in this dev environment (${reason}). ` +
85
91
  `Continuing without it; see the Qafka docs for local development setup.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qafka/react-native",
3
- "version": "2.8.1",
3
+ "version": "2.8.2",
4
4
  "description": "Drop-in AI assistant for React Native: chat, voice, and tool execution with screen-aware navigation.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",