n8n-nodes-sendit 1.0.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.
@@ -0,0 +1,9 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class SendItApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SendItApi = void 0;
4
+ class SendItApi {
5
+ constructor() {
6
+ this.name = 'sendItApi';
7
+ this.displayName = 'SendIt API';
8
+ this.documentationUrl = 'https://sendit.infiniteappsai.com/docs/api';
9
+ this.properties = [
10
+ {
11
+ displayName: 'API Key',
12
+ name: 'apiKey',
13
+ type: 'string',
14
+ typeOptions: {
15
+ password: true,
16
+ },
17
+ default: '',
18
+ required: true,
19
+ description: 'Your SendIt API key (starts with sk_live_). Get it from your SendIt Dashboard.',
20
+ },
21
+ ];
22
+ this.authenticate = {
23
+ type: 'generic',
24
+ properties: {
25
+ headers: {
26
+ Authorization: '={{"Bearer " + $credentials.apiKey}}',
27
+ },
28
+ },
29
+ };
30
+ this.test = {
31
+ request: {
32
+ baseURL: 'https://sendit.infiniteappsai.com/api/v1',
33
+ url: '/accounts',
34
+ },
35
+ };
36
+ }
37
+ }
38
+ exports.SendItApi = SendItApi;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class SendIt implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,432 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SendIt = void 0;
4
+ class SendIt {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: 'SendIt',
8
+ name: 'sendIt',
9
+ icon: 'file:sendit.svg',
10
+ group: ['transform'],
11
+ version: 1,
12
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
13
+ description: 'Multi-platform social media publishing',
14
+ defaults: {
15
+ name: 'SendIt',
16
+ },
17
+ inputs: ['main'],
18
+ outputs: ['main'],
19
+ credentials: [
20
+ {
21
+ name: 'sendItApi',
22
+ required: true,
23
+ },
24
+ ],
25
+ requestDefaults: {
26
+ baseURL: 'https://sendit.infiniteappsai.com/api/v1',
27
+ headers: {
28
+ Accept: 'application/json',
29
+ 'Content-Type': 'application/json',
30
+ },
31
+ },
32
+ properties: [
33
+ {
34
+ displayName: 'Resource',
35
+ name: 'resource',
36
+ type: 'options',
37
+ noDataExpression: true,
38
+ options: [
39
+ {
40
+ name: 'Post',
41
+ value: 'post',
42
+ },
43
+ {
44
+ name: 'Scheduled Post',
45
+ value: 'scheduledPost',
46
+ },
47
+ {
48
+ name: 'Account',
49
+ value: 'account',
50
+ },
51
+ {
52
+ name: 'Validation',
53
+ value: 'validation',
54
+ },
55
+ ],
56
+ default: 'post',
57
+ },
58
+ // Post operations
59
+ {
60
+ displayName: 'Operation',
61
+ name: 'operation',
62
+ type: 'options',
63
+ noDataExpression: true,
64
+ displayOptions: {
65
+ show: {
66
+ resource: ['post'],
67
+ },
68
+ },
69
+ options: [
70
+ {
71
+ name: 'Publish',
72
+ value: 'publish',
73
+ description: 'Publish content to social media platforms immediately',
74
+ action: 'Publish a post',
75
+ },
76
+ ],
77
+ default: 'publish',
78
+ },
79
+ // Scheduled Post operations
80
+ {
81
+ displayName: 'Operation',
82
+ name: 'operation',
83
+ type: 'options',
84
+ noDataExpression: true,
85
+ displayOptions: {
86
+ show: {
87
+ resource: ['scheduledPost'],
88
+ },
89
+ },
90
+ options: [
91
+ {
92
+ name: 'Create',
93
+ value: 'create',
94
+ description: 'Schedule a post for future publishing',
95
+ action: 'Schedule a post',
96
+ },
97
+ {
98
+ name: 'Get All',
99
+ value: 'getAll',
100
+ description: 'Get all scheduled posts',
101
+ action: 'Get all scheduled posts',
102
+ },
103
+ {
104
+ name: 'Delete',
105
+ value: 'delete',
106
+ description: 'Cancel a scheduled post',
107
+ action: 'Cancel a scheduled post',
108
+ },
109
+ {
110
+ name: 'Trigger Now',
111
+ value: 'trigger',
112
+ description: 'Publish a scheduled post immediately',
113
+ action: 'Trigger scheduled post now',
114
+ },
115
+ ],
116
+ default: 'create',
117
+ },
118
+ // Account operations
119
+ {
120
+ displayName: 'Operation',
121
+ name: 'operation',
122
+ type: 'options',
123
+ noDataExpression: true,
124
+ displayOptions: {
125
+ show: {
126
+ resource: ['account'],
127
+ },
128
+ },
129
+ options: [
130
+ {
131
+ name: 'Get All',
132
+ value: 'getAll',
133
+ description: 'Get all connected accounts',
134
+ action: 'Get all accounts',
135
+ },
136
+ ],
137
+ default: 'getAll',
138
+ },
139
+ // Validation operations
140
+ {
141
+ displayName: 'Operation',
142
+ name: 'operation',
143
+ type: 'options',
144
+ noDataExpression: true,
145
+ displayOptions: {
146
+ show: {
147
+ resource: ['validation'],
148
+ },
149
+ },
150
+ options: [
151
+ {
152
+ name: 'Validate',
153
+ value: 'validate',
154
+ description: 'Validate content before publishing',
155
+ action: 'Validate content',
156
+ },
157
+ ],
158
+ default: 'validate',
159
+ },
160
+ // Platforms field
161
+ {
162
+ displayName: 'Platforms',
163
+ name: 'platforms',
164
+ type: 'multiOptions',
165
+ options: [
166
+ { name: 'LinkedIn', value: 'linkedin' },
167
+ { name: 'Instagram', value: 'instagram' },
168
+ { name: 'Threads', value: 'threads' },
169
+ { name: 'TikTok', value: 'tiktok' },
170
+ { name: 'X (Twitter)', value: 'x' },
171
+ ],
172
+ default: [],
173
+ required: true,
174
+ displayOptions: {
175
+ show: {
176
+ resource: ['post', 'scheduledPost', 'validation'],
177
+ operation: ['publish', 'create', 'validate'],
178
+ },
179
+ },
180
+ description: 'Select platforms to publish to',
181
+ },
182
+ // Text content
183
+ {
184
+ displayName: 'Text',
185
+ name: 'text',
186
+ type: 'string',
187
+ typeOptions: {
188
+ rows: 4,
189
+ },
190
+ default: '',
191
+ required: true,
192
+ displayOptions: {
193
+ show: {
194
+ resource: ['post', 'scheduledPost', 'validation'],
195
+ operation: ['publish', 'create', 'validate'],
196
+ },
197
+ },
198
+ description: 'The text content of your post',
199
+ },
200
+ // Media URL
201
+ {
202
+ displayName: 'Media URL',
203
+ name: 'mediaUrl',
204
+ type: 'string',
205
+ default: '',
206
+ displayOptions: {
207
+ show: {
208
+ resource: ['post', 'scheduledPost', 'validation'],
209
+ operation: ['publish', 'create', 'validate'],
210
+ },
211
+ },
212
+ description: 'URL to an image or video (required for Instagram and TikTok)',
213
+ },
214
+ // Scheduled Time
215
+ {
216
+ displayName: 'Scheduled Time',
217
+ name: 'scheduledTime',
218
+ type: 'dateTime',
219
+ default: '',
220
+ required: true,
221
+ displayOptions: {
222
+ show: {
223
+ resource: ['scheduledPost'],
224
+ operation: ['create'],
225
+ },
226
+ },
227
+ description: 'When to publish the post',
228
+ },
229
+ // Schedule ID
230
+ {
231
+ displayName: 'Schedule ID',
232
+ name: 'scheduleId',
233
+ type: 'string',
234
+ default: '',
235
+ required: true,
236
+ displayOptions: {
237
+ show: {
238
+ resource: ['scheduledPost'],
239
+ operation: ['delete', 'trigger'],
240
+ },
241
+ },
242
+ description: 'The ID of the scheduled post',
243
+ },
244
+ // Platform filter
245
+ {
246
+ displayName: 'Platform Filter',
247
+ name: 'platformFilter',
248
+ type: 'options',
249
+ options: [
250
+ { name: 'All Platforms', value: '' },
251
+ { name: 'LinkedIn', value: 'linkedin' },
252
+ { name: 'Instagram', value: 'instagram' },
253
+ { name: 'Threads', value: 'threads' },
254
+ { name: 'TikTok', value: 'tiktok' },
255
+ { name: 'X (Twitter)', value: 'x' },
256
+ ],
257
+ default: '',
258
+ displayOptions: {
259
+ show: {
260
+ resource: ['scheduledPost'],
261
+ operation: ['getAll'],
262
+ },
263
+ },
264
+ description: 'Filter scheduled posts by platform',
265
+ },
266
+ // Additional options
267
+ {
268
+ displayName: 'Additional Options',
269
+ name: 'additionalOptions',
270
+ type: 'collection',
271
+ placeholder: 'Add Option',
272
+ default: {},
273
+ displayOptions: {
274
+ show: {
275
+ resource: ['post', 'validation'],
276
+ operation: ['publish', 'validate'],
277
+ },
278
+ },
279
+ options: [
280
+ {
281
+ displayName: 'Media URLs (for carousel)',
282
+ name: 'mediaUrls',
283
+ type: 'string',
284
+ default: '',
285
+ description: 'Comma-separated URLs for carousel posts',
286
+ },
287
+ {
288
+ displayName: 'Media Type',
289
+ name: 'mediaType',
290
+ type: 'options',
291
+ options: [
292
+ { name: 'Auto-detect', value: 'auto' },
293
+ { name: 'Image', value: 'image' },
294
+ { name: 'Video', value: 'video' },
295
+ ],
296
+ default: 'auto',
297
+ description: 'Specify the media type',
298
+ },
299
+ ],
300
+ },
301
+ ],
302
+ };
303
+ }
304
+ async execute() {
305
+ const items = this.getInputData();
306
+ const returnData = [];
307
+ const resource = this.getNodeParameter('resource', 0);
308
+ const operation = this.getNodeParameter('operation', 0);
309
+ for (let i = 0; i < items.length; i++) {
310
+ try {
311
+ let response;
312
+ if (resource === 'post') {
313
+ if (operation === 'publish') {
314
+ const platforms = this.getNodeParameter('platforms', i);
315
+ const text = this.getNodeParameter('text', i);
316
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
317
+ const additionalOptions = this.getNodeParameter('additionalOptions', i);
318
+ const body = {
319
+ platforms,
320
+ content: {
321
+ text,
322
+ mediaUrl: mediaUrl || undefined,
323
+ mediaUrls: additionalOptions.mediaUrls
324
+ ? additionalOptions.mediaUrls.split(',').map((u) => u.trim())
325
+ : undefined,
326
+ mediaType: additionalOptions.mediaType || 'auto',
327
+ },
328
+ };
329
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
330
+ method: 'POST',
331
+ url: '/publish',
332
+ body,
333
+ });
334
+ }
335
+ }
336
+ else if (resource === 'scheduledPost') {
337
+ if (operation === 'create') {
338
+ const platforms = this.getNodeParameter('platforms', i);
339
+ const text = this.getNodeParameter('text', i);
340
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
341
+ const scheduledTime = this.getNodeParameter('scheduledTime', i);
342
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
343
+ method: 'POST',
344
+ url: '/schedule',
345
+ body: {
346
+ platforms,
347
+ content: {
348
+ text,
349
+ mediaUrl: mediaUrl || undefined,
350
+ },
351
+ scheduledTime,
352
+ },
353
+ });
354
+ }
355
+ else if (operation === 'getAll') {
356
+ const platformFilter = this.getNodeParameter('platformFilter', i);
357
+ const qs = {};
358
+ if (platformFilter) {
359
+ qs.platform = platformFilter;
360
+ }
361
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
362
+ method: 'GET',
363
+ url: '/scheduled',
364
+ qs,
365
+ });
366
+ }
367
+ else if (operation === 'delete') {
368
+ const scheduleId = this.getNodeParameter('scheduleId', i);
369
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
370
+ method: 'DELETE',
371
+ url: `/scheduled/${scheduleId}`,
372
+ });
373
+ }
374
+ else if (operation === 'trigger') {
375
+ const scheduleId = this.getNodeParameter('scheduleId', i);
376
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
377
+ method: 'POST',
378
+ url: `/scheduled/${scheduleId}/trigger`,
379
+ });
380
+ }
381
+ }
382
+ else if (resource === 'account') {
383
+ if (operation === 'getAll') {
384
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
385
+ method: 'GET',
386
+ url: '/accounts',
387
+ });
388
+ }
389
+ }
390
+ else if (resource === 'validation') {
391
+ if (operation === 'validate') {
392
+ const platforms = this.getNodeParameter('platforms', i);
393
+ const text = this.getNodeParameter('text', i);
394
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
395
+ const additionalOptions = this.getNodeParameter('additionalOptions', i);
396
+ response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
397
+ method: 'POST',
398
+ url: '/validate',
399
+ body: {
400
+ platforms,
401
+ content: {
402
+ text,
403
+ mediaUrl: mediaUrl || undefined,
404
+ mediaUrls: additionalOptions.mediaUrls
405
+ ? additionalOptions.mediaUrls.split(',').map((u) => u.trim())
406
+ : undefined,
407
+ mediaType: additionalOptions.mediaType || 'auto',
408
+ },
409
+ },
410
+ });
411
+ }
412
+ }
413
+ returnData.push({
414
+ json: response,
415
+ });
416
+ }
417
+ catch (error) {
418
+ if (this.continueOnFail()) {
419
+ returnData.push({
420
+ json: {
421
+ error: error.message,
422
+ },
423
+ });
424
+ continue;
425
+ }
426
+ throw error;
427
+ }
428
+ }
429
+ return [returnData];
430
+ }
431
+ }
432
+ exports.SendIt = SendIt;
@@ -0,0 +1,12 @@
1
+ import { IHookFunctions, IWebhookFunctions, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
2
+ export declare class SendItTrigger implements INodeType {
3
+ description: INodeTypeDescription;
4
+ webhookMethods: {
5
+ default: {
6
+ checkExists(this: IHookFunctions): Promise<boolean>;
7
+ create(this: IHookFunctions): Promise<boolean>;
8
+ delete(this: IHookFunctions): Promise<boolean>;
9
+ };
10
+ };
11
+ webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
12
+ }
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SendItTrigger = void 0;
4
+ class SendItTrigger {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: 'SendIt Trigger',
8
+ name: 'sendItTrigger',
9
+ icon: 'file:sendit.svg',
10
+ group: ['trigger'],
11
+ version: 1,
12
+ subtitle: '={{$parameter["event"]}}',
13
+ description: 'Triggers when events occur in SendIt',
14
+ defaults: {
15
+ name: 'SendIt Trigger',
16
+ },
17
+ inputs: [],
18
+ outputs: ['main'],
19
+ credentials: [
20
+ {
21
+ name: 'sendItApi',
22
+ required: true,
23
+ },
24
+ ],
25
+ webhooks: [
26
+ {
27
+ name: 'default',
28
+ httpMethod: 'POST',
29
+ responseMode: 'onReceived',
30
+ path: 'webhook',
31
+ },
32
+ ],
33
+ properties: [
34
+ {
35
+ displayName: 'Event',
36
+ name: 'event',
37
+ type: 'options',
38
+ options: [
39
+ {
40
+ name: 'Post Published',
41
+ value: 'post.published',
42
+ description: 'Triggered when a post is successfully published',
43
+ },
44
+ {
45
+ name: 'Post Scheduled',
46
+ value: 'post.scheduled',
47
+ description: 'Triggered when a post is scheduled',
48
+ },
49
+ {
50
+ name: 'Post Failed',
51
+ value: 'post.failed',
52
+ description: 'Triggered when a post fails to publish',
53
+ },
54
+ {
55
+ name: 'Post Deleted',
56
+ value: 'post.deleted',
57
+ description: 'Triggered when a scheduled post is deleted',
58
+ },
59
+ {
60
+ name: 'Account Connected',
61
+ value: 'account.connected',
62
+ description: 'Triggered when a social account is connected',
63
+ },
64
+ {
65
+ name: 'Account Disconnected',
66
+ value: 'account.disconnected',
67
+ description: 'Triggered when a social account is disconnected',
68
+ },
69
+ ],
70
+ default: 'post.published',
71
+ required: true,
72
+ description: 'The event to listen for',
73
+ },
74
+ ],
75
+ };
76
+ this.webhookMethods = {
77
+ default: {
78
+ async checkExists() {
79
+ var _a;
80
+ const webhookUrl = this.getNodeWebhookUrl('default');
81
+ const webhookData = this.getWorkflowStaticData('node');
82
+ // If we have stored webhook data, check if it still exists
83
+ if (webhookData.webhookId) {
84
+ try {
85
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
86
+ method: 'GET',
87
+ url: `https://sendit.infiniteappsai.com/api/v1/webhooks/${webhookData.webhookId}`,
88
+ });
89
+ if (response && ((_a = response.webhook) === null || _a === void 0 ? void 0 : _a.url) === webhookUrl) {
90
+ return true;
91
+ }
92
+ }
93
+ catch {
94
+ // Webhook doesn't exist anymore
95
+ }
96
+ }
97
+ return false;
98
+ },
99
+ async create() {
100
+ var _a;
101
+ const webhookUrl = this.getNodeWebhookUrl('default');
102
+ const event = this.getNodeParameter('event');
103
+ const webhookData = this.getWorkflowStaticData('node');
104
+ const body = {
105
+ url: webhookUrl,
106
+ events: [event],
107
+ };
108
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
109
+ method: 'POST',
110
+ url: 'https://sendit.infiniteappsai.com/api/v1/webhooks',
111
+ body,
112
+ });
113
+ const webhookResponse = response;
114
+ if ((_a = webhookResponse.webhook) === null || _a === void 0 ? void 0 : _a.id) {
115
+ webhookData.webhookId = webhookResponse.webhook.id;
116
+ webhookData.webhookSecret = webhookResponse.webhook.secret;
117
+ return true;
118
+ }
119
+ return false;
120
+ },
121
+ async delete() {
122
+ const webhookData = this.getWorkflowStaticData('node');
123
+ if (webhookData.webhookId) {
124
+ try {
125
+ await this.helpers.httpRequestWithAuthentication.call(this, 'sendItApi', {
126
+ method: 'DELETE',
127
+ url: `https://sendit.infiniteappsai.com/api/v1/webhooks/${webhookData.webhookId}`,
128
+ });
129
+ }
130
+ catch {
131
+ // Ignore errors during deletion
132
+ }
133
+ delete webhookData.webhookId;
134
+ delete webhookData.webhookSecret;
135
+ }
136
+ return true;
137
+ },
138
+ },
139
+ };
140
+ }
141
+ async webhook() {
142
+ const bodyData = this.getBodyData();
143
+ return {
144
+ workflowData: [
145
+ this.helpers.returnJsonArray(bodyData),
146
+ ],
147
+ };
148
+ }
149
+ }
150
+ exports.SendItTrigger = SendItTrigger;
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "n8n-nodes-sendit",
3
+ "version": "1.0.0",
4
+ "description": "n8n community node for SendIt - Multi-platform social media publishing",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "social-media",
8
+ "linkedin",
9
+ "instagram",
10
+ "threads",
11
+ "tiktok",
12
+ "twitter",
13
+ "publishing",
14
+ "scheduling"
15
+ ],
16
+ "license": "MIT",
17
+ "homepage": "https://sendit.infiniteappsai.com",
18
+ "author": {
19
+ "name": "SendIt",
20
+ "email": "support@infiniteappsai.com"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/infiniteappsai/sendit"
25
+ },
26
+ "main": "index.js",
27
+ "scripts": {
28
+ "build": "tsc && npm run copy:icons",
29
+ "copy:icons": "mkdir -p dist/nodes/SendIt && cp nodes/SendIt/*.svg dist/nodes/SendIt/ 2>/dev/null || true",
30
+ "dev": "tsc --watch",
31
+ "format": "prettier nodes credentials --write",
32
+ "lint": "eslint nodes credentials --ext .ts --fix",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "files": [
36
+ "dist"
37
+ ],
38
+ "n8n": {
39
+ "n8nNodesApiVersion": 1,
40
+ "credentials": [
41
+ "dist/credentials/SendItApi.credentials.js"
42
+ ],
43
+ "nodes": [
44
+ "dist/nodes/SendIt/SendIt.node.js",
45
+ "dist/nodes/SendIt/SendItTrigger.node.js"
46
+ ]
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^20.10.0",
50
+ "gulp": "^4.0.2",
51
+ "n8n-workflow": "^1.0.0",
52
+ "prettier": "^3.1.0",
53
+ "typescript": "^5.3.0"
54
+ },
55
+ "peerDependencies": {
56
+ "n8n-workflow": "*"
57
+ }
58
+ }