n8n-nodes-commandos-image 0.1.9 → 0.1.10

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.
@@ -1,7 +1,3 @@
1
- /**
2
- * Version 0.1.9: Forced lightweight formats (JPEG/JPG) for ALL models.
3
- * Removed the Output Format option from the UI to avoid confusion.
4
- */
5
1
  import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
6
2
  export declare class CommandosImage implements INodeType {
7
3
  description: INodeTypeDescription;
@@ -24,7 +24,7 @@ const mapRatio = (model, ratio) => {
24
24
  }
25
25
  return ratio;
26
26
  };
27
- const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'basic', resolution = '1K', }) => {
27
+ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'basic', resolution = '1K', outputFormat, }) => {
28
28
  const hasReferences = references.length > 0;
29
29
  const requestedModel = model;
30
30
  let resolvedModel = model;
@@ -62,7 +62,7 @@ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'b
62
62
  prompt,
63
63
  aspect_ratio: ratio,
64
64
  resolution,
65
- output_format: 'jpeg', // Force jpeg
65
+ output_format: 'jpeg',
66
66
  ...(hasReferences ? { input_urls: references } : {}),
67
67
  },
68
68
  };
@@ -74,7 +74,7 @@ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'b
74
74
  prompt,
75
75
  aspect_ratio: mapRatio(resolvedModel, ratio),
76
76
  quality,
77
- output_format: 'jpeg', // Force jpeg
77
+ output_format: 'jpeg',
78
78
  ...(hasReferences ? { image_urls: references } : {}),
79
79
  },
80
80
  };
@@ -86,7 +86,7 @@ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'b
86
86
  prompt,
87
87
  aspect_ratio: ratio,
88
88
  resolution,
89
- output_format: 'jpg', // Force jpg for pro
89
+ output_format: outputFormat || 'jpg', // User selection or fallback to jpg
90
90
  ...(hasReferences ? { image_input: references } : {}),
91
91
  },
92
92
  };
@@ -97,7 +97,7 @@ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'b
97
97
  input: {
98
98
  prompt,
99
99
  image_size: ratio,
100
- output_format: 'jpeg', // Force jpeg
100
+ output_format: 'jpeg',
101
101
  ...(hasReferences ? { image_urls: references } : {}),
102
102
  },
103
103
  };
@@ -119,7 +119,7 @@ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'b
119
119
  image_urls: references,
120
120
  prompt,
121
121
  image_size: mapRatio('seedream', ratio),
122
- output_format: 'jpeg', // Default jpeg
122
+ output_format: 'jpeg',
123
123
  },
124
124
  };
125
125
  }
@@ -134,9 +134,8 @@ const buildGenerationRequest = ({ model, prompt, ratio, references, quality = 'b
134
134
  };
135
135
  };
