@barrysolomon/mobile-react-native 0.2.0-alpha → 0.2.1-alpha

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/README.md CHANGED
@@ -1,23 +1,52 @@
1
- # @dash0/mobile-react-native
1
+ # @barrysolomon/mobile-react-native
2
2
 
3
3
  Dash0 Mobile Observability SDK for React Native. Bridges JS/TS into the
4
4
  existing native Android (`otel-android-mobile`) and iOS (`otel-ios-mobile`)
5
5
  SDKs — native owns buffering, policy evaluation, OTLP export, and crash
6
6
  recovery. JS stays thin.
7
7
 
8
- **Status:** Complete and validated end-to-end in Dash0. Both Android and iOS
9
- builds produce real binaries (140 MB APK, 239 MB .app) and telemetry lands in
10
- Dash0 within ~3 s. All 4 platforms (Android native, iOS native, RN Android,
11
- RN iOS) have a UAT matrix of 12/12 cells green. 83 Jest tests pass.
8
+ **Version:** `0.2.1-alpha`, published under the `alpha` dist-tag.
9
+
10
+ **Status:** Validated end-to-end in Dash0. All 4 platforms (Android native,
11
+ iOS native, RN Android, RN iOS) have a UAT matrix of 12/12 cells green.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ # Install the alpha (a bare `npm install @barrysolomon/mobile-react-native`
17
+ # resolves the OLD 0.1.0-alpha — always pin the dist-tag or version):
18
+ npm install @barrysolomon/mobile-react-native@alpha
19
+ # or pin the exact version:
20
+ # npm install @barrysolomon/mobile-react-native@0.2.1-alpha
21
+
22
+ cd ios && pod install
23
+ ```
24
+
25
+ This JS package wraps the native SDKs; install those too:
26
+
27
+ - **iOS** — add the Swift Package `https://github.com/barrysolomon/mobile-otel`
28
+ at tag `v0.2.1-alpha` to your app target, then copy
29
+ `OTelMobileCallSink.swift` (+ `BoundedLiveSpanStore.swift`) from this package
30
+ into your app target and call
31
+ `Dash0MobileModule.installSink { OTelMobileCallSink() }`. The pod intentionally
32
+ excludes the sink because it depends on the SwiftPM SDK delivered on the app
33
+ side.
34
+ - **Android** — `io.opentelemetry.android:mobile:0.2.1-alpha` from GitHub
35
+ Packages (`https://maven.pkg.github.com/barrysolomon/mobile-otel`). As of
36
+ 0.2.0-alpha the full module set (`mobile-core` + all
37
+ `mobile-instrumentation-*` modules) publishes there, so the dependency tree
38
+ resolves.
12
39
 
13
40
  ## Quickstart
14
41
 
15
42
  ```ts
16
- import { Dash0Mobile } from '@dash0/mobile-react-native';
43
+ import { Dash0Mobile } from '@barrysolomon/mobile-react-native';
17
44
 
18
45
  await Dash0Mobile.start({
19
46
  serviceName: 'my-rn-app',
20
- endpoint: 'https://ingress.us-west-2.aws.dash0.com/v1/logs',
47
+ // Base ingress host — per-signal URLs are built as
48
+ // `<endpoint>/v1/{logs,traces,metrics}`; do NOT append `/v1/...` yourself.
49
+ endpoint: 'https://ingress.us-west-2.aws.dash0.com',
21
50
  authToken: process.env.DASH0_AUTH_TOKEN,
22
51
  dataset: 'otel-mobile',
23
52
  });
@@ -35,7 +64,7 @@ await Dash0Mobile.span('checkout', async () => {
35
64
  # Install dependencies (first time)
36
65
  npm install
37
66
 
38
- # Jest — bridge contract + auto-instrumentation (83 tests)
67
+ # Jest — bridge contract + auto-instrumentation
39
68
  npm test
40
69
 
41
70
  # Type-check
@@ -53,34 +82,56 @@ src/
53
82
  types.ts # cross-repo seam — DO NOT change without coordinating
54
83
  NativeBridge.ts # debounced batching marshaller (50 ms batch window)
55
84
  instrumentation/
56
- fetch.ts # fetch/XHR span auto-capture
57
- xhr.ts # XHR span auto-capture
85
+ fetch.ts # fetch span shim (non-RN/web; off on RN — fetch is XHR-backed)
86
+ xhr.ts # XHR span shim (authoritative JS layer; gated off on Android)
58
87
  errors.ts # JS error log auto-capture
59
88
  unhandledRejection.ts # unhandled promise rejection capture
60
- navigation.ts # React Navigation screen-view auto-capture
61
- touch.ts # tap event auto-capture
89
+ navigation.ts # React Navigation screen-view auto-capture (opt-in)
90
+ touch.ts # tap event auto-capture (opt-in via withTapTelemetry)
62
91
  otel-compat.ts # OTel-API shim (third-party JS libs flow through bridge)
63
92
  index.ts # public API
64
- android/ # Kotlin ReactContextBaseJavaModule + BridgeCallSink
65
- ios/ # Swift RCTDash0MobileModule + BridgeCallSink
66
- __tests__/ # Jest — 83 tests across bridge + instrumentation
93
+ android/ # Kotlin ReactContextBaseJavaModule + OkHttp net interceptor
94
+ ios/ # Swift RCTDash0MobileModule + OTelMobileCallSink
95
+ __tests__/ # Jest — bridge contract + instrumentation suites
67
96
  ```
