n8n-nodes-meta-mpublisher 1.1.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.
Files changed (52) hide show
  1. package/LICENSE.md +19 -0
  2. package/README.md +654 -0
  3. package/dist/credentials/MetaGraphApi.credentials.d.ts +7 -0
  4. package/dist/credentials/MetaGraphApi.credentials.js +23 -0
  5. package/dist/credentials/MetaGraphApi.credentials.js.map +1 -0
  6. package/dist/nodes/MetaPublisher/MetaPublisher.node.d.ts +5 -0
  7. package/dist/nodes/MetaPublisher/MetaPublisher.node.js +934 -0
  8. package/dist/nodes/MetaPublisher/MetaPublisher.node.js.map +1 -0
  9. package/dist/nodes/MetaPublisher/MetaPublisher.svg +1 -0
  10. package/dist/nodes/MetaPublisher/lib/client.d.ts +4 -0
  11. package/dist/nodes/MetaPublisher/lib/client.js +34 -0
  12. package/dist/nodes/MetaPublisher/lib/client.js.map +1 -0
  13. package/dist/nodes/MetaPublisher/lib/constant.d.ts +25 -0
  14. package/dist/nodes/MetaPublisher/lib/constant.js +29 -0
  15. package/dist/nodes/MetaPublisher/lib/constant.js.map +1 -0
  16. package/dist/nodes/MetaPublisher/lib/fb.d.ts +68 -0
  17. package/dist/nodes/MetaPublisher/lib/fb.js +155 -0
  18. package/dist/nodes/MetaPublisher/lib/fb.js.map +1 -0
  19. package/dist/nodes/MetaPublisher/lib/ig.d.ts +78 -0
  20. package/dist/nodes/MetaPublisher/lib/ig.js +106 -0
  21. package/dist/nodes/MetaPublisher/lib/ig.js.map +1 -0
  22. package/dist/nodes/MetaPublisher/lib/ops.d.ts +127 -0
  23. package/dist/nodes/MetaPublisher/lib/ops.js +564 -0
  24. package/dist/nodes/MetaPublisher/lib/ops.js.map +1 -0
  25. package/dist/nodes/MetaPublisher/lib/poll.d.ts +7 -0
  26. package/dist/nodes/MetaPublisher/lib/poll.js +19 -0
  27. package/dist/nodes/MetaPublisher/lib/poll.js.map +1 -0
  28. package/dist/nodes/MetaPublisher/lib/threads.d.ts +30 -0
  29. package/dist/nodes/MetaPublisher/lib/threads.js +92 -0
  30. package/dist/nodes/MetaPublisher/lib/threads.js.map +1 -0
  31. package/dist/nodes/MetaPublisher/lib/types.d.ts +31 -0
  32. package/dist/nodes/MetaPublisher/lib/types.js +3 -0
  33. package/dist/nodes/MetaPublisher/lib/types.js.map +1 -0
  34. package/dist/nodes/MetaPublisher/lib/utils.d.ts +7 -0
  35. package/dist/nodes/MetaPublisher/lib/utils.js +28 -0
  36. package/dist/nodes/MetaPublisher/lib/utils.js.map +1 -0
  37. package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisher.svg +1 -0
  38. package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisherBinaryUpload.node.d.ts +4 -0
  39. package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisherBinaryUpload.node.js +39 -0
  40. package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisherBinaryUpload.node.js.map +1 -0
  41. package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisher.svg +1 -0
  42. package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisherJsonGenerator.node.d.ts +5 -0
  43. package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisherJsonGenerator.node.js +730 -0
  44. package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisherJsonGenerator.node.js.map +1 -0
  45. package/dist/nodes/MetaPublisherUtils/MetaPublisher.svg +1 -0
  46. package/dist/nodes/MetaPublisherUtils/MetaPublisherUtils.node.d.ts +5 -0
  47. package/dist/nodes/MetaPublisherUtils/MetaPublisherUtils.node.js +570 -0
  48. package/dist/nodes/MetaPublisherUtils/MetaPublisherUtils.node.js.map +1 -0
  49. package/dist/package.json +70 -0
  50. package/dist/tsconfig.tsbuildinfo +1 -0
  51. package/index.js +0 -0
  52. package/package.json +70 -0
