n8n-nodes-tareno 1.2.1 → 1.3.1

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.
@@ -30,26 +30,10 @@ class Tareno {
30
30
  type: 'options',
31
31
  noDataExpression: true,
32
32
  options: [
33
- {
34
- name: 'Post',
35
- value: 'post',
36
- description: 'Create and manage social media posts',
37
- },
38
- {
39
- name: 'Media Library',
40
- value: 'media',
41
- description: 'Send content to Tareno Media Library',
42
- },
43
- {
44
- name: 'Account',
45
- value: 'account',
46
- description: 'Get connected social media accounts',
47
- },
48
- {
49
- name: 'Usage',
50
- value: 'usage',
51
- description: 'Get API usage statistics',
52
- },
33
+ { name: 'Post', value: 'post', description: 'Create and manage social media posts' },
34
+ { name: 'Media Library', value: 'media', description: 'Send content to Tareno Media Library' },
35
+ { name: 'Account', value: 'account', description: 'Get connected social media accounts' },
36
+ { name: 'Usage', value: 'usage', description: 'Get API usage statistics' },
53
37
  ],
54
38
  default: 'post',
55
39
  },
@@ -61,63 +45,34 @@ class Tareno {
61
45
  name: 'operation',
62
46
  type: 'options',
63
47
  noDataExpression: true,
64
- displayOptions: {
65
- show: {
66
- resource: ['post'],
67
- },
68
- },
48
+ displayOptions: { show: { resource: ['post'] } },
69
49
  options: [
70
- {
71
- name: 'Publish',
72
- value: 'publish',
73
- description: 'Publish a post immediately',
74
- action: 'Publish a post',
75
- },
76
- {
77
- name: 'Schedule',
78
- value: 'schedule',
79
- description: 'Schedule a post for later',
80
- action: 'Schedule a post',
81
- },
50
+ { name: 'Publish', value: 'publish', action: 'Publish a post' },
51
+ { name: 'Schedule', value: 'schedule', action: 'Schedule a post' },
82
52
  ],
83
53
  default: 'publish',
84
54
  },
85
- // Account Selection (Dynamic from API)
86
55
  {
87
56
  displayName: 'Account',
88
57
  name: 'accountId',
89
58
  type: 'options',
90
59
  required: true,
91
- typeOptions: {
92
- loadOptionsMethod: 'getAccounts',
93
- },
94
- displayOptions: {
95
- show: {
96
- resource: ['post'],
97
- },
98
- },
60
+ typeOptions: { loadOptionsMethod: 'getAccounts' },
61
+ displayOptions: { show: { resource: ['post'] } },
99
62
  default: '',
100
- description: 'Select a connected social media account',
101
63
  },
102
- // Format Selection for Instagram/Facebook
103
64
  {
104
65
  displayName: 'Format',
105
66
  name: 'format',
106
67
  type: 'options',
107
- displayOptions: {
108
- show: {
109
- resource: ['post'],
110
- },
111
- },
68
+ displayOptions: { show: { resource: ['post'] } },
112
69
  options: [
113
70
  { name: 'Feed Post', value: 'post' },
114
71
  { name: 'Story', value: 'story' },
115
72
  { name: 'Reel', value: 'reel' },
116
73
  ],
117
74
  default: 'post',
118
- description: 'Content format (applies to Instagram/Facebook)',
119
75
  },
120
- // Pinterest Board Selection
121
76
  {
122
77
  displayName: 'Pinterest Board',
123
78
  name: 'pinterestBoard',
@@ -126,96 +81,45 @@ class Tareno {
126
81
  loadOptionsMethod: 'getPinterestBoards',
127
82
  loadOptionsDependsOn: ['accountId'],
128
83
  },
129
- displayOptions: {
130
- show: {
131
- resource: ['post'],
132
- },
133
- },
84
+ displayOptions: { show: { resource: ['post'] } },
134
85
  default: '',
135
- description: 'Select a Pinterest board (only for Pinterest accounts)',
136
86
  },
