@codmir/sdk 0.1.1

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.
@@ -0,0 +1,95 @@
1
+ import { O as OverseerConfig } from '../index-BlgYnCLd.cjs';
2
+ export { B as Breadcrumb, S as SeverityLevel, U as UserContext, d as addBreadcrumb, c as captureException, a as captureMessage, e as close, f as flush, g as getClient, b as setTags, s as setUser } from '../index-BlgYnCLd.cjs';
3
+
4
+ /**
5
+ * @codmir/sdk/react-native - React Native Integration
6
+ *
7
+ * Error tracking and monitoring for React Native applications.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // App.tsx
12
+ * import * as Codmir from '@codmir/sdk/react-native';
13
+ *
14
+ * Codmir.init({
15
+ * dsn: 'https://your-project.codmir.com/api/overseer',
16
+ * });
17
+ *
18
+ * export default function App() {
19
+ * return (
20
+ * <Codmir.ErrorBoundary fallback={<ErrorScreen />}>
21
+ * <YourApp />
22
+ * </Codmir.ErrorBoundary>
23
+ * );
24
+ * }
25
+ * ```
26
+ */
27
+
28
+ interface ReactNativeConfig extends OverseerConfig {
29
+ /** Automatically capture native crashes */
30
+ captureNativeCrashes?: boolean;
31
+ /** Automatically track screen views */
32
+ trackScreenViews?: boolean;
33
+ /** Automatically track app state changes */
34
+ trackAppState?: boolean;
35
+ /** Include device info in events */
36
+ includeDeviceInfo?: boolean;
37
+ }
38
+ interface DeviceInfo {
39
+ platform: "ios" | "android";
40
+ osVersion?: string;
41
+ deviceModel?: string;
42
+ appVersion?: string;
43
+ buildNumber?: string;
44
+ isEmulator?: boolean;
45
+ }
46
+ declare function init(config?: ReactNativeConfig): void;
47
+ /**
48
+ * Set device information (call this after getting device info from react-native-device-info)
49
+ */
50
+ declare function setDeviceInfo(info: DeviceInfo): void;
51
+ /**
52
+ * Track screen view (call this from your navigation listener)
53
+ */
54
+ declare function trackScreenView(screenName: string, params?: Record<string, unknown>): void;
55
+ /**
56
+ * Create a navigation listener for React Navigation
57
+ */
58
+ declare function createNavigationListener(): (state: any) => void;
59
+ /**
60
+ * Track app state change (foreground/background)
61
+ */
62
+ declare function trackAppStateChange(state: "active" | "background" | "inactive"): void;
63
+ /**
64
+ * Error Boundary props
65
+ */
66
+ interface ErrorBoundaryProps {
67
+ children: React.ReactNode;
68
+ fallback: React.ReactNode | ((error: Error) => React.ReactNode);
69
+ onError?: (error: Error, componentStack: string) => void;
70
+ }
71
+ /**
72
+ * Note: ErrorBoundary is a class component placeholder.
73
+ * In actual usage, import React and implement properly.
74
+ */
75
+ declare function createErrorBoundary(React: any): {
76
+ new (props: ErrorBoundaryProps): {
77
+ [x: string]: any;
78
+ componentDidCatch(error: Error, errorInfo: {
79
+ componentStack: string;
80
+ }): void;
81
+ render(): any;
82
+ };
83
+ [x: string]: any;
84
+ getDerivedStateFromError(error: Error): {
85
+ hasError: boolean;
86
+ error: Error;
87
+ };
88
+ };
89
+
90
+ /**
91
+ * Check if Overseer is initialized
92
+ */
93
+ declare function isOverseerInitialized(): boolean;
94
+
95
+ export { type DeviceInfo, type ErrorBoundaryProps, OverseerConfig, type ReactNativeConfig, createErrorBoundary, createNavigationListener, init, isOverseerInitialized, setDeviceInfo, trackAppStateChange, trackScreenView };
@@ -0,0 +1,95 @@
1
+ import { O as OverseerConfig } from '../index-BlgYnCLd.js';
2
+ export { B as Breadcrumb, S as SeverityLevel, U as UserContext, d as addBreadcrumb, c as captureException, a as captureMessage, e as close, f as flush, g as getClient, b as setTags, s as setUser } from '../index-BlgYnCLd.js';
3
+
4
+ /**
5
+ * @codmir/sdk/react-native - React Native Integration
6
+ *
7
+ * Error tracking and monitoring for React Native applications.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // App.tsx
12
+ * import * as Codmir from '@codmir/sdk/react-native';
13
+ *
14
+ * Codmir.init({
15
+ * dsn: 'https://your-project.codmir.com/api/overseer',
16
+ * });
17
+ *
18
+ * export default function App() {
19
+ * return (
20
+ * <Codmir.ErrorBoundary fallback={<ErrorScreen />}>
21
+ * <YourApp />
22
+ * </Codmir.ErrorBoundary>
23
+ * );
24
+ * }
25
+ * ```
26
+ */
27
+
28
+ interface ReactNativeConfig extends OverseerConfig {
29
+ /** Automatically capture native crashes */
30
+ captureNativeCrashes?: boolean;
31
+ /** Automatically track screen views */
32
+ trackScreenViews?: boolean;
33
+ /** Automatically track app state changes */
34
+ trackAppState?: boolean;
35
+ /** Include device info in events */
36
+ includeDeviceInfo?: boolean;
37
+ }
38
+ interface DeviceInfo {
39
+ platform: "ios" | "android";
40
+ osVersion?: string;
41
+ deviceModel?: string;
42
+ appVersion?: string;
43
+ buildNumber?: string;
44
+ isEmulator?: boolean;
45
+ }
46
+ declare function init(config?: ReactNativeConfig): void;
47
+ /**
48
+ * Set device information (call this after getting device info from react-native-device-info)
49
+ */
50
+ declare function setDeviceInfo(info: DeviceInfo): void;
51
+ /**
52
+ * Track screen view (call this from your navigation listener)
53
+ */
54
+ declare function trackScreenView(screenName: string, params?: Record<string, unknown>): void;
55
+ /**
56
+ * Create a navigation listener for React Navigation
57
+ */
58
+ declare function createNavigationListener(): (state: any) => void;
59
+ /**
60
+ * Track app state change (foreground/background)
61
+ */
62
+ declare function trackAppStateChange(state: "active" | "background" | "inactive"): void;
63
+ /**
64
+ * Error Boundary props
65
+ */
66
+ interface ErrorBoundaryProps {
67
+ children: React.ReactNode;
68
+ fallback: React.ReactNode | ((error: Error) => React.ReactNode);
69
+ onError?: (error: Error, componentStack: string) => void;
70
+ }
71
+ /**
72
+ * Note: ErrorBoundary is a class component placeholder.
73
+ * In actual usage, import React and implement properly.
74
+ */
75
+ declare function createErrorBoundary(React: any): {
76
+ new (props: ErrorBoundaryProps): {
77
+ [x: string]: any;
78
+ componentDidCatch(error: Error, errorInfo: {
79
+ componentStack: string;
80
+ }): void;
81
+ render(): any;
82
+ };
83
+ [x: string]: any;
84
+ getDerivedStateFromError(error: Error): {
85
+ hasError: boolean;
86
+ error: Error;
87
+ };
88
+ };
89
+
90
+ /**
91
+ * Check if Overseer is initialized
92
+ */
93
+ declare function isOverseerInitialized(): boolean;
94
+
95
+ export { type DeviceInfo, type ErrorBoundaryProps, OverseerConfig, type ReactNativeConfig, createErrorBoundary, createNavigationListener, init, isOverseerInitialized, setDeviceInfo, trackAppStateChange, trackScreenView };
@@ -0,0 +1,128 @@
1
+ import {
2
+ addBreadcrumb,
3
+ captureException,
4
+ captureMessage,
5
+ close,
6
+ flush,
7
+ getClient,
8
+ init,
9
+ setTags,
10
+ setUser
11
+ } from "../chunk-T7OAAOG2.js";
12
+ import "../chunk-MLKGABMK.js";
13
+
14
+ // src/react-native/index.ts
15
+ var isInitialized = false;
16
+ var deviceInfo = null;
17
+ function init2(config = {}) {
18
+ if (isInitialized) return;
19
+ const {
20
+ captureNativeCrashes = true,
21
+ trackScreenViews = true,
22
+ trackAppState = true,
23
+ includeDeviceInfo = true,
24
+ ...coreConfig
25
+ } = config;
26
+ init(coreConfig);
27
+ isInitialized = true;
28
+ const originalHandler = ErrorUtils.getGlobalHandler();
29
+ ErrorUtils.setGlobalHandler((error, isFatal) => {
30
+ captureException(error, {
31
+ handled: false,
32
+ mechanism: "global-error-handler",
33
+ fatal: isFatal,
34
+ device: deviceInfo
35
+ });
36
+ if (originalHandler) {
37
+ originalHandler(error, isFatal);
38
+ }
39
+ });
40
+ }
41
+ function setDeviceInfo(info) {
42
+ deviceInfo = info;
43
+ setTags({
44
+ "device.platform": info.platform,
45
+ "device.os_version": info.osVersion || "unknown",
46
+ "device.model": info.deviceModel || "unknown",
47
+ "app.version": info.appVersion || "unknown",
48
+ "app.build": info.buildNumber || "unknown"
49
+ });
50
+ }
51
+ function trackScreenView(screenName, params) {
52
+ addBreadcrumb({
53
+ category: "navigation",
54
+ message: `Screen: ${screenName}`,
55
+ data: params
56
+ });
57
+ }
58
+ function createNavigationListener() {
59
+ return (state) => {
60
+ const currentRoute = getCurrentRouteName(state);
61
+ if (currentRoute) {
62
+ trackScreenView(currentRoute);
63
+ }
64
+ };
65
+ }
66
+ function getCurrentRouteName(state) {
67
+ if (!state) return null;
68
+ const route = state.routes[state.index];
69
+ if (route.state) {
70
+ return getCurrentRouteName(route.state);
71
+ }
72
+ return route.name;
73
+ }
74
+ function trackAppStateChange(state) {
75
+ addBreadcrumb({
76
+ category: "app.lifecycle",
77
+ message: `App state: ${state}`,
78
+ data: { state }
79
+ });
80
+ }
81
+ function createErrorBoundary(React) {
82
+ return class ErrorBoundary extends React.Component {
83
+ constructor(props) {
84
+ super(props);
85
+ this.state = { hasError: false, error: null };
86
+ }
87
+ static getDerivedStateFromError(error) {
88
+ return { hasError: true, error };
89
+ }
90
+ componentDidCatch(error, errorInfo) {
91
+ captureException(error, {
92
+ mechanism: "react-error-boundary",
93
+ componentStack: errorInfo.componentStack
94
+ });
95
+ this.props.onError?.(error, errorInfo.componentStack);
96
+ }
97
+ render() {
98
+ if (this.state.hasError) {
99
+ const { fallback } = this.props;
100
+ if (typeof fallback === "function") {
101
+ return fallback(this.state.error);
102
+ }
103
+ return fallback;
104
+ }
105
+ return this.props.children;
106
+ }
107
+ };
108
+ }
109
+ function isOverseerInitialized() {
110
+ return isInitialized && getClient() !== null;
111
+ }
112
+ export {
113
+ addBreadcrumb,
114
+ captureException,
115
+ captureMessage,
116
+ close,
117
+ createErrorBoundary,
118
+ createNavigationListener,
119
+ flush,
120
+ getClient,
121
+ init2 as init,
122
+ isOverseerInitialized,
123
+ setDeviceInfo,
124
+ setTags,
125
+ setUser,
126
+ trackAppStateChange,
127
+ trackScreenView
128
+ };
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/replay/index.ts
21
+ var replay_exports = {};
22
+ __export(replay_exports, {
23
+ ReplayPlayer: () => ReplayPlayer,
24
+ ReplayRecorder: () => ReplayRecorder,
25
+ createReplayPlayer: () => createReplayPlayer,
26
+ createReplayRecorder: () => createReplayRecorder
27
+ });
28
+ module.exports = __toCommonJS(replay_exports);
29
+ var import_nanoid = require("nanoid");
30
+ var DEFAULT_PRIVACY = {
31
+ maskAllInputs: false,
32
+ maskInputTypes: ["password", "credit-card"],
33
+ maskSelectors: ["[data-private]", ".private"],
34
+ blockSelectors: ["[data-block-replay]"],
35
+ ignoreSelectors: []
36
+ };
37
+ var DEFAULT_CONFIG = {
38
+ sessionSampleRate: 0.1,
39
+ errorSampleRate: 1,
40
+ maxSessionDuration: 60 * 60 * 1e3,
41
+ segmentDuration: 5 * 60 * 1e3,
42
+ privacy: DEFAULT_PRIVACY
43
+ };
44
+ var ReplayRecorder = class {
45
+ config;
46
+ session = null;
47
+ currentSegment = null;
48
+ isRecording = false;
49
+ sessionStartTime = 0;
50
+ cleanupFns = [];
51
+ onSegmentReady;
52
+ onSessionEnd;
53
+ constructor(config = {}) {
54
+ this.config = { ...DEFAULT_CONFIG, ...config };
55
+ }
56
+ start(options) {
57
+ if (this.isRecording) return this.session?.id || null;
58
+ if (typeof window === "undefined") return null;
59
+ if (Math.random() > this.config.sessionSampleRate) return null;
60
+ this.sessionStartTime = Date.now();
61
+ this.session = {
62
+ id: (0, import_nanoid.nanoid)(),
63
+ userId: options?.userId,
64
+ startedAt: /* @__PURE__ */ new Date(),
65
+ duration: 0,
66
+ url: window.location.href,
67
+ userAgent: navigator.userAgent,
68
+ viewport: { width: window.innerWidth, height: window.innerHeight },
69
+ events: [],
70
+ errorIds: [],
71
+ segments: [],
72
+ tags: options?.tags || {}
73
+ };
74
+ this.startNewSegment();
75
+ this.isRecording = true;
76
+ this.setupEventListeners();
77
+ this.captureSnapshot();
78
+ return this.session.id;
79
+ }
80
+ stop() {
81
+ if (!this.isRecording || !this.session) return null;
82
+ this.isRecording = false;
83
+ this.session.endedAt = /* @__PURE__ */ new Date();
84
+ this.session.duration = Date.now() - this.sessionStartTime;
85
+ if (this.currentSegment) {
86
+ this.currentSegment.endTime = this.session.duration;
87
+ this.session.segments.push(this.currentSegment);
88
+ this.onSegmentReady?.(this.currentSegment);
89
+ }
90
+ this.cleanupFns.forEach((fn) => fn());
91
+ this.cleanupFns = [];
92
+ let finalSession = this.session;
93
+ if (this.config.beforeSend) {
94
+ const processed = this.config.beforeSend(this.session);
95
+ if (!processed) {
96
+ this.session = null;
97
+ return null;
98
+ }
99
+ finalSession = processed;
100
+ }
101
+ this.onSessionEnd?.(finalSession);
102
+ const result = finalSession;
103
+ this.session = null;
104
+ this.currentSegment = null;
105
+ return result;
106
+ }
107
+ markError(errorId) {
108
+ this.session?.errorIds.push(errorId);
109
+ }
110
+ addCustomEvent(name, payload) {
111
+ this.addEvent({
112
+ type: "custom",
113
+ timestamp: this.getRelativeTime(),
114
+ data: { name, payload }
115
+ });
116
+ }
117
+ getSessionId() {
118
+ return this.session?.id || null;
119
+ }
120
+ isActive() {
121
+ return this.isRecording;
122
+ }
123
+ onSegment(handler) {
124
+ this.onSegmentReady = handler;
125
+ }
126
+ onSession(handler) {
127
+ this.onSessionEnd = handler;
128
+ }
129
+ getRelativeTime() {
130
+ return Date.now() - this.sessionStartTime;
131
+ }
132
+ addEvent(event) {
133
+ if (!this.isRecording || !this.currentSegment) return;
134
+ this.currentSegment.events.push(event);
135
+ if (event.timestamp - this.currentSegment.startTime >= this.config.segmentDuration) {
136
+ this.finalizeSegment();
137
+ this.startNewSegment();
138
+ }
139
+ if (event.timestamp >= this.config.maxSessionDuration) {
140
+ this.stop();
141
+ }
142
+ }
143
+ startNewSegment() {
144
+ this.currentSegment = {
145
+ id: (0, import_nanoid.nanoid)(),
146
+ sessionId: this.session.id,
147
+ sequenceNumber: this.session.segments.length,
148
+ startTime: this.getRelativeTime(),
149
+ endTime: 0,
150
+ events: []
151
+ };
152
+ }
153
+ finalizeSegment() {
154
+ if (!this.currentSegment || !this.session) return;
155
+ this.currentSegment.endTime = this.getRelativeTime();
156
+ this.session.segments.push(this.currentSegment);
157
+ this.onSegmentReady?.(this.currentSegment);
158
+ }
159
+ captureSnapshot() {
160
+ if (typeof document === "undefined") return;
161
+ this.addEvent({
162
+ type: "dom_snapshot",
163
+ timestamp: this.getRelativeTime(),
164
+ data: {
165
+ html: document.documentElement.outerHTML,
166
+ baseUrl: document.baseURI,
167
+ doctype: document.doctype ? `<!DOCTYPE ${document.doctype.name}>` : void 0
168
+ }
169
+ });
170
+ }
171
+ setupEventListeners() {
172
+ let lastMouseMove = 0;
173
+ const onMouseMove = (e) => {
174
+ if (Date.now() - lastMouseMove < 50) return;
175
+ lastMouseMove = Date.now();
176
+ this.addEvent({
177
+ type: "mouse_move",
178
+ timestamp: this.getRelativeTime(),
179
+ data: { x: e.clientX, y: e.clientY }
180
+ });
181
+ };
182
+ window.addEventListener("mousemove", onMouseMove);
183
+ this.cleanupFns.push(() => window.removeEventListener("mousemove", onMouseMove));
184
+ const onClick = (e) => {
185
+ this.addEvent({
186
+ type: "mouse_click",
187
+ timestamp: this.getRelativeTime(),
188
+ data: { x: e.clientX, y: e.clientY, button: e.button }
189
+ });
190
+ };
191
+ window.addEventListener("click", onClick);
192
+ this.cleanupFns.push(() => window.removeEventListener("click", onClick));
193
+ let lastScroll = 0;
194
+ const onScroll = () => {
195
+ if (Date.now() - lastScroll < 100) return;
196
+ lastScroll = Date.now();
197
+ this.addEvent({
198
+ type: "scroll",
199
+ timestamp: this.getRelativeTime(),
200
+ data: { targetId: "window", x: window.scrollX, y: window.scrollY }
201
+ });
202
+ };
203
+ window.addEventListener("scroll", onScroll);
204
+ this.cleanupFns.push(() => window.removeEventListener("scroll", onScroll));
205
+ const onResize = () => {
206
+ this.addEvent({
207
+ type: "viewport",
208
+ timestamp: this.getRelativeTime(),
209
+ data: { width: window.innerWidth, height: window.innerHeight }
210
+ });
211
+ };
212
+ window.addEventListener("resize", onResize);
213
+ this.cleanupFns.push(() => window.removeEventListener("resize", onResize));
214
+ }
215
+ };
216
+ var ReplayPlayer = class {
217
+ config;
218
+ session = null;
219
+ state = "idle";
220
+ currentTime = 0;
221
+ animationFrameId = null;
222
+ constructor(config) {
223
+ this.config = {
224
+ speed: 1,
225
+ skipInactiveThreshold: 5e3,
226
+ showCursor: true,
227
+ showClickRipple: true,
228
+ highlightErrors: true,
229
+ ...config
230
+ };
231
+ }
232
+ load(session) {
233
+ this.session = session;
234
+ this.currentTime = 0;
235
+ this.state = "idle";
236
+ }
237
+ play() {
238
+ if (!this.session) return;
239
+ this.state = "playing";
240
+ }
241
+ pause() {
242
+ this.state = "paused";
243
+ if (this.animationFrameId) {
244
+ cancelAnimationFrame(this.animationFrameId);
245
+ }
246
+ }
247
+ stop() {
248
+ this.pause();
249
+ this.currentTime = 0;
250
+ this.state = "idle";
251
+ }
252
+ seek(time) {
253
+ if (!this.session) return;
254
+ this.currentTime = Math.max(0, Math.min(time, this.session.duration));
255
+ }
256
+ setSpeed(speed) {
257
+ this.config.speed = speed;
258
+ }
259
+ getState() {
260
+ return this.state;
261
+ }
262
+ getCurrentTime() {
263
+ return this.currentTime;
264
+ }
265
+ getDuration() {
266
+ return this.session?.duration || 0;
267
+ }
268
+ destroy() {
269
+ this.stop();
270
+ }
271
+ };
272
+ function createReplayRecorder(config) {
273
+ return new ReplayRecorder(config);
274
+ }
275
+ function createReplayPlayer(config) {
276
+ return new ReplayPlayer(config);
277
+ }
278
+ // Annotate the CommonJS export names for ESM import in node:
279
+ 0 && (module.exports = {
280
+ ReplayPlayer,
281
+ ReplayRecorder,
282
+ createReplayPlayer,
283
+ createReplayRecorder
284
+ });