n8n-nodes-tareno 1.3.2 → 1.4.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.
@@ -4,7 +4,6 @@ export declare class Tareno implements INodeType {
4
4
  methods: {
5
5
  loadOptions: {
6
6
  getAccounts(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
7
- getPinterestBoards(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
8
7
  };
9
8
  };
10
9
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
@@ -11,33 +11,28 @@ class Tareno {
11
11
  version: 1,
12
12
  subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
13
13
  description: 'Publish and manage social media posts via Tareno',
14
- defaults: {
15
- name: 'Tareno',
16
- },
14
+ defaults: { name: 'Tareno' },
17
15
  inputs: ['main'],
18
16
  outputs: ['main'],
19
- credentials: [
20
- {
21
- name: 'tarenoApi',
22
- required: true,
23
- },
24
- ],
17
+ credentials: [{ name: 'tarenoApi', required: true }],
25
18
  properties: [
26
- // Resource Selection
19
+ // ========================
20
+ // RESOURCE SELECTION
21
+ // ========================
27
22
  {
28
23
  displayName: 'Resource',
29
24
  name: 'resource',
30
25
  type: 'options',
31
26
  noDataExpression: true,
32
27
  options: [
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' },
28
+ { name: 'Post', value: 'post', description: 'Create a social media post' },
29
+ { name: 'Media Library', value: 'media', description: 'Upload to Tareno Media Library' },
30
+ { name: 'Account', value: 'account', description: 'Get connected accounts' },
36
31
  ],
37
32
  default: 'post',
38
33
  },
39
34
  // ========================
40
- // POST OPERATIONS
35
+ // POST RESOURCE
41
36
  // ========================
42
37
  {
43
38
  displayName: 'Operation',
@@ -46,19 +41,19 @@ class Tareno {
46
41
  noDataExpression: true,
47
42
  displayOptions: { show: { resource: ['post'] } },
48
43
  options: [
49
- { name: 'Publish', value: 'publish', action: 'Publish a post' },
50
- { name: 'Schedule', value: 'schedule', action: 'Schedule a post' },
44
+ { name: 'Publish Now', value: 'publish', action: 'Publish immediately' },
45
+ { name: 'Schedule', value: 'schedule', action: 'Schedule for later' },
51
46
  ],
52
47
  default: 'publish',
53
48
  },
54
- // Platform Filter (Helper for UI)
49
+ // Account Filter (just for UI convenience)
55
50
  {
56
- displayName: 'Platform (UI Filter)',
51
+ displayName: 'Filter Accounts by Platform',
57
52
  name: 'platformFilter',
58
53
  type: 'options',
59
54
  displayOptions: { show: { resource: ['post'] } },
60
55
  options: [
61
- { name: 'All / Auto-detect', value: 'all' },
56
+ { name: 'Show All', value: 'all' },
62
57
  { name: 'Instagram', value: 'instagram' },
63
58
  { name: 'Facebook', value: 'facebook' },
64
59
  { name: 'YouTube', value: 'youtube' },
@@ -68,9 +63,9 @@ class Tareno {
68
63
  { name: 'Threads', value: 'threads' },
69
64
  ],
70
65
  default: 'all',
71
- description: 'Filter accounts and show specific fields for this platform',
66
+ description: 'Filter the account dropdown (one post = one account)',
72
67
  },
73
- // Account Selection (Dynamic)
68
+ // Account Selection
74
69
  {
75
70
  displayName: 'Account',
76
71
  name: 'accountId',
@@ -82,66 +77,19 @@ class Tareno {
82
77
  },
83
78
  displayOptions: { show: { resource: ['post'] } },
84
79
  default: '',
80
+ description: 'Select ONE account to post to',
85
81
  },
86
- // Format Selection (Only for Meta)
87
- {
88
- displayName: 'Format',
89
- name: 'format',
90
- type: 'options',
91
- displayOptions: {
92
- show: {
93
- resource: ['post'],
94
- platformFilter: ['instagram', 'facebook', 'all']
95
- }
96
- },
97
- options: [
98
- { name: 'Feed Post', value: 'post' },
99
- { name: 'Story', value: 'story' },
100
- { name: 'Reel', value: 'reel' },
101
- ],
102
- default: 'post',
103
- description: 'Format for Instagram/Facebook (ignored for others)',
104
- },
105
- // Pinterest Board (Only for Pinterest)
82
+ // Text/Caption
106
83
  {
107
- displayName: 'Pinterest Board',
108
- name: 'pinterestBoard',
109
- type: 'options',
110
- typeOptions: {
111
- loadOptionsMethod: 'getPinterestBoards',
112
- loadOptionsDependsOn: ['accountId'],
113
- },
114
- displayOptions: {
115
- show: {
116
- resource: ['post'],
117
- platformFilter: ['pinterest', 'all']
118
- }
119
- },
120
- default: '',
121
- description: 'Select a Pinterest board',
122
- },
123
- {
124
- displayName: 'Text/Caption',
84
+ displayName: 'Text / Caption',
125
85
  name: 'text',
126
86
  type: 'string',
127
87
  typeOptions: { rows: 4 },
128
88
  displayOptions: { show: { resource: ['post'] } },
129
89
  default: '',
90
+ description: 'The text content of your post',
130
91
  },
131
- // Video Title (Only for YouTube)
132
- {
133
- displayName: 'Video Title',
134
- name: 'videoTitle',
135
- type: 'string',
136
- displayOptions: {
137
- show: {
138
- resource: ['post'],
139
- platformFilter: ['youtube']
140
- }
141
- },
142
- default: '',
143
- placeholder: 'My Great Video',
144
- },
92
+ // Media URLs
145
93
  {
146
94
  displayName: 'Media URLs',
147
95
  name: 'mediaUrls',
@@ -149,8 +97,10 @@ class Tareno {
149
97
  typeOptions: { rows: 2 },
150
98
  displayOptions: { show: { resource: ['post'] } },
151
99
  default: '',
152
- description: 'Comma-separated list of media URLs',
100
+ placeholder: 'https://example.com/image.jpg, https://example.com/video.mp4',
101
+ description: 'Comma-separated URLs of media files. Tip: First upload to Media Library to get URLs.',
153
102
  },
103
+ // Schedule Time
154
104
  {
155
105
  displayName: 'Schedule Time',
156
106
  name: 'scheduledAt',
@@ -159,6 +109,25 @@ class Tareno {
159
109
  displayOptions: { show: { resource: ['post'], operation: ['schedule'] } },
160
110
  default: '',
161
111
  },
112
+ // Format (Only for Instagram/Facebook)
113
+ {
114
+ displayName: 'Format (Instagram/Facebook)',
115
+ name: 'format',
116
+ type: 'options',
117
+ displayOptions: {
118
+ show: {
119
+ resource: ['post'],
120
+ platformFilter: ['instagram', 'facebook']
121
+ }
122
+ },
123
+ options: [
124
+ { name: 'Feed Post', value: 'post' },
125
+ { name: 'Story', value: 'story' },
126
+ { name: 'Reel', value: 'reel' },
127
+ ],
128
+ default: 'post',
129
+ },
130
+ // Additional Options (Platform-specific)
162
131
  {
163
132
  displayName: 'Additional Options',
164
133
  name: 'additionalOptions',
@@ -167,13 +136,59 @@ class Tareno {
167
136
  displayOptions: { show: { resource: ['post'] } },
168
137
  default: {},
169
138
  options: [
170
- { displayName: 'YouTube Description', name: 'youtubeDescription', type: 'string', typeOptions: { rows: 3 }, default: '' },
171
- { displayName: 'Pinterest Link', name: 'pinterestLink', type: 'string', default: '' },
172
- { displayName: 'Disable Comments', name: 'disableComments', type: 'boolean', default: false },
139
+ // YouTube
140
+ {
141
+ displayName: 'YouTube Title',
142
+ name: 'youtubeTitle',
143
+ type: 'string',
144
+ default: '',
145
+ description: 'Title for YouTube videos'
146
+ },
147
+ {
148
+ displayName: 'YouTube Description',
149
+ name: 'youtubeDescription',
150
+ type: 'string',
151
+ typeOptions: { rows: 3 },
152
+ default: '',
153
+ },
154
+ // Pinterest
155
+ {
156
+ displayName: 'Pinterest Board ID',
157
+ name: 'pinterestBoard',
158
+ type: 'string',
159
+ default: '',
160
+ description: 'The Pinterest board ID to pin to (optional - uses default board if empty)'
161
+ },
162
+ {
163
+ displayName: 'Pinterest Link',
164
+ name: 'pinterestLink',
165
+ type: 'string',
166
+ default: '',
167
+ description: 'URL to link the pin to'
168
+ },
169
+ // TikTok
170
+ {
171
+ displayName: 'TikTok Privacy',
172
+ name: 'tiktokPrivacy',
173
+ type: 'options',
174
+ options: [
175
+ { name: 'Public', value: 'PUBLIC_TO_EVERYONE' },
176
+ { name: 'Friends', value: 'MUTUAL_FOLLOW_FRIENDS' },
177
+ { name: 'Private', value: 'SELF_ONLY' },
178
+ ],
179
+ default: 'PUBLIC_TO_EVERYONE',
180
+ },
181
+ // General
182
+ {
183
+ displayName: 'Disable Comments',
184
+ name: 'disableComments',
185
+ type: 'boolean',
186
+ default: false,
187
+ },
173
188
  ],
174
189
  },
175
190
  // ========================
176
- // MEDIA LIBRARY OPERATIONS
191
+ // MEDIA LIBRARY RESOURCE
177
192
  // ========================
178
193
  {
179
194
  displayName: 'Operation',
@@ -182,7 +197,8 @@ class Tareno {
182
197
  noDataExpression: true,
183
198
  displayOptions: { show: { resource: ['media'] } },
184
199
  options: [
185
- { name: 'Upload', value: 'upload', action: 'Upload to media library' },
200
+ { name: 'Upload', value: 'upload', action: 'Upload file to library' },
201
+ { name: 'List', value: 'list', action: 'List files in library' },
186
202
  ],
187
203
  default: 'upload',
188
204
  },
@@ -190,35 +206,37 @@ class Tareno {
190
206
  displayName: 'Upload Mode',
191
207
  name: 'uploadMode',
192
208
  type: 'options',
193
- displayOptions: { show: { resource: ['media'] } },
209
+ displayOptions: { show: { resource: ['media'], operation: ['upload'] } },
194
210
  options: [
195
- { name: 'File (Binary)', value: 'file' },
196
- { name: 'URL', value: 'url' },
211
+ { name: 'Binary File', value: 'file', description: 'Upload from previous node (e.g. Google Drive)' },
212
+ { name: 'URL', value: 'url', description: 'Download from URL and upload' },
197
213
  ],
198
214
  default: 'file',
199
215
  },
200
216
  {
201
- displayName: 'Input Data Field Name',
217
+ displayName: 'Binary Property',
202
218
  name: 'binaryPropertyName',
203
219
  type: 'string',
204
220
  default: 'data',
205
221
  required: true,
206
- displayOptions: { show: { resource: ['media'], uploadMode: ['file'] } },
222
+ displayOptions: { show: { resource: ['media'], operation: ['upload'], uploadMode: ['file'] } },
223
+ description: 'Name of the binary property containing the file',
207
224
  },
208
225
  {
209
226
  displayName: 'Media URL',
210
227
  name: 'mediaUrl',
211
228
  type: 'string',
212
229
  required: true,
213
- displayOptions: { show: { resource: ['media'], uploadMode: ['url'] } },
230
+ displayOptions: { show: { resource: ['media'], operation: ['upload'], uploadMode: ['url'] } },
214
231
  default: '',
215
232
  },
216
233
  {
217
234
  displayName: 'File Name',
218
235
  name: 'fileName',
219
236
  type: 'string',
220
- displayOptions: { show: { resource: ['media'] } },
237
+ displayOptions: { show: { resource: ['media'], operation: ['upload'] } },
221
238
  default: '',
239
+ description: 'Optional custom filename',
222
240
  },
223
241
  ],
224
242
  };
@@ -236,11 +254,11 @@ class Tareno {
236
254
  json: true,
237
255
  });
238
256
  if (response.accounts && Array.isArray(response.accounts)) {
239
- let filtered = response.accounts;
257
+ let accounts = response.accounts;
240
258
  if (platformFilter !== 'all') {
241
- filtered = response.accounts.filter((a) => a.platform === platformFilter);
259
+ accounts = accounts.filter((a) => a.platform === platformFilter);
242
260
  }
243
- return filtered.map((account) => ({
261
+ return accounts.map((account) => ({
244
262
  name: `${account.platform.toUpperCase()} - ${account.username || account.displayName || 'Unknown'}`,
245
263
  value: account.id,
246
264
  }));
@@ -248,29 +266,7 @@ class Tareno {
248
266
  return [];
249
267
  }
250
268
  catch (error) {
251
- return [];
252
- }
253
- },
254
- async getPinterestBoards() {
255
- const credentials = await this.getCredentials('tarenoApi');
256
- const baseUrl = credentials.baseUrl || 'https://tareno.co';
257
- const accountId = this.getNodeParameter('accountId', '');
258
- if (!accountId)
259
- return [];
260
- try {
261
- const response = await this.helpers.httpRequest({
262
- method: 'GET',
263
- url: `${baseUrl}/api/external/pinterest/boards?accountId=${accountId}`,
264
- headers: { 'X-Tareno-API-Key': credentials.apiKey },
265
- json: true,
266
- });
267
- if (response.boards && Array.isArray(response.boards)) {
268
- return response.boards.map((board) => ({ name: board.name, value: board.id }));
269
- }
270
- return [];
271
- }
272
- catch (error) {
273
- return [];
269
+ return [{ name: 'Error loading accounts', value: '' }];
274
270
  }
275
271
  },
276
272
  },
@@ -286,29 +282,30 @@ class Tareno {
286
282
  const resource = this.getNodeParameter('resource', i);
287
283
  const operation = this.getNodeParameter('operation', i);
288
284
  let responseData;
285
+ // ========================
286
+ // POST
287
+ // ========================
289
288
  if (resource === 'post') {
290
289
  const accountId = this.getNodeParameter('accountId', i);
291
- const format = this.getNodeParameter('format', i);
292
- const pinterestBoard = this.getNodeParameter('pinterestBoard', i, '');
293
290
  const text = this.getNodeParameter('text', i);
294
- const videoTitle = this.getNodeParameter('videoTitle', i, '');
295
291
  const mediaUrlsRaw = this.getNodeParameter('mediaUrls', i, '');
296
- const additionalOptions = this.getNodeParameter('additionalOptions', i);
292
+ const additionalOptions = this.getNodeParameter('additionalOptions', i, {});
293
+ // Get format only if it exists (Instagram/Facebook)
294
+ let format = 'post';
295
+ try {
296
+ format = this.getNodeParameter('format', i);
297
+ }
298
+ catch (e) { }
297
299
  const mediaUrls = mediaUrlsRaw ? mediaUrlsRaw.split(',').map(url => url.trim()).filter(Boolean) : [];
298
300
  const body = {
299
301
  accountId,
300
302
  text,
301
303
  mediaUrls,
302
- metadata: {
303
- format,
304
- videoTitle,
305
- ...additionalOptions
306
- }
304
+ metadata: { format, ...additionalOptions }
307
305
  };
308
- if (pinterestBoard)
309
- body.metadata.pinterestBoard = pinterestBoard;
310
- if (operation === 'schedule')
306
+ if (operation === 'schedule') {
311
307
  body.scheduledAt = this.getNodeParameter('scheduledAt', i);
308
+ }
312
309
  responseData = await this.helpers.httpRequest({
313
310
  method: 'POST',
314
311
  url: `${baseUrl}/api/external/publish`,
@@ -317,41 +314,65 @@ class Tareno {
317
314
  json: true,
318
315
  });
319
316
  }
320
- else if (resource === 'media' && operation === 'upload') {
321
- const uploadMode = this.getNodeParameter('uploadMode', i);
322
- const fileName = this.getNodeParameter('fileName', i);
323
- if (uploadMode === 'url') {
324
- const mediaUrl = this.getNodeParameter('mediaUrl', i);
317
+ // ========================
318
+ // MEDIA LIBRARY
319
+ // ========================
320
+ if (resource === 'media') {
321
+ if (operation === 'upload') {
322
+ const uploadMode = this.getNodeParameter('uploadMode', i);
323
+ const fileName = this.getNodeParameter('fileName', i, '');
324
+ if (uploadMode === 'url') {
325
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
326
+ responseData = await this.helpers.httpRequest({
327
+ method: 'POST',
328
+ url: `${baseUrl}/api/external/media`,
329
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
330
+ body: { mediaUrl, fileName: fileName || undefined },
331
+ json: true,
332
+ });
333
+ }
334
+ else {
335
+ const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
336
+ const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
337
+ const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
338
+ responseData = await this.helpers.httpRequest({
339
+ method: 'POST',
340
+ url: `${baseUrl}/api/external/media`,
341
+ headers: {
342
+ 'X-Tareno-API-Key': credentials.apiKey,
343
+ 'Content-Type': 'application/octet-stream',
344
+ 'X-File-Name': fileName || binaryData.fileName || 'upload',
345
+ 'X-Content-Type': binaryData.mimeType,
346
+ },
347
+ body: binaryBuffer,
348
+ });
349
+ if (typeof responseData === 'string') {
350
+ try {
351
+ responseData = JSON.parse(responseData);
352
+ }
353
+ catch (e) { }
354
+ }
355
+ }
356
+ }
357
+ else if (operation === 'list') {
325
358
  responseData = await this.helpers.httpRequest({
326
- method: 'POST',
359
+ method: 'GET',
327
360
  url: `${baseUrl}/api/external/media`,
328
361
  headers: { 'X-Tareno-API-Key': credentials.apiKey },
329
- body: { mediaUrl, fileName: fileName || undefined },
330
362
  json: true,
331
363
  });
332
364
  }
333
- else {
334
- const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
335
- const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
336
- const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
337
- responseData = await this.helpers.httpRequest({
338
- method: 'POST',
339
- url: `${baseUrl}/api/external/media`,
340
- headers: {
341
- 'X-Tareno-API-Key': credentials.apiKey,
342
- 'Content-Type': 'application/octet-stream',
343
- 'X-File-Name': fileName || binaryData.fileName || 'upload',
344
- 'X-Content-Type': binaryData.mimeType,
345
- },
346
- body: binaryBuffer,
347
- });
348
- if (typeof responseData === 'string') {
349
- try {
350
- responseData = JSON.parse(responseData);
351
- }
352
- catch (e) { }
353
- }
354
- }
365
+ }
366
+ // ========================
367
+ // ACCOUNTS
368
+ // ========================
369
+ if (resource === 'account') {
370
+ responseData = await this.helpers.httpRequest({
371
+ method: 'GET',
372
+ url: `${baseUrl}/api/external/accounts`,
373
+ headers: { 'X-Tareno-API-Key': credentials.apiKey },
374
+ json: true,
375
+ });
355
376
  }
356
377
  if (responseData)
357
378
  returnData.push({ json: responseData });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-tareno",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "N8N community nodes for Tareno - Social Media Management Platform",
5
5
  "license": "MIT",
6
6
  "homepage": "https://tareno.co",