expo-observe 0.1.4 → 0.1.5

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.
@@ -46,6 +46,8 @@ android {
46
46
  defaultConfig {
47
47
  versionCode 1
48
48
  versionName packageJson.version
49
+
50
+ buildConfigField "String", "EXPO_OBSERVE_VERSION", "\"${packageJson.version}\""
49
51
  }
50
52
  }
51
53
 
@@ -54,6 +54,7 @@ data class EASMetric(
54
54
  val name: String,
55
55
  val value: Double,
56
56
  val routeName: String? = null,
57
+ val updateId: String? = null,
57
58
  val customParams: JsonObject? = null
58
59
  ) {
59
60
  companion object {
@@ -65,6 +66,7 @@ data class EASMetric(
65
66
  name = metric.name,
66
67
  value = metric.value,
67
68
  routeName = metric.routeName,
69
+ updateId = metric.updateId,
68
70
  // TODO(@lukmccall): Consider using `org.json.JSONObject` instead of kotlinx.serialization. Also, we're not handling exceptions that might be thrown here.
69
71
  customParams = metric.params?.let { Json.decodeFromString<JsonObject>(it) }
70
72
  )
@@ -1,7 +1,6 @@
1
1
  package expo.modules.observe
2
2
 
3
3
  import expo.modules.appmetrics.utils.TimeUtils.timestampToDateNS
4
- import java.util.UUID
5
4
  import kotlinx.serialization.Serializable
6
5
  import kotlinx.serialization.json.Json
7
6
 
@@ -93,6 +92,9 @@ private val metricNameMap = mapOf(
93
92
  // Legacy metrics - will be removed in a future release
94
93
  "loadTime" to "expo.app_startup.load_time",
95
94
  "launchTime" to "expo.app_startup.launch_time",
95
+
96
+ // Updates
97
+ "updateDownloadTime" to "expo.updates.download_time",
96
98
  )
97
99
 
98
100
  fun EASMetric.toOTMetric(): OTMetric {
@@ -102,6 +104,9 @@ fun EASMetric.toOTMetric(): OTMetric {
102
104
  routeName?.let {
103
105
  attributes.add(OTAttribute.of(key = "expo.route_name", rawValue = it))
104
106
  }
107
+ updateId?.let {
108
+ attributes.add(OTAttribute.of(key = "expo.update_id", rawValue = it))
109
+ }
105
110
  customParams?.let {
106
111
  attributes.add(OTAttribute.of(key = "expo.custom_params", rawValue = it.toString()))
107
112
  }
@@ -179,7 +184,7 @@ fun Event.toOTEvent(easClientId: String): OTEvent {
179
184
  resource = toOTMetadata(easClientId),
180
185
  scopeMetrics = listOf(
181
186
  OTScopeMetrics(
182
- scope = OTScope(name = "expo-observe", version = metadata.clientVersion ?: ""),
187
+ scope = OTScope(name = "expo-observe", version = BuildConfig.EXPO_OBSERVE_VERSION),
183
188
  metrics = metrics.map { it.toOTMetric() }
184
189
  )
185
190
  )
package/ios/Event.swift CHANGED
@@ -46,6 +46,7 @@ struct Event: Codable, Sendable {
46
46
 
47
47
  // Metadata
48
48
  let routeName: String?
49
+ let updateId: String?
49
50
  let customParams: AnyCodable?
50
51
  }
51
52
 
@@ -60,15 +61,15 @@ struct Event: Codable, Sendable {
60
61
  appVersion: app.appVersion,
61
62
  appBuildNumber: app.buildNumber,
62
63
  appUpdateId: app.updateId,
63
- appEasBuildId: app.easBuildId == "" ? nil : app.easBuildId,
64
+ appEasBuildId: app.easBuildId,
64
65
 
65
66
  deviceName: device.modelName,
66
67
  deviceModel: device.modelIdentifier,
67
68
  deviceOs: device.systemName,
68
69
  deviceOsVersion: device.systemVersion,
69
70
 
70
- reactNativeVersion: ObserveVersions.reactNativeVersion,
71
- expoSdkVersion: ObserveVersions.expoSdkVersion,
71
+ reactNativeVersion: app.reactNativeVersion,
72
+ expoSdkVersion: app.expoSdkVersion,
72
73
  clientVersion: ObserveVersions.clientVersion,
73
74
 
74
75
  languageTag: Locale.preferredLanguages.first ?? "en-US",
@@ -84,6 +85,7 @@ struct Event: Codable, Sendable {
84
85
  sessionId: session.id,
85
86
  parentSessionId: nil,
86
87
  routeName: metric.routeName,
88
+ updateId: metric.updateId,
87
89
  customParams: metric.params
88
90
  )
89
91
  }
@@ -2,10 +2,6 @@ require 'json'
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
4
 
5
- reactNativeVersion = begin `node --print "require('react-native/package.json').version"`.strip rescue '0.0.0' end
6
- expoSdkVersion = begin `node --print "require('expo/package.json').version"`.strip rescue '0.0.0' end
7
- easBuildId = ENV.has_key?('EAS_BUILD_ID') ? ENV['EAS_BUILD_ID'] : nil
8
-
9
5
  Pod::Spec.new do |s|
10
6
  s.name = 'ExpoObserve'
11
7
  s.version = package['version']
@@ -32,10 +28,7 @@ Pod::Spec.new do |s|
32
28
  'DEFINES_MODULE' => 'YES',
33
29
  'SWIFT_COMPILATION_MODE' => 'wholemodule',
34
30
  'GCC_PREPROCESSOR_DEFINITIONS' => [
35
- "REACT_NATIVE_VERSION=\"#{reactNativeVersion}\"",
36
- "EXPO_SDK_VERSION=\"#{expoSdkVersion}\"",
37
- "EXPO_OBSERVE_VERSION=\"#{package['version']}\"",
38
- easBuildId ? "EXPO_OBSERVE_BUILD_ID=\"#{easBuildId}\"" : nil
31
+ "EXPO_OBSERVE_VERSION=\"#{package['version']}\""
39
32
  ].compact
40
33
  }
41
34
 
@@ -4,9 +4,6 @@
4
4
 
5
5
  @interface ObserveVersions : NSObject
6
6
 
7
- @property (class, readonly, nonnull) NSString *reactNativeVersion;
8
- @property (class, readonly, nonnull) NSString *expoSdkVersion;
9
7
  @property (class, readonly, nonnull) NSString *clientVersion;
10
- @property (class, readonly, nullable) NSString *easBuildId;
11
8
 
12
9
  @end
@@ -5,35 +5,13 @@
5
5
  #define STRINGIZE(x) #x
6
6
  #define STRINGIZE2(x) STRINGIZE(x)
7
7
 
8
- #define REACT_NATIVE_VERSION_STRING STRINGIZE2(REACT_NATIVE_VERSION)
9
- #define EXPO_SDK_VERSION_STRING STRINGIZE2(EXPO_SDK_VERSION)
10
8
  #define EXPO_OBSERVE_VERSION_STRING STRINGIZE2(EXPO_OBSERVE_VERSION)
11
- #define EXPO_OBSERVE_BUILD_ID_STRING STRINGIZE2(EXPO_OBSERVE_BUILD_ID)
12
9
 
13
10
  @implementation ObserveVersions
14
11
 
15
- + (NSString *)reactNativeVersion
16
- {
17
- return @REACT_NATIVE_VERSION_STRING;
18
- }
19
-
20
- + (NSString *)expoSdkVersion
21
- {
22
- return @EXPO_SDK_VERSION_STRING;
23
- }
24
-
25
12
  + (NSString *)clientVersion
26
13
  {
27
14
  return @EXPO_OBSERVE_VERSION_STRING;
28
15
  }
29
16
 
30
- + (NSString *)easBuildId
31
- {
32
- #ifdef EXPO_OBSERVE_BUILD_ID
33
- return @EXPO_OBSERVE_BUILD_ID_STRING;
34
- #else
35
- return nil;
36
- #endif
37
- }
38
-
39
17
  @end
@@ -1,4 +1,5 @@
1
1
  import Foundation
2
+ import ExpoAppMetrics
2
3
 
3
4
  // MARK: -- Open Telemetry data classes
4
5
 
@@ -65,6 +66,9 @@ let metricNameMap = [
65
66
  // Legacy metrics - will be removed in a future release
66
67
  "loadTime": "expo.app_startup.load_time",
67
68
  "launchTime": "expo.app_startup.launch_time",
69
+
70
+ // Updates
71
+ "updateDownloadTime": "expo.updates.download_time"
68
72
  ]
69
73
 
70
74
  nonisolated(unsafe) let formatter = ISO8601DateFormatter()
@@ -85,6 +89,9 @@ extension Event.Metric {
85
89
  if let routeName {
86
90
  attributes.append(OTAttribute(key: "expo.route_name", rawValue: routeName))
87
91
  }
92
+ if let updateId {
93
+ attributes.append(OTAttribute(key: "expo.update_id", rawValue: updateId))
94
+ }
88
95
  if let customParamsString = try? customParams?.toJSONString() {
89
96
  attributes.append(OTAttribute(key: "expo.custom_params", rawValue: customParamsString))
90
97
  }
@@ -36,6 +36,7 @@ struct OpenTelemetryTests {
36
36
  sessionId: testSessionId,
37
37
  parentSessionId: nil,
38
38
  routeName: nil,
39
+ updateId: nil,
39
40
  customParams: nil
40
41
  )
41
42
  }
@@ -235,6 +236,7 @@ struct OpenTelemetryTests {
235
236
  sessionId: testSessionId,
236
237
  parentSessionId: nil,
237
238
  routeName: "/home",
239
+ updateId: nil,
238
240
  customParams: nil
239
241
  )
240
242
  let otMetric = metric.toOTMetric()
@@ -243,6 +245,36 @@ struct OpenTelemetryTests {
243
245
  #expect(attrs["expo.route_name"] == "/home")
244
246
  }
245
247
 
248
+ @Test
249
+ func `toOTMetric includes update id attribute when present`() {
250
+ let metric = Event.Metric(
251
+ category: "updates",
252
+ name: "updateDownloadTime",
253
+ value: 2.5,
254
+ timestamp: "2026-01-01T00:00:00Z",
255
+ sessionId: testSessionId,
256
+ parentSessionId: nil,
257
+ routeName: nil,
258
+ updateId: "abc123-def456",
259
+ customParams: nil
260
+ )
261
+ let otMetric = metric.toOTMetric()
262
+ let attrs = Dictionary(uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) })
263
+
264
+ #expect(otMetric.name == "expo.updates.download_time")
265
+ #expect(attrs["expo.update_id"] == "abc123-def456")
266
+ #expect(attrs["session.id"] == testSessionId)
267
+ }
268
+
269
+ @Test
270
+ func `toOTMetric excludes update id attribute when nil`() {
271
+ let metric = makeMetric(name: "bundleLoadTime", value: 1.0, timestamp: "2026-01-01T00:00:00Z")
272
+ let otMetric = metric.toOTMetric()
273
+ let keys = otMetric.gauge.dataPoints[0].attributes.map { $0.key }
274
+
275
+ #expect(keys.contains("expo.update_id") == false)
276
+ }
277
+
246
278
  @Test
247
279
  func `toOTMetric excludes route name attribute when nil`() {
248
280
  let metric = makeMetric(name: "bundleLoadTime", value: 1.0, timestamp: "2026-01-01T00:00:00Z")
@@ -262,6 +294,7 @@ struct OpenTelemetryTests {
262
294
  sessionId: testSessionId,
263
295
  parentSessionId: nil,
264
296
  routeName: nil,
297
+ updateId: nil,
265
298
  customParams: AnyCodable(["screen": "dashboard", "variant": "A"] as [String: Any])
266
299
  )
267
300
  let otMetric = metric.toOTMetric()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "expo-observe",
3
3
  "title": "Expo Observe",
4
- "version": "0.1.4",
4
+ "version": "0.1.5",
5
5
  "description": "Expo module that dispatches collected app metrics to EAS Observe",
6
6
  "main": "src/index.ts",
7
7
  "types": "build/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  "author": "650 Industries, Inc.",
34
34
  "license": "MIT",
35
35
  "dependencies": {
36
- "expo-app-metrics": "~0.1.4",
36
+ "expo-app-metrics": "~0.1.5",
37
37
  "expo-eas-client": "~55.0.3"
38
38
  },
39
39
  "devDependencies": {