@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.
- package/README.md +206 -0
- package/dist/browser/index.cjs +409 -0
- package/dist/browser/index.d.cts +47 -0
- package/dist/browser/index.d.ts +47 -0
- package/dist/browser/index.js +186 -0
- package/dist/chunk-233XBWQD.js +43 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-T7OAAOG2.js +235 -0
- package/dist/chunk-X6Y5XEK5.js +255 -0
- package/dist/client.cjs +315 -0
- package/dist/client.d.cts +52 -0
- package/dist/client.d.ts +52 -0
- package/dist/client.js +10 -0
- package/dist/index-BlgYnCLd.d.cts +171 -0
- package/dist/index-BlgYnCLd.d.ts +171 -0
- package/dist/index.cjs +540 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +21 -0
- package/dist/nextjs/index.cjs +371 -0
- package/dist/nextjs/index.d.cts +77 -0
- package/dist/nextjs/index.d.ts +77 -0
- package/dist/nextjs/index.js +142 -0
- package/dist/overseer/index.cjs +250 -0
- package/dist/overseer/index.d.cts +1 -0
- package/dist/overseer/index.d.ts +1 -0
- package/dist/overseer/index.js +27 -0
- package/dist/react-native/index.cjs +356 -0
- package/dist/react-native/index.d.cts +95 -0
- package/dist/react-native/index.d.ts +95 -0
- package/dist/react-native/index.js +128 -0
- package/dist/replay/index.cjs +284 -0
- package/dist/replay/index.d.cts +206 -0
- package/dist/replay/index.d.ts +206 -0
- package/dist/replay/index.js +258 -0
- package/dist/types.cjs +69 -0
- package/dist/types.d.cts +281 -0
- package/dist/types.d.ts +281 -0
- package/dist/types.js +11 -0
- package/package.json +116 -0
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# @codmir/sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for the Codmir API.
|
|
4
|
+
|
|
5
|
+
> **Note:** For CLI usage, install the `codmir` package instead: `npm install -g codmir`
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @codmir/sdk
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @codmir/sdk
|
|
13
|
+
# or
|
|
14
|
+
yarn add @codmir/sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { CodmirClient } from '@codmir/sdk';
|
|
21
|
+
|
|
22
|
+
const client = new CodmirClient({
|
|
23
|
+
apiKey: process.env.CODMIR_API_KEY,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// List projects
|
|
27
|
+
const projects = await client.listProjects();
|
|
28
|
+
|
|
29
|
+
// Create a ticket
|
|
30
|
+
const ticket = await client.createTicket({
|
|
31
|
+
title: 'Fix login bug',
|
|
32
|
+
description: 'Users cannot login with SSO',
|
|
33
|
+
type: 'bug',
|
|
34
|
+
priority: 'high',
|
|
35
|
+
projectId: 'project-123',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Use AI chat
|
|
39
|
+
const response = await client.chat('How do I implement OAuth2?');
|
|
40
|
+
console.log(response);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const client = new CodmirClient({
|
|
47
|
+
apiKey: 'your-api-key', // Or set CODMIR_API_KEY env var
|
|
48
|
+
baseUrl: 'https://codmir.com/api', // Optional, defaults to production
|
|
49
|
+
timeout: 30000, // Request timeout in ms
|
|
50
|
+
headers: { // Custom headers
|
|
51
|
+
'X-Custom-Header': 'value',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
### Authentication
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Get current user
|
|
62
|
+
const user = await client.whoami();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Projects
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// List all projects
|
|
69
|
+
const projects = await client.listProjects();
|
|
70
|
+
|
|
71
|
+
// Get a specific project
|
|
72
|
+
const project = await client.getProject('project-id');
|
|
73
|
+
|
|
74
|
+
// Create a project
|
|
75
|
+
const newProject = await client.createProject({
|
|
76
|
+
name: 'My Project',
|
|
77
|
+
organizationId: 'org-id',
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Tickets
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// List tickets
|
|
85
|
+
const tickets = await client.listTickets('project-id', {
|
|
86
|
+
page: 1,
|
|
87
|
+
pageSize: 20,
|
|
88
|
+
status: 'open',
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Get a ticket
|
|
92
|
+
const ticket = await client.getTicket('project-id', 'ticket-id');
|
|
93
|
+
|
|
94
|
+
// Create a ticket
|
|
95
|
+
const ticket = await client.createTicket({
|
|
96
|
+
title: 'Bug report',
|
|
97
|
+
description: 'Something is broken',
|
|
98
|
+
type: 'bug',
|
|
99
|
+
priority: 'high',
|
|
100
|
+
projectId: 'project-id',
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Update a ticket
|
|
104
|
+
const updated = await client.updateTicket('project-id', 'ticket-id', {
|
|
105
|
+
status: 'in_progress',
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Delete a ticket
|
|
109
|
+
await client.deleteTicket('project-id', 'ticket-id');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Test Cases
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// List test cases
|
|
116
|
+
const testCases = await client.listTestCases('project-id');
|
|
117
|
+
|
|
118
|
+
// Create a test case
|
|
119
|
+
const testCase = await client.createTestCase({
|
|
120
|
+
title: 'Login flow',
|
|
121
|
+
projectId: 'project-id',
|
|
122
|
+
steps: [
|
|
123
|
+
{ order: 1, action: 'Open login page', expectedResult: 'Login form displayed' },
|
|
124
|
+
{ order: 2, action: 'Enter credentials', expectedResult: 'Fields populated' },
|
|
125
|
+
{ order: 3, action: 'Click submit', expectedResult: 'User logged in' },
|
|
126
|
+
],
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### AI Agent Tasks
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Create an agent task
|
|
134
|
+
const task = await client.createAgentTask({
|
|
135
|
+
type: 'code_review',
|
|
136
|
+
prompt: 'Review this pull request for security issues',
|
|
137
|
+
projectId: 'project-id',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Run the task
|
|
141
|
+
const execution = await client.runAgentTask({
|
|
142
|
+
taskId: task.id,
|
|
143
|
+
options: {
|
|
144
|
+
model: 'gpt-4-turbo',
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Get task status
|
|
149
|
+
const status = await client.getAgentTask(task.id);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### AI Chat
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Simple chat
|
|
156
|
+
const response = await client.chat('Explain dependency injection');
|
|
157
|
+
|
|
158
|
+
// Chat with project context
|
|
159
|
+
const response = await client.chat('How is auth implemented?', {
|
|
160
|
+
projectId: 'project-id',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Streaming chat
|
|
164
|
+
const fullResponse = await client.streamChat('Write a function to...', {
|
|
165
|
+
onChunk: (chunk) => process.stdout.write(chunk),
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Error Handling
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { CodmirClient, CodmirApiError } from '@codmir/sdk';
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const ticket = await client.getTicket('project-id', 'invalid-id');
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (error instanceof CodmirApiError) {
|
|
178
|
+
console.error(`API Error: ${error.code} - ${error.message}`);
|
|
179
|
+
console.error(`Status: ${error.statusCode}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## TypeScript Support
|
|
185
|
+
|
|
186
|
+
Full TypeScript support with exported types:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import type {
|
|
190
|
+
Ticket,
|
|
191
|
+
CreateTicketInput,
|
|
192
|
+
TicketStatus,
|
|
193
|
+
TicketPriority,
|
|
194
|
+
AgentTask,
|
|
195
|
+
AgentTaskType,
|
|
196
|
+
} from '@codmir/sdk';
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Related Packages
|
|
200
|
+
|
|
201
|
+
- `codmir` - CLI tool for terminal usage
|
|
202
|
+
- `@codmir/types` - Shared type definitions
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT
|
|
@@ -0,0 +1,409 @@
|
|
|
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/browser/index.ts
|
|
21
|
+
var browser_exports = {};
|
|
22
|
+
__export(browser_exports, {
|
|
23
|
+
addBreadcrumb: () => addBreadcrumb,
|
|
24
|
+
captureException: () => captureException,
|
|
25
|
+
captureMessage: () => captureMessage,
|
|
26
|
+
close: () => close,
|
|
27
|
+
flush: () => flush,
|
|
28
|
+
getClient: () => getClient,
|
|
29
|
+
init: () => init2,
|
|
30
|
+
isOverseerInitialized: () => isOverseerInitialized,
|
|
31
|
+
setTags: () => setTags,
|
|
32
|
+
setUser: () => setUser
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(browser_exports);
|
|
35
|
+
|
|
36
|
+
// src/overseer/index.ts
|
|
37
|
+
var import_nanoid = require("nanoid");
|
|
38
|
+
var OverseerClient = class {
|
|
39
|
+
config;
|
|
40
|
+
user = null;
|
|
41
|
+
tags = {};
|
|
42
|
+
breadcrumbs = [];
|
|
43
|
+
eventQueue = [];
|
|
44
|
+
flushTimer = null;
|
|
45
|
+
isInitialized = false;
|
|
46
|
+
constructor(config = {}) {
|
|
47
|
+
this.config = {
|
|
48
|
+
dsn: config.dsn || "",
|
|
49
|
+
environment: config.environment || "development",
|
|
50
|
+
release: config.release || "unknown",
|
|
51
|
+
enabled: config.enabled ?? true,
|
|
52
|
+
debug: config.debug ?? false,
|
|
53
|
+
sampleRate: config.sampleRate ?? 1,
|
|
54
|
+
tracesSampleRate: config.tracesSampleRate ?? 0,
|
|
55
|
+
replaysSessionSampleRate: config.replaysSessionSampleRate ?? 0,
|
|
56
|
+
replaysOnErrorSampleRate: config.replaysOnErrorSampleRate ?? 1,
|
|
57
|
+
beforeSend: config.beforeSend || ((e) => e),
|
|
58
|
+
initialUser: config.initialUser,
|
|
59
|
+
initialTags: config.initialTags || {}
|
|
60
|
+
};
|
|
61
|
+
if (this.config.initialUser) {
|
|
62
|
+
this.user = this.config.initialUser;
|
|
63
|
+
}
|
|
64
|
+
if (this.config.initialTags) {
|
|
65
|
+
this.tags = { ...this.config.initialTags };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
init() {
|
|
69
|
+
if (this.isInitialized) return;
|
|
70
|
+
this.isInitialized = true;
|
|
71
|
+
if (this.config.debug) {
|
|
72
|
+
console.log("[Overseer] Initialized", {
|
|
73
|
+
dsn: this.config.dsn,
|
|
74
|
+
environment: this.config.environment
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
captureException(error, context) {
|
|
79
|
+
if (!this.config.enabled) return "";
|
|
80
|
+
if (!this.shouldSample(this.config.sampleRate)) return "";
|
|
81
|
+
const eventId = (0, import_nanoid.nanoid)();
|
|
82
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
83
|
+
const event = {
|
|
84
|
+
id: eventId,
|
|
85
|
+
type: "error",
|
|
86
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
87
|
+
level: "error",
|
|
88
|
+
message: err.message,
|
|
89
|
+
exception: {
|
|
90
|
+
type: err.name,
|
|
91
|
+
value: err.message,
|
|
92
|
+
stacktrace: this.parseStackTrace(err.stack),
|
|
93
|
+
mechanism: { type: "generic", handled: true }
|
|
94
|
+
},
|
|
95
|
+
user: this.user || void 0,
|
|
96
|
+
tags: { ...this.tags },
|
|
97
|
+
extra: context,
|
|
98
|
+
breadcrumbs: [...this.breadcrumbs],
|
|
99
|
+
environment: this.config.environment,
|
|
100
|
+
release: this.config.release,
|
|
101
|
+
sdk: { name: "@codmir/sdk", version: "1.0.0" }
|
|
102
|
+
};
|
|
103
|
+
this.sendEvent(event);
|
|
104
|
+
return eventId;
|
|
105
|
+
}
|
|
106
|
+
captureMessage(message, level = "info") {
|
|
107
|
+
if (!this.config.enabled) return "";
|
|
108
|
+
if (!this.shouldSample(this.config.sampleRate)) return "";
|
|
109
|
+
const eventId = (0, import_nanoid.nanoid)();
|
|
110
|
+
const event = {
|
|
111
|
+
id: eventId,
|
|
112
|
+
type: "message",
|
|
113
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
114
|
+
level,
|
|
115
|
+
message,
|
|
116
|
+
user: this.user || void 0,
|
|
117
|
+
tags: { ...this.tags },
|
|
118
|
+
breadcrumbs: [...this.breadcrumbs],
|
|
119
|
+
environment: this.config.environment,
|
|
120
|
+
release: this.config.release,
|
|
121
|
+
sdk: { name: "@codmir/sdk", version: "1.0.0" }
|
|
122
|
+
};
|
|
123
|
+
this.sendEvent(event);
|
|
124
|
+
return eventId;
|
|
125
|
+
}
|
|
126
|
+
setUser(user) {
|
|
127
|
+
this.user = user;
|
|
128
|
+
}
|
|
129
|
+
setTag(key, value) {
|
|
130
|
+
this.tags[key] = value;
|
|
131
|
+
}
|
|
132
|
+
setTags(tags) {
|
|
133
|
+
this.tags = { ...this.tags, ...tags };
|
|
134
|
+
}
|
|
135
|
+
setExtra(key, value) {
|
|
136
|
+
}
|
|
137
|
+
addBreadcrumb(breadcrumb) {
|
|
138
|
+
this.breadcrumbs.push({
|
|
139
|
+
...breadcrumb,
|
|
140
|
+
timestamp: breadcrumb.timestamp || (/* @__PURE__ */ new Date()).toISOString()
|
|
141
|
+
});
|
|
142
|
+
if (this.breadcrumbs.length > 100) {
|
|
143
|
+
this.breadcrumbs = this.breadcrumbs.slice(-100);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async flush(timeout) {
|
|
147
|
+
if (this.eventQueue.length === 0) return true;
|
|
148
|
+
const events = [...this.eventQueue];
|
|
149
|
+
this.eventQueue = [];
|
|
150
|
+
try {
|
|
151
|
+
await this.sendBatch(events);
|
|
152
|
+
return true;
|
|
153
|
+
} catch {
|
|
154
|
+
this.eventQueue.unshift(...events);
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
close() {
|
|
159
|
+
if (this.flushTimer) {
|
|
160
|
+
clearTimeout(this.flushTimer);
|
|
161
|
+
}
|
|
162
|
+
this.flush();
|
|
163
|
+
}
|
|
164
|
+
// Private methods
|
|
165
|
+
shouldSample(rate) {
|
|
166
|
+
return Math.random() < rate;
|
|
167
|
+
}
|
|
168
|
+
parseStackTrace(stack) {
|
|
169
|
+
if (!stack) return [];
|
|
170
|
+
return stack.split("\n").slice(1).map((line) => {
|
|
171
|
+
const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
|
|
172
|
+
if (match) {
|
|
173
|
+
return {
|
|
174
|
+
function: match[1],
|
|
175
|
+
filename: match[2],
|
|
176
|
+
lineno: parseInt(match[3], 10),
|
|
177
|
+
colno: parseInt(match[4], 10),
|
|
178
|
+
in_app: !match[2].includes("node_modules")
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return { function: line.trim() };
|
|
182
|
+
}).filter((f) => f.function);
|
|
183
|
+
}
|
|
184
|
+
sendEvent(event) {
|
|
185
|
+
const processed = this.config.beforeSend(event);
|
|
186
|
+
if (!processed) return;
|
|
187
|
+
this.eventQueue.push(processed);
|
|
188
|
+
if (this.flushTimer) clearTimeout(this.flushTimer);
|
|
189
|
+
this.flushTimer = setTimeout(() => this.flush(), 1e3);
|
|
190
|
+
}
|
|
191
|
+
async sendBatch(events) {
|
|
192
|
+
if (!this.config.dsn) {
|
|
193
|
+
if (this.config.debug) {
|
|
194
|
+
console.log("[Overseer] No DSN configured, events:", events);
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const endpoint = this.config.dsn.endsWith("/ingest") ? this.config.dsn : `${this.config.dsn}/ingest`;
|
|
199
|
+
await fetch(endpoint, {
|
|
200
|
+
method: "POST",
|
|
201
|
+
headers: { "Content-Type": "application/json" },
|
|
202
|
+
body: JSON.stringify({ events })
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
var client = null;
|
|
207
|
+
function init(config = {}) {
|
|
208
|
+
client = new OverseerClient(config);
|
|
209
|
+
client.init();
|
|
210
|
+
}
|
|
211
|
+
function getClient() {
|
|
212
|
+
return client;
|
|
213
|
+
}
|
|
214
|
+
function captureException(error, context) {
|
|
215
|
+
return client?.captureException(error, context) || "";
|
|
216
|
+
}
|
|
217
|
+
function captureMessage(message, level) {
|
|
218
|
+
return client?.captureMessage(message, level) || "";
|
|
219
|
+
}
|
|
220
|
+
function setUser(user) {
|
|
221
|
+
client?.setUser(user);
|
|
222
|
+
}
|
|
223
|
+
function setTags(tags) {
|
|
224
|
+
client?.setTags(tags);
|
|
225
|
+
}
|
|
226
|
+
function addBreadcrumb(breadcrumb) {
|
|
227
|
+
client?.addBreadcrumb(breadcrumb);
|
|
228
|
+
}
|
|
229
|
+
function flush(timeout) {
|
|
230
|
+
return client?.flush(timeout) || Promise.resolve(true);
|
|
231
|
+
}
|
|
232
|
+
function close() {
|
|
233
|
+
client?.close();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/browser/index.ts
|
|
237
|
+
var isInitialized = false;
|
|
238
|
+
function init2(config = {}) {
|
|
239
|
+
if (typeof window === "undefined") {
|
|
240
|
+
console.warn("[@codmir/sdk/browser] Cannot initialize in non-browser environment");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (isInitialized) return;
|
|
244
|
+
const {
|
|
245
|
+
captureGlobalErrors = true,
|
|
246
|
+
captureUnhandledRejections = true,
|
|
247
|
+
captureConsoleErrors = false,
|
|
248
|
+
trackClicks = true,
|
|
249
|
+
trackInputs = false,
|
|
250
|
+
trackRequests = true,
|
|
251
|
+
...coreConfig
|
|
252
|
+
} = config;
|
|
253
|
+
init(coreConfig);
|
|
254
|
+
isInitialized = true;
|
|
255
|
+
if (captureGlobalErrors) {
|
|
256
|
+
window.addEventListener("error", (event) => {
|
|
257
|
+
captureException(event.error || event.message, {
|
|
258
|
+
handled: false,
|
|
259
|
+
mechanism: "onerror",
|
|
260
|
+
filename: event.filename,
|
|
261
|
+
lineno: event.lineno,
|
|
262
|
+
colno: event.colno
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (captureUnhandledRejections) {
|
|
267
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
268
|
+
captureException(event.reason, {
|
|
269
|
+
handled: false,
|
|
270
|
+
mechanism: "onunhandledrejection"
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
if (captureConsoleErrors) {
|
|
275
|
+
const originalError = console.error;
|
|
276
|
+
console.error = (...args) => {
|
|
277
|
+
captureMessage(args.map(String).join(" "), "error");
|
|
278
|
+
originalError.apply(console, args);
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (trackClicks) {
|
|
282
|
+
document.addEventListener("click", (event) => {
|
|
283
|
+
const target = event.target;
|
|
284
|
+
if (!target) return;
|
|
285
|
+
const breadcrumb = {
|
|
286
|
+
category: "ui.click",
|
|
287
|
+
message: getElementDescription(target),
|
|
288
|
+
data: {
|
|
289
|
+
tag: target.tagName.toLowerCase(),
|
|
290
|
+
id: target.id || void 0,
|
|
291
|
+
class: target.className || void 0
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
addBreadcrumb(breadcrumb);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
if (trackInputs) {
|
|
298
|
+
document.addEventListener("input", (event) => {
|
|
299
|
+
const target = event.target;
|
|
300
|
+
if (!target) return;
|
|
301
|
+
const breadcrumb = {
|
|
302
|
+
category: "ui.input",
|
|
303
|
+
message: getElementDescription(target),
|
|
304
|
+
data: {
|
|
305
|
+
tag: target.tagName.toLowerCase(),
|
|
306
|
+
type: target.type || "text"
|
|
307
|
+
// Never log actual values
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
addBreadcrumb(breadcrumb);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (trackRequests) {
|
|
314
|
+
setupRequestTracking();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function getElementDescription(el) {
|
|
318
|
+
let description = el.tagName.toLowerCase();
|
|
319
|
+
if (el.id) {
|
|
320
|
+
description += `#${el.id}`;
|
|
321
|
+
} else if (el.className) {
|
|
322
|
+
description += `.${el.className.split(" ")[0]}`;
|
|
323
|
+
}
|
|
324
|
+
if (el.tagName === "BUTTON" || el.tagName === "A") {
|
|
325
|
+
const text = el.textContent?.trim().slice(0, 50);
|
|
326
|
+
if (text) {
|
|
327
|
+
description += ` "${text}"`;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return description;
|
|
331
|
+
}
|
|
332
|
+
function setupRequestTracking() {
|
|
333
|
+
const originalFetch = window.fetch;
|
|
334
|
+
window.fetch = async function(input, init3) {
|
|
335
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
336
|
+
const method = init3?.method || "GET";
|
|
337
|
+
const startTime = Date.now();
|
|
338
|
+
try {
|
|
339
|
+
const response = await originalFetch.call(window, input, init3);
|
|
340
|
+
addBreadcrumb({
|
|
341
|
+
category: "fetch",
|
|
342
|
+
message: `${method} ${url}`,
|
|
343
|
+
data: {
|
|
344
|
+
method,
|
|
345
|
+
url,
|
|
346
|
+
status: response.status,
|
|
347
|
+
duration: Date.now() - startTime
|
|
348
|
+
},
|
|
349
|
+
level: response.ok ? "info" : "error"
|
|
350
|
+
});
|
|
351
|
+
return response;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
addBreadcrumb({
|
|
354
|
+
category: "fetch",
|
|
355
|
+
message: `${method} ${url}`,
|
|
356
|
+
data: {
|
|
357
|
+
method,
|
|
358
|
+
url,
|
|
359
|
+
error: error instanceof Error ? error.message : "Network error",
|
|
360
|
+
duration: Date.now() - startTime
|
|
361
|
+
},
|
|
362
|
+
level: "error"
|
|
363
|
+
});
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
368
|
+
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
369
|
+
XMLHttpRequest.prototype.open = function(method, url) {
|
|
370
|
+
this.__codmir = { method, url: url.toString(), startTime: 0 };
|
|
371
|
+
return originalXHROpen.apply(this, arguments);
|
|
372
|
+
};
|
|
373
|
+
XMLHttpRequest.prototype.send = function(body) {
|
|
374
|
+
const data = this.__codmir;
|
|
375
|
+
if (data) {
|
|
376
|
+
data.startTime = Date.now();
|
|
377
|
+
this.addEventListener("loadend", () => {
|
|
378
|
+
addBreadcrumb({
|
|
379
|
+
category: "xhr",
|
|
380
|
+
message: `${data.method} ${data.url}`,
|
|
381
|
+
data: {
|
|
382
|
+
method: data.method,
|
|
383
|
+
url: data.url,
|
|
384
|
+
status: this.status,
|
|
385
|
+
duration: Date.now() - data.startTime
|
|
386
|
+
},
|
|
387
|
+
level: this.status >= 400 ? "error" : "info"
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
return originalXHRSend.call(this, body);
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function isOverseerInitialized() {
|
|
395
|
+
return isInitialized && getClient() !== null;
|
|
396
|
+
}
|
|
397
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
398
|
+
0 && (module.exports = {
|
|
399
|
+
addBreadcrumb,
|
|
400
|
+
captureException,
|
|
401
|
+
captureMessage,
|
|
402
|
+
close,
|
|
403
|
+
flush,
|
|
404
|
+
getClient,
|
|
405
|
+
init,
|
|
406
|
+
isOverseerInitialized,
|
|
407
|
+
setTags,
|
|
408
|
+
setUser
|
|
409
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
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/browser - Browser-Only Integration
|
|
6
|
+
*
|
|
7
|
+
* Lightweight error tracking for vanilla JavaScript/TypeScript
|
|
8
|
+
* browser applications.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```html
|
|
12
|
+
* <script type="module">
|
|
13
|
+
* import { init, captureException } from '@codmir/sdk/browser';
|
|
14
|
+
*
|
|
15
|
+
* init({
|
|
16
|
+
* dsn: 'https://your-project.codmir.com/api/overseer',
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* window.onerror = (msg, url, line, col, error) => {
|
|
20
|
+
* captureException(error);
|
|
21
|
+
* };
|
|
22
|
+
* </script>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
interface BrowserConfig extends OverseerConfig {
|
|
27
|
+
/** Automatically capture global errors */
|
|
28
|
+
captureGlobalErrors?: boolean;
|
|
29
|
+
/** Automatically capture unhandled promise rejections */
|
|
30
|
+
captureUnhandledRejections?: boolean;
|
|
31
|
+
/** Automatically capture console.error */
|
|
32
|
+
captureConsoleErrors?: boolean;
|
|
33
|
+
/** Track user clicks as breadcrumbs */
|
|
34
|
+
trackClicks?: boolean;
|
|
35
|
+
/** Track user inputs as breadcrumbs (values are masked) */
|
|
36
|
+
trackInputs?: boolean;
|
|
37
|
+
/** Track XHR/fetch requests as breadcrumbs */
|
|
38
|
+
trackRequests?: boolean;
|
|
39
|
+
}
|
|
40
|
+
declare function init(config?: BrowserConfig): void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if Overseer is initialized
|
|
44
|
+
*/
|
|
45
|
+
declare function isOverseerInitialized(): boolean;
|
|
46
|
+
|
|
47
|
+
export { type BrowserConfig, OverseerConfig, init, isOverseerInitialized };
|
|
@@ -0,0 +1,47 @@
|
|
|
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/browser - Browser-Only Integration
|
|
6
|
+
*
|
|
7
|
+
* Lightweight error tracking for vanilla JavaScript/TypeScript
|
|
8
|
+
* browser applications.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```html
|
|
12
|
+
* <script type="module">
|
|
13
|
+
* import { init, captureException } from '@codmir/sdk/browser';
|
|
14
|
+
*
|
|
15
|
+
* init({
|
|
16
|
+
* dsn: 'https://your-project.codmir.com/api/overseer',
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* window.onerror = (msg, url, line, col, error) => {
|
|
20
|
+
* captureException(error);
|
|
21
|
+
* };
|
|
22
|
+
* </script>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
interface BrowserConfig extends OverseerConfig {
|
|
27
|
+
/** Automatically capture global errors */
|
|
28
|
+
captureGlobalErrors?: boolean;
|
|
29
|
+
/** Automatically capture unhandled promise rejections */
|
|
30
|
+
captureUnhandledRejections?: boolean;
|
|
31
|
+
/** Automatically capture console.error */
|
|
32
|
+
captureConsoleErrors?: boolean;
|
|
33
|
+
/** Track user clicks as breadcrumbs */
|
|
34
|
+
trackClicks?: boolean;
|
|
35
|
+
/** Track user inputs as breadcrumbs (values are masked) */
|
|
36
|
+
trackInputs?: boolean;
|
|
37
|
+
/** Track XHR/fetch requests as breadcrumbs */
|
|
38
|
+
trackRequests?: boolean;
|
|
39
|
+
}
|
|
40
|
+
declare function init(config?: BrowserConfig): void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if Overseer is initialized
|
|
44
|
+
*/
|
|
45
|
+
declare function isOverseerInitialized(): boolean;
|
|
46
|
+
|
|
47
|
+
export { type BrowserConfig, OverseerConfig, init, isOverseerInitialized };
|