136
136
  const extractReferences = (raw, model) => {
137
- if (!raw || typeof raw !== 'object') {
137
+ if (!raw || typeof raw !== 'object')
138
138
  return [];
139
- }
140
139
  const collection = raw;
141
140
  const items = Array.isArray(collection.reference) ? collection.reference : [];
142
141
  let limit = 8;
@@ -146,10 +145,7 @@ const extractReferences = (raw, model) => {
146
145
  limit = 16;
147
146
  if (model.includes('nano-banana'))
148
147
  limit = 10;
149
- return items
150
- .map((entry) => String((entry === null || entry === void 0 ? void 0 : entry.url) || '').trim())
151
- .filter((value) => value.length > 0 && /^https?:\/\//i.test(value))
152
- .slice(0, limit);
148
+ return items.map((entry) => String((entry === null || entry === void 0 ? void 0 : entry.url) || '').trim()).filter((v) => v.length > 0 && /^https?:\/\//i.test(v)).slice(0, limit);
153
149
  };
154
150
  class CommandosImage {
155
151
  constructor() {
@@ -159,18 +155,11 @@ class CommandosImage {
159
155
  group: ['transform'],
160
156
  version: 1,
161
157
  description: 'Create image tasks in Commandos API',
162
- defaults: {
163
- name: 'Commandos Image',
164
- },
158
+ defaults: { name: 'Commandos Image' },
165
159
  icon: 'file:Image.png',
166
160
  inputs: ['main'],
167
161
  outputs: ['main'],
168
- credentials: [
169
- {
170
- name: 'commandosApi',
171
- required: true,
172
- },
173
- ],
162
+ credentials: [{ name: 'commandosApi', required: true }],
174
163
  properties: [
175
164
  {
176
165
  displayName: 'Operation',
@@ -222,7 +211,37 @@ class CommandosImage {
222
211
  { name: '21:9', value: '21:9' },
223
212
  ],
224
213
  default: '2:3',
225
- displayOptions: { show: { operation: ['create'] } },
214
+ displayOptions: {
215
+ show: { operation: ['create'] },
216
+ hide: { model: ['gpt4o-image'] },
217
+ },
218
+ },
219
+ {
220
+ displayName: 'Ratio',
221
+ name: 'ratioGpt',
222
+ type: 'options',
223
+ options: [
224
+ { name: '1:1', value: '1:1' },
225
+ { name: '2:3', value: '2:3' },
226
+ { name: '3:2', value: '3:2' },
227
+ ],
228
+ default: '2:3',
229
+ displayOptions: {
230
+ show: { operation: ['create'], model: ['gpt4o-image'] },
231
+ },
232
+ },
233
+ {
234
+ displayName: 'Output Format',
235
+ name: 'outputFormatBananaPro',
236
+ type: 'options',
237
+ options: [
238
+ { name: 'PNG', value: 'png' },
239
+ { name: 'JPG', value: 'jpg' },
240
+ ],
241
+ default: 'jpg',
242
+ displayOptions: {
243
+ show: { operation: ['create'], model: ['nano-banana-pro'] },
244
+ },
226
245
  },
227
246
  {
228
247
  displayName: 'Quality',
@@ -235,10 +254,7 @@ class CommandosImage {
235
254
  ],
236
255
  default: 'basic',
237
256
  displayOptions: {
238
- show: {
239
- operation: ['create'],
240
- model: ['seedream', 'gpt4o-image', 'flux-pro'],
241
- },
257
+ show: { operation: ['create'], model: ['seedream', 'gpt4o-image', 'flux-pro'] },
242
258
  },
243
259
  },
244
260
  {
@@ -252,10 +268,7 @@ class CommandosImage {
252
268
  ],
253
269
  default: '1K',
254
270
  displayOptions: {
255
- show: {
256
- operation: ['create'],
257
- model: ['flux-pro', 'nano-banana-pro'],
258
- },
271
+ show: { operation: ['create'], model: ['flux-pro', 'nano-banana-pro'] },
259
272
  },
260
273
  },
261
274
  {
@@ -268,14 +281,7 @@ class CommandosImage {
268
281
  {
269
282
  name: 'reference',
270
283
  displayName: 'Reference',
271
- values: [
272
- {
273
- displayName: 'Reference URL',
274
- name: 'url',
275
- type: 'string',
276
- default: '',
277
- },
278
- ],
284
+ values: [{ displayName: 'Reference URL', name: 'url', type: 'string', default: '' }],
279
285
  },
280
286
  ],
281
287
  displayOptions: { show: { operation: ['create'] } },
@@ -295,44 +301,33 @@ class CommandosImage {
295
301
  const operation = this.getNodeParameter('operation', 0);
296
302
  const credentials = await this.getCredentials('commandosApi');
297
303
  const licenseKey = String(credentials.licenseKey || '').trim();
298
- if (!licenseKey) {
304
+ if (!licenseKey)
299
305
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'License key is required');
300
- }
301
306
  const results = [];
302
307
  for (let i = 0; i < items.length; i += 1) {
303
308
  try {
304
309
  if (operation === 'create') {
305
310
  const model = String(this.getNodeParameter('model', i));
306
311
  const prompt = String(this.getNodeParameter('prompt', i) || '').trim();
307
- const ratio = String(this.getNodeParameter('ratio', i));
312
+ let ratio = '';
313
+ if (model === 'gpt4o-image') {
314
+ ratio = String(this.getNodeParameter('ratioGpt', i));
315
+ }
316
+ else {
317
+ ratio = String(this.getNodeParameter('ratio', i));
318
+ }
308
319
  const references = extractReferences(this.getNodeParameter('references', i, {}), model);
309
- const quality = ['seedream', 'gpt4o-image', 'flux-pro'].includes(model)
310
- ? String(this.getNodeParameter('quality', i, 'basic'))
311
- : 'basic';
312
- const resolution = ['flux-pro', 'nano-banana-pro'].includes(model)
313
- ? String(this.getNodeParameter('resolution', i, '1K'))
314
- : '1K';
315
- if (!prompt) {
320
+ const quality = ['seedream', 'gpt4o-image', 'flux-pro'].includes(model) ? String(this.getNodeParameter('quality', i, 'basic')) : 'basic';
321
+ const resolution = ['flux-pro', 'nano-banana-pro'].includes(model) ? String(this.getNodeParameter('resolution', i, '1K')) : '1K';
322
+ const outputFormat = (model === 'nano-banana-pro') ? String(this.getNodeParameter('outputFormatBananaPro', i, 'jpg')) : undefined;
323
+ if (!prompt)
316
324
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Prompt is required', { itemIndex: i });
317
- }
318
- const request = buildGenerationRequest({ model, prompt, ratio, references, quality, resolution });
319
- const payload = {
320
- url: request.url,
321
- body: request.body,
322
- requestedModel: request.requestedModel,
323
- resolvedModel: request.resolvedModel,
324
- ratio: request.ratio,
325
- references: request.references,
326
- hasReferences: request.hasReferences,
327
- _v: '0.1.9'
328
- };
325
+ const request = buildGenerationRequest({ model, prompt, ratio, references, quality, resolution, outputFormat });
326
+ const payload = { ...request, licenseKey, _v: '0.1.10' };
329
327
  const response = await this.helpers.request({
330
328
  method: 'POST',
331
329
  url: `${COMMANDOS_API_URL}/tasks`,
332
- headers: {
333
- 'Content-Type': 'application/json',
334
- 'X-License-Key': licenseKey,
335
- },
330
+ headers: { 'Content-Type': 'application/json', 'X-License-Key': licenseKey },
336
331
  body: { process_type: 'IMAGE_GENERATION', payload },
337
332
  json: true,
338
333
  });
@@ -340,9 +335,8 @@ class CommandosImage {
340
335
  }
341
336
  else if (operation === 'status') {
342
337
  const taskId = String(this.getNodeParameter('taskId', i) || '').trim();
343
- if (!taskId) {
338
+ if (!taskId)
344
339
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Task ID is required', { itemIndex: i });
345
- }
346
340
  const response = await this.helpers.request({
347
341
  method: 'GET',
348
342
  url: `${COMMANDOS_API_URL}/tasks/${encodeURIComponent(taskId)}`,
@@ -1,7 +1,3 @@
1
- /**
2
- * Version 0.1.9: Forced lightweight formats (JPEG/JPG) for ALL models.
3
- * Removed the Output Format option from the UI to avoid confusion.
4
- */
5
1
  import type {
6
2
  IDataObject,
7
3
  IExecuteFunctions,
@@ -23,6 +19,7 @@ type BuildParams = {
23
19
  references: string[];
24
20
  quality?: string;
25
21
  resolution?: string;
22
+ outputFormat?: string;
26
23
  };
27
24
 
28
25
  type BuildResult = {
@@ -60,6 +57,7 @@ const buildGenerationRequest = ({
60
57
  references,
61
58
  quality = 'basic',
62
59
  resolution = '1K',
60
+ outputFormat,
63
61
  }: BuildParams): BuildResult => {
64
62
  const hasReferences = references.length > 0;
65
63
  const requestedModel = model;
@@ -98,7 +96,7 @@ const buildGenerationRequest = ({
98
96
  prompt,
99
97
  aspect_ratio: ratio,
100
98
  resolution,
101
- output_format: 'jpeg', // Force jpeg
99
+ output_format: 'jpeg',
102
100
  ...(hasReferences ? { input_urls: references } : {}),
103
101
  },
104
102
  };
@@ -109,7 +107,7 @@ const buildGenerationRequest = ({
109
107
  prompt,
110
108
  aspect_ratio: mapRatio(resolvedModel, ratio),
111
109
  quality,
112
- output_format: 'jpeg', // Force jpeg
110
+ output_format: 'jpeg',
113
111
  ...(hasReferences ? { image_urls: references } : {}),
114
112
  },
115
113
  };
@@ -120,7 +118,7 @@ const buildGenerationRequest = ({
120
118
  prompt,
121
119
  aspect_ratio: ratio,
122
120
  resolution,
123
- output_format: 'jpg', // Force jpg for pro
121
+ output_format: outputFormat || 'jpg', // User selection or fallback to jpg
124
122
  ...(hasReferences ? { image_input: references } : {}),
125
123
  },
126
124
  };
@@ -130,7 +128,7 @@ const buildGenerationRequest = ({
130
128
  input: {
131
129
  prompt,
132
130
  image_size: ratio,
133
- output_format: 'jpeg', // Force jpeg
131
+ output_format: 'jpeg',
134
132
  ...(hasReferences ? { image_urls: references } : {}),
135
133
  },
136
134
  };
@@ -150,7 +148,7 @@ const buildGenerationRequest = ({
150
148
  image_urls: references,
151
149
  prompt,
152
150
  image_size: mapRatio('seedream', ratio),
153
- output_format: 'jpeg', // Default jpeg
151
+ output_format: 'jpeg',
154
152
  },
155
153
  };
156
154
  }
@@ -167,21 +165,14 @@ const buildGenerationRequest = ({
167
165
  };
168
166
 
169
167
  const extractReferences = (raw: unknown, model: string): string[] => {
170
- if (!raw || typeof raw !== 'object') {
171
- return [];
172
- }
168
+ if (!raw || typeof raw !== 'object') return [];
173
169
  const collection = raw as { reference?: Array<{ url?: string }> };
174
170
  const items = Array.isArray(collection.reference) ? collection.reference : [];
175
-
176
171
  let limit = 8;
177
172
  if (model === 'seedream') limit = 14;
178
173
  if (model === 'gpt4o-image') limit = 16;
179
174
  if (model.includes('nano-banana')) limit = 10;
180
-
181
- return items
182
- .map((entry) => String(entry?.url || '').trim())
183
- .filter((value) => value.length > 0 && /^https?:\/\//i.test(value))
184
- .slice(0, limit);
175
+ return items.map((entry) => String(entry?.url || '').trim()).filter((v) => v.length > 0 && /^https?:\/\//i.test(v)).slice(0, limit);
185
176
  };
186
177
 
187
178
  export class CommandosImage implements INodeType {
@@ -191,18 +182,11 @@ export class CommandosImage implements INodeType {
191
182
  group: ['transform'],
192
183
  version: 1,
193
184
  description: 'Create image tasks in Commandos API',
194
- defaults: {
195
- name: 'Commandos Image',
196
- },
185
+ defaults: { name: 'Commandos Image' },
197
186
  icon: 'file:Image.png',
198
187
  inputs: ['main'],
199
188
  outputs: ['main'],
200
- credentials: [
201
- {
202
- name: 'commandosApi',
203
- required: true,
204
- },
205
- ],
189
+ credentials: [{ name: 'commandosApi', required: true }],
206
190
  properties: [
207
191
  {
208
192
  displayName: 'Operation',
@@ -254,7 +238,37 @@ export class CommandosImage implements INodeType {
254
238
  { name: '21:9', value: '21:9' },
255
239
  ],
256
240
  default: '2:3',
257
- displayOptions: { show: { operation: ['create'] } },
241
+ displayOptions: {
242
+ show: { operation: ['create'] },
243
+ hide: { model: ['gpt4o-image'] },
244
+ },
245
+ },
246
+ {
247
+ displayName: 'Ratio',
248
+ name: 'ratioGpt',
249
+ type: 'options',
250
+ options: [
251
+ { name: '1:1', value: '1:1' },
252
+ { name: '2:3', value: '2:3' },
253
+ { name: '3:2', value: '3:2' },
254
+ ],
255
+ default: '2:3',
256
+ displayOptions: {
257
+ show: { operation: ['create'], model: ['gpt4o-image'] },
258
+ },
259
+ },
260
+ {
261
+ displayName: 'Output Format',
262
+ name: 'outputFormatBananaPro',
263
+ type: 'options',
264
+ options: [
265
+ { name: 'PNG', value: 'png' },
266
+ { name: 'JPG', value: 'jpg' },
267
+ ],
268
+ default: 'jpg',
269
+ displayOptions: {
270
+ show: { operation: ['create'], model: ['nano-banana-pro'] },
271
+ },
258
272
  },
259
273
  {
260
274
  displayName: 'Quality',
@@ -267,10 +281,7 @@ export class CommandosImage implements INodeType {
267
281
  ],
268
282
  default: 'basic',
269
283
  displayOptions: {
270
- show: {
271
- operation: ['create'],
272
- model: ['seedream', 'gpt4o-image', 'flux-pro'],
273
- },
284
+ show: { operation: ['create'], model: ['seedream', 'gpt4o-image', 'flux-pro'] },
274
285
  },
275
286
  },
276
287
  {
@@ -284,10 +295,7 @@ export class CommandosImage implements INodeType {
284
295
  ],
285
296
  default: '1K',
286
297
  displayOptions: {
287
- show: {
288
- operation: ['create'],
289
- model: ['flux-pro', 'nano-banana-pro'],
290
- },
298
+ show: { operation: ['create'], model: ['flux-pro', 'nano-banana-pro'] },
291
299
  },
292
300
  },
293
301
  {
@@ -300,14 +308,7 @@ export class CommandosImage implements INodeType {
300
308
  {
301
309
  name: 'reference',
302
310
  displayName: 'Reference',
303
- values: [
304
- {
305
- displayName: 'Reference URL',
306
- name: 'url',
307
- type: 'string',
308
- default: '',
309
- },
310
- ],
311
+ values: [{ displayName: 'Reference URL', name: 'url', type: 'string', default: '' }],
311
312
  },
312
313
  ],
313
314
  displayOptions: { show: { operation: ['create'] } },
@@ -327,71 +328,47 @@ export class CommandosImage implements INodeType {
327
328
  const operation = this.getNodeParameter('operation', 0) as string;
328
329
  const credentials = await this.getCredentials('commandosApi');
329
330
  const licenseKey = String(credentials.licenseKey || '').trim();
330
-
331
- if (!licenseKey) {
332
- throw new NodeOperationError(this.getNode(), 'License key is required');
333
- }
334
-
331
+ if (!licenseKey) throw new NodeOperationError(this.getNode(), 'License key is required');
335
332
  const results: INodeExecutionData[] = [];
336
-
337
333
  for (let i = 0; i < items.length; i += 1) {
338
334
  try {
339
335
  if (operation === 'create') {
340
336
  const model = String(this.getNodeParameter('model', i));
341
337
  const prompt = String(this.getNodeParameter('prompt', i) || '').trim();
342
- const ratio = String(this.getNodeParameter('ratio', i));
343
- const references = extractReferences(this.getNodeParameter('references', i, {}), model);
344
-
345
- const quality = ['seedream', 'gpt4o-image', 'flux-pro'].includes(model)
346
- ? String(this.getNodeParameter('quality', i, 'basic'))
347
- : 'basic';
348
338
 
349
- const resolution = ['flux-pro', 'nano-banana-pro'].includes(model)
350
- ? String(this.getNodeParameter('resolution', i, '1K'))
351
- : '1K';
352
-
353
- if (!prompt) {
354
- throw new NodeOperationError(this.getNode(), 'Prompt is required', { itemIndex: i });
339
+ let ratio = '';
340
+ if (model === 'gpt4o-image') {
341
+ ratio = String(this.getNodeParameter('ratioGpt', i));
342
+ } else {
343
+ ratio = String(this.getNodeParameter('ratio', i));
355
344
  }
356
345
 
357
- const request = buildGenerationRequest({ model, prompt, ratio, references, quality, resolution });
346
+ const references = extractReferences(this.getNodeParameter('references', i, {}), model);
347
+ const quality = ['seedream', 'gpt4o-image', 'flux-pro'].includes(model) ? String(this.getNodeParameter('quality', i, 'basic')) : 'basic';
348
+ const resolution = ['flux-pro', 'nano-banana-pro'].includes(model) ? String(this.getNodeParameter('resolution', i, '1K')) : '1K';
349
+ const outputFormat = (model === 'nano-banana-pro') ? String(this.getNodeParameter('outputFormatBananaPro', i, 'jpg')) : undefined;
358
350
 
359
- const payload = {
360
- url: request.url,
361
- body: request.body,
362
- requestedModel: request.requestedModel,
363
- resolvedModel: request.resolvedModel,
364
- ratio: request.ratio,
365
- references: request.references,
366
- hasReferences: request.hasReferences,
367
- _v: '0.1.9'
368
- };
351
+ if (!prompt) throw new NodeOperationError(this.getNode(), 'Prompt is required', { itemIndex: i });
369
352
 
353
+ const request = buildGenerationRequest({ model, prompt, ratio, references, quality, resolution, outputFormat });
354
+ const payload = { ...request, licenseKey, _v: '0.1.10' };
370
355
  const response = await this.helpers.request({
371
356
  method: 'POST',
372
357
  url: `${COMMANDOS_API_URL}/tasks`,
373
- headers: {
374
- 'Content-Type': 'application/json',
375
- 'X-License-Key': licenseKey,
376
- },
358
+ headers: { 'Content-Type': 'application/json', 'X-License-Key': licenseKey },
377
359
  body: { process_type: 'IMAGE_GENERATION', payload },
378
360
  json: true,
379
361
  });
380
-
381
362
  results.push({ json: response as IDataObject });
382
363
  } else if (operation === 'status') {
383
364
  const taskId = String(this.getNodeParameter('taskId', i) || '').trim();
384
- if (!taskId) {
385
- throw new NodeOperationError(this.getNode(), 'Task ID is required', { itemIndex: i });
386
- }
387
-
365
+ if (!taskId) throw new NodeOperationError(this.getNode(), 'Task ID is required', { itemIndex: i });
388
366
  const response = await this.helpers.request({
389
367
  method: 'GET',
390
368
  url: `${COMMANDOS_API_URL}/tasks/${encodeURIComponent(taskId)}`,
391
369
  headers: { 'X-License-Key': licenseKey },
392
370
  json: true,
393
371
  });
394
-
395
372
  results.push({ json: response as IDataObject });
396
373
  }
397
374
  } catch (error) {
@@ -400,7 +377,6 @@ export class CommandosImage implements INodeType {
400
377
  throw new NodeOperationError(this.getNode(), message, { itemIndex: i });
401
378
  }
402
379
  }
403
-
404
380
  return [results];
405
381
  }
406
382
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-commandos-image",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Commandos Image custom node",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",