nodebb-plugin-facebook-post 1.0.37 → 1.0.38

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 (2) hide show
  1. package/library.js +39 -8
  2. package/package.json +1 -1
package/library.js CHANGED
@@ -247,6 +247,26 @@ async function getInstagramUserId() {
247
247
  return igId;
248
248
  }
249
249
 
250
+ async function waitForIgContainer(containerId, accessToken, graphVersion, { maxAttempts = 20, intervalMs = 3000 } = {}) {
251
+ const url = `https://graph.facebook.com/${graphVersion}/${containerId}`;
252
+ for (let i = 0; i < maxAttempts; i++) {
253
+ // eslint-disable-next-line no-await-in-loop
254
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
255
+ // eslint-disable-next-line no-await-in-loop
256
+ const resp = await axios.get(url, {
257
+ params: { fields: 'status_code,status', access_token: accessToken },
258
+ timeout: 10000,
259
+ });
260
+ const statusCode = resp.data && resp.data.status_code;
261
+ if (statusCode === 'FINISHED') return;
262
+ if (statusCode === 'ERROR' || statusCode === 'EXPIRED') {
263
+ throw new Error(`Instagram container ${containerId} status: ${statusCode} (${resp.data && resp.data.status})`);
264
+ }
265
+ // IN_PROGRESS or PUBLISHED → keep waiting
266
+ }
267
+ throw new Error(`Instagram container ${containerId} did not reach FINISHED after ${maxAttempts} attempts`);
268
+ }
269
+
250
270
  async function postToInstagram(ctx) {
251
271
  const rawContent = ctx.post.content || '';
252
272
  const topicTitle = decodeHtmlEntities(ctx.topic.title || 'Nouveau sujet');
@@ -269,17 +289,21 @@ async function postToInstagram(ctx) {
269
289
 
270
290
  const igUserId = await getInstagramUserId();
271
291
  const baseUrl = `https://graph.facebook.com/${settings.fbGraphVersion}/${igUserId}`;
292
+ const token = settings.fbPageAccessToken;
293
+ const graphVersion = settings.fbGraphVersion;
272
294
 
273
295
  if (imageUrls.length === 1) {
274
296
  const containerResp = await axios.post(`${baseUrl}/media`, null, {
275
- params: { image_url: imageUrls[0], caption, access_token: settings.fbPageAccessToken },
297
+ params: { image_url: imageUrls[0], caption, access_token: token },
276
298
  timeout: 20000,
277
299
  });
278
300
  const containerId = containerResp.data && containerResp.data.id;
279
301
  if (!containerId) return null;
280
302
 
303
+ await waitForIgContainer(containerId, token, graphVersion);
304
+
281
305
  const publishResp = await axios.post(`${baseUrl}/media_publish`, null, {
282
- params: { creation_id: containerId, access_token: settings.fbPageAccessToken },
306
+ params: { creation_id: containerId, access_token: token },
283
307
  timeout: 20000,
284
308
  });
285
309
  return publishResp.data && publishResp.data.id;
@@ -294,25 +318,30 @@ async function postToInstagram(ctx) {
294
318
  image_url: url,
295
319
  media_type: 'IMAGE',
296
320
  is_carousel_item: true,
297
- access_token: settings.fbPageAccessToken,
321
+ access_token: token,
298
322
  },
299
323
  timeout: 20000,
300
324
  });
301
325
  const childId = childResp.data && childResp.data.id;
302
- if (childId) childIds.push(childId);
326
+ if (childId) {
327
+ // eslint-disable-next-line no-await-in-loop
328
+ await waitForIgContainer(childId, token, graphVersion);
329
+ childIds.push(childId);
330
+ }
303
331
  }
304
332
  if (!childIds.length) return null;
305
333
 
306
334
  // Instagram requires at least 2 children for a carousel; fall back to single image
307
335
  if (childIds.length < 2) {
308
336
  const singleResp = await axios.post(`${baseUrl}/media`, null, {
309
- params: { image_url: imageUrls[0], caption, access_token: settings.fbPageAccessToken },
337
+ params: { image_url: imageUrls[0], caption, access_token: token },
310
338
  timeout: 20000,
311
339
  });
312
340
  const singleId = singleResp.data && singleResp.data.id;
313
341
  if (!singleId) return null;
342
+ await waitForIgContainer(singleId, token, graphVersion);
314
343
  const pubResp = await axios.post(`${baseUrl}/media_publish`, null, {
315
- params: { creation_id: singleId, access_token: settings.fbPageAccessToken },
344
+ params: { creation_id: singleId, access_token: token },
316
345
  timeout: 20000,
317
346
  });
318
347
  return pubResp.data && pubResp.data.id;
@@ -322,7 +351,7 @@ async function postToInstagram(ctx) {
322
351
  form.append('media_type', 'CAROUSEL');
323
352
  form.append('caption', caption);
324
353
  form.append('children', childIds.join(','));
325
- form.append('access_token', settings.fbPageAccessToken);
354
+ form.append('access_token', token);
326
355
 
327
356
  const carouselResp = await axios.post(`${baseUrl}/media`, form, {
328
357
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
@@ -331,8 +360,10 @@ async function postToInstagram(ctx) {
331
360
  const carouselId = carouselResp.data && carouselResp.data.id;
332
361
  if (!carouselId) return null;
333
362
 
363
+ await waitForIgContainer(carouselId, token, graphVersion);
364
+
334
365
  const publishResp = await axios.post(`${baseUrl}/media_publish`, null, {
335
- params: { creation_id: carouselId, access_token: settings.fbPageAccessToken },
366
+ params: { creation_id: carouselId, access_token: token },
336
367
  timeout: 20000,
337
368
  });
338
369
  return publishResp.data && publishResp.data.id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-facebook-post",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
4
4
  "description": "Auto-post new NodeBB topics to a fixed Facebook Page (text + NodeBB uploads + place id).",
5
5
  "main": "library.js",
6
6
  "dependencies": {