codmir 0.1.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/README.md ADDED
@@ -0,0 +1,322 @@
1
+ # codmir
2
+
3
+ > TypeScript SDK for codmir API - **the AI that prevents wasted engineering time**.
4
+
5
+ [![npm version](https://badge.fury.io/js/codmir.svg)](https://www.npmjs.com/package/codmir)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## Features
10
+
11
+ - โœ… **Full TypeScript support** with complete type definitions
12
+ - ๐ŸŽซ **Tickets API** - Create and manage project tickets
13
+ - ๐Ÿงช **Test Cases API** - Create, update, and manage test cases
14
+ - ๐Ÿ” **API Key authentication**
15
+ - โšก **Promise-based** async/await API
16
+ - ๐ŸŒ **Works in Node.js and browsers**
17
+ - ๐Ÿ“ฆ **Zero dependencies**
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install codmir
23
+ ```
24
+
25
+ or with pnpm:
26
+
27
+ ```bash
28
+ pnpm add codmir
29
+ ```
30
+
31
+ or with yarn:
32
+
33
+ ```bash
34
+ yarn add codmir
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```typescript
40
+ import { CodmirClient } from 'codmir';
41
+
42
+ // Initialize the client
43
+ const client = new CodmirClient({
44
+ apiKey: 'your-api-key-here',
45
+ baseUrl: 'https://codmir.com', // optional, defaults to https://codmir.com
46
+ });
47
+
48
+ // Create a ticket
49
+ const ticket = await client.tickets.create('project-id', 'board-id', {
50
+ title: 'Implement user authentication',
51
+ description: 'Add OAuth2 support for Google and GitHub',
52
+ priority: 'HIGH',
53
+ status: 'TODO',
54
+ type: 'FEATURE',
55
+ });
56
+
57
+ console.log('Created ticket:', ticket.id);
58
+
59
+ // Create a test case
60
+ const testCase = await client.testCases.create('project-id', {
61
+ title: 'Test login functionality',
62
+ suiteId: 'test-suite-id',
63
+ template: 'steps',
64
+ priority: 'High',
65
+ steps: [
66
+ { action: 'Navigate to login page', expected: 'Login form is displayed' },
67
+ { action: 'Enter valid credentials', expected: 'User is authenticated' },
68
+ { action: 'Click submit button', expected: 'User is redirected to dashboard' },
69
+ ],
70
+ });
71
+
72
+ console.log('Created test case:', testCase.id);
73
+ ```
74
+
75
+ ## API Reference
76
+
77
+ ### Client Configuration
78
+
79
+ ```typescript
80
+ interface CodmirClientConfig {
81
+ apiKey?: string; // Your API key
82
+ baseUrl?: string; // API base URL (default: https://codmir.com)
83
+ timeout?: number; // Request timeout in ms (default: 30000)
84
+ headers?: Record<string, string>; // Additional headers
85
+ }
86
+ ```
87
+
88
+ ### Tickets API
89
+
90
+ #### Create Ticket in Board
91
+
92
+ ```typescript
93
+ const ticket = await client.tickets.createInBoard(
94
+ projectId: string,
95
+ boardId: string,
96
+ data: CreateTicketInput
97
+ );
98
+ ```
99
+
100
+ #### Create Ticket in Workspace
101
+
102
+ ```typescript
103
+ const ticket = await client.tickets.createInWorkspace(
104
+ projectId: string,
105
+ workspaceId: string,
106
+ data: CreateTicketInput
107
+ );
108
+ ```
109
+
110
+ #### CreateTicketInput
111
+
112
+ ```typescript
113
+ interface CreateTicketInput {
114
+ title: string; // Required
115
+ description?: string;
116
+ status?: TicketStatus; // BACKLOG | TODO | IN_PROGRESS | DONE | CANCELED
117
+ priority?: TicketPriority; // LOW | MEDIUM | HIGH | CRITICAL
118
+ type?: TicketType; // TASK | BUG | STORY | EPIC | FEATURE | IMPROVEMENT
119
+ assigneeId?: string;
120
+ reporterId?: string;
121
+ groupId?: string;
122
+ parentId?: string;
123
+ teamId?: string;
124
+ labels?: string;
125
+ dueDate?: string; // ISO date string
126
+ order?: number;
127
+ customFields?: Record<string, any>;
128
+ }
129
+ ```
130
+
131
+ ### Test Cases API
132
+
133
+ #### List Test Cases
134
+
135
+ ```typescript
136
+ const testCases = await client.testCases.list(projectId: string);
137
+ ```
138
+
139
+ #### Get Test Case
140
+
141
+ ```typescript
142
+ const testCase = await client.testCases.get(
143
+ projectId: string,
144
+ testCaseId: string | number
145
+ );
146
+ ```
147
+
148
+ #### Create Test Case
149
+
150
+ ```typescript
151
+ const result = await client.testCases.create(
152
+ projectId: string,
153
+ data: CreateTestCaseInput
154
+ );
155
+ ```
156
+
157
+ #### Update Test Case
158
+
159
+ ```typescript
160
+ const result = await client.testCases.update(
161
+ projectId: string,
162
+ testCaseId: string | number,
163
+ data: UpdateTestCaseInput
164
+ );
165
+ ```
166
+
167
+ #### Delete Test Case
168
+
169
+ ```typescript
170
+ await client.testCases.delete(
171
+ projectId: string,
172
+ testCaseId: string | number
173
+ );
174
+ ```
175
+
176
+ #### CreateTestCaseInput
177
+
178
+ ```typescript
179
+ interface CreateTestCaseInput {
180
+ title: string; // Required
181
+ suiteId: string; // Required - Test suite ID
182
+ template?: 'steps' | 'text'; // Default: 'steps'
183
+ type?: string; // Default: 'Functional'
184
+ priority?: 'Low' | 'Medium' | 'High'; // Default: 'Medium'
185
+ estimate?: string; // e.g., '5m', '1h', '2d'
186
+ preconditions?: string;
187
+ steps?: TestCaseStep[]; // For 'steps' template
188
+ stepsText?: string; // For 'text' template
189
+ }
190
+
191
+ interface TestCaseStep {
192
+ action: string;
193
+ expected: string;
194
+ }
195
+ ```
196
+
197
+ #### UpdateTestCaseInput
198
+
199
+ ```typescript
200
+ interface UpdateTestCaseInput extends Partial<CreateTestCaseInput> {
201
+ status?: 'Not Started' | 'In Progress' | 'Passed' | 'Failed' | 'Blocked';
202
+ }
203
+ ```
204
+
205
+ ## Examples
206
+
207
+ ### Create a Bug Ticket
208
+
209
+ ```typescript
210
+ const bug = await client.tickets.create('project-id', 'board-id', {
211
+ title: 'Fix memory leak in dashboard',
212
+ description: 'Users report increasing memory usage over time',
213
+ type: 'BUG',
214
+ priority: 'CRITICAL',
215
+ status: 'TODO',
216
+ assigneeId: 'user-123',
217
+ });
218
+ ```
219
+
220
+ ### Create a Test Case with Steps
221
+
222
+ ```typescript
223
+ const testCase = await client.testCases.create('project-id', {
224
+ title: 'User registration flow',
225
+ suiteId: 'suite-123',
226
+ template: 'steps',
227
+ priority: 'High',
228
+ estimate: '15m',
229
+ preconditions: 'User is not logged in',
230
+ steps: [
231
+ {
232
+ action: 'Click "Sign Up" button',
233
+ expected: 'Registration form is displayed',
234
+ },
235
+ {
236
+ action: 'Fill in email and password',
237
+ expected: 'Form validation passes',
238
+ },
239
+ {
240
+ action: 'Submit the form',
241
+ expected: 'User account is created and email is sent',
242
+ },
243
+ ],
244
+ });
245
+ ```
246
+
247
+ ### Update Test Case Status
248
+
249
+ ```typescript
250
+ await client.testCases.update('project-id', 'TC-123', {
251
+ status: 'Passed',
252
+ });
253
+ ```
254
+
255
+ ### Error Handling
256
+
257
+ ```typescript
258
+ try {
259
+ const ticket = await client.tickets.create('project-id', 'board-id', {
260
+ title: 'New ticket',
261
+ });
262
+ } catch (error) {
263
+ if (error.statusCode === 401) {
264
+ console.error('Invalid API key');
265
+ } else if (error.statusCode === 404) {
266
+ console.error('Project or board not found');
267
+ } else {
268
+ console.error('Error:', error.message);
269
+ }
270
+ }
271
+ ```
272
+
273
+ ## Authentication
274
+
275
+ To use the API, you need an API key. You can obtain one from your codmir account settings.
276
+
277
+ Set the API key when initializing the client:
278
+
279
+ ```typescript
280
+ const client = new CodmirClient({
281
+ apiKey: process.env.CODMIR_API_KEY, // Recommended: use environment variables
282
+ });
283
+ ```
284
+
285
+ The API key will be sent in the `X-API-Key` header with each request.
286
+
287
+ ## TypeScript Support
288
+
289
+ This package is written in TypeScript and includes complete type definitions. You'll get full IDE autocomplete and type checking out of the box.
290
+
291
+ ```typescript
292
+ import type {
293
+ Ticket,
294
+ TestCase,
295
+ CreateTicketInput,
296
+ TicketPriority
297
+ } from 'codmir';
298
+ ```
299
+
300
+ ## Requirements
301
+
302
+ - Node.js >= 18.0.0
303
+ - TypeScript >= 5.0.0 (if using TypeScript)
304
+
305
+ ## Browser Support
306
+
307
+ This package uses the Fetch API which is available in all modern browsers and Node.js 18+. For older environments, you may need a polyfill.
308
+
309
+ ## License
310
+
311
+ MIT
312
+
313
+ ## Links
314
+
315
+ - [codmir Website](https://codmir.com)
316
+ - [Documentation](https://codmir.com/docs)
317
+ - [GitHub Repository](https://github.com/codmir/codmir)
318
+ - [Report Issues](https://github.com/codmir/codmir/issues)
319
+
320
+ ---
321
+
322
+ **codmir is the AI that prevents wasted engineering time.**
@@ -0,0 +1,220 @@
1
+ /**
2
+ * codmir API Types
3
+ */
4
+ type TicketStatus = 'BACKLOG' | 'TODO' | 'IN_PROGRESS' | 'DONE' | 'CANCELED' | 'OPEN';
5
+ type TicketPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
6
+ type TicketType = 'TASK' | 'BUG' | 'STORY' | 'EPIC' | 'FEATURE' | 'IMPROVEMENT';
7
+ type TestCasePriority = 'Low' | 'Medium' | 'High';
8
+ type TestCaseStatus = 'Not Started' | 'In Progress' | 'Passed' | 'Failed' | 'Blocked';
9
+ type TestCaseTemplate = 'steps' | 'text';
10
+ interface User {
11
+ id: string;
12
+ name: string | null;
13
+ email: string | null;
14
+ image?: string | null;
15
+ }
16
+ interface Ticket {
17
+ id: string;
18
+ title: string;
19
+ description: string | null;
20
+ status: TicketStatus;
21
+ priority: TicketPriority;
22
+ type?: TicketType | null;
23
+ assigneeId?: string | null;
24
+ assignee?: User | null;
25
+ reporterId?: string | null;
26
+ reporter?: User | null;
27
+ projectId: string;
28
+ workspaceId?: string | null;
29
+ organizationId?: string;
30
+ groupId?: string | null;
31
+ parentId?: string | null;
32
+ teamId?: string | null;
33
+ orderIndex?: number | null;
34
+ labels?: string | null;
35
+ due_date?: Date | null;
36
+ createdAt: Date;
37
+ updatedAt: Date;
38
+ }
39
+ interface CreateTicketInput {
40
+ title: string;
41
+ description?: string;
42
+ status?: TicketStatus | string;
43
+ priority?: TicketPriority | string;
44
+ type?: TicketType;
45
+ assigneeId?: string;
46
+ reporterId?: string;
47
+ groupId?: string;
48
+ parentId?: string;
49
+ teamId?: string;
50
+ labels?: string;
51
+ dueDate?: string;
52
+ order?: number;
53
+ customFields?: Record<string, any>;
54
+ }
55
+ interface UpdateTicketInput extends Partial<CreateTicketInput> {
56
+ id: string;
57
+ }
58
+ interface TestCaseStep {
59
+ action: string;
60
+ expected: string;
61
+ }
62
+ interface TestCase {
63
+ id: string;
64
+ ud?: number;
65
+ title: string;
66
+ status: TestCaseStatus;
67
+ priority: TestCasePriority;
68
+ suiteId: string | null;
69
+ suiteName?: string | null;
70
+ estimate?: string;
71
+ template?: TestCaseTemplate;
72
+ type?: string;
73
+ preconditions?: string;
74
+ steps?: TestCaseStep[];
75
+ stepsText?: string;
76
+ }
77
+ interface CreateTestCaseInput {
78
+ title: string;
79
+ suiteId: string;
80
+ template?: TestCaseTemplate;
81
+ type?: string;
82
+ priority?: TestCasePriority;
83
+ estimate?: string;
84
+ preconditions?: string;
85
+ steps?: TestCaseStep[];
86
+ stepsText?: string;
87
+ }
88
+ interface UpdateTestCaseInput extends Partial<CreateTestCaseInput> {
89
+ status?: TestCaseStatus;
90
+ }
91
+ interface ApiResponse<T> {
92
+ data?: T;
93
+ error?: string;
94
+ }
95
+ interface PaginatedResponse<T> {
96
+ data: T[];
97
+ total?: number;
98
+ page?: number;
99
+ pageSize?: number;
100
+ }
101
+ interface CodmirClientConfig {
102
+ apiKey?: string;
103
+ baseUrl?: string;
104
+ timeout?: number;
105
+ headers?: Record<string, string>;
106
+ }
107
+ declare class CodmirError extends Error {
108
+ statusCode?: number | undefined;
109
+ response?: any | undefined;
110
+ constructor(message: string, statusCode?: number | undefined, response?: any | undefined);
111
+ }
112
+
113
+ /**
114
+ * Main codmir API Client
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const client = new CodmirClient({
119
+ * apiKey: 'your-api-key',
120
+ * baseUrl: 'https://codmir.com'
121
+ * });
122
+ *
123
+ * // Create a ticket
124
+ * const ticket = await client.tickets.create('project-id', {
125
+ * title: 'New feature request',
126
+ * description: 'Add dark mode support',
127
+ * priority: 'HIGH'
128
+ * });
129
+ * ```
130
+ */
131
+ declare class CodmirClient {
132
+ private readonly config;
133
+ readonly tickets: TicketsAPI;
134
+ readonly testCases: TestCasesAPI;
135
+ constructor(config: CodmirClientConfig);
136
+ /**
137
+ * Make an HTTP request to the codmir API
138
+ */
139
+ private request;
140
+ private createError;
141
+ }
142
+ /**
143
+ * Tickets API
144
+ */
145
+ declare class TicketsAPI {
146
+ private config;
147
+ constructor(config: Required<CodmirClientConfig>);
148
+ private request;
149
+ /**
150
+ * Create a ticket in a board
151
+ *
152
+ * @param projectId - The project ID
153
+ * @param boardId - The board ID
154
+ * @param data - Ticket data
155
+ */
156
+ createInBoard(projectId: string, boardId: string, data: CreateTicketInput): Promise<Ticket>;
157
+ /**
158
+ * Create a ticket in a workspace
159
+ *
160
+ * @param projectId - The project ID
161
+ * @param workspaceId - The workspace ID
162
+ * @param data - Ticket data
163
+ */
164
+ createInWorkspace(projectId: string, workspaceId: string, data: CreateTicketInput): Promise<Ticket>;
165
+ /**
166
+ * Alias for createInBoard - creates a ticket in a board
167
+ */
168
+ create(projectId: string, boardId: string, data: CreateTicketInput): Promise<Ticket>;
169
+ }
170
+ /**
171
+ * Test Cases API
172
+ */
173
+ declare class TestCasesAPI {
174
+ private config;
175
+ constructor(config: Required<CodmirClientConfig>);
176
+ private request;
177
+ /**
178
+ * List all test cases for a project
179
+ *
180
+ * @param projectId - The project ID
181
+ */
182
+ list(projectId: string): Promise<TestCase[]>;
183
+ /**
184
+ * Get a specific test case by ID
185
+ *
186
+ * @param projectId - The project ID
187
+ * @param testCaseId - The test case ID (numeric UD)
188
+ */
189
+ get(projectId: string, testCaseId: string | number): Promise<TestCase>;
190
+ /**
191
+ * Create a new test case
192
+ *
193
+ * @param projectId - The project ID
194
+ * @param data - Test case data
195
+ */
196
+ create(projectId: string, data: CreateTestCaseInput): Promise<{
197
+ id: string;
198
+ title: string;
199
+ }>;
200
+ /**
201
+ * Update an existing test case
202
+ *
203
+ * @param projectId - The project ID
204
+ * @param testCaseId - The test case ID (numeric UD)
205
+ * @param data - Test case update data
206
+ */
207
+ update(projectId: string, testCaseId: string | number, data: UpdateTestCaseInput): Promise<{
208
+ id: string;
209
+ title: string;
210
+ }>;
211
+ /**
212
+ * Delete a test case
213
+ *
214
+ * @param projectId - The project ID
215
+ * @param testCaseId - The test case ID (numeric UD)
216
+ */
217
+ delete(projectId: string, testCaseId: string | number): Promise<void>;
218
+ }
219
+
220
+ export { type ApiResponse, CodmirClient, type CodmirClientConfig, CodmirError, type CreateTestCaseInput, type CreateTicketInput, type PaginatedResponse, type TestCase, type TestCasePriority, type TestCaseStatus, type TestCaseStep, type TestCaseTemplate, type Ticket, type TicketPriority, type TicketStatus, type TicketType, type UpdateTestCaseInput, type UpdateTicketInput, type User };
@@ -0,0 +1,220 @@
1
+ /**
2
+ * codmir API Types
3
+ */
4
+ type TicketStatus = 'BACKLOG' | 'TODO' | 'IN_PROGRESS' | 'DONE' | 'CANCELED' | 'OPEN';
5
+ type TicketPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
6
+ type TicketType = 'TASK' | 'BUG' | 'STORY' | 'EPIC' | 'FEATURE' | 'IMPROVEMENT';
7
+ type TestCasePriority = 'Low' | 'Medium' | 'High';
8
+ type TestCaseStatus = 'Not Started' | 'In Progress' | 'Passed' | 'Failed' | 'Blocked';
9
+ type TestCaseTemplate = 'steps' | 'text';
10
+ interface User {
11
+ id: string;
12
+ name: string | null;
13
+ email: string | null;
14
+ image?: string | null;
15
+ }
16
+ interface Ticket {
17
+ id: string;
18
+ title: string;
19
+ description: string | null;
20
+ status: TicketStatus;
21
+ priority: TicketPriority;
22
+ type?: TicketType | null;
23
+ assigneeId?: string | null;
24
+ assignee?: User | null;
25
+ reporterId?: string | null;
26
+ reporter?: User | null;
27
+ projectId: string;
28
+ workspaceId?: string | null;
29
+ organizationId?: string;
30
+ groupId?: string | null;
31
+ parentId?: string | null;
32
+ teamId?: string | null;
33
+ orderIndex?: number | null;
34
+ labels?: string | null;
35
+ due_date?: Date | null;
36
+ createdAt: Date;
37
+ updatedAt: Date;
38
+ }
39
+ interface CreateTicketInput {
40
+ title: string;
41
+ description?: string;
42
+ status?: TicketStatus | string;
43
+ priority?: TicketPriority | string;
44
+ type?: TicketType;
45
+ assigneeId?: string;
46
+ reporterId?: string;
47
+ groupId?: string;
48
+ parentId?: string;
49
+ teamId?: string;
50
+ labels?: string;
51
+ dueDate?: string;
52
+ order?: number;
53
+ customFields?: Record<string, any>;
54
+ }
55
+ interface UpdateTicketInput extends Partial<CreateTicketInput> {
56
+ id: string;
57
+ }
58
+ interface TestCaseStep {
59
+ action: string;
60
+ expected: string;
61
+ }
62
+ interface TestCase {
63
+ id: string;
64
+ ud?: number;
65
+ title: string;
66
+ status: TestCaseStatus;
67
+ priority: TestCasePriority;
68
+ suiteId: string | null;
69
+ suiteName?: string | null;
70
+ estimate?: string;
71
+ template?: TestCaseTemplate;
72
+ type?: string;
73
+ preconditions?: string;
74
+ steps?: TestCaseStep[];
75
+ stepsText?: string;
76
+ }
77
+ interface CreateTestCaseInput {
78
+ title: string;
79
+ suiteId: string;
80
+ template?: TestCaseTemplate;
81
+ type?: string;
82
+ priority?: TestCasePriority;
83
+ estimate?: string;
84
+ preconditions?: string;
85
+ steps?: TestCaseStep[];
86
+ stepsText?: string;
87
+ }
88
+ interface UpdateTestCaseInput extends Partial<CreateTestCaseInput> {
89
+ status?: TestCaseStatus;
90
+ }
91
+ interface ApiResponse<T> {
92
+ data?: T;
93
+ error?: string;
94
+ }
95
+ interface PaginatedResponse<T> {
96
+ data: T[];
97
+ total?: number;
98
+ page?: number;
99
+ pageSize?: number;
100
+ }
101
+ interface CodmirClientConfig {
102
+ apiKey?: string;
103
+ baseUrl?: string;
104
+ timeout?: number;
105
+ headers?: Record<string, string>;
106
+ }
107
+ declare class CodmirError extends Error {
108
+ statusCode?: number | undefined;
109
+ response?: any | undefined;
110
+ constructor(message: string, statusCode?: number | undefined, response?: any | undefined);
111
+ }
112
+
113
+ /**
114
+ * Main codmir API Client
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const client = new CodmirClient({
119
+ * apiKey: 'your-api-key',
120
+ * baseUrl: 'https://codmir.com'
121
+ * });
122
+ *
123
+ * // Create a ticket
124
+ * const ticket = await client.tickets.create('project-id', {
125
+ * title: 'New feature request',
126
+ * description: 'Add dark mode support',
127
+ * priority: 'HIGH'
128
+ * });
129
+ * ```
130
+ */
131
+ declare class CodmirClient {
132
+ private readonly config;
133
+ readonly tickets: TicketsAPI;
134
+ readonly testCases: TestCasesAPI;
135
+ constructor(config: CodmirClientConfig);
136
+ /**
137
+ * Make an HTTP request to the codmir API
138
+ */
139
+ private request;
140
+ private createError;
141
+ }
142
+ /**
143
+ * Tickets API
144
+ */
145
+ declare class TicketsAPI {
146
+ private config;
147
+ constructor(config: Required<CodmirClientConfig>);
148
+ private request;
149
+ /**
150
+ * Create a ticket in a board
151
+ *
152
+ * @param projectId - The project ID
153
+ * @param boardId - The board ID
154
+ * @param data - Ticket data
155
+ */
156
+ createInBoard(projectId: string, boardId: string, data: CreateTicketInput): Promise<Ticket>;
157
+ /**
158
+ * Create a ticket in a workspace
159
+ *
160
+ * @param projectId - The project ID
161
+ * @param workspaceId - The workspace ID
162
+ * @param data - Ticket data
163
+ */
164
+ createInWorkspace(projectId: string, workspaceId: string, data: CreateTicketInput): Promise<Ticket>;
165
+ /**
166
+ * Alias for createInBoard - creates a ticket in a board
167
+ */
168
+ create(projectId: string, boardId: string, data: CreateTicketInput): Promise<Ticket>;
169
+ }
170
+ /**
171
+ * Test Cases API
172
+ */
173
+ declare class TestCasesAPI {
174
+ private config;
175
+ constructor(config: Required<CodmirClientConfig>);
176
+ private request;
177
+ /**
178
+ * List all test cases for a project
179
+ *
180
+ * @param projectId - The project ID
181
+ */
182
+ list(projectId: string): Promise<TestCase[]>;
183
+ /**
184
+ * Get a specific test case by ID
185
+ *
186
+ * @param projectId - The project ID
187
+ * @param testCaseId - The test case ID (numeric UD)
188
+ */
189
+ get(projectId: string, testCaseId: string | number): Promise<TestCase>;
190
+ /**
191
+ * Create a new test case
192
+ *
193
+ * @param projectId - The project ID
194
+ * @param data - Test case data
195
+ */
196
+ create(projectId: string, data: CreateTestCaseInput): Promise<{
197
+ id: string;
198
+ title: string;
199
+ }>;
200
+ /**
201
+ * Update an existing test case
202
+ *
203
+ * @param projectId - The project ID
204
+ * @param testCaseId - The test case ID (numeric UD)
205
+ * @param data - Test case update data
206
+ */
207
+ update(projectId: string, testCaseId: string | number, data: UpdateTestCaseInput): Promise<{
208
+ id: string;
209
+ title: string;
210
+ }>;
211
+ /**
212
+ * Delete a test case
213
+ *
214
+ * @param projectId - The project ID
215
+ * @param testCaseId - The test case ID (numeric UD)
216
+ */
217
+ delete(projectId: string, testCaseId: string | number): Promise<void>;
218
+ }
219
+
220
+ export { type ApiResponse, CodmirClient, type CodmirClientConfig, CodmirError, type CreateTestCaseInput, type CreateTicketInput, type PaginatedResponse, type TestCase, type TestCasePriority, type TestCaseStatus, type TestCaseStep, type TestCaseTemplate, type Ticket, type TicketPriority, type TicketStatus, type TicketType, type UpdateTestCaseInput, type UpdateTicketInput, type User };
package/dist/index.js ADDED
@@ -0,0 +1,299 @@
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/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ CodmirClient: () => CodmirClient
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/client.ts
28
+ var CodmirClient = class {
29
+ constructor(config) {
30
+ this.config = {
31
+ apiKey: config.apiKey || "",
32
+ baseUrl: config.baseUrl || "https://codmir.com",
33
+ timeout: config.timeout || 3e4,
34
+ headers: config.headers || {}
35
+ };
36
+ this.tickets = new TicketsAPI(this.config);
37
+ this.testCases = new TestCasesAPI(this.config);
38
+ }
39
+ /**
40
+ * Make an HTTP request to the codmir API
41
+ */
42
+ async request(method, path, body) {
43
+ const url = `${this.config.baseUrl}${path}`;
44
+ const headers = {
45
+ "Content-Type": "application/json",
46
+ ...this.config.headers
47
+ };
48
+ if (this.config.apiKey) {
49
+ headers["X-API-Key"] = this.config.apiKey;
50
+ }
51
+ const controller = new AbortController();
52
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
53
+ try {
54
+ const response = await fetch(url, {
55
+ method,
56
+ headers,
57
+ body: body ? JSON.stringify(body) : void 0,
58
+ signal: controller.signal
59
+ });
60
+ clearTimeout(timeoutId);
61
+ if (!response.ok) {
62
+ const errorData = await response.json().catch(() => ({}));
63
+ throw this.createError(
64
+ errorData.error || `HTTP ${response.status}: ${response.statusText}`,
65
+ response.status,
66
+ errorData
67
+ );
68
+ }
69
+ if (response.status === 204) {
70
+ return {};
71
+ }
72
+ return await response.json();
73
+ } catch (error) {
74
+ clearTimeout(timeoutId);
75
+ if (error.name === "AbortError") {
76
+ throw this.createError("Request timeout", 408);
77
+ }
78
+ if (error instanceof Error && "statusCode" in error) {
79
+ throw error;
80
+ }
81
+ throw this.createError(
82
+ error.message || "Network error occurred",
83
+ void 0,
84
+ error
85
+ );
86
+ }
87
+ }
88
+ createError(message, statusCode, response) {
89
+ const error = new Error(message);
90
+ error.name = "CodmirError";
91
+ error.statusCode = statusCode;
92
+ error.response = response;
93
+ return error;
94
+ }
95
+ };
96
+ var TicketsAPI = class {
97
+ constructor(config) {
98
+ this.config = config;
99
+ }
100
+ async request(method, path, body) {
101
+ const url = `${this.config.baseUrl}${path}`;
102
+ const headers = {
103
+ "Content-Type": "application/json",
104
+ ...this.config.headers
105
+ };
106
+ if (this.config.apiKey) {
107
+ headers["X-API-Key"] = this.config.apiKey;
108
+ }
109
+ const controller = new AbortController();
110
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
111
+ try {
112
+ const response = await fetch(url, {
113
+ method,
114
+ headers,
115
+ body: body ? JSON.stringify(body) : void 0,
116
+ signal: controller.signal
117
+ });
118
+ clearTimeout(timeoutId);
119
+ if (!response.ok) {
120
+ const errorData = await response.json().catch(() => ({}));
121
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
122
+ error.statusCode = response.status;
123
+ error.response = errorData;
124
+ throw error;
125
+ }
126
+ if (response.status === 204) {
127
+ return {};
128
+ }
129
+ return await response.json();
130
+ } catch (error) {
131
+ clearTimeout(timeoutId);
132
+ if (error.name === "AbortError") {
133
+ const timeoutError = new Error("Request timeout");
134
+ timeoutError.statusCode = 408;
135
+ throw timeoutError;
136
+ }
137
+ throw error;
138
+ }
139
+ }
140
+ /**
141
+ * Create a ticket in a board
142
+ *
143
+ * @param projectId - The project ID
144
+ * @param boardId - The board ID
145
+ * @param data - Ticket data
146
+ */
147
+ async createInBoard(projectId, boardId, data) {
148
+ const response = await this.request(
149
+ "POST",
150
+ `/api/project/${projectId}/board/${boardId}/ticket`,
151
+ data
152
+ );
153
+ return response.ticket;
154
+ }
155
+ /**
156
+ * Create a ticket in a workspace
157
+ *
158
+ * @param projectId - The project ID
159
+ * @param workspaceId - The workspace ID
160
+ * @param data - Ticket data
161
+ */
162
+ async createInWorkspace(projectId, workspaceId, data) {
163
+ return this.request(
164
+ "POST",
165
+ `/api/project/${projectId}/workspaces/${workspaceId}/tickets`,
166
+ data
167
+ );
168
+ }
169
+ /**
170
+ * Alias for createInBoard - creates a ticket in a board
171
+ */
172
+ async create(projectId, boardId, data) {
173
+ return this.createInBoard(projectId, boardId, data);
174
+ }
175
+ };
176
+ var TestCasesAPI = class {
177
+ constructor(config) {
178
+ this.config = config;
179
+ }
180
+ async request(method, path, body) {
181
+ const url = `${this.config.baseUrl}${path}`;
182
+ const headers = {
183
+ "Content-Type": "application/json",
184
+ ...this.config.headers
185
+ };
186
+ if (this.config.apiKey) {
187
+ headers["X-API-Key"] = this.config.apiKey;
188
+ }
189
+ const controller = new AbortController();
190
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
191
+ try {
192
+ const response = await fetch(url, {
193
+ method,
194
+ headers,
195
+ body: body ? JSON.stringify(body) : void 0,
196
+ signal: controller.signal
197
+ });
198
+ clearTimeout(timeoutId);
199
+ if (!response.ok) {
200
+ const errorData = await response.json().catch(() => ({}));
201
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
202
+ error.statusCode = response.status;
203
+ error.response = errorData;
204
+ throw error;
205
+ }
206
+ if (response.status === 204) {
207
+ return {};
208
+ }
209
+ return await response.json();
210
+ } catch (error) {
211
+ clearTimeout(timeoutId);
212
+ if (error.name === "AbortError") {
213
+ const timeoutError = new Error("Request timeout");
214
+ timeoutError.statusCode = 408;
215
+ throw timeoutError;
216
+ }
217
+ throw error;
218
+ }
219
+ }
220
+ /**
221
+ * List all test cases for a project
222
+ *
223
+ * @param projectId - The project ID
224
+ */
225
+ async list(projectId) {
226
+ const response = await this.request(
227
+ "GET",
228
+ `/api/project/${projectId}/test-cases`
229
+ );
230
+ return response.data || [];
231
+ }
232
+ /**
233
+ * Get a specific test case by ID
234
+ *
235
+ * @param projectId - The project ID
236
+ * @param testCaseId - The test case ID (numeric UD)
237
+ */
238
+ async get(projectId, testCaseId) {
239
+ const response = await this.request(
240
+ "GET",
241
+ `/api/project/${projectId}/test-cases/${testCaseId}`
242
+ );
243
+ if (!response.data) {
244
+ throw new Error("Test case not found");
245
+ }
246
+ return response.data;
247
+ }
248
+ /**
249
+ * Create a new test case
250
+ *
251
+ * @param projectId - The project ID
252
+ * @param data - Test case data
253
+ */
254
+ async create(projectId, data) {
255
+ const response = await this.request(
256
+ "POST",
257
+ `/api/project/${projectId}/test-cases`,
258
+ data
259
+ );
260
+ if (!response.data) {
261
+ throw new Error("Failed to create test case");
262
+ }
263
+ return response.data;
264
+ }
265
+ /**
266
+ * Update an existing test case
267
+ *
268
+ * @param projectId - The project ID
269
+ * @param testCaseId - The test case ID (numeric UD)
270
+ * @param data - Test case update data
271
+ */
272
+ async update(projectId, testCaseId, data) {
273
+ const response = await this.request(
274
+ "PATCH",
275
+ `/api/project/${projectId}/test-cases/${testCaseId}`,
276
+ data
277
+ );
278
+ if (!response.data) {
279
+ throw new Error("Failed to update test case");
280
+ }
281
+ return response.data;
282
+ }
283
+ /**
284
+ * Delete a test case
285
+ *
286
+ * @param projectId - The project ID
287
+ * @param testCaseId - The test case ID (numeric UD)
288
+ */
289
+ async delete(projectId, testCaseId) {
290
+ await this.request(
291
+ "DELETE",
292
+ `/api/project/${projectId}/test-cases/${testCaseId}`
293
+ );
294
+ }
295
+ };
296
+ // Annotate the CommonJS export names for ESM import in node:
297
+ 0 && (module.exports = {
298
+ CodmirClient
299
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,272 @@
1
+ // src/client.ts
2
+ var CodmirClient = class {
3
+ constructor(config) {
4
+ this.config = {
5
+ apiKey: config.apiKey || "",
6
+ baseUrl: config.baseUrl || "https://codmir.com",
7
+ timeout: config.timeout || 3e4,
8
+ headers: config.headers || {}
9
+ };
10
+ this.tickets = new TicketsAPI(this.config);
11
+ this.testCases = new TestCasesAPI(this.config);
12
+ }
13
+ /**
14
+ * Make an HTTP request to the codmir API
15
+ */
16
+ async request(method, path, body) {
17
+ const url = `${this.config.baseUrl}${path}`;
18
+ const headers = {
19
+ "Content-Type": "application/json",
20
+ ...this.config.headers
21
+ };
22
+ if (this.config.apiKey) {
23
+ headers["X-API-Key"] = this.config.apiKey;
24
+ }
25
+ const controller = new AbortController();
26
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
27
+ try {
28
+ const response = await fetch(url, {
29
+ method,
30
+ headers,
31
+ body: body ? JSON.stringify(body) : void 0,
32
+ signal: controller.signal
33
+ });
34
+ clearTimeout(timeoutId);
35
+ if (!response.ok) {
36
+ const errorData = await response.json().catch(() => ({}));
37
+ throw this.createError(
38
+ errorData.error || `HTTP ${response.status}: ${response.statusText}`,
39
+ response.status,
40
+ errorData
41
+ );
42
+ }
43
+ if (response.status === 204) {
44
+ return {};
45
+ }
46
+ return await response.json();
47
+ } catch (error) {
48
+ clearTimeout(timeoutId);
49
+ if (error.name === "AbortError") {
50
+ throw this.createError("Request timeout", 408);
51
+ }
52
+ if (error instanceof Error && "statusCode" in error) {
53
+ throw error;
54
+ }
55
+ throw this.createError(
56
+ error.message || "Network error occurred",
57
+ void 0,
58
+ error
59
+ );
60
+ }
61
+ }
62
+ createError(message, statusCode, response) {
63
+ const error = new Error(message);
64
+ error.name = "CodmirError";
65
+ error.statusCode = statusCode;
66
+ error.response = response;
67
+ return error;
68
+ }
69
+ };
70
+ var TicketsAPI = class {
71
+ constructor(config) {
72
+ this.config = config;
73
+ }
74
+ async request(method, path, body) {
75
+ const url = `${this.config.baseUrl}${path}`;
76
+ const headers = {
77
+ "Content-Type": "application/json",
78
+ ...this.config.headers
79
+ };
80
+ if (this.config.apiKey) {
81
+ headers["X-API-Key"] = this.config.apiKey;
82
+ }
83
+ const controller = new AbortController();
84
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
85
+ try {
86
+ const response = await fetch(url, {
87
+ method,
88
+ headers,
89
+ body: body ? JSON.stringify(body) : void 0,
90
+ signal: controller.signal
91
+ });
92
+ clearTimeout(timeoutId);
93
+ if (!response.ok) {
94
+ const errorData = await response.json().catch(() => ({}));
95
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
96
+ error.statusCode = response.status;
97
+ error.response = errorData;
98
+ throw error;
99
+ }
100
+ if (response.status === 204) {
101
+ return {};
102
+ }
103
+ return await response.json();
104
+ } catch (error) {
105
+ clearTimeout(timeoutId);
106
+ if (error.name === "AbortError") {
107
+ const timeoutError = new Error("Request timeout");
108
+ timeoutError.statusCode = 408;
109
+ throw timeoutError;
110
+ }
111
+ throw error;
112
+ }
113
+ }
114
+ /**
115
+ * Create a ticket in a board
116
+ *
117
+ * @param projectId - The project ID
118
+ * @param boardId - The board ID
119
+ * @param data - Ticket data
120
+ */
121
+ async createInBoard(projectId, boardId, data) {
122
+ const response = await this.request(
123
+ "POST",
124
+ `/api/project/${projectId}/board/${boardId}/ticket`,
125
+ data
126
+ );
127
+ return response.ticket;
128
+ }
129
+ /**
130
+ * Create a ticket in a workspace
131
+ *
132
+ * @param projectId - The project ID
133
+ * @param workspaceId - The workspace ID
134
+ * @param data - Ticket data
135
+ */
136
+ async createInWorkspace(projectId, workspaceId, data) {
137
+ return this.request(
138
+ "POST",
139
+ `/api/project/${projectId}/workspaces/${workspaceId}/tickets`,
140
+ data
141
+ );
142
+ }
143
+ /**
144
+ * Alias for createInBoard - creates a ticket in a board
145
+ */
146
+ async create(projectId, boardId, data) {
147
+ return this.createInBoard(projectId, boardId, data);
148
+ }
149
+ };
150
+ var TestCasesAPI = class {
151
+ constructor(config) {
152
+ this.config = config;
153
+ }
154
+ async request(method, path, body) {
155
+ const url = `${this.config.baseUrl}${path}`;
156
+ const headers = {
157
+ "Content-Type": "application/json",
158
+ ...this.config.headers
159
+ };
160
+ if (this.config.apiKey) {
161
+ headers["X-API-Key"] = this.config.apiKey;
162
+ }
163
+ const controller = new AbortController();
164
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
165
+ try {
166
+ const response = await fetch(url, {
167
+ method,
168
+ headers,
169
+ body: body ? JSON.stringify(body) : void 0,
170
+ signal: controller.signal
171
+ });
172
+ clearTimeout(timeoutId);
173
+ if (!response.ok) {
174
+ const errorData = await response.json().catch(() => ({}));
175
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
176
+ error.statusCode = response.status;
177
+ error.response = errorData;
178
+ throw error;
179
+ }
180
+ if (response.status === 204) {
181
+ return {};
182
+ }
183
+ return await response.json();
184
+ } catch (error) {
185
+ clearTimeout(timeoutId);
186
+ if (error.name === "AbortError") {
187
+ const timeoutError = new Error("Request timeout");
188
+ timeoutError.statusCode = 408;
189
+ throw timeoutError;
190
+ }
191
+ throw error;
192
+ }
193
+ }
194
+ /**
195
+ * List all test cases for a project
196
+ *
197
+ * @param projectId - The project ID
198
+ */
199
+ async list(projectId) {
200
+ const response = await this.request(
201
+ "GET",
202
+ `/api/project/${projectId}/test-cases`
203
+ );
204
+ return response.data || [];
205
+ }
206
+ /**
207
+ * Get a specific test case by ID
208
+ *
209
+ * @param projectId - The project ID
210
+ * @param testCaseId - The test case ID (numeric UD)
211
+ */
212
+ async get(projectId, testCaseId) {
213
+ const response = await this.request(
214
+ "GET",
215
+ `/api/project/${projectId}/test-cases/${testCaseId}`
216
+ );
217
+ if (!response.data) {
218
+ throw new Error("Test case not found");
219
+ }
220
+ return response.data;
221
+ }
222
+ /**
223
+ * Create a new test case
224
+ *
225
+ * @param projectId - The project ID
226
+ * @param data - Test case data
227
+ */
228
+ async create(projectId, data) {
229
+ const response = await this.request(
230
+ "POST",
231
+ `/api/project/${projectId}/test-cases`,
232
+ data
233
+ );
234
+ if (!response.data) {
235
+ throw new Error("Failed to create test case");
236
+ }
237
+ return response.data;
238
+ }
239
+ /**
240
+ * Update an existing test case
241
+ *
242
+ * @param projectId - The project ID
243
+ * @param testCaseId - The test case ID (numeric UD)
244
+ * @param data - Test case update data
245
+ */
246
+ async update(projectId, testCaseId, data) {
247
+ const response = await this.request(
248
+ "PATCH",
249
+ `/api/project/${projectId}/test-cases/${testCaseId}`,
250
+ data
251
+ );
252
+ if (!response.data) {
253
+ throw new Error("Failed to update test case");
254
+ }
255
+ return response.data;
256
+ }
257
+ /**
258
+ * Delete a test case
259
+ *
260
+ * @param projectId - The project ID
261
+ * @param testCaseId - The test case ID (numeric UD)
262
+ */
263
+ async delete(projectId, testCaseId) {
264
+ await this.request(
265
+ "DELETE",
266
+ `/api/project/${projectId}/test-cases/${testCaseId}`
267
+ );
268
+ }
269
+ };
270
+ export {
271
+ CodmirClient
272
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "codmir",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for codmir API - the AI that prevents wasted engineering time",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "require": "./dist/index.js",
12
+ "import": "./dist/index.mjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
22
+ "prepublishOnly": "pnpm build",
23
+ "test": "jest"
24
+ },
25
+ "keywords": [
26
+ "codmir",
27
+ "api-client",
28
+ "typescript",
29
+ "sdk",
30
+ "developer-tools",
31
+ "project-management",
32
+ "test-automation"
33
+ ],
34
+ "author": "codmir",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/codmir/codmir.git",
39
+ "directory": "packages/codmir-client"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/codmir/codmir/issues"
43
+ },
44
+ "homepage": "https://codmir.com",
45
+ "devDependencies": {
46
+ "@types/node": "^20.10.0",
47
+ "tsup": "^8.0.1",
48
+ "typescript": "^5.8.3"
49
+ },
50
+ "dependencies": {},
51
+ "peerDependencies": {},
52
+ "engines": {
53
+ "node": ">=18.0.0"
54
+ }
55
+ }