← back to Norma

agents/facebook-agent/skills/post.js

108 lines

/**
 * Facebook Post Skill
 *
 * Posts content to a Facebook Page via Meta Graph API.
 * Runs in simulation mode when FB_PAGE_ACCESS_TOKEN is not set.
 *
 * Real endpoint:
 *   POST https://graph.facebook.com/v19.0/{page_id}/feed
 *   Params: message, link, access_token
 */

const { loadCredentials } = require('../../shared/credentials');

const AGENT = 'facebook-agent';
const PLATFORM = 'facebook';

/**
 * Check if Facebook credentials are configured (DB-first, env-fallback).
 * @returns {Promise<{has: boolean, creds: Object}>}
 */
async function getCredentials() {
  const creds = await loadCredentials('facebook');
  return {
    has: !!(creds?.FB_PAGE_ID && creds?.FB_PAGE_ACCESS_TOKEN),
    pageId: creds?.FB_PAGE_ID || '',
    accessToken: creds?.FB_PAGE_ACCESS_TOKEN || '',
  };
}

/**
 * @param {Object} params - Request body
 * @param {string} [params.message] - Post message text
 * @param {string} [params.link] - URL to attach to the post
 * @param {string} [params.petition_title] - Title for auto-generation context
 * @param {string} [params.petition_url] - Petition URL (alias for link)
 * @param {string} [params.pipeline_id] - Pipeline entry ID to link
 * @returns {Promise<Object>}
 */
module.exports = async function post(params) {
  const message = params.message || params.text || '';
  const link = params.link || params.petition_url || '';
  const { has: hasCreds, pageId, accessToken } = await getCredentials();
  const simulated = !hasCreds;

  console.log(`[${AGENT}] Post skill invoked — simulation=${simulated}`);
  console.log(`[${AGENT}] Message: ${message.substring(0, 100)}${message.length > 100 ? '...' : ''}`);
  if (link) console.log(`[${AGENT}] Link: ${link}`);

  if (simulated) {
    // --- Simulation mode ---
    const simulatedId = `fb_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;

    console.log(`[${AGENT}] SIMULATED post created: ${simulatedId}`);

    return {
      post_id: simulatedId,
      message,
      link: link || null,
      url: `https://www.facebook.com/${process.env.FB_PAGE_ID || 'page'}/posts/${simulatedId}`,
      simulated: true,
      posted: false,
      platform: PLATFORM,
      pipeline_id: params.pipeline_id || null,
      created_at: new Date().toISOString(),
    };
  }

  // --- Real API call (commented out until credentials are configured) ---
  //
  // const pageId = process.env.FB_PAGE_ID;
  // const accessToken = process.env.FB_PAGE_ACCESS_TOKEN;
  //
  // const url = `https://graph.facebook.com/v19.0/${pageId}/feed`;
  //
  // const body = {
  //   message,
  //   access_token: accessToken,
  // };
  // if (link) body.link = link;
  //
  // const response = await fetch(url, {
  //   method: 'POST',
  //   headers: { 'Content-Type': 'application/json' },
  //   body: JSON.stringify(body),
  // });
  //
  // const data = await response.json();
  //
  // if (data.error) {
  //   throw new Error(`Facebook API error: ${data.error.message}`);
  // }
  //
  // return {
  //   post_id: data.id,
  //   message,
  //   link: link || null,
  //   url: `https://www.facebook.com/${data.id}`,
  //   simulated: false,
  //   posted: true,
  //   platform: PLATFORM,
  //   pipeline_id: params.pipeline_id || null,
  //   created_at: new Date().toISOString(),
  // };

  // Fallback (should not reach here when credentials are set and above is uncommented)
  return { error: 'Real API call not yet enabled. Uncomment the code above.' };
};