diff --git a/mobile/package.json b/mobile/package.json
index 9d66794..e528fdb 100644
--- a/mobile/package.json
+++ b/mobile/package.json
@@ -28,6 +28,7 @@
"@bytelyst/survey-client": "^0.1.0",
"@bytelyst/telemetry-client": "^0.1.0",
"expo": "~55.0.4",
+ "expo-constants": "~18.0.13",
"expo-router": "~6.0.4",
"expo-status-bar": "~3.0.9",
"react": "19.2.0",
diff --git a/mobile/src/app/(tabs)/_layout.tsx b/mobile/src/app/(tabs)/_layout.tsx
index 4477ae2..f9f218b 100644
--- a/mobile/src/app/(tabs)/_layout.tsx
+++ b/mobile/src/app/(tabs)/_layout.tsx
@@ -3,11 +3,11 @@ import { Tabs } from 'expo-router';
export default function TabLayout() {
return (
-
-
-
-
-
+
+
+
+
+
);
}
diff --git a/mobile/src/app/(tabs)/capture.tsx b/mobile/src/app/(tabs)/capture.tsx
index c1afe3c..188f9e7 100644
--- a/mobile/src/app/(tabs)/capture.tsx
+++ b/mobile/src/app/(tabs)/capture.tsx
@@ -64,6 +64,7 @@ export default function CaptureScreen() {
textAlignVertical="top"
/>
{
const didSave = await saveDraft(activeWorkspaceId, title, body);
setSaved(didSave);
diff --git a/mobile/src/app/(tabs)/inbox.tsx b/mobile/src/app/(tabs)/inbox.tsx
index a212df8..8645e30 100644
--- a/mobile/src/app/(tabs)/inbox.tsx
+++ b/mobile/src/app/(tabs)/inbox.tsx
@@ -40,6 +40,7 @@ export default function InboxScreen() {
Status: {item.status}
{errorMessage ? {errorMessage} : null}
{
const didAuthenticate =
mode === 'signin'
@@ -87,6 +88,7 @@ export default function AuthScreen() {
{
setErrorMessage(null);
setMode((current) => (current === 'signin' ? 'register' : 'signin'));
diff --git a/mobile/src/lib/app-metadata.ts b/mobile/src/lib/app-metadata.ts
new file mode 100644
index 0000000..246e108
--- /dev/null
+++ b/mobile/src/lib/app-metadata.ts
@@ -0,0 +1,12 @@
+import Constants from 'expo-constants';
+import { Platform } from 'react-native';
+
+export const APP_PLATFORM: 'ios' | 'android' = Platform.OS === 'android' ? 'android' : 'ios';
+
+export const APP_VERSION = Constants.expoConfig?.version ?? '0.1.0';
+
+export const BUILD_NUMBER =
+ Constants.expoConfig?.ios?.buildNumber ??
+ (Constants.expoConfig?.android?.versionCode ? String(Constants.expoConfig.android.versionCode) : '1');
+
+export const OS_VERSION = typeof Platform.Version === 'string' ? Platform.Version : String(Platform.Version ?? 'unknown');
diff --git a/mobile/src/lib/broadcast-client.ts b/mobile/src/lib/broadcast-client.ts
index 7d9a7bf..2b93137 100644
--- a/mobile/src/lib/broadcast-client.ts
+++ b/mobile/src/lib/broadcast-client.ts
@@ -1,6 +1,7 @@
import { createBroadcastClient, type BroadcastClient } from '@bytelyst/broadcast-client';
import { API_CONFIG, PRODUCT_ID } from '../api/config';
import { getAuthClient } from '../api/auth';
+import { APP_PLATFORM, APP_VERSION, OS_VERSION } from './app-metadata';
let broadcastClient: BroadcastClient | null = null;
@@ -10,9 +11,9 @@ export function getBroadcastClient(): BroadcastClient {
baseUrl: API_CONFIG.platformBaseUrl,
productId: PRODUCT_ID,
getAuthToken: () => getAuthClient().getAccessToken() ?? '',
- platform: 'ios',
- appVersion: '0.1.0',
- osVersion: 'unknown',
+ platform: APP_PLATFORM,
+ appVersion: APP_VERSION,
+ osVersion: OS_VERSION,
});
}
diff --git a/mobile/src/lib/platform.ts b/mobile/src/lib/platform.ts
index b28e368..32bdb5f 100644
--- a/mobile/src/lib/platform.ts
+++ b/mobile/src/lib/platform.ts
@@ -5,6 +5,7 @@ import { createBlobClient } from '@bytelyst/blob-client';
import { DiagnosticsClient } from '@bytelyst/diagnostics-client';
import { API_CONFIG, PRODUCT_ID } from '../api/config';
import { mmkvStorage } from '../store/mmkv-storage';
+import { APP_VERSION, BUILD_NUMBER, OS_VERSION } from './app-metadata';
function getAccessToken(): string | null {
return mmkvStorage.getItem(`${PRODUCT_ID}_access_token`);
@@ -17,10 +18,10 @@ export const telemetryClient = createTelemetryClient({
platform: 'mobile',
channel: 'notelett_mobile',
transport: 'fetch',
- appVersion: '0.1.0',
- buildNumber: '1',
+ appVersion: APP_VERSION,
+ buildNumber: BUILD_NUMBER,
releaseChannel: 'dev',
- osFamily: 'other',
+ osFamily: OS_VERSION,
});
export const featureFlagClient = createFeatureFlagClient({
@@ -54,9 +55,9 @@ export function getDiagnosticsClient() {
platform: 'mobile',
channel: 'notelett_mobile',
anonymousInstallId: mmkvStorage.getItem(`${PRODUCT_ID}_install_id`) ?? 'unknown',
- osFamily: 'other',
- appVersion: '0.1.0',
- buildNumber: '1',
+ osFamily: OS_VERSION,
+ appVersion: APP_VERSION,
+ buildNumber: BUILD_NUMBER,
releaseChannel: 'dev',
getAuthToken: () => getAccessToken() ?? '',
});
diff --git a/mobile/src/lib/survey-client.ts b/mobile/src/lib/survey-client.ts
index c195401..aab844f 100644
--- a/mobile/src/lib/survey-client.ts
+++ b/mobile/src/lib/survey-client.ts
@@ -1,6 +1,7 @@
import { createSurveyClient, type SurveyClient } from '@bytelyst/survey-client';
import { API_CONFIG, PRODUCT_ID } from '../api/config';
import { getAuthClient } from '../api/auth';
+import { APP_PLATFORM, APP_VERSION, OS_VERSION } from './app-metadata';
let surveyClient: SurveyClient | null = null;
@@ -10,9 +11,9 @@ export function getSurveyClient(): SurveyClient {
baseUrl: API_CONFIG.platformBaseUrl,
productId: PRODUCT_ID,
getAuthToken: () => getAuthClient().getAccessToken() ?? '',
- platform: 'ios',
- appVersion: '0.1.0',
- osVersion: 'unknown',
+ platform: APP_PLATFORM,
+ appVersion: APP_VERSION,
+ osVersion: OS_VERSION,
});
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e1f67bb..fd71078 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -126,9 +126,12 @@ importers:
expo:
specifier: ~55.0.4
version: 55.0.8(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@6.0.23)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+ expo-constants:
+ specifier: ~18.0.13
+ version: 18.0.13(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))
expo-router:
specifier: ~6.0.4
- version: 6.0.23(fbac16d1b6e18492193348f9e089f0a0)
+ version: 6.0.23(8f4d8b3ea945913a36065f8394178341)
expo-status-bar:
specifier: ~3.0.9
version: 3.0.9(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
@@ -7335,7 +7338,7 @@ snapshots:
'@exodus/bytes@1.15.0': {}
- '@expo/cli@55.0.18(@expo/dom-webview@55.0.3)(expo-constants@55.0.9)(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)':
+ '@expo/cli@55.0.18(@expo/dom-webview@55.0.3)(expo-constants@55.0.9(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3))(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)':
dependencies:
'@expo/code-signing-certificates': 0.0.6
'@expo/config': 55.0.10(typescript@5.9.3)
@@ -7352,7 +7355,7 @@ snapshots:
'@expo/plist': 0.5.2
'@expo/prebuild-config': 55.0.10(expo@55.0.8)(typescript@5.9.3)
'@expo/require-utils': 55.0.3(typescript@5.9.3)
- '@expo/router-server': 55.0.11(expo-constants@55.0.9)(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo-server@55.0.6)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@expo/router-server': 55.0.11(expo-constants@55.0.9(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3))(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo-server@55.0.6)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@expo/schema-utils': 55.0.2
'@expo/spawn-async': 1.7.2
'@expo/ws-tunnel': 1.0.6
@@ -7396,7 +7399,7 @@ snapshots:
ws: 8.20.0
zod: 3.25.76
optionalDependencies:
- expo-router: 6.0.23(fbac16d1b6e18492193348f9e089f0a0)
+ expo-router: 6.0.23(8f4d8b3ea945913a36065f8394178341)
react-native: 0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0)
transitivePeerDependencies:
- '@expo/dom-webview'
@@ -7679,7 +7682,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@expo/router-server@55.0.11(expo-constants@55.0.9)(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo-server@55.0.6)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ '@expo/router-server@55.0.11(expo-constants@55.0.9(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3))(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo-server@55.0.6)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
debug: 4.4.3
expo: 55.0.8(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@6.0.23)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
@@ -7688,7 +7691,7 @@ snapshots:
expo-server: 55.0.6
react: 19.2.0
optionalDependencies:
- expo-router: 6.0.23(fbac16d1b6e18492193348f9e089f0a0)
+ expo-router: 6.0.23(8f4d8b3ea945913a36065f8394178341)
react-dom: 19.2.0(react@19.2.0)
transitivePeerDependencies:
- supports-color
@@ -8409,9 +8412,7 @@ snapshots:
metro-runtime: 0.83.5
transitivePeerDependencies:
- '@babel/core'
- - bufferutil
- supports-color
- - utf-8-validate
'@react-native/normalize-colors@0.83.2': {}
@@ -10365,7 +10366,7 @@ snapshots:
react: 19.2.0
react-native: 0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0)
- expo-router@6.0.23(fbac16d1b6e18492193348f9e089f0a0):
+ expo-router@6.0.23(8f4d8b3ea945913a36065f8394178341):
dependencies:
'@expo/schema-utils': 0.1.8
'@radix-ui/react-slot': 1.2.0(@types/react@19.2.14)(react@19.2.0)
@@ -10377,7 +10378,7 @@ snapshots:
debug: 4.4.3
escape-string-regexp: 4.0.0
expo: 55.0.8(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@6.0.23)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
- expo-constants: 55.0.9(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3)
+ expo-constants: 18.0.13(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))
expo-linking: 8.0.11(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
expo-server: 1.0.5
fast-deep-equal: 3.1.3
@@ -10419,7 +10420,7 @@ snapshots:
expo@55.0.8(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@6.0.23)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3):
dependencies:
'@babel/runtime': 7.29.2
- '@expo/cli': 55.0.18(@expo/dom-webview@55.0.3)(expo-constants@55.0.9)(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
+ '@expo/cli': 55.0.18(@expo/dom-webview@55.0.3)(expo-constants@55.0.9(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3))(expo-font@55.0.4(expo@55.0.8)(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@6.0.23)(expo@55.0.8)(react-dom@19.2.0(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)
'@expo/config': 55.0.10(typescript@5.9.3)
'@expo/config-plugins': 55.0.7
'@expo/devtools': 55.0.2(react-native@0.83.2(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)