137
- // Post Text
138
87
  {
139
88
  displayName: 'Text/Caption',
140
89
  name: 'text',
141
90
  type: 'string',
142
- typeOptions: {
143
- rows: 4,
144
- },
145
- displayOptions: {
146
- show: {
147
- resource: ['post'],
148
- },
149
- },
91
+ typeOptions: { rows: 4 },
92
+ displayOptions: { show: { resource: ['post'] } },
150
93
  default: '',
151
- description: 'The text content of your post',
152
94
  },
153
- // Media URLs
154
95
  {
155
96
  displayName: 'Media URLs',
156
97
  name: 'mediaUrls',
157
98
  type: 'string',
158
- typeOptions: {
159
- rows: 2,
160
- },
161
- displayOptions: {
162
- show: {
163
- resource: ['post'],
164
- },
165
- },
99
+ typeOptions: { rows: 2 },
100
+ displayOptions: { show: { resource: ['post'] } },
166
101
  default: '',
167
- description: 'Comma-separated list of media URLs (images/videos)',
102
+ description: 'Comma-separated list of media URLs',
168
103
  },
169
- // Schedule Time (only for schedule operation)
170
104
  {
171
105
  displayName: 'Schedule Time',
172
106
  name: 'scheduledAt',
173
107
  type: 'dateTime',
174
108
  required: true,
175
- displayOptions: {
176
- show: {
177
- resource: ['post'],
178
- operation: ['schedule'],
179
- },
180
- },
109
+ displayOptions: { show: { resource: ['post'], operation: ['schedule'] } },
181
110
  default: '',
182
- description: 'When to publish the post (ISO 8601 format)',
183
111
  },
184
- // Additional Options
185
112
  {
186
113
  displayName: 'Additional Options',
187
114
  name: 'additionalOptions',
188
115
  type: 'collection',
189
116
  placeholder: 'Add Option',
190
- displayOptions: {
191
- show: {
192
- resource: ['post'],
193
- },
194
- },
117
+ displayOptions: { show: { resource: ['post'] } },
195
118
  default: {},
196
119
  options: [
197
- {
198
- displayName: 'YouTube Title',
199
- name: 'youtubeTitle',
200
- type: 'string',
201
- default: '',
202
- description: 'Title for YouTube videos',
203
- },
204
- {
205
- displayName: 'YouTube Description',
206
- name: 'youtubeDescription',
207
- type: 'string',
208
- typeOptions: { rows: 3 },
209
- default: '',
210
- description: 'Description for YouTube videos',
211
- },
212
- {
213
- displayName: 'Pinterest Link',
214
- name: 'pinterestLink',
215
- type: 'string',
216
- default: '',
217
- description: 'URL to link the pin to',
218
- },
120
+ { displayName: 'YouTube Title', name: 'youtubeTitle', type: 'string', default: '' },
121
+ { displayName: 'YouTube Description', name: 'youtubeDescription', type: 'string', typeOptions: { rows: 3 }, default: '' },
122
+ { displayName: 'Pinterest Link', name: 'pinterestLink', type: 'string', default: '' },
219
123
  ],
220
124
  },
221
125
  // ========================
@@ -226,91 +130,68 @@ class Tareno {
226
130
  name: 'operation',
227
131
  type: 'options',
228
132
  noDataExpression: true,
229
- displayOptions: {
230
- show: {
231
- resource: ['media'],
232
- },
233
- },
133
+ displayOptions: { show: { resource: ['media'] } },
234
134
  options: [
235
- {
236
- name: 'Upload',
237
- value: 'upload',
238
- description: 'Upload media to Tareno library',
239
- action: 'Upload to media library',
240
- },
135
+ { name: 'Upload', value: 'upload', action: 'Upload to media library' },
241
136
  ],
242
137
  default: 'upload',
243
138
  },
