@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 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 };