68
97
 
69
98
  ## Auto-instrumentation
70
99
 
71
- Enabled by default when `Dash0Mobile.start()` is called. Opt out per signal:
100
+ `network` and `errors` are enabled by default when `Dash0Mobile.start()` is
101
+ called. Opt out per signal:
72
102
 
73
103
  ```ts
74
104
  await Dash0Mobile.start({
75
105
  // ...
76
106
  autoCapture: {
77
- network: false, // disable fetch/XHR spans
78
- errors: false, // disable JS error + rejection logs
79
- lifecycle: false, // disable AppState fg/bg
107
+ network: false, // disable HTTP capture (JS fetch/XHR shims + native net)
108
+ errors: false, // disable JS error + unhandled-rejection logs
80
109
  },
81
110
  });
82
111
  ```
83
112
 
113
+ App lifecycle (`app.foreground` / `app.background` / `app.start`) is **always
114
+ on via native instrumentation** (Android `ProcessLifecycleOwner`, iOS
115
+ `NotificationCenter`) — there is no JS or per-flag knob for it. The other
116
+ `autoCapture` flags (`tap`, `scroll`, `textInput`, `screen`, `freeze`,
117
+ `vitals`, `deviceStats`, `screenshot`, `wireframe`) toggle native-only capture
118
+ suites and default **off** on RN.
119
+
120
+ ### HTTP capture on Android is native (Expo SDK 52+)
121
+
122
+ On Android, network capture is owned by a native OkHttp interceptor
123
+ (`OTelNetworkInterceptor`) installed before JS runs. It records native CLIENT
124
+ spans and injects a W3C `traceparent` from the real native span context, so
125
+ Android mobile→backend traces stitch. The JS `XMLHttpRequest` shim is
126
+ auto-gated **off** on Android to avoid double-counting.
127
+
128
+ This matters because **Expo SDK 52+ replaced the global `fetch` with
129
+ `expo/fetch`, a non-XHR-backed client.** The JS `fetch`/XHR shims wrap the JS
130
+ globals and see nothing there — only the native interceptor (which sits under
131
+ OkHttp) captures `expo/fetch` traffic. On iOS the JS XHR shim is kept (RN iOS
132
+ `fetch` is XHR-backed and the native `URLProtocol` swizzle is opt-in/off by
133
+ default for RN).
134
+
84
135
  ## Sampling
85
136
 
86
137
  **The RN bridge defaults to `always_on` (100% of spans)** — unlike the native
@@ -117,15 +168,18 @@ native SDK on each platform:
117
168
  ```text
118
169
  JS (fetch/XHR/errors/nav/tap)
119
170
  ↓ 50 ms batch window
120
- NativeBridge.ts → NativeDash0Mobile → Android: OTelMobile (gRPC :4317)
121
- → iOS: OTelMobile (HTTP :4318)
171
+ NativeBridge.ts → NativeDash0Mobile → Android: OTelMobile (OTLP/HTTP)
172
+ → iOS: OTelMobile (OTLP/HTTP)
122
173
 
123
174
  OTLP Collector → Dash0
124
175
  ```
125
176
 
126
- **Transport note:** Android uses OTLP/gRPC on port 4317; iOS uses OTLP/HTTP on
127
- port 4318. The shared `otel-config.json` uses a per-platform port rewrite at
128
- startup do not assume a single endpoint works for both.
177
+ **Transport note:** As of 0.2.0-alpha both platforms default to OTLP/HTTP
178
+ (protobuf) against a single endpoint, with per-signal URLs built as
179
+ `<endpoint>/v1/{logs,traces,metrics}`. Android changed from gRPC to HTTP so
180
+ exports traverse HTTPS-terminating proxies / managed ingress that can't forward
181
+ HTTP/2 gRPC. gRPC-only collector? Restore it on Android with
182
+ `MobileConfig.protocol = OtlpProtocol.GRPC`.
129
183
 