244
- // Media URL for library
139
+ {
140
+ displayName: 'Upload Mode',
141
+ name: 'uploadMode',
142
+ type: 'options',
143
+ displayOptions: { show: { resource: ['media'] } },
144
+ options: [
145
+ { name: 'File (Binary)', value: 'file' },
146
+ { name: 'URL', value: 'url' },
147
+ ],
148
+ default: 'file',
149
+ },
150
+ {
151
+ displayName: 'Input Data Field Name',
152
+ name: 'binaryPropertyName',
153
+ type: 'string',
154
+ default: 'data',
155
+ required: true,
156
+ displayOptions: { show: { resource: ['media'], uploadMode: ['file'] } },
157
+ },
245
158
  {
246
159
  displayName: 'Media URL',
247
160
  name: 'mediaUrl',
248
161
  type: 'string',
249
162
  required: true,
250
- displayOptions: {
251
- show: {
252
- resource: ['media'],
253
- },
254
- },
163
+ displayOptions: { show: { resource: ['media'], uploadMode: ['url'] } },
255
164
  default: '',
256
- description: 'URL of the media to upload to your library',
257
165
  },
258
- // Media name for library
259
166
  {
260
167
  displayName: 'File Name',
261
168
  name: 'fileName',
262
169
  type: 'string',
263
- displayOptions: {
264
- show: {
265
- resource: ['media'],
266
- },
267
- },
170
+ displayOptions: { show: { resource: ['media'] } },
268
171
  default: '',
269
- description: 'Optional name for the file',
270
172
  },
271
173
  // ========================
272
- // ACCOUNT OPERATIONS
174
+ // OTHER RESOURCES
273
175
  // ========================
274
176
  {
275
177
  displayName: 'Operation',
276
178
  name: 'operation',
277
179
  type: 'options',
278
180
  noDataExpression: true,
279
- displayOptions: {
280
- show: {
281
- resource: ['account'],
282
- },
283
- },
181
+ displayOptions: { show: { resource: ['account'] } },
284
182
  options: [
285
- {
286
- name: 'Get All',
287
- value: 'getAll',
288
- description: 'Get all connected accounts',
289
- action: 'Get all accounts',
290
- },
183
+ { name: 'Get All', value: 'getAll', action: 'Get all accounts' },
291
184
  ],
292
185
  default: 'getAll',
293
186
  },
294
- // ========================
295
- // USAGE OPERATIONS
296
- // ========================
297
187
  {
298
188
  displayName: 'Operation',
299
189
  name: 'operation',
300
190
  type: 'options',
301
191
  noDataExpression: true,
302
- displayOptions: {
303
- show: {
304
- resource: ['usage'],
305
- },
306
- },
192
+ displayOptions: { show: { resource: ['usage'] } },
307
193
  options: [
308
- {
309
- name: 'Get Statistics',
310
- value: 'getStats',
311
- description: 'Get API usage statistics',
312
- action: 'Get usage statistics',
313
- },
194
+ { name: 'Get Statistics', value: 'getStats', action: 'Get usage statistics' },
314
195
  ],
315
196
  default: 'getStats',
316
197
  },
@@ -318,7 +199,6 @@ class Tareno {
318
199
  };
