← 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.' };
};