n8n-nodes-tareno 1.0.0 → 1.2.0
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,5 +1,11 @@
|
|
|
1
|
-
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
1
|
+
import { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
2
|
export declare class Tareno implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
loadOptions: {
|
|
6
|
+
getAccounts(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
|
+
getPinterestBoards(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
4
10
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
11
|
}
|
|
@@ -35,6 +35,11 @@ class Tareno {
|
|
|
35
35
|
value: 'post',
|
|
36
36
|
description: 'Create and manage social media posts',
|
|
37
37
|
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Media Library',
|
|
40
|
+
value: 'media',
|
|
41
|
+
description: 'Send content to Tareno Media Library',
|
|
42
|
+
},
|
|
38
43
|
{
|
|
39
44
|
name: 'Account',
|
|
40
45
|
value: 'account',
|
|
@@ -77,42 +82,57 @@ class Tareno {
|
|
|
77
82
|
],
|
|
78
83
|
default: 'publish',
|
|
79
84
|
},
|
|
80
|
-
//
|
|
85
|
+
// Account Selection (Dynamic from API)
|
|
81
86
|
{
|
|
82
|
-
displayName: '
|
|
83
|
-
name: '
|
|
87
|
+
displayName: 'Account',
|
|
88
|
+
name: 'accountId',
|
|
84
89
|
type: 'options',
|
|
85
90
|
required: true,
|
|
91
|
+
typeOptions: {
|
|
92
|
+
loadOptionsMethod: 'getAccounts',
|
|
93
|
+
},
|
|
94
|
+
displayOptions: {
|
|
95
|
+
show: {
|
|
96
|
+
resource: ['post'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
default: '',
|
|
100
|
+
description: 'Select a connected social media account',
|
|
101
|
+
},
|
|
102
|
+
// Format Selection for Instagram/Facebook
|
|
103
|
+
{
|
|
104
|
+
displayName: 'Format',
|
|
105
|
+
name: 'format',
|
|
106
|
+
type: 'options',
|
|
86
107
|
displayOptions: {
|
|
87
108
|
show: {
|
|
88
109
|
resource: ['post'],
|
|
89
110
|
},
|
|
90
111
|
},
|
|
91
112
|
options: [
|
|
92
|
-
{ name: '
|
|
93
|
-
{ name: '
|
|
94
|
-
{ name: '
|
|
95
|
-
{ name: 'TikTok', value: 'tiktok' },
|
|
96
|
-
{ name: 'Twitter/X', value: 'twitter' },
|
|
97
|
-
{ name: 'Threads', value: 'threads' },
|
|
98
|
-
{ name: 'Pinterest', value: 'pinterest' },
|
|
113
|
+
{ name: 'Feed Post', value: 'post' },
|
|
114
|
+
{ name: 'Story', value: 'story' },
|
|
115
|
+
{ name: 'Reel', value: 'reel' },
|
|
99
116
|
],
|
|
100
|
-
default: '
|
|
101
|
-
description: '
|
|
117
|
+
default: 'post',
|
|
118
|
+
description: 'Content format (applies to Instagram/Facebook)',
|
|
102
119
|
},
|
|
103
|
-
//
|
|
120
|
+
// Pinterest Board Selection
|
|
104
121
|
{
|
|
105
|
-
displayName: '
|
|
106
|
-
name: '
|
|
107
|
-
type: '
|
|
108
|
-
|
|
122
|
+
displayName: 'Pinterest Board',
|
|
123
|
+
name: 'pinterestBoard',
|
|
124
|
+
type: 'options',
|
|
125
|
+
typeOptions: {
|
|
126
|
+
loadOptionsMethod: 'getPinterestBoards',
|
|
127
|
+
loadOptionsDependsOn: ['accountId'],
|
|
128
|
+
},
|
|
109
129
|
displayOptions: {
|
|
110
130
|
show: {
|
|
111
131
|
resource: ['post'],
|
|
112
132
|
},
|
|
113
133
|
},
|
|
114
134
|
default: '',
|
|
115
|
-
description: '
|
|
135
|
+
description: 'Select a Pinterest board (only for Pinterest accounts)',
|
|
116
136
|
},
|
|
117
137
|
// Post Text
|
|
118
138
|
{
|
|
@@ -189,13 +209,6 @@ class Tareno {
|
|
|
189
209
|
default: '',
|
|
190
210
|
description: 'Description for YouTube videos',
|
|
191
211
|
},
|
|
192
|
-
{
|
|
193
|
-
displayName: 'Pinterest Board',
|
|
194
|
-
name: 'pinterestBoard',
|
|
195
|
-
type: 'string',
|
|
196
|
-
default: '',
|
|
197
|
-
description: 'Pinterest board name or ID',
|
|
198
|
-
},
|
|
199
212
|
{
|
|
200
213
|
displayName: 'Pinterest Link',
|
|
201
214
|
name: 'pinterestLink',
|
|
@@ -206,6 +219,56 @@ class Tareno {
|
|
|
206
219
|
],
|
|
207
220
|
},
|
|
208
221
|
// ========================
|
|
222
|
+
// MEDIA LIBRARY OPERATIONS
|
|
223
|
+
// ========================
|
|
224
|
+
{
|
|
225
|
+
displayName: 'Operation',
|
|
226
|
+
name: 'operation',
|
|
227
|
+
type: 'options',
|
|
228
|
+
noDataExpression: true,
|
|
229
|
+
displayOptions: {
|
|
230
|
+
show: {
|
|
231
|
+
resource: ['media'],
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
options: [
|
|
235
|
+
{
|
|
236
|
+
name: 'Upload',
|
|
237
|
+
value: 'upload',
|
|
238
|
+
description: 'Upload media to Tareno library',
|
|
239
|
+
action: 'Upload to media library',
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
default: 'upload',
|
|
243
|
+
},
|
|
244
|
+
// Media URL for library
|
|
245
|
+
{
|
|
246
|
+
displayName: 'Media URL',
|
|
247
|
+
name: 'mediaUrl',
|
|
248
|
+
type: 'string',
|
|
249
|
+
required: true,
|
|
250
|
+
displayOptions: {
|
|
251
|
+
show: {
|
|
252
|
+
resource: ['media'],
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
default: '',
|
|
256
|
+
description: 'URL of the media to upload to your library',
|
|
257
|
+
},
|
|
258
|
+
// Media name for library
|
|
259
|
+
{
|
|
260
|
+
displayName: 'File Name',
|
|
261
|
+
name: 'fileName',
|
|
262
|
+
type: 'string',
|
|
263
|
+
displayOptions: {
|
|
264
|
+
show: {
|
|
265
|
+
resource: ['media'],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
default: '',
|
|
269
|
+
description: 'Optional name for the file',
|
|
270
|
+
},
|
|
271
|
+
// ========================
|
|
209
272
|
// ACCOUNT OPERATIONS
|
|
210
273
|
// ========================
|
|
211
274
|
{
|
|
@@ -253,6 +316,75 @@ class Tareno {
|
|
|
253
316
|
},
|
|
254
317
|
],
|
|
255
318
|
};
|
|
319
|
+
this.methods = {
|
|
320
|
+
loadOptions: {
|
|
321
|
+
// Dynamically load connected accounts from API
|
|
322
|
+
async getAccounts() {
|
|
323
|
+
const credentials = await this.getCredentials('tarenoApi');
|
|
324
|
+
const baseUrl = credentials.baseUrl || 'https://tareno.co';
|
|
325
|
+
try {
|
|
326
|
+
const response = await this.helpers.httpRequest({
|
|
327
|
+
method: 'GET',
|
|
328
|
+
url: `${baseUrl}/api/external/accounts`,
|
|
329
|
+
headers: {
|
|
330
|
+
'X-Tareno-API-Key': credentials.apiKey,
|
|
331
|
+
},
|
|
332
|
+
json: true,
|
|
333
|
+
});
|
|
334
|
+
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
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
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
|
+
];
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
// Dynamically load Pinterest boards
|
|
358
|
+
async getPinterestBoards() {
|
|
359
|
+
const credentials = await this.getCredentials('tarenoApi');
|
|
360
|
+
const baseUrl = credentials.baseUrl || 'https://tareno.co';
|
|
361
|
+
const accountId = this.getNodeParameter('accountId', '');
|
|
362
|
+
if (!accountId) {
|
|
363
|
+
return [{ name: 'Select an account first', value: '' }];
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
const response = await this.helpers.httpRequest({
|
|
367
|
+
method: 'GET',
|
|
368
|
+
url: `${baseUrl}/api/external/pinterest/boards?accountId=${accountId}`,
|
|
369
|
+
headers: {
|
|
370
|
+
'X-Tareno-API-Key': credentials.apiKey,
|
|
371
|
+
},
|
|
372
|
+
json: true,
|
|
373
|
+
});
|
|
374
|
+
if (response.boards && Array.isArray(response.boards)) {
|
|
375
|
+
return response.boards.map((board) => ({
|
|
376
|
+
name: board.name,
|
|
377
|
+
value: board.id,
|
|
378
|
+
}));
|
|
379
|
+
}
|
|
380
|
+
return [{ name: 'No boards found (or not a Pinterest account)', value: '' }];
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
return [{ name: 'Not a Pinterest account', value: '' }];
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
};
|
|
256
388
|
}
|
|
257
389
|
async execute() {
|
|
258
390
|
const items = this.getInputData();
|
|
@@ -268,8 +400,9 @@ class Tareno {
|
|
|
268
400
|
// POST RESOURCE
|
|
269
401
|
// ========================
|
|
270
402
|
if (resource === 'post') {
|
|
271
|
-
const platform = this.getNodeParameter('platform', i);
|
|
272
403
|
const accountId = this.getNodeParameter('accountId', i);
|
|
404
|
+
const format = this.getNodeParameter('format', i);
|
|
405
|
+
const pinterestBoard = this.getNodeParameter('pinterestBoard', i);
|
|
273
406
|
const text = this.getNodeParameter('text', i);
|
|
274
407
|
const mediaUrlsRaw = this.getNodeParameter('mediaUrls', i);
|
|
275
408
|
const additionalOptions = this.getNodeParameter('additionalOptions', i);
|
|
@@ -277,20 +410,23 @@ class Tareno {
|
|
|
277
410
|
? mediaUrlsRaw.split(',').map(url => url.trim()).filter(Boolean)
|
|
278
411
|
: [];
|
|
279
412
|
const body = {
|
|
280
|
-
platform,
|
|
281
413
|
accountId,
|
|
282
414
|
text,
|
|
283
415
|
mediaUrls,
|
|
416
|
+
metadata: {
|
|
417
|
+
format,
|
|
418
|
+
...additionalOptions,
|
|
419
|
+
},
|
|
284
420
|
};
|
|
421
|
+
// Add Pinterest board if selected
|
|
422
|
+
if (pinterestBoard) {
|
|
423
|
+
body.metadata.pinterestBoard = pinterestBoard;
|
|
424
|
+
}
|
|
285
425
|
// Add schedule time if scheduling
|
|
286
426
|
if (operation === 'schedule') {
|
|
287
427
|
const scheduledAt = this.getNodeParameter('scheduledAt', i);
|
|
288
428
|
body.scheduledAt = scheduledAt;
|
|
289
429
|
}
|
|
290
|
-
// Add metadata for platform-specific options
|
|
291
|
-
if (Object.keys(additionalOptions).length > 0) {
|
|
292
|
-
body.metadata = additionalOptions;
|
|
293
|
-
}
|
|
294
430
|
responseData = await this.helpers.httpRequest({
|
|
295
431
|
method: 'POST',
|
|
296
432
|
url: `${baseUrl}/api/external/publish`,
|
|
@@ -303,6 +439,26 @@ class Tareno {
|
|
|
303
439
|
});
|
|
304
440
|
}
|
|
305
441
|
// ========================
|
|
442
|
+
// MEDIA LIBRARY RESOURCE
|
|
443
|
+
// ========================
|
|
444
|
+
if (resource === 'media' && operation === 'upload') {
|
|
445
|
+
const mediaUrl = this.getNodeParameter('mediaUrl', i);
|
|
446
|
+
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
|
+
});
|
|
460
|
+
}
|
|
461
|
+
// ========================
|
|
306
462
|
// ACCOUNT RESOURCE
|
|
307
463
|
// ========================
|
|
308
464
|
if (resource === 'account' && operation === 'getAll') {
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="none">
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="tarenoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#10B981"/>
|
|
5
|
+
<stop offset="50%" style="stop-color:#059669"/>
|
|
6
|
+
<stop offset="100%" style="stop-color:#047857"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
</defs>
|
|
9
|
+
<!-- Background -->
|
|
10
|
+
<rect width="100" height="100" rx="20" fill="url(#tarenoGradient)"/>
|
|
11
|
+
<!-- T letter stylized -->
|
|
12
|
+
<path d="M25 25 H75 V35 H55 V75 H45 V35 H25 Z" fill="white"/>
|
|
13
|
+
<!-- Decorative check/arrow -->
|
|
14
|
+
<path d="M60 55 L70 65 L85 45" stroke="white" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" fill="none" opacity="0.9"/>
|
|
6
15
|
</svg>
|