Skip to content

Commit

Permalink
#327: Package form-data replaced to formdata-node for add esm sup…
Browse files Browse the repository at this point in the history
…port (#341)

* #327: Package `form-data` replaced to `formdata-node` for add esm support

* #327: Add `Buffer` type support using `formdata-node` package

- Implemented `Buffer` to `File` conversion for attachment uploads.
- Added `attachment.mimeType` an optional property.
- Added automatic MIME type detection based on file extensions.

* #327: Fixed the issue with the absence of the `File` class in Node.js v18.x.x by using `File` from `formdata-node`.

- Enhanced documentation with TSDoc and examples for better clarity.
  • Loading branch information
MrRefactoring authored Jan 3, 2025
1 parent df8e9d2 commit e050109
Show file tree
Hide file tree
Showing 10 changed files with 517 additions and 553 deletions.
709 changes: 174 additions & 535 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"code:formatting": "npm run replace:all && npm run prettier && npm run lint:fix"
},
"devDependencies": {
"@types/mime-types": "^2.1.4",
"@types/node": "^18.19.69",
"@types/sinon": "^17.0.3",
"@typescript-eslint/eslint-plugin": "^8.19.0",
Expand All @@ -63,7 +64,7 @@
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"prettier": "^3.4.2",
"prettier-plugin-jsdoc": "^1.3.0",
"prettier-plugin-jsdoc": "^1.3.2",
"sinon": "^18.0.1",
"typedoc": "^0.27.6",
"typescript": "^5.7.2",
Expand All @@ -72,7 +73,8 @@
},
"dependencies": {
"axios": "^1.7.9",
"form-data": "^4.0.1",
"formdata-node": "^6.0.3",
"mime-types": "^2.1.35",
"tslib": "^2.8.1"
}
}
92 changes: 91 additions & 1 deletion src/serviceDesk/parameters/attachTemporaryFile.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,103 @@
/**
* Represents an attachment to be temporarily attached to a Service Desk.
*
* @example
* ```typescript
* const attachment: Attachment = {
* filename: 'example.txt',
* file: Buffer.from('Temporary file content'),
* mimeType: 'text/plain',
* };
* ```
*/
export interface Attachment {
/**
* The name of the attachment file.
*
* @example
* ```typescript
* const filename = 'example.png';
* ```
*/
filename: string;

/**
* The content of the attachment. Can be one of the following:
*
* - `Buffer`: For binary data.
* - `ReadableStream`: For streaming large files.
* - `string`: For text-based content.
* - `Blob`: For browser-like blob objects.
* - `File`: For file objects with metadata (e.g., in web environments).
*
* @example
* ```typescript
* const fileContent = Buffer.from('Example content here');
* ```
*/
file: Buffer | ReadableStream | string | Blob | File;

/**
* Optional MIME type of the attachment. Example values include:
*
* - 'application/pdf'
* - 'image/jpeg' If not provided, the MIME type will be automatically detected based on the filename.
*
* @example
* ```typescript
* const mimeType = 'image/jpeg';
* ```
*/
mimeType?: string;
}

/**
* Parameters for attaching temporary files to a Service Desk.
*
* @example
* ```typescript
* const attachTemporaryFileParams: AttachTemporaryFile = {
* serviceDeskId: '5',
* attachment: [
* {
* filename: 'example.txt',
* file: Buffer.from('Temporary file content'),
* mimeType: 'text/plain',
* },
* ],
* };
* ```
*/
export interface AttachTemporaryFile {
/**
* The ID of the Service Desk to which the file will be attached. This can alternatively be a [project
* identifier.](#project-identifiers)
* identifier](#project-identifiers).
*
* @example
* ```typescript
* const serviceDeskId = '5';
* ```
*/
serviceDeskId: string;

/**
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
*
* @example
* ```typescript
* const attachments = [
* {
* filename: 'file1.txt',
* file: Buffer.from('Temporary content 1'),
* mimeType: 'text/plain',
* },
* {
* filename: 'file2.jpeg',
* file: Buffer.from('Temporary content 2'),
* mimeType: 'image/jpeg',
* },
* ];
* ```
*/
attachment: Attachment | Attachment[];
}
13 changes: 10 additions & 3 deletions src/serviceDesk/serviceDesk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as FormData from 'form-data';
import { FormData, File } from 'formdata-node';
import * as mime from 'mime-types';
import * as Models from './models';
import * as Parameters from './parameters';
import { Callback } from '../callback';
Expand Down Expand Up @@ -116,15 +117,21 @@ export class ServiceDesk {
const formData = new FormData();
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];

attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
attachments.forEach(attachment => {
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
const file = Buffer.isBuffer(attachment.file)
? new File([attachment.file], attachment.filename, { type: mimeType })
: attachment.file;

formData.append('file', file, attachment.filename);
});

