import { resolveMetaIntegration, type MetaAccountParams } from './accounts.ts' import { graphItems, graphRequest, requireConfirmOrDryRun, withPageAccessToken, type JsonObject, } from './core.ts' import { boundedLimit } from './validation.ts' export type PageListParams = MetaAccountParams & { limit?: number after?: string fields?: string } export type PageGetParams = MetaAccountParams & { pageId: string fields?: string } export type PagePostsParams = MetaAccountParams & { pageId: string limit?: number after?: string fields?: string } export type PagePublishParams = MetaAccountParams & { pageId: string message: string link?: string published?: boolean dryRun?: boolean confirm?: boolean } const PAGE_LIST_FIELDS = 'id,name,category,tasks,fan_count,instagram_business_account' const PAGE_GET_FIELDS = 'id,name,category,about,fan_count,link,username,instagram_business_account' const POST_FIELDS = 'id,message,created_time,permalink_url,shares,is_published' /** List Facebook Pages the connected user or system user can access. Never hard-codes a Page id. */ export async function listPages(params: PageListParams = {}) { const data = await graphRequest({ integration: resolveMetaIntegration(params), authMode: params.authMode, tokenSecret: params.tokenSecret, account: params.account, path: '/me/accounts', query: { fields: params.fields ?? PAGE_LIST_FIELDS, limit: boundedLimit(params.limit, 25, 100), after: params.after, }, }) return graphItems(data) } /** Read one Facebook Page by caller-supplied id. */ export async function getPage(params: PageGetParams) { const pageId = params.pageId?.trim() if (!pageId) throw new Error('getPage requires pageId from listPages (or the Page the caller named).') return graphRequest({ ...params, path: '/' + encodeURIComponent(pageId), query: { fields: params.fields ?? PAGE_GET_FIELDS }, }) } /** List recent posts on a Facebook Page. */ export async function listPosts(params: PagePostsParams) { const pageId = params.pageId?.trim() if (!pageId) throw new Error('listPosts requires pageId.') const data = await graphRequest({ ...params, path: '/' + encodeURIComponent(pageId) + '/posts', query: { fields: params.fields ?? POST_FIELDS, limit: boundedLimit(params.limit, 10, 50), after: params.after, }, }) return graphItems(data) } /** Read one Page post. */ export async function getPost(params: MetaAccountParams & { postId: string; fields?: string }) { const postId = params.postId?.trim() if (!postId) throw new Error('getPost requires postId.') return graphRequest({ ...params, path: '/' + encodeURIComponent(postId), query: { fields: params.fields ?? POST_FIELDS }, }) } /** Preview or publish a Page feed post. Live publish requires confirm: true. */ export async function publishPost(params: PagePublishParams) { const pageId = params.pageId?.trim() if (!pageId) throw new Error('publishPost requires pageId from listPages. Do not invent a brand Page id.') const message = params.message?.trim() if (!message) throw new Error('publishPost requires message.') const body: JsonObject = { message } if (params.link) body.link = params.link if (params.published === false) body.published = false const path = '/' + encodeURIComponent(pageId) + '/feed' const mode = requireConfirmOrDryRun({ dryRun: params.dryRun, confirm: params.confirm, action: 'publishPost', }) if (mode.dryRun) { return { dryRun: true as const, method: 'POST', path, pageId, body, } } return withPageAccessToken({ ...params, pageId }, (pageAccessToken) => graphRequest({ ...params, pageAccessToken, method: 'POST', path, body, }), ) } /** * Facebook Page helpers. * @example * import { listPages } from 'kody:@kody/meta/pages' * const { items } = await listPages({ limit: 5 }) */ export default function pages() { return { listPages, getPage, listPosts, getPost, publishPost } }