319
200
  this.methods = {
320
201
  loadOptions: {
321
- // Dynamically load connected accounts from API
322
202
  async getAccounts() {
323
203
  const credentials = await this.getCredentials('tarenoApi');
324
204
  const baseUrl = credentials.baseUrl || 'https://tareno.co';
@@ -326,58 +206,38 @@ class Tareno {
326
206
  const response = await this.helpers.httpRequest({
327
207
  method: 'GET',
328
208
  url: `${baseUrl}/api/external/accounts`,
329
- headers: {
330
- 'X-Tareno-API-Key': credentials.apiKey,
331
- },
209
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
332
210
  json: true,
333
211
  });
334
212
  if (response.accounts && Array.isArray(response.accounts)) {
335
- return response.accounts.map((account) => {
336
- const platformName = account.platform.charAt(0).toUpperCase() + account.platform.slice(1);
337
- const displayName = account.username || account.displayName || 'Unknown';
338
- return {
339
- name: `${platformName} - ${displayName}`,
340
- value: account.id,
341
- description: `Platform: ${account.platform}`,
342
- };
343
- });
213
+ return response.accounts.map((account) => ({
214
+ name: `${account.platform.charAt(0).toUpperCase() + account.platform.slice(1)} - ${account.username || account.displayName || 'Unknown'}`,
215
+ value: account.id,
216
+ }));
344
217
  }
345
218
  return [];
346
219
  }
347
220
  catch (error) {
348
- console.error('Failed to load accounts:', error);
349
- return [
350
- {
351
- name: 'Error loading accounts - check API key',
352
- value: '',
353
- },
354
- ];
221
+ return [];
355
222
  }
356
223
  },
357
- // Dynamically load Pinterest boards
358
224
  async getPinterestBoards() {
359
225
  const credentials = await this.getCredentials('tarenoApi');
360
226
  const baseUrl = credentials.baseUrl || 'https://tareno.co';
361
227
  const accountId = this.getNodeParameter('accountId', '');
362
- if (!accountId) {
228
+ if (!accountId)
363
229
  return [{ name: 'Select an account first', value: '' }];
364
- }
365
230
  try {
366
231
  const response = await this.helpers.httpRequest({
367
232
  method: 'GET',
368
233
  url: `${baseUrl}/api/external/pinterest/boards?accountId=${accountId}`,
369
- headers: {
370
- 'X-Tareno-API-Key': credentials.apiKey,
371
- },
234
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
372
235
  json: true,
373
236
  });
374
237
  if (response.boards && Array.isArray(response.boards)) {
375
- return response.boards.map((board) => ({
376
- name: board.name,
377
- value: board.id,
378
- }));
238
+ return response.boards.map((board) => ({ name: board.name, value: board.id }));
379
239
  }
380
- return [{ name: 'No boards found (or not a Pinterest account)', value: '' }];
240
+ return [{ name: 'No boards found', value: '' }];
381
241
  }
382
242
  catch (error) {
383
243
  return [{ name: 'Not a Pinterest account', value: '' }];
@@ -396,9 +256,6 @@ class Tareno {
396
256
  const resource = this.getNodeParameter('resource', i);
397
257
  const operation = this.getNodeParameter('operation', i);
398
258
  let responseData;
399
- // ========================
400
- // POST RESOURCE
401
- // ========================
402
259
  if (resource === 'post') {
403
260
  const accountId = this.getNodeParameter('accountId', i);
404
261
  const format = this.getNodeParameter('format', i);
@@ -406,101 +263,80 @@ class Tareno {
406
263
  const text = this.getNodeParameter('text', i);
407
264
  const mediaUrlsRaw = this.getNodeParameter('mediaUrls', i);
408
265
  const additionalOptions = this.getNodeParameter('additionalOptions', i);
409
- const mediaUrls = mediaUrlsRaw
410
- ? mediaUrlsRaw.split(',').map(url => url.trim()).filter(Boolean)
411
- : [];
412
- const body = {
413
- accountId,
414
- text,
415
- mediaUrls,
416
- metadata: {
417
- format,
418
- ...additionalOptions,
419
- },
420
- };
421
- // Add Pinterest board if selected
422
- if (pinterestBoard) {
266
+ const mediaUrls = mediaUrlsRaw ? mediaUrlsRaw.split(',').map(url => url.trim()).filter(Boolean) : [];
267
+ const body = { accountId, text, mediaUrls, metadata: { format, ...additionalOptions } };
268
+ if (pinterestBoard)
423
269
  body.metadata.pinterestBoard = pinterestBoard;
424
- }
425
- // Add schedule time if scheduling
426
- if (operation === 'schedule') {
427
- const scheduledAt = this.getNodeParameter('scheduledAt', i);
428
- body.scheduledAt = scheduledAt;
429
- }
270
+ if (operation === 'schedule')
271
+ body.scheduledAt = this.getNodeParameter('scheduledAt', i);
430
272
  responseData = await this.helpers.httpRequest({
431
273
  method: 'POST',
432
274
  url: `${baseUrl}/api/external/publish`,
433
- headers: {
434
- 'Content-Type': 'application/json',
435
- 'X-Tareno-API-Key': credentials.apiKey,
436
- },
275
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
437
276
  body,
438
277
  json: true,
439
278
  });
440
279
  }
441
- // ========================
442
- // MEDIA LIBRARY RESOURCE
443
- // ========================
444
- if (resource === 'media' && operation === 'upload') {
445
- const mediaUrl = this.getNodeParameter('mediaUrl', i);
280
+ else if (resource === 'media' && operation === 'upload') {
281
+ const uploadMode = this.getNodeParameter('uploadMode', i);
446
282
  const fileName = this.getNodeParameter('fileName', i);
447
- responseData = await this.helpers.httpRequest({
448
- method: 'POST',
449
- url: `${baseUrl}/api/external/media`,
450
- headers: {
451
- 'Content-Type': 'application/json',
452
- 'X-Tareno-API-Key': credentials.apiKey,
453
- },
454
- body: {
455
- mediaUrl,
456
- fileName: fileName || undefined,
457
- },
458
- json: true,
459
- });
283
+ if (uploadMode === 'url') {
284
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
285
+ responseData = await this.helpers.httpRequest({
286
+ method: 'POST',
287
+ url: `${baseUrl}/api/external/media`,
288
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
289
+ body: { mediaUrl, fileName: fileName || undefined },
290
+ json: true,
291
+ });
292
+ }
293
+ else {
294
+ const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
295
+ const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
296
+ const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
297
+ responseData = await this.helpers.httpRequest({
298
+ method: 'POST',
299
+ url: `${baseUrl}/api/external/media`,
300
+ headers: {
301
+ 'X-Tareno-API-Key': credentials.apiKey,
302
+ 'Content-Type': 'application/octet-stream',
303
+ 'X-File-Name': fileName || binaryData.fileName || 'upload',
304
+ 'X-Content-Type': binaryData.mimeType,
305
+ },
306
+ body: binaryBuffer,
307
+ });
308
+ // Parse JSON manually if n8n doesn't do it for non-JSON content types
309
+ if (typeof responseData === 'string') {
310
+ try {
311
+ responseData = JSON.parse(responseData);
312
+ }
313
+ catch (e) { }
314
+ }
315
+ }
460
316
  }
461
- // ========================
462
- // ACCOUNT RESOURCE
463
- // ========================
464
- if (resource === 'account' && operation === 'getAll') {
317
+ else if (resource === 'account' && operation === 'getAll') {
465
318
  responseData = await this.helpers.httpRequest({
466
319
  method: 'GET',
467
320
  url: `${baseUrl}/api/external/accounts`,
468
- headers: {
469
- 'X-Tareno-API-Key': credentials.apiKey,
470
- },
321
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
471
322
  json: true,
472
323
  });
473
324
  }
474
- // ========================
475
- // USAGE RESOURCE
476
- // ========================
477
- if (resource === 'usage' && operation === 'getStats') {
325
+ else if (resource === 'usage' && operation === 'getStats') {
478
326
  responseData = await this.helpers.httpRequest({
479
327
  method: 'GET',
480
328
  url: `${baseUrl}/api/external/usage`,
481
- headers: {
482
- 'X-Tareno-API-Key': credentials.apiKey,
483
- },
329
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
484
330
  json: true,
485
331
  });
486
332
  }
487
- // Add result to output
488
333
  if (responseData) {
489
- if (Array.isArray(responseData)) {
490
- returnData.push(...responseData.map(item => ({ json: item })));
491
- }
492
- else {
493
- returnData.push({ json: responseData });
494
- }
334
+ returnData.push({ json: responseData });
495
335
  }
496
336
  }
497
337
  catch (error) {
498
338
  if (this.continueOnFail()) {
499
- returnData.push({
500
- json: {
501
- error: error.message,
502
- },
503
- });
339
+ returnData.push({ json: { error: error.message } });
504
340
  continue;
505
341
  }
506
342
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tareno",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "description": "N8N community nodes for Tareno - Social Media Management Platform",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tareno.co",