n8n-nodes-github-copilot 3.2.4 → 3.2.6

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.
@@ -82,7 +82,7 @@ exports.nodeProperties = [
82
82
  name: 'includeMedia',
83
83
  type: 'boolean',
84
84
  default: false,
85
- description: 'Whether to include a media file (image or audio) in the message. Type is auto-detected.',
85
+ description: 'Whether to include a media file in the message. Supported: Images (PNG, JPEG, GIF, WebP) and Audio files. Type is auto-detected.',
86
86
  },
87
87
  {
88
88
  displayName: 'Media Source',
@@ -125,7 +125,7 @@ exports.nodeProperties = [
125
125
  },
126
126
  default: '',
127
127
  placeholder: 'Paste base64 string or file path',
128
- description: 'Media file as base64 string or file path (auto-detects image/audio)',
128
+ description: 'Media file as base64 string or file path (Images: PNG/JPEG/GIF/WebP, Audio: MP3/WAV/M4A)',
129
129
  },
130
130
  {
131
131
  displayName: 'Media URL',
@@ -139,7 +139,7 @@ exports.nodeProperties = [
139
139
  },
140
140
  default: '',
141
141
  placeholder: 'https://example.com/file.jpg',
142
- description: 'URL of the media file to download and include',
142
+ description: 'URL of the media file to download and include (Images: PNG/JPEG/GIF/WebP, Audio: MP3/WAV/M4A)',
143
143
  },
