@gongrzhe/server-jira 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.
Files changed (66) hide show
  1. package/README.md +374 -0
  2. package/dist/common/context.d.ts +15 -0
  3. package/dist/common/context.d.ts.map +1 -0
  4. package/dist/common/context.js +33 -0
  5. package/dist/common/context.js.map +1 -0
  6. package/dist/common/errors.d.ts +26 -0
  7. package/dist/common/errors.d.ts.map +1 -0
  8. package/dist/common/errors.js +71 -0
  9. package/dist/common/errors.js.map +1 -0
  10. package/dist/common/token-parser.d.ts +53 -0
  11. package/dist/common/token-parser.d.ts.map +1 -0
  12. package/dist/common/token-parser.js +117 -0
  13. package/dist/common/token-parser.js.map +1 -0
  14. package/dist/common/types.d.ts +151 -0
  15. package/dist/common/types.d.ts.map +1 -0
  16. package/dist/common/types.js +2 -0
  17. package/dist/common/types.js.map +1 -0
  18. package/dist/common/utils.d.ts +9 -0
  19. package/dist/common/utils.d.ts.map +1 -0
  20. package/dist/common/utils.js +116 -0
  21. package/dist/common/utils.js.map +1 -0
  22. package/dist/common/version.d.ts +2 -0
  23. package/dist/common/version.d.ts.map +1 -0
  24. package/dist/common/version.js +3 -0
  25. package/dist/common/version.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +505 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/operations/atlassian.d.ts +27 -0
  31. package/dist/operations/atlassian.d.ts.map +1 -0
  32. package/dist/operations/atlassian.js +27 -0
  33. package/dist/operations/atlassian.js.map +1 -0
  34. package/dist/operations/comments.d.ts +117 -0
  35. package/dist/operations/comments.d.ts.map +1 -0
  36. package/dist/operations/comments.js +153 -0
  37. package/dist/operations/comments.js.map +1 -0
  38. package/dist/operations/issues.d.ts +146 -0
  39. package/dist/operations/issues.d.ts.map +1 -0
  40. package/dist/operations/issues.js +250 -0
  41. package/dist/operations/issues.js.map +1 -0
  42. package/dist/operations/metadata.d.ts +176 -0
  43. package/dist/operations/metadata.d.ts.map +1 -0
  44. package/dist/operations/metadata.js +143 -0
  45. package/dist/operations/metadata.js.map +1 -0
  46. package/dist/operations/projects.d.ts +159 -0
  47. package/dist/operations/projects.d.ts.map +1 -0
  48. package/dist/operations/projects.js +175 -0
  49. package/dist/operations/projects.js.map +1 -0
  50. package/dist/operations/users.d.ts +130 -0
  51. package/dist/operations/users.d.ts.map +1 -0
  52. package/dist/operations/users.js +214 -0
  53. package/dist/operations/users.js.map +1 -0
  54. package/dist/operations/workflow.d.ts +110 -0
  55. package/dist/operations/workflow.d.ts.map +1 -0
  56. package/dist/operations/workflow.js +203 -0
  57. package/dist/operations/workflow.js.map +1 -0
  58. package/dist/operations/worklog.d.ts +175 -0
  59. package/dist/operations/worklog.d.ts.map +1 -0
  60. package/dist/operations/worklog.js +322 -0
  61. package/dist/operations/worklog.js.map +1 -0
  62. package/dist/test-token-discovery.d.ts +6 -0
  63. package/dist/test-token-discovery.d.ts.map +1 -0
  64. package/dist/test-token-discovery.js +26 -0
  65. package/dist/test-token-discovery.js.map +1 -0
  66. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,374 @@
