@smarthivelabs-devs/observe-expo 0.0.0-stage → 26.0.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/LICENSE +21 -0
- package/README.md +51 -2
- package/app.plugin.cjs +1 -0
- package/dist/chunk-HNIEV66S.js +362 -0
- package/dist/chunk-HNIEV66S.js.map +1 -0
- package/dist/index.cjs +399 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +130 -0
- package/dist/index.d.ts +130 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.cjs +99 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +18 -0
- package/dist/plugin.d.ts +18 -0
- package/dist/plugin.js +74 -0
- package/dist/plugin.js.map +1 -0
- package/dist/react.cjs +414 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +18 -0
- package/dist/react.d.ts +18 -0
- package/dist/react.js +24 -0
- package/dist/react.js.map +1 -0
- package/package.json +84 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Smart Hive Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @smarthivelabs-devs/observe-expo
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SmartObserve SDK for Expo and React Native. Transport failures never throw into application code. Events buffer offline and flush when the network returns.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { SmartObserve } from "@smarthivelabs-devs/observe-expo";
|
|
7
|
+
|
|
8
|
+
SmartObserve.init({ dsn: process.env.EXPO_PUBLIC_SMARTOBSERVE_DSN });
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
DSN format (public key):
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
https://<pk_public_key>@observe.smarthivelabs.dev/<project-slug>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Native ingestion sends origin `smartobserve-expo://native`. You do not add that origin in project settings. If the app also loads in a web browser, add that HTTPS origin separately.
|
|
18
|
+
|
|
19
|
+
### Expo config plugin
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"expo": {
|
|
24
|
+
"plugins": ["@smarthivelabs-devs/observe-expo"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or with options:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
["@smarthivelabs-devs/observe-expo", { dsn: process.env.EXPO_PUBLIC_SMARTOBSERVE_DSN }]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Source-map upload uses `SMARTOBSERVE_AUTH_TOKEN` from project settings (`SMARTOBSERVE_RELEASE_TOKEN` is also accepted).
|
|
36
|
+
|
|
37
|
+
The package includes persistent offline buffering, lifecycle/session capture, device context, navigation breadcrumbs, `fetch` network tracking (breadcrumbs, `http.client.duration` performance events, and `traceparent` propagation — disable with `trackNetwork: false`), a React error boundary, and an Expo config plugin.
|
|
38
|
+
|
|
39
|
+
Peer packages (install in the app): `expo`, `react`, `react-native`, `expo-application`, `expo-constants`, `expo-device`, `@react-native-async-storage/async-storage`, `@react-native-community/netinfo`.
|
|
40
|
+
|
|
41
|
+
### `allowTracePropagationTargets`
|
|
42
|
+
|
|
43
|
+
By default, outgoing `fetch` requests never receive a `traceparent` header — this option is an **allow-list**, not a deny-list. Only add hosts you control:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
SmartObserve.init({
|
|
47
|
+
dsn: process.env.EXPO_PUBLIC_SMARTOBSERVE_DSN,
|
|
48
|
+
allowTracePropagationTargets: ["https://api.yourapp.com", /^https:\/\/.*\.yourapp\.com$/],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This directory is an autonomous package root. Run `pnpm install`, `pnpm contract:verify`, `pnpm test`, and `pnpm build` here. First publish is `26.0.0`.
|
package/app.plugin.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./dist/plugin.cjs").default;
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import { AppState, Platform } from "react-native";
|
|
3
|
+
import * as Application from "expo-application";
|
|
4
|
+
import Constants from "expo-constants";
|
|
5
|
+
import * as Device from "expo-device";
|
|
6
|
+
|
|
7
|
+
// src/internal.ts
|
|
8
|
+
function id() {
|
|
9
|
+
return crypto.randomUUID();
|
|
10
|
+
}
|
|
11
|
+
function randomHex(bytes) {
|
|
12
|
+
return [...crypto.getRandomValues(new Uint8Array(bytes))].map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
13
|
+
}
|
|
14
|
+
function parseDsn(value) {
|
|
15
|
+
const url = new URL(value);
|
|
16
|
+
const key = decodeURIComponent(url.username);
|
|
17
|
+
if (!/^(pk|sk)_[A-Za-z0-9_-]{16,}$/.test(key)) throw new Error("SmartObserve DSN contains an invalid project key");
|
|
18
|
+
const slug = url.pathname.replace(/^\/+|\/+$/g, "");
|
|
19
|
+
if (!slug) throw new Error("SmartObserve DSN must include a project slug");
|
|
20
|
+
return { endpoint: `${url.protocol}//${url.host}/api/v1/envelope`, key };
|
|
21
|
+
}
|
|
22
|
+
var BLOCKED = /* @__PURE__ */ new Set(["password", "passcode", "authorization", "cookie", "access_token", "refresh_token", "api_key", "secret", "private_key", "card_number", "cvv", "cvc"]);
|
|
23
|
+
function sanitize(input, extra = []) {
|
|
24
|
+
const blocked = /* @__PURE__ */ new Set([...BLOCKED, ...extra.map((value) => value.toLowerCase())]);
|
|
25
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
26
|
+
const walk = (value, depth) => {
|
|
27
|
+
if (depth > 5) return "[Truncated]";
|
|
28
|
+
if (typeof value === "string") return value.slice(0, 8192);
|
|
29
|
+
if (value === null || typeof value !== "object") return value;
|
|
30
|
+
if (seen.has(value)) return "[Circular]";
|
|
31
|
+
seen.add(value);
|
|
32
|
+
if (Array.isArray(value)) return value.slice(0, 200).map((entry) => walk(entry, depth + 1));
|
|
33
|
+
return Object.fromEntries(Object.entries(value).slice(0, 200).map(([key, entry]) => [key, blocked.has(key.toLowerCase().replace(/[\s-]+/g, "_")) ? "[Redacted]" : walk(entry, depth + 1)]));
|
|
34
|
+
};
|
|
35
|
+
return walk(input, 0);
|
|
36
|
+
}
|
|
37
|
+
function safeUrl(value) {
|
|
38
|
+
try {
|
|
39
|
+
const url = new URL(value);
|
|
40
|
+
url.username = "";
|
|
41
|
+
url.password = "";
|
|
42
|
+
for (const key of [...url.searchParams.keys()]) url.searchParams.set(key, "[Filtered]");
|
|
43
|
+
return url.toString();
|
|
44
|
+
} catch {
|
|
45
|
+
return "[Invalid URL]";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/transport.ts
|
|
50
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
51
|
+
import NetInfo from "@react-native-community/netinfo";
|
|
52
|
+
|
|
53
|
+
// src/sdk-meta.ts
|
|
54
|
+
var SDK_NAME = "@smarthivelabs-devs/observe-expo";
|
|
55
|
+
var SDK_VERSION = "26.0.0";
|
|
56
|
+
|
|
57
|
+
// src/transport.ts
|
|
58
|
+
var STORAGE_KEY = "@smartobserve/events/v1";
|
|
59
|
+
var ExpoTransport = class {
|
|
60
|
+
constructor(options) {
|
|
61
|
+
this.options = options;
|
|
62
|
+
this.timer = setInterval(() => void this.flush(), options.flushIntervalMs);
|
|
63
|
+
this.unsubscribe = NetInfo.addEventListener((state) => {
|
|
64
|
+
this.online = state.isConnected !== false;
|
|
65
|
+
if (this.online) void this.flush();
|
|
66
|
+
});
|
|
67
|
+
void this.restore();
|
|
68
|
+
}
|
|
69
|
+
options;
|
|
70
|
+
queue = [];
|
|
71
|
+
timer;
|
|
72
|
+
flushing;
|
|
73
|
+
online = true;
|
|
74
|
+
unsubscribe;
|
|
75
|
+
closed = false;
|
|
76
|
+
enqueue(event) {
|
|
77
|
+
if (this.closed) return;
|
|
78
|
+
if (this.queue.length >= this.options.maxQueueSize) this.evict();
|
|
79
|
+
this.queue.push(event);
|
|
80
|
+
void this.persist();
|
|
81
|
+
if (this.queue.length >= 50 || event.level === "fatal") void this.flush();
|
|
82
|
+
}
|
|
83
|
+
async flush() {
|
|
84
|
+
if (this.flushing || !this.queue.length || !this.online) return this.flushing;
|
|
85
|
+
const events = this.queue.splice(0, 50);
|
|
86
|
+
this.flushing = this.send(events).then(() => this.persist()).catch((error) => {
|
|
87
|
+
this.queue.unshift(...events);
|
|
88
|
+
void this.persist();
|
|
89
|
+
if (this.options.debug) console.warn("[SmartObserve] offline batch retained", error);
|
|
90
|
+
}).finally(() => {
|
|
91
|
+
this.flushing = void 0;
|
|
92
|
+
});
|
|
93
|
+
return this.flushing;
|
|
94
|
+
}
|
|
95
|
+
async close() {
|
|
96
|
+
this.closed = true;
|
|
97
|
+
if (this.timer) clearInterval(this.timer);
|
|
98
|
+
this.unsubscribe?.();
|
|
99
|
+
await this.flush();
|
|
100
|
+
}
|
|
101
|
+
async restore() {
|
|
102
|
+
try {
|
|
103
|
+
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
|
104
|
+
if (!raw) return;
|
|
105
|
+
const stored = JSON.parse(raw);
|
|
106
|
+
this.queue.push(...stored.filter((event) => Date.now() - (event._storedAt ?? event.timestamp) < 7 * 864e5).slice(-this.options.maxQueueSize));
|
|
107
|
+
await this.flush();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (this.options.debug) console.warn("[SmartObserve] offline queue unavailable", error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async persist() {
|
|
113
|
+
try {
|
|
114
|
+
let prepared = this.queue.map((event) => ({ ...event, _storedAt: Date.now() }));
|
|
115
|
+
let raw = JSON.stringify(prepared);
|
|
116
|
+
while (raw.length > 10 * 1024 * 1024 && this.queue.length) {
|
|
117
|
+
this.evict();
|
|
118
|
+
prepared = this.queue.map((event) => ({ ...event, _storedAt: Date.now() }));
|
|
119
|
+
raw = JSON.stringify(prepared);
|
|
120
|
+
}
|
|
121
|
+
await AsyncStorage.setItem(STORAGE_KEY, raw);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (this.options.debug) console.warn("[SmartObserve] could not persist offline queue", error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async send(events) {
|
|
127
|
+
const body = JSON.stringify({ schemaVersion: 1, envelopeId: id(), sentAt: Date.now(), sdk: { name: SDK_NAME, version: SDK_VERSION }, environment: this.options.environment, release: this.options.release, dist: this.options.dist, events });
|
|
128
|
+
let attempt = 0;
|
|
129
|
+
while (true) {
|
|
130
|
+
const response = await fetch(this.options.endpoint, { method: "POST", headers: { "content-type": "application/json", "origin": "smartobserve-expo://native", "x-smartobserve-key": this.options.key, "x-smartobserve-platform": "expo", "x-smartobserve-internal": "transport" }, body });
|
|
131
|
+
if (response.ok) return;
|
|
132
|
+
if (![408, 429].includes(response.status) && response.status < 500) return;
|
|
133
|
+
if (attempt++ >= 5) throw new Error(`HTTP ${response.status}`);
|
|
134
|
+
await new Promise((resolve) => setTimeout(resolve, Math.random() * Math.min(3e4, 2 ** attempt * 1e3)));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
evict() {
|
|
138
|
+
const index = this.queue.findIndex((event) => event.type === "span" || event.type === "performance" || event.level === "debug");
|
|
139
|
+
this.queue.splice(index < 0 ? 0 : index, 1);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/client.ts
|
|
144
|
+
var SmartObserveExpoClient = class {
|
|
145
|
+
config;
|
|
146
|
+
transport;
|
|
147
|
+
user;
|
|
148
|
+
tags = {};
|
|
149
|
+
contexts = {};
|
|
150
|
+
breadcrumbs = [];
|
|
151
|
+
trace;
|
|
152
|
+
beforeSendHook;
|
|
153
|
+
cleanups = [];
|
|
154
|
+
sessionId = id();
|
|
155
|
+
sessionStarted = Date.now();
|
|
156
|
+
constructor(input = {}) {
|
|
157
|
+
this.config = { ...input, environment: input.environment ?? "production", enabled: input.enabled ?? Boolean(input.dsn), debug: input.debug ?? false, tracesSampleRate: input.tracesSampleRate ?? input.sampleRate ?? 0.1, errorSampleRate: input.errorSampleRate ?? 1, maxBreadcrumbs: input.maxBreadcrumbs ?? 100 };
|
|
158
|
+
this.beforeSendHook = input.beforeSend;
|
|
159
|
+
if (this.config.enabled && input.dsn) {
|
|
160
|
+
const parsed = parseDsn(input.dsn);
|
|
161
|
+
this.transport = new ExpoTransport({ ...parsed, environment: this.config.environment, release: input.release ?? Application.nativeApplicationVersion ?? void 0, dist: input.dist ?? Application.nativeBuildVersion ?? void 0, maxQueueSize: input.maxQueueSize ?? 1e3, flushIntervalMs: input.flushIntervalMs ?? 5e3, debug: this.config.debug });
|
|
162
|
+
this.setup(parsed.endpoint);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
captureException(error, hint = {}) {
|
|
166
|
+
const eventId = id();
|
|
167
|
+
if (Math.random() <= this.config.errorSampleRate) {
|
|
168
|
+
const exception = serialize(error);
|
|
169
|
+
void this.capture({ ...this.base("error"), eventId, message: exception.value, level: "error", exceptions: [exception], metadata: hint });
|
|
170
|
+
}
|
|
171
|
+
return eventId;
|
|
172
|
+
}
|
|
173
|
+
captureMessage(message, level = "info", metadata) {
|
|
174
|
+
const eventId = id();
|
|
175
|
+
void this.capture({ ...this.base("log"), eventId, message, level, metadata });
|
|
176
|
+
return eventId;
|
|
177
|
+
}
|
|
178
|
+
log = { debug: (m, d) => this.captureMessage(m, "debug", d), info: (m, d) => this.captureMessage(m, "info", d), warn: (m, d) => this.captureMessage(m, "warn", d), error: (m, d) => this.captureMessage(m, "error", d) };
|
|
179
|
+
addBreadcrumb(value) {
|
|
180
|
+
this.breadcrumbs.push({ ...sanitize(value, this.config.redactKeys), timestamp: value.timestamp ?? Date.now() });
|
|
181
|
+
this.breadcrumbs.splice(0, Math.max(0, this.breadcrumbs.length - this.config.maxBreadcrumbs));
|
|
182
|
+
}
|
|
183
|
+
setUser(value) {
|
|
184
|
+
this.user = value ? sanitize(value, this.config.redactKeys) : void 0;
|
|
185
|
+
}
|
|
186
|
+
setTag(key, value) {
|
|
187
|
+
if (value === null) delete this.tags[key];
|
|
188
|
+
else this.tags[key.slice(0, 64)] = value.slice(0, 256);
|
|
189
|
+
}
|
|
190
|
+
setContext(key, value) {
|
|
191
|
+
if (value === null) delete this.contexts[key];
|
|
192
|
+
else this.contexts[key] = sanitize(value, this.config.redactKeys);
|
|
193
|
+
}
|
|
194
|
+
beforeSend(callback) {
|
|
195
|
+
this.beforeSendHook = callback;
|
|
196
|
+
}
|
|
197
|
+
startSpan(options, callback) {
|
|
198
|
+
const previous = this.trace;
|
|
199
|
+
const trace = { traceId: options.parent?.traceId ?? previous?.traceId ?? randomHex(16), spanId: randomHex(8), parentSpanId: options.parent?.spanId ?? previous?.spanId, sampled: options.sampled ?? previous?.sampled ?? Math.random() < this.config.tracesSampleRate };
|
|
200
|
+
const start = Date.now();
|
|
201
|
+
const attributes = { ...options.attributes ?? {} };
|
|
202
|
+
let status = "unknown";
|
|
203
|
+
let ended = false;
|
|
204
|
+
const span = { traceId: trace.traceId, spanId: trace.spanId, setAttribute: (key, value) => {
|
|
205
|
+
attributes[key] = value;
|
|
206
|
+
}, setStatus: (value) => {
|
|
207
|
+
status = value;
|
|
208
|
+
}, recordException: (error) => {
|
|
209
|
+
status = "error";
|
|
210
|
+
this.captureException(error);
|
|
211
|
+
}, end: () => {
|
|
212
|
+
if (!ended && trace.sampled) {
|
|
213
|
+
ended = true;
|
|
214
|
+
const isRoot = !trace.parentSpanId;
|
|
215
|
+
void this.capture({ ...this.base(isRoot ? "transaction" : "span"), name: options.name, operation: options.operation, startTimestamp: start, endTimestamp: Date.now(), status, ...isRoot ? {} : { attributes }, trace });
|
|
216
|
+
}
|
|
217
|
+
} };
|
|
218
|
+
this.trace = trace;
|
|
219
|
+
try {
|
|
220
|
+
const result = callback(span);
|
|
221
|
+
if (result && typeof result.then === "function") return result.then((value) => {
|
|
222
|
+
if (status === "unknown") status = "ok";
|
|
223
|
+
span.end();
|
|
224
|
+
return value;
|
|
225
|
+
}, (error) => {
|
|
226
|
+
span.recordException(error);
|
|
227
|
+
span.end();
|
|
228
|
+
throw error;
|
|
229
|
+
}).finally(() => {
|
|
230
|
+
this.trace = previous;
|
|
231
|
+
});
|
|
232
|
+
if (status === "unknown") status = "ok";
|
|
233
|
+
span.end();
|
|
234
|
+
return result;
|
|
235
|
+
} finally {
|
|
236
|
+
if (this.trace?.spanId === trace.spanId) this.trace = previous;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
flush() {
|
|
240
|
+
return this.transport?.flush() ?? Promise.resolve();
|
|
241
|
+
}
|
|
242
|
+
async close() {
|
|
243
|
+
for (const cleanup of this.cleanups.splice(0)) cleanup();
|
|
244
|
+
await this.transport?.close();
|
|
245
|
+
}
|
|
246
|
+
trackScreen(name, params) {
|
|
247
|
+
this.addBreadcrumb({ category: "navigation", message: name, data: params });
|
|
248
|
+
}
|
|
249
|
+
base(type) {
|
|
250
|
+
return { eventId: id(), type, timestamp: Date.now(), platform: "expo", user: applyUser(this.user, this.config.sendDefaultPii), tags: { ...this.tags }, contexts: sanitize({ ...this.contexts, device: { brand: Device.brand, model: Device.modelName, deviceType: Device.deviceType, os: Platform.OS, osVersion: Platform.Version, isDevice: Device.isDevice }, app: { id: Application.applicationId, name: Application.applicationName, version: Application.nativeApplicationVersion, build: Application.nativeBuildVersion, runtimeVersion: Constants.expoConfig?.runtimeVersion } }, this.config.redactKeys), breadcrumbs: [...this.breadcrumbs], trace: this.trace };
|
|
251
|
+
}
|
|
252
|
+
async capture(raw) {
|
|
253
|
+
if (!this.transport) return;
|
|
254
|
+
try {
|
|
255
|
+
let event = sanitize(raw, this.config.redactKeys);
|
|
256
|
+
if (this.beforeSendHook) event = await this.beforeSendHook(event);
|
|
257
|
+
if (event) this.transport.enqueue(event);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
if (this.config.debug) console.warn("[SmartObserve] event dropped", error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
setup(endpoint) {
|
|
263
|
+
const original = typeof ErrorUtils !== "undefined" ? ErrorUtils.getGlobalHandler() : void 0;
|
|
264
|
+
if (original && typeof ErrorUtils !== "undefined") {
|
|
265
|
+
ErrorUtils.setGlobalHandler((error, fatal) => {
|
|
266
|
+
this.captureException(error, { mechanism: "react-native.global", fatal });
|
|
267
|
+
if (fatal) void this.capture({ ...this.base("session"), sessionId: this.sessionId, startedAt: this.sessionStarted, endedAt: Date.now(), status: "crashed" });
|
|
268
|
+
original(error, fatal);
|
|
269
|
+
});
|
|
270
|
+
this.cleanups.push(() => ErrorUtils.setGlobalHandler(original));
|
|
271
|
+
}
|
|
272
|
+
if (this.config.trackLifecycle !== false) {
|
|
273
|
+
const sub = AppState.addEventListener("change", (state) => {
|
|
274
|
+
this.addBreadcrumb({ category: "app.lifecycle", message: state });
|
|
275
|
+
if (state === "active") void this.flush();
|
|
276
|
+
if (state === "background" || state === "inactive") void this.capture({ ...this.base("session"), sessionId: this.sessionId, startedAt: this.sessionStarted, endedAt: Date.now(), status: "exited" });
|
|
277
|
+
});
|
|
278
|
+
this.cleanups.push(() => sub.remove());
|
|
279
|
+
}
|
|
280
|
+
if (this.config.trackNetwork !== false) this.patchFetch(endpoint);
|
|
281
|
+
void this.capture({ ...this.base("session"), sessionId: this.sessionId, startedAt: this.sessionStarted, status: "active" });
|
|
282
|
+
}
|
|
283
|
+
patchFetch(endpoint) {
|
|
284
|
+
const original = globalThis.fetch;
|
|
285
|
+
const client2 = this;
|
|
286
|
+
globalThis.fetch = async function(input, init) {
|
|
287
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
288
|
+
if (url.startsWith(endpoint) || init?.headers && new Headers(init.headers).has("x-smartobserve-internal")) return original(input, init);
|
|
289
|
+
const started = Date.now();
|
|
290
|
+
const method = init?.method ?? (typeof input === "object" && "method" in input ? input.method : "GET");
|
|
291
|
+
client2.addBreadcrumb({ category: "http", message: `${method} ${safeUrl(url)}`, data: { method, url: safeUrl(url) } });
|
|
292
|
+
const headers = new Headers(init?.headers ?? (typeof input === "object" && "headers" in input ? input.headers : void 0));
|
|
293
|
+
if (matches(url, client2.config.allowTracePropagationTargets) && client2.trace) headers.set("traceparent", `00-${client2.trace.traceId}-${client2.trace.spanId}-${client2.trace.sampled ? "01" : "00"}`);
|
|
294
|
+
try {
|
|
295
|
+
const response = await original(input, { ...init, headers });
|
|
296
|
+
void client2.capture({ ...client2.base("performance"), metric: "http.client.duration", value: Date.now() - started, unit: "ms", route: safeUrl(url), metadata: { method, status: response.status } });
|
|
297
|
+
return response;
|
|
298
|
+
} catch (error) {
|
|
299
|
+
client2.captureException(error, { mechanism: "fetch", url: safeUrl(url), method });
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
this.cleanups.push(() => {
|
|
304
|
+
globalThis.fetch = original;
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
function matches(value, patterns) {
|
|
309
|
+
return patterns?.some((pattern) => typeof pattern === "string" ? value.startsWith(pattern) : pattern.test(value)) ?? false;
|
|
310
|
+
}
|
|
311
|
+
function serialize(error) {
|
|
312
|
+
if (!(error instanceof Error)) return { type: typeof error, value: typeof error === "string" ? error : String(error), handled: true, mechanism: "manual" };
|
|
313
|
+
return { type: error.name, value: error.message, handled: true, mechanism: "manual", stacktrace: (error.stack ?? "").split("\n").slice(1, 101).map((line) => {
|
|
314
|
+
const match = line.match(/(?:at\s+)?(?:(.*?)\s+\()?(.+?):(\d+):(\d+)\)?$/);
|
|
315
|
+
return match ? { function: match[1] || "<anonymous>", filename: match[2], line: Number(match[3]), column: Number(match[4]), inApp: !match[2]?.includes("node_modules") } : { function: line.trim() };
|
|
316
|
+
}) };
|
|
317
|
+
}
|
|
318
|
+
function applyUser(user, sendDefaultPii) {
|
|
319
|
+
if (!user) return void 0;
|
|
320
|
+
if (sendDefaultPii) return user;
|
|
321
|
+
return { id: user.id, username: user.username };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/index.ts
|
|
325
|
+
var client;
|
|
326
|
+
var SmartObserve = { init(config = {}) {
|
|
327
|
+
return client ??= new SmartObserveExpoClient(config);
|
|
328
|
+
}, captureException(error, hint) {
|
|
329
|
+
return active().captureException(error, hint);
|
|
330
|
+
}, captureMessage(message, level, metadata) {
|
|
331
|
+
return active().captureMessage(message, level, metadata);
|
|
332
|
+
}, addBreadcrumb(value) {
|
|
333
|
+
active().addBreadcrumb(value);
|
|
334
|
+
}, setUser(value) {
|
|
335
|
+
active().setUser(value);
|
|
336
|
+
}, setTag(key, value) {
|
|
337
|
+
active().setTag(key, value);
|
|
338
|
+
}, setContext(key, value) {
|
|
339
|
+
active().setContext(key, value);
|
|
340
|
+
}, startSpan(options, callback) {
|
|
341
|
+
return active().startSpan(options, callback);
|
|
342
|
+
}, trackScreen(name, params) {
|
|
343
|
+
active().trackScreen(name, params);
|
|
344
|
+
}, beforeSend(callback) {
|
|
345
|
+
active().beforeSend(callback);
|
|
346
|
+
}, flush() {
|
|
347
|
+
return active().flush();
|
|
348
|
+
}, async close() {
|
|
349
|
+
await client?.close();
|
|
350
|
+
client = void 0;
|
|
351
|
+
}, get log() {
|
|
352
|
+
return active().log;
|
|
353
|
+
} };
|
|
354
|
+
function active() {
|
|
355
|
+
return client ??= new SmartObserveExpoClient({ enabled: false });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export {
|
|
359
|
+
SmartObserveExpoClient,
|
|
360
|
+
SmartObserve
|
|
361
|
+
};
|
|
362
|
+
//# sourceMappingURL=chunk-HNIEV66S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/internal.ts","../src/transport.ts","../src/sdk-meta.ts","../src/index.ts"],"sourcesContent":["import { AppState, Platform } from \"react-native\";\nimport * as Application from \"expo-application\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport { id, parseDsn, randomHex, safeUrl, sanitize } from \"./internal.js\";\nimport { ExpoTransport } from \"./transport.js\";\nimport type { BeforeSend, Breadcrumb, Level, ObserveEvent, ObserveSpan, ObserveUser, SmartObserveConfig, SpanOptions, TraceContext } from \"./types.js\";\n\ndeclare const ErrorUtils: { getGlobalHandler(): (error: Error, fatal?: boolean) => void; setGlobalHandler(handler: (error: Error, fatal?: boolean) => void): void } | undefined;\n\nexport class SmartObserveExpoClient {\n private config: SmartObserveConfig & { environment: string; enabled: boolean; debug: boolean; tracesSampleRate: number; errorSampleRate: number; maxBreadcrumbs: number }; private transport?: ExpoTransport; private user?: ObserveUser; private tags: Record<string, string> = {}; private contexts: Record<string, unknown> = {}; private breadcrumbs: Breadcrumb[] = []; private trace?: TraceContext; private beforeSendHook?: BeforeSend; private cleanups: Array<() => void> = []; private sessionId = id(); private sessionStarted = Date.now();\n constructor(input: SmartObserveConfig = {}) { this.config = { ...input, environment: input.environment ?? \"production\", enabled: input.enabled ?? Boolean(input.dsn), debug: input.debug ?? false, tracesSampleRate: input.tracesSampleRate ?? input.sampleRate ?? 0.1, errorSampleRate: input.errorSampleRate ?? 1, maxBreadcrumbs: input.maxBreadcrumbs ?? 100 }; this.beforeSendHook = input.beforeSend; if (this.config.enabled && input.dsn) { const parsed = parseDsn(input.dsn); this.transport = new ExpoTransport({ ...parsed, environment: this.config.environment, release: input.release ?? Application.nativeApplicationVersion ?? undefined, dist: input.dist ?? Application.nativeBuildVersion ?? undefined, maxQueueSize: input.maxQueueSize ?? 1_000, flushIntervalMs: input.flushIntervalMs ?? 5_000, debug: this.config.debug }); this.setup(parsed.endpoint); } }\n captureException(error: unknown, hint: Record<string, unknown> = {}) { const eventId = id(); if (Math.random() <= this.config.errorSampleRate) { const exception = serialize(error); void this.capture({ ...this.base(\"error\"), eventId, message: exception.value, level: \"error\", exceptions: [exception], metadata: hint }); } return eventId; }\n captureMessage(message: string, level: Level = \"info\", metadata?: Record<string, unknown>) { const eventId = id(); void this.capture({ ...this.base(\"log\"), eventId, message, level, metadata }); return eventId; }\n log = { debug: (m: string, d?: Record<string, unknown>) => this.captureMessage(m, \"debug\", d), info: (m: string, d?: Record<string, unknown>) => this.captureMessage(m, \"info\", d), warn: (m: string, d?: Record<string, unknown>) => this.captureMessage(m, \"warn\", d), error: (m: string, d?: Record<string, unknown>) => this.captureMessage(m, \"error\", d) };\n addBreadcrumb(value: Breadcrumb) { this.breadcrumbs.push({ ...sanitize(value, this.config.redactKeys), timestamp: value.timestamp ?? Date.now() }); this.breadcrumbs.splice(0, Math.max(0, this.breadcrumbs.length - this.config.maxBreadcrumbs)); }\n setUser(value: ObserveUser | null) { this.user = value ? sanitize(value, this.config.redactKeys) : undefined; }\n setTag(key: string, value: string | null) { if (value === null) delete this.tags[key]; else this.tags[key.slice(0, 64)] = value.slice(0, 256); }\n setContext(key: string, value: Record<string, unknown> | null) { if (value === null) delete this.contexts[key]; else this.contexts[key] = sanitize(value, this.config.redactKeys); }\n beforeSend(callback: BeforeSend) { this.beforeSendHook = callback; }\n startSpan<T>(options: SpanOptions, callback: (span: ObserveSpan) => T | Promise<T>): T | Promise<T> { const previous = this.trace; const trace: TraceContext = { traceId: options.parent?.traceId ?? previous?.traceId ?? randomHex(16), spanId: randomHex(8), parentSpanId: options.parent?.spanId ?? previous?.spanId, sampled: options.sampled ?? previous?.sampled ?? Math.random() < this.config.tracesSampleRate }; const start = Date.now(); const attributes = { ...(options.attributes ?? {}) }; let status: \"ok\" | \"error\" | \"cancelled\" | \"unknown\" = \"unknown\"; let ended = false; const span: ObserveSpan = { traceId: trace.traceId, spanId: trace.spanId, setAttribute: (key, value) => { attributes[key] = value; }, setStatus: (value) => { status = value; }, recordException: (error) => { status = \"error\"; this.captureException(error); }, end: () => { if (!ended && trace.sampled) { ended = true; const isRoot = !trace.parentSpanId; void this.capture({ ...this.base(isRoot ? \"transaction\" : \"span\"), name: options.name, operation: options.operation, startTimestamp: start, endTimestamp: Date.now(), status, ...(isRoot ? {} : { attributes }), trace }); } } }; this.trace = trace; try { const result = callback(span); if (result && typeof (result as Promise<T>).then === \"function\") return (result as Promise<T>).then((value) => { if (status === \"unknown\") status = \"ok\"; span.end(); return value; }, (error) => { span.recordException(error); span.end(); throw error; }).finally(() => { this.trace = previous; }); if (status === \"unknown\") status = \"ok\"; span.end(); return result; } finally { if (this.trace?.spanId === trace.spanId) this.trace = previous; } }\n flush() { return this.transport?.flush() ?? Promise.resolve(); } async close() { for (const cleanup of this.cleanups.splice(0)) cleanup(); await this.transport?.close(); }\n trackScreen(name: string, params?: Record<string, unknown>) { this.addBreadcrumb({ category: \"navigation\", message: name, data: params }); }\n private base(type: ObserveEvent[\"type\"]): ObserveEvent { return { eventId: id(), type, timestamp: Date.now(), platform: \"expo\", user: applyUser(this.user, this.config.sendDefaultPii), tags: { ...this.tags }, contexts: sanitize({ ...this.contexts, device: { brand: Device.brand, model: Device.modelName, deviceType: Device.deviceType, os: Platform.OS, osVersion: Platform.Version, isDevice: Device.isDevice }, app: { id: Application.applicationId, name: Application.applicationName, version: Application.nativeApplicationVersion, build: Application.nativeBuildVersion, runtimeVersion: Constants.expoConfig?.runtimeVersion } }, this.config.redactKeys), breadcrumbs: [...this.breadcrumbs], trace: this.trace }; }\n private async capture(raw: ObserveEvent) { if (!this.transport) return; try { let event = sanitize(raw, this.config.redactKeys); if (this.beforeSendHook) event = await this.beforeSendHook(event) as ObserveEvent; if (event) this.transport.enqueue(event); } catch (error) { if (this.config.debug) console.warn(\"[SmartObserve] event dropped\", error); } }\n private setup(endpoint: string) { const original = typeof ErrorUtils !== \"undefined\" ? ErrorUtils.getGlobalHandler() : undefined; if (original && typeof ErrorUtils !== \"undefined\") { ErrorUtils.setGlobalHandler((error, fatal) => { this.captureException(error, { mechanism: \"react-native.global\", fatal }); if (fatal) void this.capture({ ...this.base(\"session\"), sessionId: this.sessionId, startedAt: this.sessionStarted, endedAt: Date.now(), status: \"crashed\" }); original(error, fatal); }); this.cleanups.push(() => ErrorUtils.setGlobalHandler(original)); } if (this.config.trackLifecycle !== false) { const sub = AppState.addEventListener(\"change\", (state) => { this.addBreadcrumb({ category: \"app.lifecycle\", message: state }); if (state === \"active\") void this.flush(); if (state === \"background\" || state === \"inactive\") void this.capture({ ...this.base(\"session\"), sessionId: this.sessionId, startedAt: this.sessionStarted, endedAt: Date.now(), status: \"exited\" }); }); this.cleanups.push(() => sub.remove()); } if (this.config.trackNetwork !== false) this.patchFetch(endpoint); void this.capture({ ...this.base(\"session\"), sessionId: this.sessionId, startedAt: this.sessionStarted, status: \"active\" }); }\n private patchFetch(endpoint: string) { const original = globalThis.fetch; const client = this; globalThis.fetch = async function(input: RequestInfo | URL, init?: RequestInit) { const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url; if (url.startsWith(endpoint) || (init?.headers && new Headers(init.headers as HeadersInit).has(\"x-smartobserve-internal\"))) return original(input as RequestInfo, init); const started = Date.now(); const method = init?.method ?? (typeof input === \"object\" && \"method\" in input ? (input as Request).method : \"GET\"); client.addBreadcrumb({ category: \"http\", message: `${method} ${safeUrl(url)}`, data: { method, url: safeUrl(url) } }); const headers = new Headers(init?.headers ?? (typeof input === \"object\" && \"headers\" in input ? (input as Request).headers : undefined)); if (matches(url, client.config.allowTracePropagationTargets) && client.trace) headers.set(\"traceparent\", `00-${client.trace.traceId}-${client.trace.spanId}-${client.trace.sampled ? \"01\" : \"00\"}`); try { const response = await original(input as RequestInfo, { ...init, headers }); void client.capture({ ...client.base(\"performance\"), metric: \"http.client.duration\", value: Date.now() - started, unit: \"ms\", route: safeUrl(url), metadata: { method, status: response.status } }); return response; } catch (error) { client.captureException(error, { mechanism: \"fetch\", url: safeUrl(url), method }); throw error; } } as typeof fetch; this.cleanups.push(() => { globalThis.fetch = original; }); }\n}\nfunction matches(value: string, patterns?: Array<string | RegExp>) { return patterns?.some((pattern) => typeof pattern === \"string\" ? value.startsWith(pattern) : pattern.test(value)) ?? false; }\nfunction serialize(error: unknown) { if (!(error instanceof Error)) return { type: typeof error, value: typeof error === \"string\" ? error : String(error), handled: true, mechanism: \"manual\" }; return { type: error.name, value: error.message, handled: true, mechanism: \"manual\", stacktrace: (error.stack ?? \"\").split(\"\\n\").slice(1, 101).map((line) => { const match = line.match(/(?:at\\s+)?(?:(.*?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/); return match ? { function: match[1] || \"<anonymous>\", filename: match[2], line: Number(match[3]), column: Number(match[4]), inApp: !match[2]?.includes(\"node_modules\") } : { function: line.trim() }; }) }; }\nfunction applyUser(user: ObserveUser | undefined, sendDefaultPii?: boolean) { if (!user) return undefined; if (sendDefaultPii) return user; return { id: user.id, username: user.username }; }\n","export function id() { return crypto.randomUUID(); }\nexport function randomHex(bytes: number) { return [...crypto.getRandomValues(new Uint8Array(bytes))].map((value) => value.toString(16).padStart(2, \"0\")).join(\"\"); }\nexport function parseDsn(value: string) { const url = new URL(value); const key = decodeURIComponent(url.username); if (!/^(pk|sk)_[A-Za-z0-9_-]{16,}$/.test(key)) throw new Error(\"SmartObserve DSN contains an invalid project key\"); const slug = url.pathname.replace(/^\\/+|\\/+$/g, \"\"); if (!slug) throw new Error(\"SmartObserve DSN must include a project slug\"); return { endpoint: `${url.protocol}//${url.host}/api/v1/envelope`, key }; }\nconst BLOCKED = new Set([\"password\", \"passcode\", \"authorization\", \"cookie\", \"access_token\", \"refresh_token\", \"api_key\", \"secret\", \"private_key\", \"card_number\", \"cvv\", \"cvc\"]);\nexport function sanitize<T>(input: T, extra: string[] = []): T { const blocked = new Set([...BLOCKED, ...extra.map((value) => value.toLowerCase())]); const seen = new WeakSet<object>(); const walk = (value: unknown, depth: number): unknown => { if (depth > 5) return \"[Truncated]\"; if (typeof value === \"string\") return value.slice(0, 8_192); if (value === null || typeof value !== \"object\") return value; if (seen.has(value)) return \"[Circular]\"; seen.add(value); if (Array.isArray(value)) return value.slice(0, 200).map((entry) => walk(entry, depth + 1)); return Object.fromEntries(Object.entries(value).slice(0, 200).map(([key, entry]) => [key, blocked.has(key.toLowerCase().replace(/[\\s-]+/g, \"_\")) ? \"[Redacted]\" : walk(entry, depth + 1)])); }; return walk(input, 0) as T; }\nexport function safeUrl(value: string) { try { const url = new URL(value); url.username = \"\"; url.password = \"\"; for (const key of [...url.searchParams.keys()]) url.searchParams.set(key, \"[Filtered]\"); return url.toString(); } catch { return \"[Invalid URL]\"; } }\n","import AsyncStorage from \"@react-native-async-storage/async-storage\";\nimport NetInfo from \"@react-native-community/netinfo\";\nimport type { ObserveEvent } from \"./types.js\";\nimport { id } from \"./internal.js\";\nimport { SDK_NAME, SDK_VERSION } from \"./sdk-meta.js\";\nconst STORAGE_KEY = \"@smartobserve/events/v1\";\ninterface Options { endpoint: string; key: string; environment: string; release?: string; dist?: string; maxQueueSize: number; flushIntervalMs: number; debug: boolean }\nexport class ExpoTransport {\n private queue: ObserveEvent[] = []; private timer?: ReturnType<typeof setInterval>; private flushing?: Promise<void>; private online = true; private unsubscribe?: () => void; private closed = false;\n constructor(private readonly options: Options) { this.timer = setInterval(() => void this.flush(), options.flushIntervalMs); this.unsubscribe = NetInfo.addEventListener((state) => { this.online = state.isConnected !== false; if (this.online) void this.flush(); }); void this.restore(); }\n enqueue(event: ObserveEvent) { if (this.closed) return; if (this.queue.length >= this.options.maxQueueSize) this.evict(); this.queue.push(event); void this.persist(); if (this.queue.length >= 50 || event.level === \"fatal\") void this.flush(); }\n async flush() { if (this.flushing || !this.queue.length || !this.online) return this.flushing; const events = this.queue.splice(0, 50); this.flushing = this.send(events).then(() => this.persist()).catch((error) => { this.queue.unshift(...events); void this.persist(); if (this.options.debug) console.warn(\"[SmartObserve] offline batch retained\", error); }).finally(() => { this.flushing = undefined; }); return this.flushing; }\n async close() { this.closed = true; if (this.timer) clearInterval(this.timer); this.unsubscribe?.(); await this.flush(); }\n private async restore() { try { const raw = await AsyncStorage.getItem(STORAGE_KEY); if (!raw) return; const stored = JSON.parse(raw) as Array<ObserveEvent & { _storedAt?: number }>; this.queue.push(...stored.filter((event) => Date.now() - (event._storedAt ?? event.timestamp) < 7 * 86_400_000).slice(-this.options.maxQueueSize)); await this.flush(); } catch (error) { if (this.options.debug) console.warn(\"[SmartObserve] offline queue unavailable\", error); } }\n private async persist(): Promise<void> { try { let prepared = this.queue.map((event) => ({ ...event, _storedAt: Date.now() })); let raw = JSON.stringify(prepared); while (raw.length > 10 * 1024 * 1024 && this.queue.length) { this.evict(); prepared = this.queue.map((event) => ({ ...event, _storedAt: Date.now() })); raw = JSON.stringify(prepared); } await AsyncStorage.setItem(STORAGE_KEY, raw); } catch (error) { if (this.options.debug) console.warn(\"[SmartObserve] could not persist offline queue\", error); } }\n private async send(events: ObserveEvent[]) { const body = JSON.stringify({ schemaVersion: 1, envelopeId: id(), sentAt: Date.now(), sdk: { name: SDK_NAME, version: SDK_VERSION }, environment: this.options.environment, release: this.options.release, dist: this.options.dist, events }); let attempt = 0; while (true) { const response = await fetch(this.options.endpoint, { method: \"POST\", headers: { \"content-type\": \"application/json\", \"origin\": \"smartobserve-expo://native\", \"x-smartobserve-key\": this.options.key, \"x-smartobserve-platform\": \"expo\", \"x-smartobserve-internal\": \"transport\" }, body }); if (response.ok) return; if (![408, 429].includes(response.status) && response.status < 500) return; if (attempt++ >= 5) throw new Error(`HTTP ${response.status}`); await new Promise((resolve) => setTimeout(resolve, Math.random() * Math.min(30_000, 2 ** attempt * 1_000))); } }\n private evict() { const index = this.queue.findIndex((event) => event.type === \"span\" || event.type === \"performance\" || event.level === \"debug\"); this.queue.splice(index < 0 ? 0 : index, 1); }\n}\n","export const SDK_NAME = \"@smarthivelabs-devs/observe-expo\";\nexport const SDK_VERSION = \"26.0.0\";\n","import { SmartObserveExpoClient } from \"./client.js\";\nimport type { SmartObserveConfig } from \"./types.js\";\nlet client: SmartObserveExpoClient | undefined;\nexport const SmartObserve = { init(config: SmartObserveConfig = {}) { return client ??= new SmartObserveExpoClient(config); }, captureException(error: unknown, hint?: Record<string, unknown>) { return active().captureException(error, hint); }, captureMessage(message: string, level?: import(\"./types.js\").Level, metadata?: Record<string, unknown>) { return active().captureMessage(message, level, metadata); }, addBreadcrumb(value: import(\"./types.js\").Breadcrumb) { active().addBreadcrumb(value); }, setUser(value: import(\"./types.js\").ObserveUser | null) { active().setUser(value); }, setTag(key: string, value: string | null) { active().setTag(key, value); }, setContext(key: string, value: Record<string, unknown> | null) { active().setContext(key, value); }, startSpan<T>(options: import(\"./types.js\").SpanOptions, callback: (span: import(\"./types.js\").ObserveSpan) => T | Promise<T>) { return active().startSpan(options, callback); }, trackScreen(name: string, params?: Record<string, unknown>) { active().trackScreen(name, params); }, beforeSend(callback: import(\"./types.js\").BeforeSend) { active().beforeSend(callback); }, flush() { return active().flush(); }, async close() { await client?.close(); client = undefined; }, get log() { return active().log; } };\nfunction active() { return client ??= new SmartObserveExpoClient({ enabled: false }); }\nexport { SmartObserveExpoClient } from \"./client.js\"; export * from \"./types.js\";\n"],"mappings":"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","names":["client"]}
|