@lumin-monitor/react-native 0.3.0 → 0.4.0
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 +26 -0
- package/README.md +47 -1
- package/dist/index.cjs +30 -4
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +31 -5
- package/dist/react-navigation.d.cts +1 -1
- package/dist/react-navigation.d.ts +1 -1
- package/dist/{types-DMUQWor6.d.cts → types-B6rqS9Vp.d.cts} +30 -1
- package/dist/{types-DMUQWor6.d.ts → types-B6rqS9Vp.d.ts} +30 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ All notable changes to `@lumin-monitor/react-native` are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.0] - 2026-05-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Mobile device classification.** The SDK now sends an `X-Lumin-Client`
|
|
13
|
+
header on every batch — `sdk=rn/0.4.0; os=ios; os_version=17.4` plus
|
|
14
|
+
optional `device=<model>` when the new `deviceInfo` init option is
|
|
15
|
+
provided. The Lumin API uses the header to fill the same `ua_os` /
|
|
16
|
+
`ua_device_type` columns the browser SDK has always populated via the
|
|
17
|
+
User-Agent header, so mobile sessions stop showing up as empty / desktop
|
|
18
|
+
in the sessions UI. A new `ua_device` column captures the device model.
|
|
19
|
+
- `init({ deviceInfo })` — pass an instance of `react-native-device-info`
|
|
20
|
+
(or any `DeviceInfoLike` shim) to include the device model. Opt-in;
|
|
21
|
+
omit it and the SDK still reports `os` + `os_version` from React Native's
|
|
22
|
+
built-in `Platform` constants. Not auto-detected — same opt-in policy as
|
|
23
|
+
`storage` (0.3.0), to keep Metro bundling clean.
|
|
24
|
+
- Exported `DeviceInfoLike` type for consumers writing their own shims.
|
|
25
|
+
|
|
26
|
+
### Server compatibility
|
|
27
|
+
|
|
28
|
+
Requires Lumin API at or after the matching server release (which adds the
|
|
29
|
+
`X-Lumin-Client` parser and the `ua_device` column migration). Older
|
|
30
|
+
servers will ignore the header — events still ingest, mobile rows just
|
|
31
|
+
keep landing with empty `ua_*` columns.
|
|
32
|
+
|
|
8
33
|
## [0.3.0] - 2026-05-26
|
|
9
34
|
|
|
10
35
|
### Fixed
|
|
@@ -108,6 +133,7 @@ can hold events from web and mobile and tie them to the same user via
|
|
|
108
133
|
`useLuminScreenviews(client, navigationRef)` for React Navigation v6+ apps.
|
|
109
134
|
- Ships dual ESM + CJS bundle with full `.d.ts` types.
|
|
110
135
|
|
|
136
|
+
[0.4.0]: https://github.com/tamso-labs/lumin/releases/tag/sdk-react-native-v0.4.0
|
|
111
137
|
[0.3.0]: https://github.com/tamso-labs/lumin/releases/tag/sdk-react-native-v0.3.0
|
|
112
138
|
[0.2.0]: https://github.com/tamso-labs/lumin/releases/tag/sdk-react-native-v0.2.0
|
|
113
139
|
[0.1.0]: https://github.com/tamso-labs/lumin/releases/tag/sdk-react-native-v0.1.0
|
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ the same user.
|
|
|
16
16
|
pnpm add @lumin-monitor/react-native
|
|
17
17
|
# plus, if you want persistent ids across app launches (recommended):
|
|
18
18
|
pnpm add @react-native-async-storage/async-storage
|
|
19
|
+
# plus, if you want device-model tracking in the sessions UI:
|
|
20
|
+
pnpm add react-native-device-info
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
`@react-native-async-storage/async-storage` is no longer auto-detected
|
|
@@ -25,6 +27,10 @@ launches and let the 30-minute idle session window survive a cold start.
|
|
|
25
27
|
Omit `storage` (or pass `null`) to use in-memory ids that reset on every
|
|
26
28
|
cold start — fine for prototypes.
|
|
27
29
|
|
|
30
|
+
`react-native-device-info` is also opt-in (same reason). Without it the
|
|
31
|
+
SDK still reports `os` + `os_version` via the `X-Lumin-Client` header —
|
|
32
|
+
see [Device classification](#device-classification).
|
|
33
|
+
|
|
28
34
|
React Navigation is an optional peer dep, only needed if you import
|
|
29
35
|
`@lumin-monitor/react-native/react-navigation`.
|
|
30
36
|
|
|
@@ -76,10 +82,11 @@ hydration to complete before sending.
|
|
|
76
82
|
| `sessionIdleMs` | `1800000` (30 min) | A new session id is minted on the next event after this much inactivity. |
|
|
77
83
|
| `onError` | `console.warn` | Called as `(err, droppedCount)` when a batch fails. |
|
|
78
84
|
| `fetch` | global `fetch` | Override for tests. |
|
|
79
|
-
| `storage` |
|
|
85
|
+
| `storage` | `null` (in-memory ids) | Pass `AsyncStorage` for persistence across launches. See *Install* above. |
|
|
80
86
|
| `appState` | auto-detect react-native | Pass `null` to disable the background-flush listener. |
|
|
81
87
|
| `captureUnhandledErrors` | `true` | Install an `ErrorUtils.setGlobalHandler` chain. See *Error capture* below. |
|
|
82
88
|
| `errorUtils` | auto-detect global ErrorUtils | Override the ErrorUtils-like object the SDK installs into. |
|
|
89
|
+
| `deviceInfo` | `null` (no device model) | Pass `DeviceInfo` from `react-native-device-info` to include the device model in the `X-Lumin-Client` header. See *Device classification* below. |
|
|
83
90
|
|
|
84
91
|
### `screen(name?, properties?)`
|
|
85
92
|
|
|
@@ -211,6 +218,45 @@ tracking, call `screen()` manually from the route's effect.
|
|
|
211
218
|
Peer deps: `react >= 18`, `@react-navigation/native >= 6`. Both are
|
|
212
219
|
optional — the subpath only loads them when imported.
|
|
213
220
|
|
|
221
|
+
## Device classification
|
|
222
|
+
|
|
223
|
+
Browser SDKs send a meaningful `User-Agent`; the Lumin server parses it
|
|
224
|
+
into `ua_browser` / `ua_os` / `ua_device_type` columns that the sessions
|
|
225
|
+
UI groups by. React Native's `fetch` sends `okhttp/…` or `CFNetwork/…`,
|
|
226
|
+
which carries no device info, so the SDK ships an `X-Lumin-Client` header
|
|
227
|
+
on every batch instead:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
X-Lumin-Client: sdk=rn/0.4.0; os=ios; os_version=17.4
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`os` and `os_version` come from React Native's built-in `Platform`
|
|
234
|
+
constants — no peer dep required. The server folds the header into the
|
|
235
|
+
same `ua_os` / `ua_device_type` columns the browser SDK has always used,
|
|
236
|
+
so mobile sessions show up in the UI alongside web sessions.
|
|
237
|
+
|
|
238
|
+
For the device model (`iPhone15,3`, `Pixel 7`), install
|
|
239
|
+
[`react-native-device-info`](https://www.npmjs.com/package/react-native-device-info)
|
|
240
|
+
and pass it through:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import DeviceInfo from "react-native-device-info";
|
|
244
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
245
|
+
import { init } from "@lumin-monitor/react-native";
|
|
246
|
+
|
|
247
|
+
export const lumin = init({
|
|
248
|
+
apiKey: process.env.EXPO_PUBLIC_LUMIN_BROWSER_API_KEY!,
|
|
249
|
+
storage: AsyncStorage,
|
|
250
|
+
deviceInfo: DeviceInfo, // populates X-Lumin-Client: device=<model>
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The SDK never `require()`s `react-native-device-info` — same opt-in
|
|
255
|
+
policy as `storage`, to keep Metro bundling clean (see CHANGELOG 0.3.0).
|
|
256
|
+
If the installed version of `react-native-device-info` ever changes its
|
|
257
|
+
shape, ship a tiny adapter that satisfies `DeviceInfoLike`
|
|
258
|
+
(`{ getModel(): string }`).
|
|
259
|
+
|
|
214
260
|
## Session semantics
|
|
215
261
|
|
|
216
262
|
Sessions are **idle-based**, not tied to a single foreground period:
|
package/dist/index.cjs
CHANGED
|
@@ -97,6 +97,7 @@ var DEFAULT_FLUSH_MS = 500;
|
|
|
97
97
|
var DEFAULT_SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
98
98
|
var SERVER_MAX_BATCH = 1e3;
|
|
99
99
|
var DEFAULT_ENDPOINT = "https://api.getlumin.dev";
|
|
100
|
+
var SDK_VERSION = "0.4.0";
|
|
100
101
|
var Client = class {
|
|
101
102
|
constructor(opts) {
|
|
102
103
|
this.prevErrorHandler = void 0;
|
|
@@ -129,6 +130,7 @@ var Client = class {
|
|
|
129
130
|
this.storage = opts.storage ?? memoryStorage();
|
|
130
131
|
this.appState = opts.appState === void 0 ? detectAppState() : opts.appState;
|
|
131
132
|
this.errorUtils = opts.errorUtils === void 0 ? detectErrorUtils() : opts.errorUtils;
|
|
133
|
+
this.clientHeader = buildClientHeader(opts.deviceInfo ?? null);
|
|
132
134
|
this.idsReady = this.hydrateIds();
|
|
133
135
|
this.installBackgroundFlush();
|
|
134
136
|
if (opts.captureUnhandledErrors !== false) {
|
|
@@ -291,13 +293,15 @@ var Client = class {
|
|
|
291
293
|
return;
|
|
292
294
|
}
|
|
293
295
|
const body = JSON.stringify({ events: batch });
|
|
296
|
+
const headers = {
|
|
297
|
+
"Content-Type": "application/json",
|
|
298
|
+
Authorization: "Bearer " + this.apiKey
|
|
299
|
+
};
|
|
300
|
+
if (this.clientHeader) headers["X-Lumin-Client"] = this.clientHeader;
|
|
294
301
|
try {
|
|
295
302
|
const res = await this.fetchImpl(this.endpoint + "/v1/events", {
|
|
296
303
|
method: "POST",
|
|
297
|
-
headers
|
|
298
|
-
"Content-Type": "application/json",
|
|
299
|
-
Authorization: "Bearer " + this.apiKey
|
|
300
|
-
},
|
|
304
|
+
headers,
|
|
301
305
|
body
|
|
302
306
|
});
|
|
303
307
|
if (!res.ok) {
|
|
@@ -405,6 +409,28 @@ function clampBatch(n) {
|
|
|
405
409
|
if (n > SERVER_MAX_BATCH) return SERVER_MAX_BATCH;
|
|
406
410
|
return Math.floor(n);
|
|
407
411
|
}
|
|
412
|
+
function buildClientHeader(deviceInfo) {
|
|
413
|
+
const parts = [`sdk=rn/${SDK_VERSION}`];
|
|
414
|
+
const platform = import_react_native.Platform;
|
|
415
|
+
const osRaw = platform?.OS;
|
|
416
|
+
if (typeof osRaw === "string" && osRaw) {
|
|
417
|
+
parts.push(`os=${encodeURIComponent(osRaw)}`);
|
|
418
|
+
} else {
|
|
419
|
+
return "";
|
|
420
|
+
}
|
|
421
|
+
const versionRaw = platform?.Version;
|
|
422
|
+
if (versionRaw !== void 0 && versionRaw !== null && versionRaw !== "") {
|
|
423
|
+
parts.push(`os_version=${encodeURIComponent(String(versionRaw))}`);
|
|
424
|
+
}
|
|
425
|
+
if (deviceInfo && typeof deviceInfo.getModel === "function") {
|
|
426
|
+
try {
|
|
427
|
+
const model = deviceInfo.getModel();
|
|
428
|
+
if (model) parts.push(`device=${encodeURIComponent(model)}`);
|
|
429
|
+
} catch {
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return parts.join("; ");
|
|
433
|
+
}
|
|
408
434
|
function detectAppState() {
|
|
409
435
|
const candidate = import_react_native.AppState;
|
|
410
436
|
if (candidate && typeof candidate.addEventListener === "function") {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { L as LuminClient, I as InitOptions } from './types-
|
|
2
|
-
export { A as AppStateLike, a as AsyncStorageLike, E as ErrorUtilsLike, b as EventType, W as WireEvent } from './types-
|
|
1
|
+
import { L as LuminClient, I as InitOptions } from './types-B6rqS9Vp.cjs';
|
|
2
|
+
export { A as AppStateLike, a as AsyncStorageLike, D as DeviceInfoLike, E as ErrorUtilsLike, b as EventType, W as WireEvent } from './types-B6rqS9Vp.cjs';
|
|
3
3
|
|
|
4
4
|
declare class Client implements LuminClient {
|
|
5
5
|
private readonly endpoint;
|
|
@@ -12,6 +12,7 @@ declare class Client implements LuminClient {
|
|
|
12
12
|
private readonly storage;
|
|
13
13
|
private readonly appState;
|
|
14
14
|
private readonly errorUtils;
|
|
15
|
+
private readonly clientHeader;
|
|
15
16
|
private prevErrorHandler;
|
|
16
17
|
private errorHandlerInstalled;
|
|
17
18
|
private readonly recentErrors;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { L as LuminClient, I as InitOptions } from './types-
|
|
2
|
-
export { A as AppStateLike, a as AsyncStorageLike, E as ErrorUtilsLike, b as EventType, W as WireEvent } from './types-
|
|
1
|
+
import { L as LuminClient, I as InitOptions } from './types-B6rqS9Vp.js';
|
|
2
|
+
export { A as AppStateLike, a as AsyncStorageLike, D as DeviceInfoLike, E as ErrorUtilsLike, b as EventType, W as WireEvent } from './types-B6rqS9Vp.js';
|
|
3
3
|
|
|
4
4
|
declare class Client implements LuminClient {
|
|
5
5
|
private readonly endpoint;
|
|
@@ -12,6 +12,7 @@ declare class Client implements LuminClient {
|
|
|
12
12
|
private readonly storage;
|
|
13
13
|
private readonly appState;
|
|
14
14
|
private readonly errorUtils;
|
|
15
|
+
private readonly clientHeader;
|
|
15
16
|
private prevErrorHandler;
|
|
16
17
|
private errorHandlerInstalled;
|
|
17
18
|
private readonly recentErrors;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
|
-
import { AppState as RNAppState } from "react-native";
|
|
2
|
+
import { AppState as RNAppState, Platform as RNPlatform } from "react-native";
|
|
3
3
|
|
|
4
4
|
// src/ids.ts
|
|
5
5
|
function uuidv4() {
|
|
@@ -70,6 +70,7 @@ var DEFAULT_FLUSH_MS = 500;
|
|
|
70
70
|
var DEFAULT_SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
71
71
|
var SERVER_MAX_BATCH = 1e3;
|
|
72
72
|
var DEFAULT_ENDPOINT = "https://api.getlumin.dev";
|
|
73
|
+
var SDK_VERSION = "0.4.0";
|
|
73
74
|
var Client = class {
|
|
74
75
|
constructor(opts) {
|
|
75
76
|
this.prevErrorHandler = void 0;
|
|
@@ -102,6 +103,7 @@ var Client = class {
|
|
|
102
103
|
this.storage = opts.storage ?? memoryStorage();
|
|
103
104
|
this.appState = opts.appState === void 0 ? detectAppState() : opts.appState;
|
|
104
105
|
this.errorUtils = opts.errorUtils === void 0 ? detectErrorUtils() : opts.errorUtils;
|
|
106
|
+
this.clientHeader = buildClientHeader(opts.deviceInfo ?? null);
|
|
105
107
|
this.idsReady = this.hydrateIds();
|
|
106
108
|
this.installBackgroundFlush();
|
|
107
109
|
if (opts.captureUnhandledErrors !== false) {
|
|
@@ -264,13 +266,15 @@ var Client = class {
|
|
|
264
266
|
return;
|
|
265
267
|
}
|
|
266
268
|
const body = JSON.stringify({ events: batch });
|
|
269
|
+
const headers = {
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
Authorization: "Bearer " + this.apiKey
|
|
272
|
+
};
|
|
273
|
+
if (this.clientHeader) headers["X-Lumin-Client"] = this.clientHeader;
|
|
267
274
|
try {
|
|
268
275
|
const res = await this.fetchImpl(this.endpoint + "/v1/events", {
|
|
269
276
|
method: "POST",
|
|
270
|
-
headers
|
|
271
|
-
"Content-Type": "application/json",
|
|
272
|
-
Authorization: "Bearer " + this.apiKey
|
|
273
|
-
},
|
|
277
|
+
headers,
|
|
274
278
|
body
|
|
275
279
|
});
|
|
276
280
|
if (!res.ok) {
|
|
@@ -378,6 +382,28 @@ function clampBatch(n) {
|
|
|
378
382
|
if (n > SERVER_MAX_BATCH) return SERVER_MAX_BATCH;
|
|
379
383
|
return Math.floor(n);
|
|
380
384
|
}
|
|
385
|
+
function buildClientHeader(deviceInfo) {
|
|
386
|
+
const parts = [`sdk=rn/${SDK_VERSION}`];
|
|
387
|
+
const platform = RNPlatform;
|
|
388
|
+
const osRaw = platform?.OS;
|
|
389
|
+
if (typeof osRaw === "string" && osRaw) {
|
|
390
|
+
parts.push(`os=${encodeURIComponent(osRaw)}`);
|
|
391
|
+
} else {
|
|
392
|
+
return "";
|
|
393
|
+
}
|
|
394
|
+
const versionRaw = platform?.Version;
|
|
395
|
+
if (versionRaw !== void 0 && versionRaw !== null && versionRaw !== "") {
|
|
396
|
+
parts.push(`os_version=${encodeURIComponent(String(versionRaw))}`);
|
|
397
|
+
}
|
|
398
|
+
if (deviceInfo && typeof deviceInfo.getModel === "function") {
|
|
399
|
+
try {
|
|
400
|
+
const model = deviceInfo.getModel();
|
|
401
|
+
if (model) parts.push(`device=${encodeURIComponent(model)}`);
|
|
402
|
+
} catch {
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return parts.join("; ");
|
|
406
|
+
}
|
|
381
407
|
function detectAppState() {
|
|
382
408
|
const candidate = RNAppState;
|
|
383
409
|
if (candidate && typeof candidate.addEventListener === "function") {
|
|
@@ -99,6 +99,22 @@ interface InitOptions {
|
|
|
99
99
|
* runtime; tests pass a stub.
|
|
100
100
|
*/
|
|
101
101
|
errorUtils?: ErrorUtilsLike | null;
|
|
102
|
+
/**
|
|
103
|
+
* Optional `react-native-device-info` instance (or any object satisfying
|
|
104
|
+
* `DeviceInfoLike`). When passed, the SDK adds `device=<model>` to the
|
|
105
|
+
* `X-Lumin-Client` header so the server can surface the device model in
|
|
106
|
+
* the sessions UI.
|
|
107
|
+
*
|
|
108
|
+
* Not auto-detected — passing it is opt-in, matching the `storage`
|
|
109
|
+
* pattern. The SDK never `require()`s the package, which keeps Metro
|
|
110
|
+
* bundling clean.
|
|
111
|
+
*
|
|
112
|
+
* ```ts
|
|
113
|
+
* import DeviceInfo from "react-native-device-info";
|
|
114
|
+
* init({ apiKey, deviceInfo: DeviceInfo });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
deviceInfo?: DeviceInfoLike | null;
|
|
102
118
|
}
|
|
103
119
|
/**
|
|
104
120
|
* Minimal shape of React Native's ErrorUtils. The SDK uses these three
|
|
@@ -108,6 +124,19 @@ interface ErrorUtilsLike {
|
|
|
108
124
|
setGlobalHandler(handler: (err: unknown, isFatal?: boolean) => void): void;
|
|
109
125
|
getGlobalHandler?(): ((err: unknown, isFatal?: boolean) => void) | undefined;
|
|
110
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Minimal shape the SDK consumes from `react-native-device-info` (or any
|
|
129
|
+
* compatible shim). Structural so we don't pull react-native-device-info
|
|
130
|
+
* types into the SDK's public surface — the app already has them. Only
|
|
131
|
+
* `getModel` is required; future fields can be added the same way.
|
|
132
|
+
*
|
|
133
|
+
* Passed via `init({ deviceInfo: DeviceInfo })`. If omitted, the SDK still
|
|
134
|
+
* reports `os` + `os_version` from React Native's `Platform` constants —
|
|
135
|
+
* device model is the only thing that needs the optional peer dep.
|
|
136
|
+
*/
|
|
137
|
+
interface DeviceInfoLike {
|
|
138
|
+
getModel(): string;
|
|
139
|
+
}
|
|
111
140
|
/**
|
|
112
141
|
* Minimal AppState shape the SDK consumes (subset of react-native's AppState).
|
|
113
142
|
* The SDK auto-detects `react-native` at runtime; pass this only for tests or
|
|
@@ -137,4 +166,4 @@ interface LuminClient {
|
|
|
137
166
|
getAnonymousId(): Promise<string>;
|
|
138
167
|
}
|
|
139
168
|
|
|
140
|
-
export type { AppStateLike as A, ErrorUtilsLike as E, InitOptions as I, LuminClient as L, WireEvent as W, AsyncStorageLike as a, EventType as b };
|
|
169
|
+
export type { AppStateLike as A, DeviceInfoLike as D, ErrorUtilsLike as E, InitOptions as I, LuminClient as L, WireEvent as W, AsyncStorageLike as a, EventType as b };
|
|
@@ -99,6 +99,22 @@ interface InitOptions {
|
|
|
99
99
|
* runtime; tests pass a stub.
|
|
100
100
|
*/
|
|
101
101
|
errorUtils?: ErrorUtilsLike | null;
|
|
102
|
+
/**
|
|
103
|
+
* Optional `react-native-device-info` instance (or any object satisfying
|
|
104
|
+
* `DeviceInfoLike`). When passed, the SDK adds `device=<model>` to the
|
|
105
|
+
* `X-Lumin-Client` header so the server can surface the device model in
|
|
106
|
+
* the sessions UI.
|
|
107
|
+
*
|
|
108
|
+
* Not auto-detected — passing it is opt-in, matching the `storage`
|
|
109
|
+
* pattern. The SDK never `require()`s the package, which keeps Metro
|
|
110
|
+
* bundling clean.
|
|
111
|
+
*
|
|
112
|
+
* ```ts
|
|
113
|
+
* import DeviceInfo from "react-native-device-info";
|
|
114
|
+
* init({ apiKey, deviceInfo: DeviceInfo });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
deviceInfo?: DeviceInfoLike | null;
|
|
102
118
|
}
|
|
103
119
|
/**
|
|
104
120
|
* Minimal shape of React Native's ErrorUtils. The SDK uses these three
|
|
@@ -108,6 +124,19 @@ interface ErrorUtilsLike {
|
|
|
108
124
|
setGlobalHandler(handler: (err: unknown, isFatal?: boolean) => void): void;
|
|
109
125
|
getGlobalHandler?(): ((err: unknown, isFatal?: boolean) => void) | undefined;
|
|
110
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Minimal shape the SDK consumes from `react-native-device-info` (or any
|
|
129
|
+
* compatible shim). Structural so we don't pull react-native-device-info
|
|
130
|
+
* types into the SDK's public surface — the app already has them. Only
|
|
131
|
+
* `getModel` is required; future fields can be added the same way.
|
|
132
|
+
*
|
|
133
|
+
* Passed via `init({ deviceInfo: DeviceInfo })`. If omitted, the SDK still
|
|
134
|
+
* reports `os` + `os_version` from React Native's `Platform` constants —
|
|
135
|
+
* device model is the only thing that needs the optional peer dep.
|
|
136
|
+
*/
|
|
137
|
+
interface DeviceInfoLike {
|
|
138
|
+
getModel(): string;
|
|
139
|
+
}
|
|
111
140
|
/**
|
|
112
141
|
* Minimal AppState shape the SDK consumes (subset of react-native's AppState).
|
|
113
142
|
* The SDK auto-detects `react-native` at runtime; pass this only for tests or
|
|
@@ -137,4 +166,4 @@ interface LuminClient {
|
|
|
137
166
|
getAnonymousId(): Promise<string>;
|
|
138
167
|
}
|
|
139
168
|
|
|
140
|
-
export type { AppStateLike as A, ErrorUtilsLike as E, InitOptions as I, LuminClient as L, WireEvent as W, AsyncStorageLike as a, EventType as b };
|
|
169
|
+
export type { AppStateLike as A, DeviceInfoLike as D, ErrorUtilsLike as E, InitOptions as I, LuminClient as L, WireEvent as W, AsyncStorageLike as a, EventType as b };
|