Skip to content

Commit e050109

Browse files
#327: Package form-data replaced to formdata-node for add esm support (#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.
1 parent df8e9d2 commit e050109

File tree

10 files changed

+517
-553
lines changed

10 files changed

+517
-553
lines changed

package-lock.json

Lines changed: 174 additions & 535 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"code:formatting": "npm run replace:all && npm run prettier && npm run lint:fix"
5454
},
5555
"devDependencies": {
56+
"@types/mime-types": "^2.1.4",
5657
"@types/node": "^18.19.69",
5758
"@types/sinon": "^17.0.3",
5859
"@typescript-eslint/eslint-plugin": "^8.19.0",
@@ -63,7 +64,7 @@
6364
"eslint-import-resolver-typescript": "^3.7.0",
6465
"eslint-plugin-import": "^2.31.0",
6566
"prettier": "^3.4.2",
66-
"prettier-plugin-jsdoc": "^1.3.0",
67+
"prettier-plugin-jsdoc": "^1.3.2",
6768
"sinon": "^18.0.1",
6869
"typedoc": "^0.27.6",
6970
"typescript": "^5.7.2",
@@ -72,7 +73,8 @@
7273
},
7374
"dependencies": {
7475
"axios": "^1.7.9",
75-
"form-data": "^4.0.1",
76+
"formdata-node": "^6.0.3",
77+
"mime-types": "^2.1.35",
7678
"tslib": "^2.8.1"
7779
}
7880
}
Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,103 @@
1+
/**
2+
* Represents an attachment to be temporarily attached to a Service Desk.
3+
*
4+
* @example
5+
* ```typescript
6+
* const attachment: Attachment = {
7+
* filename: 'example.txt',
8+
* file: Buffer.from('Temporary file content'),
9+
* mimeType: 'text/plain',
10+
* };
11+
* ```
12+
*/
113
export interface Attachment {
14+
/**
15+
* The name of the attachment file.
16+
*
17+
* @example
18+
* ```typescript
19+
* const filename = 'example.png';
20+
* ```
21+
*/
222
filename: string;
23+
24+
/**
25+
* The content of the attachment. Can be one of the following:
26+
*
27+
* - `Buffer`: For binary data.
28+
* - `ReadableStream`: For streaming large files.
29+
* - `string`: For text-based content.
30+
* - `Blob`: For browser-like blob objects.
31+
* - `File`: For file objects with metadata (e.g., in web environments).
32+
*
33+
* @example
34+
* ```typescript
35+
* const fileContent = Buffer.from('Example content here');
36+
* ```
37+
*/
338
file: Buffer | ReadableStream | string | Blob | File;
39+
40+
/**
41+
* Optional MIME type of the attachment. Example values include:
42+
*
43+
* - 'application/pdf'
44+
* - 'image/jpeg' If not provided, the MIME type will be automatically detected based on the filename.
45+
*
46+
* @example
47+
* ```typescript
48+
* const mimeType = 'image/jpeg';
49+
* ```
50+
*/
51+
mimeType?: string;
452
}
553

54+
/**
55+
* Parameters for attaching temporary files to a Service Desk.
56+
*
57+
* @example
58+
* ```typescript
59+
* const attachTemporaryFileParams: AttachTemporaryFile = {
60+
* serviceDeskId: '5',
61+
* attachment: [
62+
* {
63+
* filename: 'example.txt',
64+
* file: Buffer.from('Temporary file content'),
65+
* mimeType: 'text/plain',
66+
* },
67+
* ],
68+
* };
69+
* ```
70+
*/
671
export interface AttachTemporaryFile {
772
/**
873
* The ID of the Service Desk to which the file will be attached. This can alternatively be a [project
9-
* identifier.](#project-identifiers)
74+
* identifier](#project-identifiers).
75+
*
76+
* @example
77+
* ```typescript
78+
* const serviceDeskId = '5';
79+
* ```
1080
*/
1181
serviceDeskId: string;
82+
83+
/**
84+
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
85+
*
86+
* @example
87+
* ```typescript
88+
* const attachments = [
89+
* {
90+
* filename: 'file1.txt',
91+
* file: Buffer.from('Temporary content 1'),
92+
* mimeType: 'text/plain',
93+
* },
94+
* {
95+
* filename: 'file2.jpeg',
96+
* file: Buffer.from('Temporary content 2'),
97+
* mimeType: 'image/jpeg',
98+
* },
99+
* ];
100+
* ```
101+
*/
12102
attachment: Attachment | Attachment[];
13103
}

src/serviceDesk/serviceDesk.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import * as FormData from 'form-data';
1+
import { FormData, File } from 'formdata-node';
2+
import * as mime from 'mime-types';
23
import * as Models from './models';
34
import * as Parameters from './parameters';
45
import { Callback } from '../callback';
@@ -116,15 +117,21 @@ export class ServiceDesk {
116117
const formData = new FormData();
117118
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];
118119

119-
attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
120+
attachments.forEach(attachment => {
121+
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
122+
const file = Buffer.isBuffer(attachment.file)
123+
? new File([attachment.file], attachment.filename, { type: mimeType })
124+
: attachment.file;
125+
126+
formData.append('file', file, attachment.filename);
127+
});
120128

121129
const config: RequestConfig = {
122130
url: `/rest/servicedeskapi/servicedesk/${parameters.serviceDeskId}/attachTemporaryFile`,
123131
method: 'POST',
124132
headers: {
125133
'X-Atlassian-Token': 'no-check',
126134
'Content-Type': 'multipart/form-data',
127-
...formData.getHeaders?.(),
128135
},
129136
data: formData,
130137
};