package/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright 2022 n8n
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,654 @@
1
+ ![Banner image](https://user-images.githubusercontent.com/10284570/173569848-c624317f-42b1-45a6-ab09-f0ea3c247648.png)
2
+
3
+ # n8n-nodes-meta-publisher
4
+
5
+ Publish to **Instagram**, **Facebook Pages**, and **Threads** from n8n — including **Images, Videos, Reels, Stories, and Carousels** — with a single, DRY node.
6
+
7
+ > Built from the official **n8n community node starter** structure so you can develop, lint, and ship confidently. 
8
+
9
+ ---
10
+
11
+ #### Workflows
12
+
13
+ ![Meta Publisher Workflow](docs/images/workflow.png)
14
+
15
+ #### Nodes and Operations
16
+
17
+ ![Meta Publisher Operations](docs/images/nodes.png)
18
+ ![Meta Publisher Operations](docs/images/operations.png)
19
+
20
+ #### JSON Generator Output
21
+
22
+ ![Meta Publisher Operations](docs/images/json-generator-output.png)
23
+
24
+ ## Table of contents
25
+
26
+ - [Features](#features)
27
+ - [Supported resources & operations](#supported-resources--operations)
28
+ - [Installation](#installation)
29
+ - [Credentials](#credentials)
30
+ - [Quick start (Fields mode)](#quick-start-fields-mode)
31
+ - [JSON payload mode (optional)](#json-payload-mode-optional)
32
+ - [Outputs](#outputs)
33
+ - [Rate limits & retries](#rate-limits--retries)
34
+ - [Development](#development)
35
+ - [Testing locally](#testing-locally)
36
+ - [Contributing](#contributing)
37
+ - [License](#license)
38
+
39
+ ---
40
+
41
+ ## Features
42
+
43
+ - One node to publish across **Instagram / Facebook Pages / Threads**
44
+ - **Create → poll → publish** workflow handled for you
45
+ - **Reels, Stories, Carousels** (IG) + **Photos/Videos** (FB) + **Text/Image/Video/Carousel** (Threads)
46
+ - Two input styles:
47
+ - **Fields mode** (simple UI fields)
48
+ - **JSON payload mode** for programmatic/batch posting
49
+
50
+ - Consistent JSON output (status, IDs, permalinks-ready payloads)
51
+ - Friendly polling with jitter; configurable timeouts
52
+
53
+ ---
54
+
55
+ ## Supported resources & operations
56
+
57
+ **Instagram**
58
+
59
+ - Publish Image, Publish Video (optional cover image)
60
+ - Publish Reel (thumb offset, share to feed)
61
+ - Publish Story (image/video)
62
+ - Publish Carousel (2–10 items)
63
+
64
+ **Facebook Pages**
65
+
66
+ - Publish Photo
67
+ - Publish Video (status polled until ready)
68
+ - Publish Reel (status polled until ready)
69
+ - Publish Story (image/video)
70
+ - ~~Publish Multi-Photo~~ (work in progress...)
71
+
72
+ **Threads**
73
+
74
+ - Publish Text
75
+ - Publish Image (optional alt text)
76
+ - Publish Video (optional alt text)
77
+ - Publish Carousel (2–20 items)
78
+
79
+ ---
80
+
81
+ ## Installation
82
+
83
+ ### Community Nodes (recommended for users)
84
+
85
+ - Install `n8n-node-meta-publisher` via n8n _Community Nodes_.
86
+
87
+ ![Meta Publisher workflow](docs/images/community-nodes.png)
88
+
89
+ ## Credentials
90
+
91
+ Add a credential in n8n called **Meta Graph API** with an **Access Token** (prefer long-lived).
92
+ The node will also attempt **OAuth2** if configured in your instance, then fall back to the access token.
93
+
94
+ > Keep tokens in **Credentials**, not in node fields. This keeps secrets secure and reusable across workflows.
95
+
96
+ ---
97
+
98
+ ## Quick start (Fields mode)
99
+
100
+ 1. Drag **Meta Publisher** into your workflow.
101
+ 2. Choose **Resource**:
102
+ - Instagram / Facebook Page / Threads
103
+
104
+ 3. Choose **Operation** (e.g., _Publish Reel_).
105
+ 4. Fill required fields (e.g., IG User ID, Media URL, Caption).
106
+ 5. Optionally adjust **Polling Interval** and **Max Wait**.
107
+ 6. Run the workflow.
108
+
109
+ **Example (IG → Publish Image)**
110
+
111
+ - Resource: Instagram
112
+ - Operation: Publish Image
113
+ - IG User ID: `1789…`
114
+ - Image URL: `https://…/photo.jpg`
115
+ - Caption: `Hello from n8n 🚀`
116
+
117
+ ---
118
+
119
+ ## JSON payload mode (optional)
120
+
121
+ Instead of filling parameters in the node UI, you can set **Input Source = JSON Property**.
122
+ This allows you to feed one or more publishing jobs from the incoming item JSON.
123
+
124
+ ### 1. Configure the Node
125
+
126
+ - Set **Input Source** → `From JSON Property`
127
+ - Set **JSON Property Path** → the field in your input JSON where the job(s) are stored.
128
+ - Use `$json` to pass the entire input item.
129
+ - Use a path like `data.post` if your jobs are nested inside `{"data": { "post": {...}}}`.
130
+
131
+ ### 2. JSON Job Format
132
+
133
+ Each job must be an object with at least:
134
+
135
+ - `resource`: `"instagram" | "facebook" | "threads"`
136
+ - `operation`: one of the supported operations
137
+ - Required fields for that operation (see below)
138
+
139
+ ---
140
+
141
+ #### **Common Fields**
142
+
143
+ - `resource` – platform to publish to
144
+ - `operation` – type of publish action
145
+ - `pollSec` _(optional)_ – polling interval (default: `2`)
146
+ - `maxWaitSec` _(optional)_ – max wait before timeout (default: `300`)
147
+
148
+ ---
149
+
150
+ #### **Instagram**
151
+
152
+ All Instagram jobs require:
153
+
154
+ - `igUserId` – Instagram Business User ID
155
+ - `autoPublish` _(default: true)_
156
+
157
+ Operations:
158
+
159
+ - `publishImage` → `mediaUrl`, `caption?`
160
+ - `publishVideo` → `mediaUrl`, `caption?`, `coverUrl?`
161
+ - `publishReel` → `videoUrl`, `caption?`, `thumbOffsetMs?`, `shareToFeed?`
162
+ - `publishStory` → `mediaUrl`, `storyKind` (`"image"` | `"video"`), `caption?`
163
+ - `publishCarousel` → `items[]` (`{ type: "image|video", url: "..." }`), `caption?`
164
+
165
+ #### Instagram User Tags
166
+
167
+ You can tag users in supported Instagram posts using:
168
+
169
+ ```json
170
+ {
171
+ "userTags": [
172
+ {
173
+ "username": "someuser",
174
+ "x": 0.5,
175
+ "y": 0.5
176
+ }
177
+ ]
178
+ }
179
+ ```
180
+
181
+ ---
182
+
183
+ #### **Facebook Page**
184
+
185
+ All Facebook jobs require:
186
+
187
+ - `pageId` – Page ID
188
+
189
+ Operations:
190
+
191
+ - `publishFbPhoto` → `imageUrl`, `caption?`
192
+ - `publishFbVideo` → `videoUrl`, `title?`, `description?`
193
+
194
+ ---
195
+
196
+ #### **Threads**
197
+
198
+ All Threads jobs require:
199
+
200
+ - `thUserId` (or `userId` alias) – Threads User ID
201
+
202
+ Operations:
203
+
204
+ - `threadsPublishText` → `text`
205
+ - `threadsPublishImage` → `imageUrl`, `text?`, `altText?`
206
+ - `threadsPublishVideo` → `videoUrl`, `text?`, `altText?`
207
+ - `threadsPublishCarousel` → `items[]` (`{ type: "image|video", url: "...", altText? }`), `text?`
208
+
209
+ You can also pass **an array of jobs** to publish multiple posts in one execution.
210
+
211
+ ### 3. Example: Multiple Jobs
212
+
213
+ ```json
214
+ [
215
+ {
216
+ "resource": "instagram",
217
+ "operation": "publishStory",
218
+ "igUserId": "112233445566",
219
+ "mediaUrl": "https://www.example.com/video.mp4",
220
+ "caption": "This is an example caption.",
221
+ "storyKind": "video",
222
+ "autoPublish": true
223
+ },
224
+ {
225
+ "resource": "instagram",
226
+ "operation": "publishStory",
227
+ "igUserId": "112233445566",
228
+ "mediaUrl": "https://www.example.com/image.jpg",
229
+ "caption": "This is an example caption.",
230
+ "storyKind": "image",
231
+ "autoPublish": true
232
+ },
233
+ {
234
+ "resource": "instagram",
235
+ "operation": "publishImage",
236
+ "igUserId": "112233445566",
237
+ "mediaUrl": "https://www.example.com/image.jpg",
238
+ "caption": "This is an example caption.",
239
+ "userTags": [{ "username": "someuser", "x": 0.5, "y": 0.5 }],
240
+ "autoPublish": true
241
+ },
242
+ {
243
+ "resource": "instagram",
244
+ "operation": "publishVideo",
245
+ "igUserId": "112233445566",
246
+ "mediaUrl": "https://www.example.com/video.mp4",
247
+ "caption": "This is an example caption.",
248
+ "coverUrl": "https://www.example.com/image.jpg",
249
+ "userTags": [{ "username": "someuser", "x": 0.5, "y": 0.5 }],
250
+ "autoPublish": true
251
+ },
252
+ {
253
+ "resource": "instagram",
254
+ "operation": "publishReel",
255
+ "igUserId": "112233445566",
256
+ "videoUrl": "https://www.example.com/video.mp4",
257
+ "caption": "This is an example caption.",
258
+ "userTags": [{ "username": "someuser", "x": 0.5, "y": 0.5 }],
259
+ "thumbOffsetMs": 0,
260
+ "shareToFeed": true,
261
+ "autoPublish": true
262
+ },
263
+ {
264
+ "resource": "instagram",
265
+ "operation": "publishCarousel",
266
+ "igUserId": "112233445566",
267
+ "items": [
268
+ {
269
+ "type": "image",
270
+ "url": "https://www.example.com/image.jpg",
271
+ "caption": "This is an example caption.",
272
+ "userTags": [{ "username": "someuser", "x": 0.1, "y": 0.8 }]
273
+ },
274
+ {
275
+ "type": "video",
276
+ "url": "https://www.example.com/video.mp4",
277
+ "caption": "This is an example caption.",
278
+ "userTags": [{ "username": "someuser", "x": 0.1, "y": 0.8 }]
279
+ }
280
+ ],
281
+ "caption": "This is an example caption.",
282
+ "autoPublish": true
283
+ },
284
+ {
285
+ "resource": "facebook",
286
+ "operation": "publishFbPhoto",
287
+ "pageId": "112233445566",
288
+ "imageUrl": "https://www.example.com/image.jpg",
289
+ "caption": "This is an example caption."
290
+ },
291
+ {
292
+ "resource": "facebook",
293
+ "operation": "publishFbVideo",
294
+ "pageId": "112233445566",
295
+ "videoUrl": "https://www.example.com/video.mp4",
296
+ "title": "This is an example title.",
297
+ "description": "This is an example description."
298
+ },
299
+ {
300
+ "resource": "facebook",
301
+ "operation": "publishFbStoryPhoto",
302
+ "pageId": "112233445566",
303
+ "imageUrl": "https://www.example.com/image.jpg"
304
+ },
305
+ {
306
+ "resource": "facebook",
307
+ "operation": "publishFbStoryVideo",
308
+ "pageId": "112233445566",
309
+ "videoUrl": "https://www.example.com/video.mp4"
310
+ },
311
+ {
312
+ "resource": "facebook",
313
+ "operation": "publishFbReel",
314
+ "pageId": "112233445566",
315
+ "videoUrl": "https://www.example.com/video.mp4",
316
+ "description": "FB Reel Description"
317
+ },
318
+ {
319
+ "resource": "threads",
320
+ "operation": "threadsPublishText",
321
+ "thUserId": "112233445566",
322
+ "text": "This is an example text."
323
+ },
324
+ {
325
+ "resource": "threads",
326
+ "operation": "threadsPublishImage",
327
+ "thUserId": "112233445566",
328
+ "imageUrl": "https://www.example.com/image.jpg",
329
+ "text": "This is an example caption.",
330
+ "altText": "This is an example alt text."
331
+ },
332
+ {
333
+ "resource": "threads",
334
+ "operation": "threadsPublishVideo",
335
+ "thUserId": "112233445566",
336
+ "videoUrl": "https://www.example.com/video.mp4",
337
+ "text": "This is an example caption.",
338
+ "altText": "This is an example alt text."
339
+ },
340
+ {
341
+ "resource": "threads",
342
+ "operation": "threadsPublishCarousel",
343
+ "thUserId": "112233445566",
344
+ "items": [
345
+ {
346
+ "type": "image",
347
+ "url": "https://www.example.com/image.jpg",
348
+ "altText": "This is an example alt text.",
349
+ "caption": "This is an example caption."
350
+ },
351
+ {
352
+ "type": "video",
353
+ "url": "https://www.example.com/video.mp4",
354
+ "altText": "This is an example alt text.",
355
+ "caption": "This is an example caption."
356
+ }
357
+ ],
358
+ "text": "This is an example caption."
359
+ }
360
+ ]
361
+ ```
362
+
363
+ ### 4. Example: Single Job
364
+
365
+ ```json
366
+ {
367
+ "resource": "instagram",
368
+ "operation": "publishImage",
369
+ "igUserId": "112233445566",
370
+ "mediaUrl": "https://example.com/image.jpg",
371
+ "caption": "My first IG post",
372
+ "autoPublish": true
373
+ }
374
+ ```
375
+
376
+ ---
377
+
378
+ ## Outputs
379
+
380
+ Every successful publish returns a consistent JSON shape (fields may vary slightly by resource/operation):
381
+
382
+ ```json
383
+ {
384
+ "resource": "instagram|facebook|threads",
385
+ "type": "image|video|reel|story|carousel|text",
386
+ "creationId": "1789...", // IG/Threads container or parent (when applicable)
387
+ "children": ["childId1"], // for carousels
388
+ "status": "FINISHED|PUBLISHED|READY|ERROR|...",
389
+ "published": true,
390
+ "publishResult": { "id": "1790..." }, // media/thread object
391
+ "videoId": "1234567890" // FB video id when relevant
392
+ }
393
+ ```
394
+
395
+ Use this to chain downstream steps (e.g., fetch permalink, store IDs).
396
+
397
+ ---
398
+
399
+ ## Rate limits & retries
400
+
401
+ - The node polls at your chosen interval with gentle jitter to be friendly to API limits.
402
+ - Increase **Max Wait (sec)** for long videos/reels.
403
+ - For high-volume workflows, consider spacing items or batching upstream.
404
+
405
+ ---
406
+
407
+ ## Meta Publisher Utils — how to use
408
+
409
+ The **Meta Publisher Utils** node generates a ready-to-run JSON payload for the **Meta Publisher** node. It’s perfect for assembling multiple posts (IG/FB/Threads) from a single set of inputs, templates, or upstream data.
410
+
411
+ ---
412
+
413
+ ### What it does
414
+
415
+ - You select:
416
+ - **Resources** (Instagram, Facebook Page, Threads)
417
+ - **Operations** per resource (checkboxes; only relevant options appear)
418
+
419
+ - You provide common inputs (e.g., `imageUrl`, `videoUrl`, `caption`, IDs)
420
+ - The node outputs **one item** whose `json.data` is an **array of jobs** ready for the Meta Publisher node’s **JSON input** mode.
421
+
422
+ ---
423
+
424
+ ### Basic wiring
425
+
426
+ 1. **Meta Publisher Utils** → **Meta Publisher**
427
+
428
+ - In **Meta Publisher**:
429
+ - Set **Input Source** = `From JSON Property`
430
+ - Set **JSON Property Path** = `data`
431
+
432
+ That’s it—Meta Publisher will execute each generated job in the array.
433
+
434
+ ---
435
+
436
+ ### Quick start (example)
437
+
438
+ 1. Drop **Meta Publisher Utils**.
439
+ 2. In **Resources**, tick **Instagram** and **Threads**.
440
+ 3. In **Instagram Operations**, tick **Publish Image** and **Publish Reel**.
441
+ 4. Fill:
442
+ - **IG User ID**: `1789…`
443
+ - **Image URL**: `https://example.com/image.jpg`
444
+ - **Video URL**: `https://example.com/reel.mp4`
445
+ - **Caption**: `Hello from n8n`
446
+
447
+ 5. In **Threads Operations**, tick **Publish Text**:
448
+ - **Threads User ID**: `9876…`
449
+ - **Threads Text**: `Posting from n8n 💚`
450
+
451
+ 6. (Optional) Leave **Skip Missing** enabled to silently skip incomplete jobs.
452
+ 7. Connect to **Meta Publisher** (JSON mode as above) and run.
453
+
454
+ The Utils node will output something like:
455
+
456
+ ```json
457
+ {
458
+ "data": [
459
+ {
460
+ "resource": "instagram",
461
+ "operation": "publishImage",
462
+ "igUserId": "1789...",
463
+ "mediaUrl": "https://example.com/image.jpg",
464
+ "caption": "Hello from n8n",
465
+ "userTags": [{ "username": "someuser", "x": 0.1, "y": 0.8 }],
466
+ "autoPublish": true
467
+ },
468
+ {
469
+ "resource": "instagram",
470
+ "operation": "publishReel",
471
+ "igUserId": "1789...",
472
+ "videoUrl": "https://example.com/reel.mp4",
473
+ "caption": "Hello from n8n",
474
+ "userTags": [{ "username": "someuser", "x": 0.1, "y": 0.8 }],
475
+ "thumbOffsetMs": 0,
476
+ "shareToFeed": true,
477
+ "autoPublish": true
478
+ },
479
+ {
480
+ "resource": "threads",
481
+ "operation": "threadsPublishText",
482
+ "thUserId": "9876...",
483
+ "text": "Posting from n8n 💚"
484
+ }
485
+ ],
486
+ "count": 3
487
+ }
488
+ ```
489
+
490
+ ---
491
+
492
+ ### Editable fields (high level)
493
+
494
+ - **Resources** (multi-select):
495
+ - Instagram / Facebook Page / Threads
496
+
497
+ - **Operations** (checkboxes shown only when the resource is selected):
498
+ - **Instagram:** `publishStory`, `publishImage`, `publishVideo`, `publishReel`, `publishCarousel`
499
+ - **Facebook Page:** `publishFbPhoto`, `publishFbVideo`
500
+ - **Threads:** `threadsPublishText`, `threadsPublishImage`, `threadsPublishVideo`, `threadsPublishCarousel`
501
+
502
+ - **Common inputs:** `imageUrl`, `videoUrl`, `caption`
503
+ - **Per-resource IDs:** `igUserId`, `pageId`, `thUserId`
504
+ - **Extras:**
505
+ - IG: `coverUrl` (video), `reelVideoUrl`, `thumbOffsetMs`, `shareToFeed`, `igItems` (carousel)
506
+ - IG Story: `storyImageUrl`, `storyVideoUrl` (if omitted, falls back to common URLs)
507
+ - Threads: `text`, `altText`, `thItems` (carousel: image/video entries with `altText`, optional `caption`)
508
+
509
+ - **Behavior toggles:**
510
+ - **Skip Missing:** Whether to skip incomplete jobs instead of throwing errors.
511
+ - **Include Example Set:** Whether to include example URLs/IDs when you don’t have real ones yet (for demos).
512
+
513
+ > Tip: When building carousels, supply at least **2 items**; the Utils node will warn/skip otherwise (depending on **Skip Missing**).
514
+
515
+ ---
516
+
517
+ ### Feeding dynamic data
518
+
519
+ Upstream nodes (e.g., **Set**, **Spreadsheet File**, **HTTP Request**) can provide per-item fields like `igUserId`, `imageUrl`, etc. Use n8n expressions in the Utils node (e.g., `={{$json.imageUrl}}`) to populate the payload dynamically.
520
+
521
+ - To create **many jobs** from a single record, fill the common fields and tick multiple operations/resources.
522
+ - To create **one job per record**, feed the Utils node multiple items (one per row/record). It outputs one payload per input item.
523
+
524
+ ---
525
+
526
+ ### Minimal recipes
527
+
528
+ **Instagram → Image**
529
+
530
+ ```json
531
+ {
532
+ "resource": "instagram",
533
+ "operation": "publishImage",
534
+ "igUserId": "1789...",
535
+ "mediaUrl": "https://example.com/photo.jpg",
536
+ "caption": "My IG post",
537
+ "userTags": [{ "username": "someuser", "x": 0.1, "y": 0.8 }],
538
+ "autoPublish": true
539
+ }
540
+ ```
541
+
542
+ **Instagram → Story (video)**
543
+
544
+ ```json
545
+ {
546
+ "resource": "instagram",
547
+ "operation": "publishStory",
548
+ "igUserId": "1789...",
549
+ "mediaUrl": "https://example.com/story.mp4",
550
+ "caption": "Story time",
551
+ "storyKind": "video",
552
+ "autoPublish": true
553
+ }
554
+ ```
555
+
556
+ **Facebook Page → Photo**
557
+
558
+ ```json
559
+ {
560
+ "resource": "facebook",
561
+ "operation": "publishFbPhoto",
562
+ "pageId": "112233445566",
563
+ "imageUrl": "https://example.com/photo.jpg",
564
+ "caption": "FB photo caption"
565
+ }
566
+ ```
567
+
568
+ **Threads → Image**
569
+
570
+ ```json
571
+ {
572
+ "resource": "threads",
573
+ "operation": "threadsPublishImage",
574
+ "thUserId": "987654321",
575
+ "imageUrl": "https://example.com/thread.jpg",
576
+ "text": "Threads image caption",
577
+ "altText": "Alt text for accessibility"
578
+ }
579
+ ```
580
+
581
+ ---
582
+
583
+ ### Common pitfalls & tips
584
+
585
+ - **IDs are required** per platform:
586
+ - Instagram → `igUserId`
587
+ - Facebook Page → `pageId`
588
+ - Threads → `thUserId`
589
+
590
+ - **Skip Missing** is your friend during setup—flip it off for stricter validation later.
591
+ - **Carousels:** provide 2–10 items (IG) or 2–20 (Threads). The Publisher node will also **poll children first** for IG.
592
+ - **Meta Publisher node:** in JSON mode it expects `platform` internally, but we accept `resource` and normalize it—your Utils output uses `resource` as shown here (works with our Publisher).
593
+ - **Permalinks/insights:** use a downstream HTTP Request or an enhanced Publisher to fetch them after publish.
594
+
595
+ ---
596
+
597
+ ### Chaining to Meta Publisher
598
+
599
+ 1. **Meta Publisher Utils** (outputs `{ data: [...] }`)
600
+ 2. **Meta Publisher**
601
+ - **Input Source** = `From JSON Property`
602
+ - **JSON Property Path** = `data`
603
+
604
+ 3. Optional: add **If** / **Switch** nodes to route successes vs errors (use `status`, `published`, etc.).
605
+
606
+ ---
607
+
608
+ With this utility in front of your Publisher, you can define one compact set of inputs and instantly generate all the platform-specific jobs your workflow needs.
609
+
610
+ ## Development
611
+
612
+ This repo uses the same conventions as the n8n node starter:
613
+
614
+ - TypeScript build to `dist/`
615
+ - ESLint + Prettier for quality
616
+ - Starter-like scripts: `build`, `lint`, `lintfix`
617
+
618
+ Typical loop:
619
+
620
+ ```bash
621
+ npm i
622
+ npm run dev # tsc --watch
623
+ # In another terminal, run n8n and test
624
+ ```
625
+
626
+ Refer to n8n’s “Using this starter” steps (generate repo, install deps, lint, test locally, publish) for overall workflow. 
627
+
628
+ ---
629
+
630
+ ## Testing locally
631
+
632
+ n8n documents how to **run your node locally**; follow those instructions to link your development build and iterate quickly. 
633
+
634
+ ---
635
+
636
+ ## Contributing
637
+
638
+ Issues and PRs are welcome! Please:
639
+
640
+ - Lint before committing (`npm run lint` / `npm run lintfix`)
641
+ - Keep code DRY: use shared client, poller, and resource adapters
642
+
643
+ ---
644
+
645
+ ## License
646
+
647
+ MIT — same as the official starter. 
648
+
649
+ ---
650
+
651
+ ### Notes
652
+
653
+ - Ensure your Meta app has the appropriate permissions for your chosen resource(s) and that your IG account is a professional account linked to a Page when required.
654
+ - Threads uses a separate host (`graph.threads.net`) under the Meta umbrella; this node handles it internally — you just choose **Threads** in the UI.
@@ -0,0 +1,7 @@
1
+ import type { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class MetaGraphApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MetaGraphApi = void 0;
4
+ class MetaGraphApi {
5
+ constructor() {
6
+ this.name = 'metaGraphApi';
7
+ this.displayName = 'Meta Graph API (Access Token) API';
8
+ this.documentationUrl = 'https://developers.facebook.com/';
9
+ this.properties = [
10
+ {
11
+ displayName: 'Access Token',
12
+ name: 'accessToken',
13
+ type: 'string',
14
+ typeOptions: { password: true },
15
+ default: '',
16
+ required: true,
17
+ description: 'Page/IG/Threads access token',
18
+ },
19
+ ];
20
+ }
21
+ }
22
+ exports.MetaGraphApi = MetaGraphApi;
23
+ //# sourceMappingURL=MetaGraphApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetaGraphApi.credentials.js","sourceRoot":"","sources":["../../credentials/MetaGraphApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IAAzB;QACC,SAAI,GAAG,cAAc,CAAC;QACtB,gBAAW,GAAG,mCAAmC,CAAC;QAClD,qBAAgB,GAAG,kCAAkC,CAAC;QACtD,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,8BAA8B;aAC3C;SACD,CAAC;IACH,CAAC;CAAA;AAfD,oCAeC"}