@venturialstd/jira
v0.1.35
Published
Comprehensive NestJS SDK for Jira Cloud Platform REST API v3 - Full integration with Atlassian Jira
Keywords
Readme
@venturialstd/jira
A comprehensive NestJS SDK for Jira Cloud Platform REST API v3, developed by Venturial, that provides full integration with Atlassian Jira. This module enables seamless issue management, project operations, user management, and all Jira API capabilities.
Features
- Issue Management: Create, read, update, delete, and search issues with full support for all issue operations
- Project Operations: Get project details, components, versions, statuses, roles, and properties
- User Management: Search users, get user details, and manage user picker operations
- Comments: Add, update, delete, and retrieve comments on issues
- Worklogs: Create, update, delete, and retrieve worklogs for time tracking
- Attachments: Upload, download, and manage file attachments
- Search & JQL: Powerful JQL-based search capabilities for finding issues
- Transitions: Get available transitions and transition issues through workflows
- Changelogs: Retrieve issue changelogs and history
- Bulk Operations: Bulk create, fetch, archive, and unarchive issues
- Webhooks: Register, manage, and monitor dynamic webhooks for real-time event notifications
- Type Safety: Full TypeScript support with comprehensive type definitions
- Configuration Flexibility: Configure credentials globally via settings or pass them per-request
Installation
npm install @venturialstd/jira
# or
yarn add @venturialstd/jiraPeer Dependencies
This package requires the following peer dependencies:
npm install @nestjs/common@^11.0.11 @nestjs/core@^11.0.5 @nestjs/axios@^4.0.0 @venturialstd/core@^1.0.16 rxjs@^7.8.1Basic Usage
1. Import the Module
import { Module } from '@nestjs/common';
import { JiraModule } from '@venturialstd/jira';
@Module({
imports: [
JiraModule,
],
})
export class AppModule {}2. Inject and Use Services
import { Injectable } from '@nestjs/common';
import {
JiraIssueService,
JiraSearchService,
JiraCommentService,
JiraProjectService,
JiraConfig,
} from '@venturialstd/jira';
@Injectable()
export class TaskService {
constructor(
private readonly issueService: JiraIssueService,
private readonly searchService: JiraSearchService,
private readonly commentService: JiraCommentService,
private readonly projectService: JiraProjectService,
) {}
async createTask(summary: string, description: string) {
// Create an issue
const issue = await this.issueService.createIssue(null, {
fields: {
project: { key: 'PROJ' },
summary,
description: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: description }],
},
],
},
issuetype: { name: 'Task' },
},
});
return issue;
}
async searchTasks(jql: string) {
// Search issues using JQL
const results = await this.searchService.searchIssues(null, {
jql,
maxResults: 50,
});
return results.issues;
}
async addComment(issueKey: string, comment: string) {
// Add a comment to an issue
return await this.commentService.addComment(null, issueKey, {
body: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: comment }],
},
],
},
});
}
}3. Configuration
The module uses SettingsService from @venturialstd/core to retrieve credentials. Configure the following settings:
GLOBAL:JIRA:GENERAL:JIRA_API_TOKEN: Your Jira API tokenGLOBAL:JIRA:GENERAL:JIRA_USER_EMAIL: Your Jira user emailGLOBAL:JIRA:GENERAL:JIRA_ISSUE_BASE_URL: Base URL for your Jira instance (e.g.,https://your-domain.atlassian.net)
Alternatively, you can pass configuration directly to service methods:
const config: JiraConfig = {
auth: {
token: 'your-api-token',
user: '[email protected]',
},
baseUrl: 'https://your-domain.atlassian.net',
};
await this.issueService.getIssue(config, 'PROJ-123');Note: All service methods have config: JiraConfig | null = null as the first parameter. Pass null to use settings-based configuration, or provide a JiraConfig object for per-request configuration.
API
JiraIssueService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getIssue(config, issueIdOrKey, ...) | GET /rest/api/3/issue/{issueIdOrKey} | Get issue details |
| createIssue(config, request, updateHistory?) | POST /rest/api/3/issue | Create a new issue |
| editIssue(config, issueIdOrKey, request, ...) | PUT /rest/api/3/issue/{issueIdOrKey} | Edit an issue |
| deleteIssue(config, issueIdOrKey, deleteSubtasks?) | DELETE /rest/api/3/issue/{issueIdOrKey} | Delete an issue |
| assignIssue(config, issueIdOrKey, request) | PUT /rest/api/3/issue/{issueIdOrKey}/assignee | Assign an issue |
| getChangelogs(config, issueIdOrKey, startAt?, maxResults?) | GET /rest/api/3/issue/{issueIdOrKey}/changelog | Get issue changelogs |
| getChangelogsByIds(config, issueIdOrKey, request) | POST /rest/api/3/issue/{issueIdOrKey}/changelog/list | Get changelogs by IDs |
| getEditMeta(config, issueIdOrKey, ...) | GET /rest/api/3/issue/{issueIdOrKey}/editmeta | Get edit metadata |
| sendNotification(config, issueIdOrKey, request) | POST /rest/api/3/issue/{issueIdOrKey}/notify | Send notification |
| getTransitions(config, issueIdOrKey, ...) | GET /rest/api/3/issue/{issueIdOrKey}/transitions | Get available transitions |
| transitionIssue(config, issueIdOrKey, request) | POST /rest/api/3/issue/{issueIdOrKey}/transitions | Transition an issue |
| bulkCreateIssues(config, request) | POST /rest/api/3/issue/bulk | Bulk create issues (up to 50) |
| bulkFetchIssues(config, request) | POST /rest/api/3/issue/bulkfetch | Bulk fetch issues (up to 100) |
| archiveIssues(config, request) | PUT /rest/api/3/issue/archive | Archive issues by ID/key (up to 1000) |
| archiveIssuesByJql(config, request) | POST /rest/api/3/issue/archive | Archive issues by JQL (up to 100,000) |
| unarchiveIssues(config, request) | PUT /rest/api/3/issue/unarchive | Unarchive issues (up to 1000) |
| getIssueLimitReport(config, isReturningKeys?) | GET /rest/api/3/issue/limit/report | Get issue limit report |
| exportArchivedIssues(config, request) | PUT /rest/api/3/issues/archive/export | Export archived issues |
| getCreateMeta(config, ...) | GET /rest/api/3/issue/createmeta | Get create issue metadata |
| getCreateMetaIssueTypes(config, projectIdOrKey, ...) | GET /rest/api/3/issue/createmeta/{projectIdOrKey}/issuetypes | Get issue types for project |
| getCreateMetaFields(config, projectIdOrKey, issueTypeId, ...) | GET /rest/api/3/issue/createmeta/{projectIdOrKey}/issuetypes/{issueTypeId} | Get fields for issue type |
| bulkFetchChangelogs(config, request) | POST /rest/api/3/changelog/bulkfetch | Bulk fetch changelogs |
JiraSearchService
| Method | Endpoint | Description |
|--------|----------|-------------|
| searchIssues(config, request) | GET /rest/api/3/search | Search issues using JQL |
JiraCommentService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getComments(config, issueIdOrKey, ...) | GET /rest/api/3/issue/{issueIdOrKey}/comment | Get comments for an issue |
| getComment(config, issueIdOrKey, commentId, expand?) | GET /rest/api/3/issue/{issueIdOrKey}/comment/{commentId} | Get a specific comment |
| addComment(config, issueIdOrKey, request, expand?) | POST /rest/api/3/issue/{issueIdOrKey}/comment | Add a comment |
| updateComment(config, issueIdOrKey, commentId, request, expand?) | PUT /rest/api/3/issue/{issueIdOrKey}/comment/{commentId} | Update a comment |
| deleteComment(config, issueIdOrKey, commentId) | DELETE /rest/api/3/issue/{issueIdOrKey}/comment/{commentId} | Delete a comment |
JiraWorklogService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getWorklogs(config, issueIdOrKey, ...) | GET /rest/api/3/issue/{issueIdOrKey}/worklog | Get worklogs for an issue |
| getWorklog(config, issueIdOrKey, worklogId, expand?) | GET /rest/api/3/issue/{issueIdOrKey}/worklog/{worklogId} | Get a specific worklog |
| addWorklog(config, issueIdOrKey, request, ...) | POST /rest/api/3/issue/{issueIdOrKey}/worklog | Add a worklog |
| updateWorklog(config, issueIdOrKey, worklogId, request, ...) | PUT /rest/api/3/issue/{issueIdOrKey}/worklog/{worklogId} | Update a worklog |
| deleteWorklog(config, issueIdOrKey, worklogId, ...) | DELETE /rest/api/3/issue/{issueIdOrKey}/worklog/{worklogId} | Delete a worklog |
JiraAttachmentService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getAttachments(config, issueIdOrKey) | GET /rest/api/3/issue/{issueIdOrKey} | Get attachments for an issue |
| getAttachment(config, attachmentId) | GET /rest/api/3/attachment/{attachmentId} | Get a specific attachment |
| addAttachment(config, issueIdOrKey, file, filename) | POST /rest/api/3/issue/{issueIdOrKey}/attachments | Add an attachment |
| deleteAttachment(config, attachmentId) | DELETE /rest/api/3/attachment/{attachmentId} | Delete an attachment |
JiraProjectService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getProjects(config, expand?, recent?, properties?) | GET /rest/api/3/project | Get all projects |
| getProject(config, projectIdOrKey, expand?, properties?) | GET /rest/api/3/project/{projectIdOrKey} | Get a project |
| getProjectAvatars(config, projectIdOrKey) | GET /rest/api/3/project/{projectIdOrKey}/avatars | Get project avatars |
| getProjectComponents(config, projectIdOrKey) | GET /rest/api/3/project/{projectIdOrKey}/components | Get project components |
| getProjectProperties(config, projectIdOrKey) | GET /rest/api/3/project/{projectIdOrKey}/properties | Get project properties |
| getProjectProperty(config, projectIdOrKey, propertyKey) | GET /rest/api/3/project/{projectIdOrKey}/properties/{propertyKey} | Get a project property |
| setProjectProperty(config, projectIdOrKey, propertyKey, value) | PUT /rest/api/3/project/{projectIdOrKey}/properties/{propertyKey} | Set a project property |
| deleteProjectProperty(config, projectIdOrKey, propertyKey) | DELETE /rest/api/3/project/{projectIdOrKey}/properties/{propertyKey} | Delete a project property |
| getProjectRoles(config, projectIdOrKey) | GET /rest/api/3/project/{projectIdOrKey}/role | Get project roles |
| getProjectRole(config, projectIdOrKey, roleId) | GET /rest/api/3/project/{projectIdOrKey}/role/{roleId} | Get a project role |
| getProjectStatuses(config, projectIdOrKey) | GET /rest/api/3/project/{projectIdOrKey}/statuses | Get project statuses |
| getProjectVersions(config, projectIdOrKey, expand?) | GET /rest/api/3/project/{projectIdOrKey}/versions | Get project versions |
JiraUserService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getUser(config, accountId, expand?) | GET /rest/api/3/user | Get user by account ID |
| searchUsers(config, query, startAt?, maxResults?) | GET /rest/api/3/user/search | Search for users |
| getUserPicker(config, query, ...) | GET /rest/api/3/user/picker | Get user picker suggestions |
| getMyself(config, expand?) | GET /rest/api/3/myself | Get current user |
JiraEventService
| Method | Endpoint | Description |
|--------|----------|-------------|
| getEvents(config) | GET /rest/api/3/events | Get all issue events (requires Administer Jira permission) |
Type Definitions
JiraConfig
interface JiraConfig {
auth: {
token: string;
user: string;
};
baseUrl?: string;
}Common Types
JiraIssue: Complete issue object with fields, metadata, and propertiesJiraProject: Project informationJiraUser: User informationJiraComment: Comment with ADF (Atlassian Document Format) supportJiraWorklog: Worklog entry for time trackingJiraAttachment: File attachment informationJiraSearchResult: Search results with paginationJiraPageBean<T>: Paginated response wrapperJiraWebhook: Webhook information with events, filters, and expirationJiraFailedWebhook: Failed webhook information for monitoring
All types support the Atlassian Document Format (ADF) for rich text content in descriptions, comments, and other text fields.
Error Handling
The module includes comprehensive error handling that provides detailed information about:
- HTTP Status Codes: Identifies error types (400, 401, 403, 404, 422, etc.)
- Error Messages: Shows specific error messages from Jira API
- Validation Errors: Lists fields that failed validation
- Contextual Information: Includes endpoint, HTTP method, and request details
- Jira Error Collection: Structured error responses from Jira
Example Error Handling
try {
await this.issueService.createIssue(null, request);
} catch (error: any) {
console.log(error.statusCode); // HTTP status code
console.log(error.responseData); // Full response data
console.log(error.message); // Detailed error message
}Notes
- API Version: This module uses Jira Cloud Platform REST API v3, which supports Atlassian Document Format (ADF) for rich text content
- Authentication: Uses Basic Authentication with API token and user email
- Configuration: All service methods accept
config: JiraConfig | null = nullas the first parameter. Passnullto use settings, or provide config for per-request authentication - Type Safety: All request and response types are fully typed for better IDE support and compile-time error checking
- Logging: All API calls are automatically logged with timing information using
AppLoggerfrom@venturialstd/core - Rate Limiting: Be aware of Jira's rate limits when making multiple API calls
- Permissions: Most operations require specific Jira permissions. Ensure your API token has the necessary permissions
- Bulk Operations: Bulk operations have limits (e.g., 50 for create, 100 for fetch, 1000 for archive)
- ADF Format: Descriptions, comments, and textarea custom fields use ADF format. Single-line text fields accept plain strings
- Pagination: Many endpoints support pagination with
startAtandmaxResultsparameters - Expand Parameters: Use
expandparameters to include additional data in responses (e.g.,expand=names,renderedFields)
Examples
Create an Issue with ADF Description
const issue = await this.issueService.createIssue(null, {
fields: {
project: { key: 'PROJ' },
summary: 'Fix critical bug',
description: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [
{ type: 'text', text: 'This is a ' },
{ type: 'text', text: 'critical', marks: [{ type: 'strong' }] },
{ type: 'text', text: ' bug that needs immediate attention.' },
],
},
],
},
issuetype: { name: 'Bug' },
priority: { name: 'Highest' },
},
});Search Issues with JQL
const results = await this.searchService.searchIssues(null, {
jql: 'project = PROJ AND status = "In Progress"',
maxResults: 50,
fields: ['summary', 'status', 'assignee'],
});
results.issues.forEach(issue => {
console.log(`${issue.key}: ${issue.fields.summary}`);
});Add Worklog
await this.worklogService.addWorklog(null, 'PROJ-123', {
timeSpent: '2h 30m',
started: '2024-01-15T10:00:00.000+0000',
comment: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Worked on fixing the bug' }],
},
],
},
});Transition an Issue
await this.issueService.transitionIssue(null, 'PROJ-123', {
transition: { id: '21' },
fields: {
resolution: { name: 'Fixed' },
},
update: {
comment: [
{
add: {
body: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Issue has been resolved' }],
},
],
},
},
},
],
},
});Register Webhooks
const result = await this.webhookService.registerWebhooks(null, {
url: 'https://your-app.example.com/webhook-received',
webhooks: [
{
events: ['jira:issue_created', 'jira:issue_updated'],
jqlFilter: 'project = PROJ',
fieldIdsFilter: ['summary', 'customfield_10029'],
},
{
events: ['jira:issue_deleted'],
jqlFilter: 'project IN (PROJ, EXP) AND status = done',
},
],
});
// Check registration results
result.webhookRegistrationResult.forEach((result, index) => {
if (result.createdWebhookId) {
console.log(`Webhook ${index} registered with ID: ${result.createdWebhookId}`);
} else if (result.errors) {
console.error(`Webhook ${index} failed:`, result.errors);
}
});Get and Manage Webhooks
// Get all webhooks
const webhooks = await this.webhookService.getWebhooks(null, {
startAt: 0,
maxResults: 50,
});
// Extend webhook life (webhooks expire after 30 days)
await this.webhookService.extendWebhookLife(null, {
webhookIds: [10000, 10001],
});
// Get failed webhooks
const failedWebhooks = await this.webhookService.getFailedWebhooks(null, {
maxResults: 100,
after: 1573118132000, // Optional: cursor for pagination
});
// Delete webhooks
await this.webhookService.deleteWebhooks(null, {
webhookIds: [10000, 10001],
});License
MIT
Support
For issues, questions, or contributions, please contact the Venturial development team.