1
+ # JIRA MCP Server
2
+
3
+ A stateless, multi-tenant Model Context Protocol (MCP) server for Atlassian JIRA, providing comprehensive access to JIRA's REST API through standardized tools.
4
+
5
+ ## Features
6
+
7
+ - **🎯 Zero Configuration**: Just provide your token - Jira URL is auto-discovered!
8
+ - **🔐 Dual Authentication**: Support for both OAuth 2.0 and API tokens
9
+ - **🌐 Multi-Tenant Architecture**: Each user connects to their own Jira instance
10
+ - **⚡ Stateless Design**: Complete request isolation with no session management
11
+ - **🔑 Smart Routing**: OAuth tokens → API Gateway, API tokens → Direct URL
12
+ - **📦 Fresh Instance Per Request**: Each request gets a new server instance
13
+ - **🛠️ Comprehensive API Coverage**: 30+ tools covering all major JIRA operations
14
+ - **📈 Horizontal Scaling**: Stateless design enables easy load balancing
15
+ - **💾 Smart Caching**: Token-to-URL mappings cached for performance (5-min TTL)
16
+ - **🚀 OAuth Helper**: Included script for easy OAuth token generation
17
+
18
+ ## Tools Overview
19
+
20
+ ### Issue Management (7 tools)
21
+ - `jira_get_issue` - Get issue details by key
22
+ - `jira_search_issues` - Search using JQL queries
23
+ - `jira_create_issue` - Create new issues
24
+ - `jira_update_issue` - Update issue fields
25
+ - `jira_delete_issue` - Delete issues
26
+ - `jira_assign_issue` - Assign issues to users
27
+ - `jira_link_issues` - Create issue relationships
28
+
29
+ ### Comments (4 tools)
30
+ - `jira_get_comments` - Retrieve all comments
31
+ - `jira_add_comment` - Add new comments
32
+ - `jira_update_comment` - Modify comments
33
+ - `jira_delete_comment` - Remove comments
34
+
35
+ ### Projects (6 tools)
36
+ - `jira_list_projects` - List accessible projects
37
+ - `jira_get_project` - Get project details
38
+ - `jira_get_project_issues` - Get issues in project
39
+ - `jira_get_project_versions` - Get project versions
40
+ - `jira_get_project_components` - Get project components
41
+ - `jira_search_projects` - Search projects
42
+
43
+ ### Workflow (3 tools)
44
+ - `jira_get_transitions` - Get available transitions
45
+ - `jira_transition_issue` - Move issues through workflow
46
+ - `jira_get_workflows` - List workflows
47
+
48
+ ### Users & Watchers (5 tools)
49
+ - `jira_get_current_user` - Current user info
50
+ - `jira_search_users` - Find users
51
+ - `jira_get_watchers` - Get issue watchers
52
+ - `jira_add_watcher` - Add watchers
53
+ - `jira_remove_watcher` - Remove watchers
54
+
55
+ ### Metadata (5 tools)
56
+ - `jira_get_issue_types` - Available issue types
57
+ - `jira_get_priorities` - Available priorities
58
+ - `jira_get_statuses` - Available statuses
59
+ - `jira_get_fields` - System/custom fields
60
+ - `jira_get_resolutions` - Available resolutions
61
+
62
+ ### Time Tracking (4 tools)
63
+ - `jira_get_worklogs` - Get time entries
64
+ - `jira_add_worklog` - Log work time
65
+ - `jira_update_worklog` - Update time entries
66
+ - `jira_delete_worklog` - Remove time entries
67
+
68
+ ## Authentication
69
+
70
+ The server supports **two authentication methods** with **automatic Jira URL discovery**:
71
+
72
+ 1. **API Tokens** - For personal/service account access
73
+ 2. **OAuth 2.0** - For delegated user access (recommended for production)
74
+
75
+ Both methods automatically discover your Jira instance URL - no manual configuration needed!
76
+
77
+ ### Option 1: API Token Authentication (Quick Start)
78
+
79
+ #### Getting Your API Token
80
+
81
+ 1. Go to https://id.atlassian.com/manage-profile/security/api-tokens
82
+ 2. Click "Create API token"
83
+ 3. Give it a label (e.g., "MCP Server")
84
+ 4. Copy the generated token
85
+
86
+ #### Using API Tokens
87
+
88
+ ```bash
89
+ curl -X POST http://localhost:30000/mcp \
90
+ -H "Authorization: Bearer YOUR_API_TOKEN" \
91
+ -H "Content-Type: application/json" \
92
+ -H "Accept: application/json, text/event-stream" \
93
+ -d '{
94
+ "jsonrpc": "2.0",
95
+ "id": "1",
96
+ "method": "tools/call",
97
+ "params": {
98
+ "name": "jira_get_current_user",
99
+ "arguments": {}
100
+ }
101
+ }'
102
+ ```
103
+
104
+ ### Option 2: OAuth 2.0 Authentication (Recommended)
105
+
106
+ OAuth 2.0 provides better security and user experience for production deployments.
107
+
108
+ #### Setting Up OAuth 2.0
109
+
110
+ 1. **Create OAuth 2.0 App** at https://developer.atlassian.com/console/myapps/
111
+ - Click "Create" → "OAuth 2.0 integration"
112
+ - Set Authorization callback URL (e.g., `https://your-app.com/callback`)
113
+ - Add permissions: `read:jira-work`, `write:jira-work`, `read:jira-user`, `offline_access`
114
+ - Save your Client ID and Client Secret
115
+
116
+ 2. **Generate Access Token** using the included helper:
117
+ ```bash
118
+ JIRA_CLIENT_ID=your_client_id \
119
+ JIRA_CLIENT_SECRET=your_client_secret \
120
+ node get-oauth-token.js
121
+ ```
122
+
123
+ 3. **Use OAuth Token** (same as API token):
124
+ ```bash
125
+ curl -X POST http://localhost:30000/mcp \
126
+ -H "Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN" \
127
+ -H "Content-Type: application/json" \
128
+ -H "Accept: application/json, text/event-stream" \
129
+ -d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"jira_get_current_user","arguments":{}}}'
130
+ ```
131
+
132
+ #### OAuth vs API Tokens
133
+
134
+ | Feature | OAuth 2.0 | API Tokens |
135
+ |---------|-----------|------------|
136
+ | User delegation | ✅ Yes | ❌ No (account-level) |
137
+ | Token refresh | ✅ Yes (refresh tokens) | ❌ No |
138
+ | Granular scopes | ✅ Yes | ❌ All permissions |
139
+ | Revocation | ✅ Per-app | ❌ All or nothing |
140
+ | Best for | Production apps | Development/testing |
141
+
142
+ ### How It Works
143
+
144
+ **Both authentication methods automatically:**
145
+ - ✅ Discover your Jira URL from the token (API tokens use direct instance URL)
146
+ - ✅ Discover your Jira URL and Cloud ID (OAuth uses Atlassian API Gateway)
147
+ - ✅ Cache the URL for fast subsequent requests (5-minute TTL)
148
+ - ✅ Handle multi-site tokens (uses the first/primary site)
149
+ - ✅ Route requests correctly (OAuth → API Gateway, API tokens → direct)
150
+
151
+ ## Quick Start
152
+
153
+ ### Development Mode
154
+
155
+ ```bash
156
+ # Install dependencies
157
+ npm install
158
+
159
+ # Run in development mode
160
+ npm run dev
161
+ ```
162
+
163
+ ### Production Mode
164
+
165
+ ```bash
166
+ # Build the project
167
+ npm run build
168
+
169
+ # Start the server
170
+ npm start
171
+ ```
172
+
173
+ The server will start on port 30000 by default (configurable via `PORT` environment variable).
174
+
175
+ **No environment variables required!** Each request provides its own JIRA URL.
176
+
177
+ ## Usage Examples
178
+
179
+ **Important**: Only provide your API token - the Jira URL is auto-discovered!
180
+
181
+ ### Search Issues
182
+ ```bash
183
+ curl -X POST http://localhost:30000/mcp \
184
+ -H "Authorization: Bearer YOUR_TOKEN" \
185
+ -H "Content-Type: application/json" \
186
+ -H "Accept: application/json, text/event-stream" \
187
+ -d '{
188
+ "jsonrpc": "2.0",
189
+ "id": "1",
190
+ "method": "tools/call",
191
+ "params": {
192
+ "name": "jira_search_issues",
193
+ "arguments": {
194
+ "jql": "project = PROJ AND status = \"In Progress\"",
195
+ "maxResults": 10
196
+ }
197
+ }
198
+ }'
199
+ ```
200
+
201
+ ### Create Issue
202
+ ```bash
203
+ curl -X POST http://localhost:30000/mcp \
204
+ -H "Authorization: Bearer YOUR_TOKEN" \
205
+ -H "Content-Type: application/json" \
206
+ -H "Accept: application/json, text/event-stream" \
207
+ -d '{
208
+ "jsonrpc": "2.0",
209
+ "id": "2",
210
+ "method": "tools/call",
211
+ "params": {
212
+ "name": "jira_create_issue",
213
+ "arguments": {
214
+ "project": "PROJ",
215
+ "issueType": "Task",
216
+ "summary": "New task from MCP server",
217
+ "description": "Created via MCP JIRA server"
218
+ }
219
+ }
220
+ }'
221
+ ```
222
+
223
+ ### Add Comment
224
+ ```bash
225
+ curl -X POST http://localhost:30000/mcp \
226
+ -H "Authorization: Bearer YOUR_TOKEN" \
227
+ -H "Content-Type: application/json" \
228
+ -H "Accept: application/json, text/event-stream" \
229
+ -d '{
230
+ "jsonrpc": "2.0",
231
+ "id": "3",
232
+ "method": "tools/call",
233
+ "params": {
234
+ "name": "jira_add_comment",
235
+ "arguments": {
236
+ "issueKey": "PROJ-123",
237
+ "body": "This is a comment from the MCP server"
238
+ }
239
+ }
240
+ }'
241
+ ```
242
+
243
+ ### Transition Issue
244
+ ```bash
245
+ curl -X POST http://localhost:30000/mcp \
246
+ -H "Authorization: Bearer YOUR_TOKEN" \
247
+ -H "Content-Type: application/json" \
248
+ -H "Accept: application/json, text/event-stream" \
249
+ -d '{
250
+ "jsonrpc": "2.0",
251
+ "id": "4",
252
+ "method": "tools/call",
253
+ "params": {
254
+ "name": "jira_transition_issue",
255
+ "arguments": {
256
+ "issueKey": "PROJ-123",
257
+ "transitionId": "41",
258
+ "comment": "Transitioning via MCP server"
259
+ }
260
+ }
261
+ }'
262
+ ```
263
+
264
+ ## Configuration
265
+
266
+ ### Environment Variables
267
+
268
+ The server requires **zero configuration**:
269
+
270
+ - `PORT` - Server port (default: 30000) - **Optional**
271
+
272
+ **That's it!** Users only provide:
273
+ - API token - Via `Authorization: Bearer <token>` header
274
+ - Jira URL - **Automatically discovered from the token**
275
+
276
+ ### JQL (JIRA Query Language)
277
+
278
+ Many tools support JQL for powerful querying:
279
+
280
+ ```sql
281
+ -- Basic searches
282
+ project = "PROJ"
283
+ status = "In Progress"
284
+ assignee = currentUser()
285
+
286
+ -- Advanced searches
287
+ project = "PROJ" AND status WAS "In Progress" DURING ("2024-01-01", "2024-12-31")
288
+ worklogAuthor = currentUser() AND worklogDate >= startOfWeek()
289
+ issueType = Bug AND priority = High AND created >= -7d
290
+ ```
291
+
292
+ ## Error Handling
293
+
294
+ The server provides structured error responses:
295
+
296
+ ```json
297
+ {
298
+ "error": true,
299
+ "tool": "jira_get_issue",
300
+ "message": "Error in jira_get_issue: [404] Issue not found: PROJ-999",
301
+ "timestamp": "2024-01-15T10:30:00.000Z"
302
+ }
303
+ ```
304
+
305
+ Common error codes:
306
+ - `401` - Authentication required/invalid
307
+ - `403` - Permission denied
308
+ - `404` - Resource not found
309
+ - `400` - Validation error
310
+ - `429` - Rate limit exceeded
311
+
312
+ ## Health Check
313
+
314
+ ```bash
315
+ curl http://localhost:30000/health
316
+ ```
317
+
318
+ Returns:
319
+ ```json
320
+ {
321
+ "status": "healthy",
322
+ "version": "0.1.0",
323
+ "timestamp": "2024-01-15T10:30:00.000Z",
324
+ "mode": "stateless"
325
+ }
326
+ ```
327
+
328
+ ## Architecture
329
+
330
+ ### Smart Token Discovery
331
+ - Calls Atlassian's `oauth/token/accessible-resources` API
332
+ - Discovers all Jira instances accessible to the token
333
+ - Uses the primary/first site automatically
334
+ - Caches URL mappings for 5 minutes (configurable)
335
+ - Automatic cache cleanup for memory efficiency
336
+
337
+ ### Multi-Tenant Support
338
+ - Each user's token maps to their own Jira instance
339
+ - No shared configuration between users
340
+ - Perfect for SaaS deployments
341
+ - Supports JIRA Cloud, Server, and Data Center
342
+ - Handles multi-site tokens gracefully
343
+
344
+ ### Stateless Design
345
+ - Fresh server instance per request
346
+ - No session management
347
+ - Complete request isolation
348
+ - Automatic cleanup prevents memory leaks
349
+
350
+ ### Security
351
+ - No token storage (except in-memory cache)
352
+ - Request-level authentication and discovery
353
+ - Standard Bearer token support
354
+ - Fresh token validation per request
355
+ - Zero cross-tenant contamination
356
+
357
+ ### Performance
358
+ - Horizontal scaling ready
359
+ - Intelligent caching (5-min TTL)
360
+ - Minimal memory footprint
361
+ - Fast startup time
362
+ - Zero configuration overhead
363
+ - Automatic cache eviction
364
+
365
+ ## API Compatibility
366
+
367
+ This server is compatible with:
368
+ - JIRA Cloud
369
+ - JIRA Server/Data Center (7.0+)
370
+ - JIRA REST API v2
371
+
372
+ ## License
373
+
374
+ MIT
@@ -0,0 +1,15 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ interface AuthContext {
3
+ token: string | null;
4
+ jiraUrl: string | null;
5
+ cloudId: string | null;
6
+ }
7
+ export declare const authStorage: AsyncLocalStorage<AuthContext>;
8
+ export declare function getAuthToken(): string | null;
9
+ export declare function requireAuthToken(): string;
10
+ export declare function getJiraUrl(): string | null;
11
+ export declare function requireJiraUrl(): string;
12
+ export declare function getCloudId(): string | null;
13
+ export declare function requireCloudId(): string;
14
+ export {};
15
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../common/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,eAAO,MAAM,WAAW,gCAAuC,CAAC;AAEhE,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAMvC"}
@@ -0,0 +1,33 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ export const authStorage = new AsyncLocalStorage();
3
+ export function getAuthToken() {
4
+ return authStorage.getStore()?.token || null;
5
+ }
6
+ export function requireAuthToken() {
7
+ const token = getAuthToken();
8
+ if (!token) {
9
+ throw new Error("Authentication token is required");
10
+ }
11
+ return token;
12
+ }
13
+ export function getJiraUrl() {
14
+ return authStorage.getStore()?.jiraUrl || null;
15
+ }
16
+ export function requireJiraUrl() {
17
+ const jiraUrl = getJiraUrl();
18
+ if (!jiraUrl) {
19
+ throw new Error("JIRA URL is required");
20
+ }
21
+ return jiraUrl;
22
+ }
23
+ export function getCloudId() {
24
+ return authStorage.getStore()?.cloudId || null;
25
+ }
26
+ export function requireCloudId() {
27
+ const cloudId = getCloudId();
28
+ if (!cloudId) {
29
+ throw new Error("Cloud ID is required for OAuth 2.0 authentication");
30
+ }
31
+ return cloudId;
32
+ }
33
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../common/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAQrD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,iBAAiB,EAAe,CAAC;AAEhE,MAAM,UAAU,YAAY;IAC1B,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,OAAO,IAAI,IAAI,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,OAAO,IAAI,IAAI,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,26 @@
1
+ export declare class JiraError extends Error {
2
+ statusCode?: number | undefined;
3
+ errorCode?: string | undefined;
4
+ constructor(message: string, statusCode?: number | undefined, errorCode?: string | undefined);
5
+ }
6
+ export declare class JiraAuthenticationError extends JiraError {
7
+ constructor(message?: string);
8
+ }
9
+ export declare class JiraPermissionError extends JiraError {
10
+ constructor(message?: string);
11
+ }
12
+ export declare class JiraResourceNotFoundError extends JiraError {
13
+ constructor(resource: string, identifier: string);
14
+ }
15
+ export declare class JiraValidationError extends JiraError {
16
+ constructor(message: string);
17
+ }
18
+ export declare class JiraRateLimitError extends JiraError {
19
+ constructor(message?: string);
20
+ }
21
+ export declare class JiraConflictError extends JiraError {
22
+ constructor(message: string);
23
+ }
24
+ export declare function isJiraError(error: unknown): error is JiraError;
25
+ export declare function createJiraErrorFromResponse(response: Response, responseBody: any): JiraError;
26
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../common/errors.ts"],"names":[],"mappings":"AACA,qBAAa,SAAU,SAAQ,KAAK;IACE,UAAU,CAAC,EAAE,MAAM;IAAS,SAAS,CAAC,EAAE,MAAM;gBAAtE,OAAO,EAAE,MAAM,EAAS,UAAU,CAAC,EAAE,MAAM,YAAA,EAAS,SAAS,CAAC,EAAE,MAAM,YAAA;CAInF;AAED,qBAAa,uBAAwB,SAAQ,SAAS;gBACxC,OAAO,GAAE,MAAgC;CAItD;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,GAAE,MAA4B;CAIlD;AAED,qBAAa,yBAA0B,SAAQ,SAAS;gBAC1C,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAIjD;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,GAAE,MAA8B;CAIpD;AAED,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,GAAG,SAAS,CAoB5F"}
@@ -0,0 +1,71 @@
1
+ // JIRA-specific error classes
2
+ export class JiraError extends Error {
3
+ statusCode;
4
+ errorCode;
5
+ constructor(message, statusCode, errorCode) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.errorCode = errorCode;
9
+ this.name = 'JiraError';
10
+ }
11
+ }
12
+ export class JiraAuthenticationError extends JiraError {
13
+ constructor(message = 'Authentication failed') {
14
+ super(message, 401, 'JIRA_AUTH_ERROR');
15
+ this.name = 'JiraAuthenticationError';
16
+ }
17
+ }
18
+ export class JiraPermissionError extends JiraError {
19
+ constructor(message = 'Permission denied') {
20
+ super(message, 403, 'JIRA_PERMISSION_ERROR');
21
+ this.name = 'JiraPermissionError';
22
+ }
23
+ }
24
+ export class JiraResourceNotFoundError extends JiraError {
25
+ constructor(resource, identifier) {
26
+ super(`${resource} not found: ${identifier}`, 404, 'JIRA_NOT_FOUND');
27
+ this.name = 'JiraResourceNotFoundError';
28
+ }
29
+ }
30
+ export class JiraValidationError extends JiraError {
31
+ constructor(message) {
32
+ super(message, 400, 'JIRA_VALIDATION_ERROR');
33
+ this.name = 'JiraValidationError';
34
+ }
35
+ }
36
+ export class JiraRateLimitError extends JiraError {
37
+ constructor(message = 'Rate limit exceeded') {
38
+ super(message, 429, 'JIRA_RATE_LIMIT');
39
+ this.name = 'JiraRateLimitError';
40
+ }
41
+ }
42
+ export class JiraConflictError extends JiraError {
43
+ constructor(message) {
44
+ super(message, 409, 'JIRA_CONFLICT');
45
+ this.name = 'JiraConflictError';
46
+ }
47
+ }
48
+ export function isJiraError(error) {
49
+ return error instanceof JiraError;
50
+ }
51
+ export function createJiraErrorFromResponse(response, responseBody) {
52
+ const status = response.status;
53
+ const message = responseBody?.errorMessages?.join('; ') ||
54
+ responseBody?.message ||
55
+ `JIRA API error: ${response.statusText}`;
56
+ switch (status) {
57
+ case 401:
58
+ return new JiraAuthenticationError(message);
59
+ case 403:
60
+ return new JiraPermissionError(message);
61
+ case 404:
62
+ return new JiraResourceNotFoundError('Resource', response.url || 'Unknown');
63
+ case 409:
64
+ return new JiraConflictError(message);
65
+ case 429:
66
+ return new JiraRateLimitError(message);
67
+ default:
68
+ return new JiraError(message, status);
69
+ }
70
+ }
71
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../common/errors.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,MAAM,OAAO,SAAU,SAAQ,KAAK;IACE;IAA4B;IAAhE,YAAY,OAAe,EAAS,UAAmB,EAAS,SAAkB;QAChF,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,eAAU,GAAV,UAAU,CAAS;QAAS,cAAS,GAAT,SAAS,CAAS;QAEhF,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,SAAS;IACpD,YAAY,UAAkB,uBAAuB;QACnD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,YAAY,UAAkB,mBAAmB;QAC/C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,SAAS;IACtD,YAAY,QAAgB,EAAE,UAAkB;QAC9C,KAAK,CAAC,GAAG,QAAQ,eAAe,UAAU,EAAE,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,SAAS;IAC/C,YAAY,UAAkB,qBAAqB;QACjD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,SAAS,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAkB,EAAE,YAAiB;IAC/E,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC/B,MAAM,OAAO,GAAG,YAAY,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC;QACxC,YAAY,EAAE,OAAO;QACrB,mBAAmB,QAAQ,CAAC,UAAU,EAAE,CAAC;IAExD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,IAAI,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,GAAG;YACN,OAAO,IAAI,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAC1C,KAAK,GAAG;YACN,OAAO,IAAI,yBAAyB,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC;QAC9E,KAAK,GAAG;YACN,OAAO,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACxC,KAAK,GAAG;YACN,OAAO,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACzC;YACE,OAAO,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Jira Token Parser
3
+ *
4
+ * Extracts Jira site information from API tokens by making a discovery call
5
+ * to the Jira API to determine the accessible sites for the given token.
6
+ */
7
+ export interface JiraSite {
8
+ id: string;
9
+ url: string;
10
+ name: string;
11
+ scopes: string[];
12
+ avatarUrl: string;
13
+ }
14
+ /**
15
+ * Get accessible Jira sites for the given API token
16
+ * This calls the Atlassian API to discover which Jira instances the token has access to
17
+ */
18
+ export declare function getAccessibleSites(apiToken: string): Promise<JiraSite[]>;
19
+ /**
20
+ * Get the primary/first Jira site URL from the API token
21
+ * This is the recommended approach for single-site users
22
+ */
23
+ export declare function getJiraUrlFromToken(apiToken: string): Promise<string>;
24
+ /**
25
+ * Get the cloud ID from the API token
26
+ * Cloud ID is required for OAuth 2.0 tokens to use the Atlassian API Gateway
27
+ */
28
+ export declare function getCloudIdFromToken(apiToken: string): Promise<string>;
29
+ /**
30
+ * Site information containing both URL and cloud ID
31
+ */
32
+ export interface SiteInfo {
33
+ url: string;
34
+ cloudId: string;
35
+ name: string;
36
+ }
37
+ /**
38
+ * Get both URL and cloud ID from token
39
+ */
40
+ export declare function getSiteInfoFromToken(apiToken: string): Promise<SiteInfo>;
41
+ /**
42
+ * Get Jira site info from token with caching
43
+ */
44
+ export declare function getCachedSiteInfo(apiToken: string): Promise<SiteInfo>;
45
+ /**
46
+ * Get Jira URL from token with caching (backward compatibility)
47
+ */
48
+ export declare function getCachedJiraUrl(apiToken: string): Promise<string>;
49
+ /**
50
+ * Clear the token cache (useful for testing)
51
+ */
52
+ export declare function clearTokenCache(): void;
53
+ //# sourceMappingURL=token-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-parser.d.ts","sourceRoot":"","sources":["../../common/token-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAqB9E;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAU3E;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAU3E;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAa9E;AAQD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2B3E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGxE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}