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.
- package/LICENSE.md +19 -0
- package/README.md +654 -0
- package/dist/credentials/MetaGraphApi.credentials.d.ts +7 -0
- package/dist/credentials/MetaGraphApi.credentials.js +23 -0
- package/dist/credentials/MetaGraphApi.credentials.js.map +1 -0
- package/dist/nodes/MetaPublisher/MetaPublisher.node.d.ts +5 -0
- package/dist/nodes/MetaPublisher/MetaPublisher.node.js +934 -0
- package/dist/nodes/MetaPublisher/MetaPublisher.node.js.map +1 -0
- package/dist/nodes/MetaPublisher/MetaPublisher.svg +1 -0
- package/dist/nodes/MetaPublisher/lib/client.d.ts +4 -0
- package/dist/nodes/MetaPublisher/lib/client.js +34 -0
- package/dist/nodes/MetaPublisher/lib/client.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/constant.d.ts +25 -0
- package/dist/nodes/MetaPublisher/lib/constant.js +29 -0
- package/dist/nodes/MetaPublisher/lib/constant.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/fb.d.ts +68 -0
- package/dist/nodes/MetaPublisher/lib/fb.js +155 -0
- package/dist/nodes/MetaPublisher/lib/fb.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/ig.d.ts +78 -0
- package/dist/nodes/MetaPublisher/lib/ig.js +106 -0
- package/dist/nodes/MetaPublisher/lib/ig.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/ops.d.ts +127 -0
- package/dist/nodes/MetaPublisher/lib/ops.js +564 -0
- package/dist/nodes/MetaPublisher/lib/ops.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/poll.d.ts +7 -0
- package/dist/nodes/MetaPublisher/lib/poll.js +19 -0
- package/dist/nodes/MetaPublisher/lib/poll.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/threads.d.ts +30 -0
- package/dist/nodes/MetaPublisher/lib/threads.js +92 -0
- package/dist/nodes/MetaPublisher/lib/threads.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/types.d.ts +31 -0
- package/dist/nodes/MetaPublisher/lib/types.js +3 -0
- package/dist/nodes/MetaPublisher/lib/types.js.map +1 -0
- package/dist/nodes/MetaPublisher/lib/utils.d.ts +7 -0
- package/dist/nodes/MetaPublisher/lib/utils.js +28 -0
- package/dist/nodes/MetaPublisher/lib/utils.js.map +1 -0
- package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisher.svg +1 -0
- package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisherBinaryUpload.node.d.ts +4 -0
- package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisherBinaryUpload.node.js +39 -0
- package/dist/nodes/MetaPublisherBinaryUpload/MetaPublisherBinaryUpload.node.js.map +1 -0
- package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisher.svg +1 -0
- package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisherJsonGenerator.node.d.ts +5 -0
- package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisherJsonGenerator.node.js +730 -0
- package/dist/nodes/MetaPublisherJsonGenerator/MetaPublisherJsonGenerator.node.js.map +1 -0
- package/dist/nodes/MetaPublisherUtils/MetaPublisher.svg +1 -0
- package/dist/nodes/MetaPublisherUtils/MetaPublisherUtils.node.d.ts +5 -0
- package/dist/nodes/MetaPublisherUtils/MetaPublisherUtils.node.js +570 -0
- package/dist/nodes/MetaPublisherUtils/MetaPublisherUtils.node.js.map +1 -0
- package/dist/package.json +70 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/index.js +0 -0
- 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
|
+

|
|
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
|
+

|
|
14
|
+
|
|
15
|
+
#### Nodes and Operations
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
#### JSON Generator Output
|
|
21
|
+
|
|
22
|
+

|
|
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
|
+

|
|
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,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"}
|