@atlassian-dc-mcp/jira 0.17.0 → 0.18.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/CHANGELOG.md +22 -0
- package/build/__tests__/jira-service.test.js +29 -2
- package/build/__tests__/jira-service.test.js.map +1 -1
- package/build/__tests__/request-timeout.test.d.ts +2 -0
- package/build/__tests__/request-timeout.test.d.ts.map +1 -0
- package/build/__tests__/request-timeout.test.js +38 -0
- package/build/__tests__/request-timeout.test.js.map +1 -0
- package/build/config.d.ts.map +1 -1
- package/build/config.js +2 -1
- package/build/config.js.map +1 -1
- package/build/jira-client/core/request.d.ts.map +1 -1
- package/build/jira-client/core/request.js +21 -2
- package/build/jira-client/core/request.js.map +1 -1
- package/build/jira-service.d.ts +2 -1
- package/build/jira-service.d.ts.map +1 -1
- package/build/jira-service.js +13 -13
- package/build/jira-service.js.map +1 -1
- package/build/setup.js +14 -2
- package/build/setup.js.map +1 -1
- package/jest.config.js +1 -0
- package/package.json +3 -3
- package/src/__tests__/jira-service.test.ts +32 -2
- package/src/__tests__/request-timeout.test.ts +54 -0
- package/src/config.ts +2 -1
- package/src/jira-client/core/request.ts +22 -2
- package/src/jira-service.ts +14 -12
- package/src/setup.ts +13 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/build/__tests__/setup.test.d.ts +0 -2
- package/build/__tests__/setup.test.d.ts.map +0 -1
- package/build/__tests__/setup.test.js +0 -11
- package/build/__tests__/setup.test.js.map +0 -1
- package/src/__tests__/setup.test.ts +0 -11
package/src/config.ts
CHANGED
|
@@ -12,7 +12,8 @@ export const JIRA_PRODUCT: ProductDefinition = {
|
|
|
12
12
|
token: 'JIRA_API_TOKEN',
|
|
13
13
|
defaultPageSize: 'JIRA_DEFAULT_PAGE_SIZE',
|
|
14
14
|
},
|
|
15
|
-
defaultApiBasePath: '/rest
|
|
15
|
+
defaultApiBasePath: '/rest',
|
|
16
|
+
apiBasePathStrippableSuffixes: ['/api/2'],
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export function getJiraRuntimeConfig() {
|
|
@@ -9,6 +9,9 @@ import { CancelablePromise } from './CancelablePromise.js';
|
|
|
9
9
|
import type { OnCancel } from './CancelablePromise.js';
|
|
10
10
|
import type { OpenAPIConfig } from './OpenAPI.js';
|
|
11
11
|
|
|
12
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
13
|
+
const REQUEST_TIMEOUT_MS_ENV_VAR = 'ATLASSIAN_DC_MCP_REQUEST_TIMEOUT_MS';
|
|
14
|
+
|
|
12
15
|
export const isDefined = <T>(value: T | null | undefined): value is Exclude<T, null | undefined> => {
|
|
13
16
|
return value !== undefined && value !== null;
|
|
14
17
|
};
|
|
@@ -129,6 +132,15 @@ export const getFormData = (options: ApiRequestOptions): FormData | undefined =>
|
|
|
129
132
|
|
|
130
133
|
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
|
131
134
|
|
|
135
|
+
const getRequestTimeoutMs = (): number => {
|
|
136
|
+
const raw = process.env[REQUEST_TIMEOUT_MS_ENV_VAR];
|
|
137
|
+
if (!raw) {
|
|
138
|
+
return DEFAULT_REQUEST_TIMEOUT_MS;
|
|
139
|
+
}
|
|
140
|
+
const parsed = Number.parseInt(raw.trim(), 10);
|
|
141
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_REQUEST_TIMEOUT_MS;
|
|
142
|
+
};
|
|
143
|
+
|
|
132
144
|
export const resolve = async <T>(options: ApiRequestOptions, resolver?: T | Resolver<T>): Promise<T | undefined> => {
|
|
133
145
|
if (typeof resolver === 'function') {
|
|
134
146
|
return (resolver as Resolver<T>)(options);
|
|
@@ -202,6 +214,7 @@ export const sendRequest = async (
|
|
|
202
214
|
onCancel: OnCancel
|
|
203
215
|
): Promise<Response> => {
|
|
204
216
|
const controller = new AbortController();
|
|
217
|
+
const timeout = setTimeout(() => controller.abort(), getRequestTimeoutMs());
|
|
205
218
|
|
|
206
219
|
const request: RequestInit = {
|
|
207
220
|
headers,
|
|
@@ -214,9 +227,16 @@ export const sendRequest = async (
|
|
|
214
227
|
request.credentials = config.CREDENTIALS;
|
|
215
228
|
}
|
|
216
229
|
|
|
217
|
-
onCancel(() =>
|
|
230
|
+
onCancel(() => {
|
|
231
|
+
clearTimeout(timeout);
|
|
232
|
+
controller.abort();
|
|
233
|
+
});
|
|
218
234
|
|
|
219
|
-
|
|
235
|
+
try {
|
|
236
|
+
return await fetch(url, request);
|
|
237
|
+
} finally {
|
|
238
|
+
clearTimeout(timeout);
|
|
239
|
+
}
|
|
220
240
|
};
|
|
221
241
|
|
|
222
242
|
export const getResponseHeader = (response: Response, responseHeader?: string): string | undefined => {
|
package/src/jira-service.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { handleApiOperation } from '@atlassian-dc-mcp/common';
|
|
3
|
-
import { IssueService, OpenAPI, SearchService } from './jira-client/index.js';
|
|
2
|
+
import { handleApiOperation, resolveOpenApiBase } from '@atlassian-dc-mcp/common';
|
|
3
|
+
import { IssueService, MyselfService, OpenAPI, SearchService } from './jira-client/index.js';
|
|
4
4
|
import type { StringList } from './jira-client/models/StringList.js';
|
|
5
|
-
import { getDefaultPageSize, getMissingConfig } from './config.js';
|
|
5
|
+
import { getDefaultPageSize, getMissingConfig, JIRA_PRODUCT } from './config.js';
|
|
6
6
|
|
|
7
7
|
const DEFAULT_SEARCH_FIELDS = ['summary', 'description', 'status', 'assignee', 'reporter', 'priority', 'issuetype', 'labels', 'updated'];
|
|
8
8
|
const DEFAULT_ISSUE_FIELDS = [...DEFAULT_SEARCH_FIELDS, 'parent', 'subtasks'];
|
|
@@ -28,17 +28,15 @@ export class JiraService {
|
|
|
28
28
|
constructor(
|
|
29
29
|
host: string | undefined,
|
|
30
30
|
token: string | (() => string | undefined),
|
|
31
|
-
|
|
31
|
+
apiBasePath?: string,
|
|
32
32
|
getPageSize: () => number = getDefaultPageSize,
|
|
33
33
|
) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
34
|
+
OpenAPI.BASE = resolveOpenApiBase({
|
|
35
|
+
host,
|
|
36
|
+
apiBasePath,
|
|
37
|
+
defaultBasePath: JIRA_PRODUCT.defaultApiBasePath ?? '/rest',
|
|
38
|
+
strippableSuffixes: JIRA_PRODUCT.apiBasePathStrippableSuffixes,
|
|
39
|
+
});
|
|
42
40
|
OpenAPI.TOKEN = resolveToken(token, 'Missing required environment variable: JIRA_API_TOKEN');
|
|
43
41
|
OpenAPI.VERSION = '2';
|
|
44
42
|
this.getPageSize = getPageSize;
|
|
@@ -147,6 +145,10 @@ export class JiraService {
|
|
|
147
145
|
}, 'Error transitioning issue');
|
|
148
146
|
}
|
|
149
147
|
|
|
148
|
+
async validateSetup(): Promise<void> {
|
|
149
|
+
await MyselfService.getUser();
|
|
150
|
+
}
|
|
151
|
+
|
|
150
152
|
static validateConfig(): string[] {
|
|
151
153
|
return getMissingConfig();
|
|
152
154
|
}
|
package/src/setup.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import { runSetup } from '@atlassian-dc-mcp/common';
|
|
1
|
+
import { describeValidationError, runSetup } from '@atlassian-dc-mcp/common';
|
|
2
2
|
import { JIRA_PRODUCT } from './config.js';
|
|
3
|
+
import { JiraService } from './jira-service.js';
|
|
3
4
|
|
|
4
|
-
await runSetup(JIRA_PRODUCT
|
|
5
|
+
await runSetup(JIRA_PRODUCT, {
|
|
6
|
+
validateCredentials: async ({ host, apiBasePath, token }) => {
|
|
7
|
+
const service = new JiraService(host || undefined, token, apiBasePath || undefined);
|
|
8
|
+
try {
|
|
9
|
+
await service.validateSetup();
|
|
10
|
+
return { ok: true };
|
|
11
|
+
} catch (error) {
|
|
12
|
+
return { ok: false, message: describeValidationError(error) };
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
});
|