src/version2/issueAttachments.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// @ts-expect-error Wrong form data typings
2-
import FormData from 'form-data';
1+
import { FormData, File } from 'formdata-node';
2+
import * as mime from 'mime-types';
33
import * as Models from './models';
44
import * as Parameters from './parameters';
55
import { Callback } from '../callback';
@@ -426,15 +426,21 @@ export class IssueAttachments {
426426
const formData = new FormData();
427427
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];
428428

429-
attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
429+
attachments.forEach(attachment => {
430+
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
431+
const file = Buffer.isBuffer(attachment.file)
432+
? new File([attachment.file], attachment.filename, { type: mimeType })
433+
: attachment.file;
434+
435+
formData.append('file', file, attachment.filename);
436+
});
430437

431438
const config: RequestConfig = {
432439
url: `/rest/api/2/issue/${parameters.issueIdOrKey}/attachments`,
433440
method: 'POST',
434441
headers: {
435442
'X-Atlassian-Token': 'no-check',
436443
'Content-Type': 'multipart/form-data',
437-
...formData.getHeaders?.(),
438444
},
439445
data: formData,
440446
maxBodyLength: Infinity,
Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,101 @@
1+
/**
2+
* Represents an attachment to be added to an issue.
3+
*
4+
* @example
5+
* ```typescript
6+
* const attachment: Attachment = {
7+
* filename: 'example.txt',
8+
* file: Buffer.from('Hello, world!'),
9+
* mimeType: 'text/plain',
10+
* };
11+
* ```
12+
*/
113
export interface Attachment {
14+
/**
15+
* The name of the attachment file.
16+
*
17+
* @example
18+
* ```typescript
19+
* const filename = 'document.pdf';
20+
* ```
21+
*/
222
filename: string;
23+
24+
/**
25+
* The content of the attachment. Can be one of the following:
26+
*
27+
* - `Buffer`: For binary data.
28+
* - `ReadableStream`: For streaming large files.
29+
* - `string`: For text-based content.
30+
* - `Blob`: For browser-like blob objects.
31+
* - `File`: For file objects with metadata (e.g., in web environments).
32+
*
33+
* @example
34+
* ```typescript
35+
* const fileContent = fs.readFileSync('./document.pdf');
36+
* ```
37+
*/
338
file: Buffer | ReadableStream | string | Blob | File;
39+
40+
/**
41+
* Optional MIME type of the attachment. Example values include:
42+
*
43+
* - 'application/pdf'
44+
* - 'image/png'
45+
*
46+
* If not provided, the MIME type will be automatically detected based on the filename.
47+
*
48+
* @example
49+
* ```typescript
50+
* const mimeType = 'application/pdf';
51+
* ```
52+
*/
53+
mimeType?: string;
454
}
555

56+
/**
57+
* Parameters for adding attachments to an issue.
58+
*
59+
* @example
60+
* ```typescript
61+
* const addAttachmentParams: AddAttachment = {
62+
* issueIdOrKey: 'PROJECT-123',
63+
* attachment: {
64+
* filename: 'example.txt',
65+
* file: 'Hello, world!',
66+
* mimeType: 'text/plain',
67+
* },
68+
* };
69+
* ```
70+
*/
671
export interface AddAttachment {
7-
/** The ID or key of the issue that attachments are added to. */
72+
/**
73+
* The ID or key of the issue to which the attachments will be added.
74+
*
75+
* @example
76+
* ```typescript
77+
* const issueIdOrKey = 'PROJECT-123';
78+
* ```
79+
*/
880
issueIdOrKey: string;
981

82+
/**
83+
* The attachment(s) to be added. Can be a single `Attachment` object or an array of `Attachment` objects.
84+
*
85+
* @example
86+
* ```typescript
87+
* const attachments = [
88+
* {
89+
* filename: 'file1.txt',
90+
* file: Buffer.from('File 1 content'),
91+
* mimeType: 'text/plain',
92+
* },
93+
* {
94+
* filename: 'proof image.png',
95+
* file: fs.readFileSync('./image.png'), // Reads the image file into a Buffer
96+
* },
97+
* ];
98+
* ```
99+
*/
10100
attachment: Attachment | Attachment[];
11101
}

src/version3/issueAttachments.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// @ts-expect-error Wrong form data typings
2-
import FormData from 'form-data';
1+
import { FormData, File } from 'formdata-node';
2+
import * as mime from 'mime-types';
33
import * as Models from './models';
44
import * as Parameters from './parameters';
55
import { Callback } from '../callback';
@@ -426,15 +426,21 @@ export class IssueAttachments {
426426
const formData = new FormData();
427427
const attachments = Array.isArray(parameters.attachment) ? parameters.attachment : [parameters.attachment];
428428

429-
attachments.forEach(attachment => formData.append('file', attachment.file, attachment.filename));
429+
attachments.forEach(attachment => {
430+
const mimeType = attachment.mimeType ?? (mime.lookup(attachment.filename) || undefined);
431+
const file = Buffer.isBuffer(attachment.file)
432+
? new File([attachment.file], attachment.filename, { type: mimeType })
433+
: attachment.file;
434+
435+
formData.append('file', file, attachment.filename);
436+
});
430437

431438
const config: RequestConfig = {
432439
url: `/rest/api/3/issue/${parameters.issueIdOrKey}/attachments`,
433440
method: 'POST',
434441
headers: {
435442
'X-Atlassian-Token': 'no-check',
436443
'Content-Type': 'multipart/form-data',
437-
...formData.getHeaders?.(),
438444
},
439445
data: formData,
440446
maxBodyLength: Infinity,

0 commit comments

Comments
 (0)