130
184
  ## Test strategy
131
185
 
@@ -133,12 +187,16 @@ Three layers, all must pass on every PR:
133
187
 
134
188
  1. **Jest** — `npm test` in this directory; contract + bridge + instrumentation
135
189
  2. **Native unit** — `./gradlew :android:test` (Android) + `swift test` (iOS)
136
- 3. **Real-app E2E** — `scripts/test/validate-rn-end-to-end.sh` boots
137
- AstronomyShopRN on iOS Simulator + Android emulator, queries Dash0 after 75 s
190
+ 3. **Real-app E2E** — `scripts/test/validate-rn-end-to-end.sh` (use `--mode=jest`
191
+ for the package + AstronomyShopRN demo tests; `--mode=device` boots
192
+ AstronomyShopRN on iOS Simulator + Android emulator and queries Dash0)
138
193
 
139
194
  ## Known limitations
140
195
 
141
- - **Expo** — not supported without eject (bare workflow only). An Expo config
142
- plugin is planned as a follow-up.
196
+ - **Expo** — works in the bare/dev-client workflow (native modules required).
197
+ 0.2.0-alpha was hardened against a real Expo SDK 56 / RN 0.85 integration,
198
+ including the Expo SDK 52+ `expo/fetch` capture via native Android
199
+ instrumentation (see above). A managed-workflow config plugin (no prebuild)
200
+ is tracked as a follow-up (EXPO-001).
143
201
  - **Realm / Amplify DataStore** — scoped in a separate epic.
144
202
  - **Web / desktop RN targets** — not supported.
@@ -97,7 +97,7 @@ ext.reactAndroidVersion = project.findProperty('Dash0Mobile_reactAndroidVersion'
97
97
  // dependency strings (which silently drifted to 0.1.0-alpha vs the published
98
98
  // 0.2.0-alpha and broke clean-.m2 CI while passing on caches that still had the
99
99
  // old artifact).
100
- ext.dash0SdkVersion = project.findProperty('Dash0Mobile_sdkVersion') ?: '0.2.0-alpha'
100
+ ext.dash0SdkVersion = project.findProperty('Dash0Mobile_sdkVersion') ?: '0.2.1-alpha'
101
101
 
102
102
  dependencies {
103
103
  implementation "com.facebook.react:react-android:$reactAndroidVersion"
@@ -11,9 +11,9 @@ org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
11
11
  Dash0Mobile_standaloneTestBuild=true
12
12
 
13
13
  # Version of the native Android SDK (io.opentelemetry.android:mobile) this module
14
- # depends on. MUST match the version the repo publishes (currently 0.2.0-alpha).
14
+ # depends on. MUST match the version the repo publishes (currently 0.2.1-alpha).
15
15
  # Single source of truth, read by build.gradle's dash0SdkVersion.
16
- Dash0Mobile_sdkVersion=0.2.0-alpha
16
+ Dash0Mobile_sdkVersion=0.2.1-alpha
17
17
 
18
18
  # Pin the Kotlin version the module's build.gradle reads (it defaults to
19
19
  # 2.1.20 and honors this property) so stdlib matches the compiler the
package/lib/index.js CHANGED
@@ -105,7 +105,7 @@ function resolveNative() {
105
105
  // callers and correlate issues to a specific bridge release. Keep this in
106
106
  // sync with package.json on each release.
107
107
  const DISTRO_NAME = 'dash0-react-native';
108
- const DISTRO_VERSION = '0.1.0-alpha';
108
+ const DISTRO_VERSION = '0.2.1-alpha';
109
109
  function resolveReactNativeVersion() {
110
110
  try {
111
111
  // eslint-disable-next-line @typescript-eslint/no-var-requires
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barrysolomon/mobile-react-native",
3
- "version": "0.2.0-alpha",
3
+ "version": "0.2.1-alpha",
4
4
  "description": "Dash0 Mobile Observability SDK for React Native (JS/TS bridge). For native iOS use the Swift Package at https://github.com/barrysolomon/mobile-otel. For native Android use io.opentelemetry.android:mobile on GitHub Packages.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.js",
package/src/index.ts CHANGED
@@ -142,7 +142,7 @@ function resolveNative(): NativeDash0MobileModule | null {
142
142
  // callers and correlate issues to a specific bridge release. Keep this in
143
143
  // sync with package.json on each release.
144
144
  const DISTRO_NAME = 'dash0-react-native';
145
- const DISTRO_VERSION = '0.1.0-alpha';
145
+ const DISTRO_VERSION = '0.2.1-alpha';
146
146
 
147
147
  function resolveReactNativeVersion(): string | undefined {
148
148
  try {