codmir 0.1.0 → 0.3.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 +22 -2
- package/dist/chunk-7HVQNURM.mjs +273 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +769 -0
- package/dist/cli/index.mjs +479 -0
- package/dist/index.mjs +3 -269
- package/package.json +22 -6
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
21
|
+
### As a Package
|
|
22
|
+
|
|
21
23
|
```bash
|
|
22
24
|
npm install codmir
|
|
23
25
|
```
|
|
@@ -25,15 +27,33 @@ npm install codmir
|
|
|
25
27
|
or with pnpm:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
|
-
pnpm add codmir
|
|
30
|
+
pnpm add @jobrayan/codmir
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
or with yarn:
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
|
-
yarn add codmir
|
|
36
|
+
yarn add @jobrayan/codmir
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### As a CLI (Global)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @jobrayan/codmir
|
|
43
|
+
# or
|
|
44
|
+
pnpm add -g @jobrayan/codmir
|
|
35
45
|
```
|
|
36
46
|
|
|
47
|
+
Then authenticate and link your project:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
codmir login # Authenticate via browser
|
|
51
|
+
codmir link # Link current directory to a project
|
|
52
|
+
codmir init # Initialize with examples
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See [CLI Documentation](./CLI.md) for more details.
|
|
56
|
+
|
|
37
57
|
## Quick Start
|
|
38
58
|
|
|
39
59
|
```typescript
|
|
@@ -0,0 +1,273 @@
|
|
|
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
|
+
|
|
271
|
+
export {
|
|
272
|
+
CodmirClient
|
|
273
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|