const config: RequestConfig = {
url: `/rest/servicedeskapi/servicedesk/${parameters.serviceDeskId}/attachTemporaryFile`,
method: 'POST',
headers: {
'X-Atlassian-Token': 'no-check',
'Content-Type': 'multipart/form-data',
...formData.getHeaders?.(),
},
data: formData,
};
Expand Down
14 changes: 10 additions & 4 deletions src/version2/issueAttachments.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-expect-error Wrong form data typings
import FormData from 'form-data';
import { FormData, File } from 'formdata-node';
import * as mime from 'mime-types';
import * as Models from './models';
import * as Parameters from './parameters';
import { Callback } from '../callback';
Expand Down Expand Up @@ -426,15 +426,21 @@ export class IssueAttachments {
const formData = new FormData();
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];

attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
attachments.forEach(attachment => {
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
const file = Buffer.isBuffer(attachment.file)
? new File([attachment.file], attachment.filename, { type: mimeType })
: attachment.file;

formData.append('file', file, attachment.filename);
});

const config: RequestConfig = {
url: `/rest/api/2/issue/${parameters.issueIdOrKey}/attachments`,
method: 'POST',
headers: {
'X-Atlassian-Token': 'no-check',
'Content-Type': 'multipart/form-data',
...formData.getHeaders?.(),
},
data: formData,
maxBodyLength: Infinity,
Expand Down
92 changes: 91 additions & 1 deletion src/version2/parameters/addAttachment.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,101 @@
/**
* Represents an attachment to be added to an issue.
*
* @example
* ```typescript
* const attachment: Attachment = {
* filename: 'example.txt',
* file: Buffer.from('Hello, world!'),
* mimeType: 'text/plain',
* };
* ```
*/
export interface Attachment {
/**
* The name of the attachment file.
*
* @example
* ```typescript
* const filename = 'document.pdf';
* ```
*/
filename: string;

/**
* The content of the attachment. Can be one of the following:
*
* - `Buffer`: For binary data.
* - `ReadableStream`: For streaming large files.
* - `string`: For text-based content.
* - `Blob`: For browser-like blob objects.
* - `File`: For file objects with metadata (e.g., in web environments).
*
* @example
* ```typescript
* const fileContent = fs.readFileSync('./document.pdf');
* ```
*/
file: Buffer | ReadableStream | string | Blob | File;

/**
* Optional MIME type of the attachment. Example values include:
*
* - 'application/pdf'
* - 'image/png'
*
* If not provided, the MIME type will be automatically detected based on the filename.
*
* @example
* ```typescript
* const mimeType = 'application/pdf';
* ```
*/
mimeType?: string;
}

/**
* Parameters for adding attachments to an issue.
*
* @example
* ```typescript
* const addAttachmentParams: AddAttachment = {
* issueIdOrKey: 'PROJECT-123',
* attachment: {
* filename: 'example.txt',
* file: 'Hello, world!',
* mimeType: 'text/plain',
* },
* };
* ```
*/
export interface AddAttachment {
/** The ID or key of the issue that attachments are added to. */
/**
* The ID or key of the issue to which the attachments will be added.
*
* @example
* ```typescript
* const issueIdOrKey = 'PROJECT-123';
* ```
*/
issueIdOrKey: string;

/**
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
*
* @example
* ```typescript
* const attachments = [
* {
* filename: 'file1.txt',
* file: Buffer.from('File 1 content'),
* mimeType: 'text/plain',
* },
* {
* filename: 'proof image.png',
* file: fs.readFileSync('./image.png'), // Reads the image file into a Buffer
* },
* ];
* ```
*/
attachment: Attachment | Attachment[];
}
14 changes: 10 additions & 4 deletions src/version3/issueAttachments.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-expect-error Wrong form data typings
import FormData from 'form-data';
import { FormData, File } from 'formdata-node';
import * as mime from 'mime-types';
import * as Models from './models';
import * as Parameters from './parameters';
import { Callback } from '../callback';
Expand Down Expand Up @@ -426,15 +426,21 @@ export class IssueAttachments {
const formData = new FormData();
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];

attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
attachments.forEach(attachment => {
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
const file = Buffer.isBuffer(attachment.file)
? new File([attachment.file], attachment.filename, { type: mimeType })
: attachment.file;

formData.append('file', file, attachment.filename);
});

const config: RequestConfig = {
url: `/rest/api/3/issue/${parameters.issueIdOrKey}/attachments`,
method: 'POST',
headers: {
'X-Atlassian-Token': 'no-check',
'Content-Type': 'multipart/form-data',
...formData.getHeaders?.(),
},
data: formData,
maxBodyLength: Infinity,
Expand Down
Loading

0 comments on commit e050109

Please sign in to comment.