144
144
  {
145
145
  displayName: 'Media Binary Property',
@@ -7,3 +7,9 @@ export declare function processMediaFile(context: IExecuteFunctions, itemIndex:
7
7
  }>;
8
8
  export declare function isImageMimeType(mimeType: string): boolean;
9
9
  export declare function isAudioMimeType(mimeType: string): boolean;
10
+ export declare function validateImageFormat(mimeType: string): {
11
+ isValid: boolean;
12
+ error?: string;
13
+ };
14
+ export declare function getFileExtensionFromMimeType(mimeType: string): string;
15
+ export declare function suggestImageConversion(mimeType: string): string;
@@ -1,30 +1,144 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isAudioMimeType = exports.isImageMimeType = exports.processMediaFile = void 0;
3
+ exports.suggestImageConversion = exports.getFileExtensionFromMimeType = exports.validateImageFormat = exports.isAudioMimeType = exports.isImageMimeType = exports.processMediaFile = void 0;
4
4
  const index_1 = require("./index");
5
- async function processMediaFile(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty) {
5
+ async function detectMimeType(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty) {
6
+ var _a, _b;
6
7
  try {
7
- try {
8
- const imageResult = await (0, index_1.processImageFile)(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
9
- return {
10
- type: 'image',
11
- dataUrl: `data:${imageResult.mimeType};base64,${imageResult.data}`,
12
- description: `Image file: ${imageResult.filename} (${Math.round(imageResult.size / 1024)}KB)`,
13
- mimeType: imageResult.mimeType,
8
+ if (source === 'binary') {
9
+ const binaryData = context.getInputData()[itemIndex].binary;
10
+ if (binaryData && binaryProperty && binaryData[binaryProperty]) {
11
+ return binaryData[binaryProperty].mimeType || 'application/octet-stream';
12
+ }
13
+ }
14
+ else if (source === 'url' && mediaUrl) {
15
+ const extension = (_a = mediaUrl.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
16
+ const extToMime = {
17
+ 'png': 'image/png',
18
+ 'jpg': 'image/jpeg',
19
+ 'jpeg': 'image/jpeg',
20
+ 'gif': 'image/gif',
21
+ 'webp': 'image/webp',
22
+ 'mp3': 'audio/mpeg',
23
+ 'wav': 'audio/wav',
24
+ 'm4a': 'audio/mp4',
25
+ 'ogg': 'audio/ogg',
26
+ 'mp4': 'video/mp4'
14
27
  };
28
+ return extToMime[extension || ''] || 'application/octet-stream';
15
29
  }
16
- catch (imageError) {
30
+ else if (source === 'manual' && mediaFile) {
31
+ if (mediaFile.startsWith('data:')) {
32
+ const mimeMatch = mediaFile.match(/data:([^;]+)/);
33
+ if (mimeMatch)
34
+ return mimeMatch[1];
35
+ }
36
+ const extension = (_b = mediaFile.split('.').pop()) === null || _b === void 0 ? void 0 : _b.toLowerCase();
37
+ const extToMime = {
38
+ 'png': 'image/png',
39
+ 'jpg': 'image/jpeg',
40
+ 'jpeg': 'image/jpeg',
41
+ 'gif': 'image/gif',
42
+ 'webp': 'image/webp',
43
+ 'mp3': 'audio/mpeg',
44
+ 'wav': 'audio/wav',
45
+ 'm4a': 'audio/mp4',
46
+ 'ogg': 'audio/ogg',
47
+ 'mp4': 'video/mp4'
48
+ };
49
+ return extToMime[extension || ''] || 'application/octet-stream';
50
+ }
51
+ }
52
+ catch (error) {
53
+ }
54
+ return 'application/octet-stream';
55
+ }
56
+ async function processMediaFile(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty) {
57
+ try {
58
+ const detectedMimeType = await detectMimeType(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
59
+ const isLikelyImage = isImageMimeType(detectedMimeType);
60
+ const isLikelyAudio = isAudioMimeType(detectedMimeType);
61
+ if (isLikelyAudio && !isLikelyImage) {
17
62
  try {
18
63
  const audioResult = await (0, index_1.processAudioFile)(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
19
64
  return {
20
65
  type: 'audio',
21
66
  dataUrl: `data:${audioResult.mimeType};base64,${audioResult.data}`,
22
- description: `Audio file: ${audioResult.filename} (${Math.round(audioResult.size / 1024)}KB)`,
67
+ description: `Audio file: ${audioResult.filename} (${Math.round(audioResult.size / 1024)}KB, ${audioResult.mimeType})`,
23
68
  mimeType: audioResult.mimeType,
24
69
  };
25
70
  }
26
71
  catch (audioError) {
27
- throw new Error(`File is neither a valid image nor audio file. Image error: ${imageError instanceof Error ? imageError.message : 'Unknown'}. Audio error: ${audioError instanceof Error ? audioError.message : 'Unknown'}`);
72
+ throw new Error(`Audio processing failed: ${audioError instanceof Error ? audioError.message : 'Unknown error'}`);
73
+ }
74
+ }
75
+ else if (isLikelyImage && !isLikelyAudio) {
76
+ try {
77
+ const imageResult = await (0, index_1.processImageFile)(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
78
+ const formatValidation = validateImageFormat(imageResult.mimeType);
79
+ if (!formatValidation.isValid) {
80
+ throw new Error(suggestImageConversion(imageResult.mimeType));
81
+ }
82
+ return {
83
+ type: 'image',
84
+ dataUrl: `data:${imageResult.mimeType};base64,${imageResult.data}`,
85
+ description: `Image file: ${imageResult.filename} (${Math.round(imageResult.size / 1024)}KB, ${imageResult.mimeType})`,
86
+ mimeType: imageResult.mimeType,
87
+ };
88
+ }
89
+ catch (imageError) {
90
+ throw new Error(`Image processing failed: ${imageError instanceof Error ? imageError.message : 'Unknown error'}`);
91
+ }
92
+ }
93
+ else {
94
+ if (detectedMimeType.includes('mpeg') || detectedMimeType.includes('mp3')) {
95
+ try {
96
+ const audioResult = await (0, index_1.processAudioFile)(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
97
+ return {
98
+ type: 'audio',
99
+ dataUrl: `data:${audioResult.mimeType};base64,${audioResult.data}`,
100
+ description: `Audio file: ${audioResult.filename} (${Math.round(audioResult.size / 1024)}KB, ${audioResult.mimeType})`,
101
+ mimeType: audioResult.mimeType,
102
+ };
103
+ }
104
+ catch (audioError) {
105
+ throw new Error(`MPEG audio processing failed: ${audioError instanceof Error ? audioError.message : 'Unknown error'}`);
106
+ }
107
+ }
108
+ else {
109
+ try {
110
+ const imageResult = await (0, index_1.processImageFile)(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
111
+ const formatValidation = validateImageFormat(imageResult.mimeType);
112
+ if (!formatValidation.isValid) {
113
+ throw new Error(suggestImageConversion(imageResult.mimeType));
114
+ }
115
+ return {
116
+ type: 'image',
117
+ dataUrl: `data:${imageResult.mimeType};base64,${imageResult.data}`,
118
+ description: `Image file: ${imageResult.filename} (${Math.round(imageResult.size / 1024)}KB, ${imageResult.mimeType})`,
119
+ mimeType: imageResult.mimeType,
120
+ };
121
+ }
122
+ catch (imageError) {
123
+ try {
124
+ const audioResult = await (0, index_1.processAudioFile)(context, itemIndex, source, mediaFile, mediaUrl, binaryProperty);
125
+ return {
126
+ type: 'audio',
127
+ dataUrl: `data:${audioResult.mimeType};base64,${audioResult.data}`,
128
+ description: `Audio file: ${audioResult.filename} (${Math.round(audioResult.size / 1024)}KB, ${audioResult.mimeType})`,
129
+ mimeType: audioResult.mimeType,
130
+ };
131
+ }
132
+ catch (audioError) {
133
+ const supportedImageFormats = ['PNG', 'JPEG', 'GIF', 'WebP'];
134
+ const supportedAudioFormats = ['MP3', 'WAV', 'M4A', 'OGG'];
135
+ throw new Error(`File is neither a valid image nor audio file (detected MIME: ${detectedMimeType}).\n` +
136
+ `Supported image formats: ${supportedImageFormats.join(', ')}\n` +
137
+ `Supported audio formats: ${supportedAudioFormats.join(', ')}\n` +
138
+ `Image error: ${imageError instanceof Error ? imageError.message : 'Unknown'}\n` +
139
+ `Audio error: ${audioError instanceof Error ? audioError.message : 'Unknown'}`);
140
+ }
141
+ }
28
142
  }
29
143
  }
30
144
  }
@@ -38,7 +152,14 @@ async function processMediaFile(context, itemIndex, source, mediaFile, mediaUrl,
38
152
  }
39
153
  exports.processMediaFile = processMediaFile;
40
154
  function isImageMimeType(mimeType) {
41
- return mimeType.startsWith('image/') && !mimeType.includes('svg');
155
+ const supportedFormats = [
156
+ 'image/png',
157
+ 'image/jpeg',
158
+ 'image/jpg',
159
+ 'image/gif',
160
+ 'image/webp'
161
+ ];
162
+ return supportedFormats.includes(mimeType.toLowerCase());
42
163
  }
43
164
  exports.isImageMimeType = isImageMimeType;
44
165
  function isAudioMimeType(mimeType) {
@@ -47,3 +168,36 @@ function isAudioMimeType(mimeType) {
47
168
  mimeType === 'video/mp4';
48
169
  }
49
170
  exports.isAudioMimeType = isAudioMimeType;
171
+ function validateImageFormat(mimeType) {
172
+ if (!isImageMimeType(mimeType)) {
173
+ const supportedFormats = ['PNG', 'JPEG', 'GIF', 'WebP'];
174
+ return {
175
+ isValid: false,
176
+ error: `Unsupported image format: ${mimeType}. GitHub Copilot API only supports: ${supportedFormats.join(', ')}`
177
+ };
178
+ }
179
+ return { isValid: true };
180
+ }
181
+ exports.validateImageFormat = validateImageFormat;
182
+ function getFileExtensionFromMimeType(mimeType) {
183
+ const mimeToExt = {
184
+ 'image/png': 'png',
185
+ 'image/jpeg': 'jpg',
186
+ 'image/jpg': 'jpg',
187
+ 'image/gif': 'gif',
188
+ 'image/webp': 'webp',
189
+ 'image/bmp': 'bmp',
190
+ 'image/tiff': 'tiff',
191
+ 'image/svg+xml': 'svg',
192
+ };
193
+ return mimeToExt[mimeType.toLowerCase()] || 'unknown';
194
+ }
195
+ exports.getFileExtensionFromMimeType = getFileExtensionFromMimeType;
196
+ function suggestImageConversion(mimeType) {
197
+ const ext = getFileExtensionFromMimeType(mimeType);
198
+ const supportedFormats = ['PNG', 'JPEG', 'GIF', 'WebP'];
199
+ return `Image format ${ext.toUpperCase()} is not supported by GitHub Copilot API. ` +
200
+ `Please convert your image to one of these formats: ${supportedFormats.join(', ')}. ` +
201
+ `Recommended: Convert to PNG or WebP for best compatibility.`;
202
+ }
203
+ exports.suggestImageConversion = suggestImageConversion;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.2.4",
3
+ "version": "3.2.6",
4
4
  "description": "n8n community node for GitHub Copilot with CLI integration and official Chat API access to GPT-5, Claude, Gemini and more using your existing Copilot credits",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",