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 +322 -0
- package/dist/index.d.mts +220 -0
- package/dist/index.d.ts +220 -0
- package/dist/index.js +299 -0
- package/dist/index.mjs +272 -0
- package/package.json +55 -0
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
|
+
[](https://www.npmjs.com/package/codmir)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](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.**
|
package/dist/index.d.mts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|