@agentforge-io/connectors-meta 0.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/dist/connector.d.ts +80 -0
- package/dist/connector.js +263 -0
- package/dist/http.d.ts +89 -0
- package/dist/http.js +157 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +71 -0
- package/dist/page.d.ts +164 -0
- package/dist/page.js +139 -0
- package/dist/tools/_shared.d.ts +25 -0
- package/dist/tools/_shared.js +31 -0
- package/dist/tools/facebook-pages.d.ts +41 -0
- package/dist/tools/facebook-pages.js +362 -0
- package/dist/tools/instagram.d.ts +42 -0
- package/dist/tools/instagram.js +389 -0
- package/dist/tools/messenger.d.ts +43 -0
- package/dist/tools/messenger.js +320 -0
- package/dist/tools/whatsapp.d.ts +39 -0
- package/dist/tools/whatsapp.js +242 -0
- package/package.json +24 -0
package/dist/page.d.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page-token + WhatsApp business helpers.
|
|
3
|
+
*
|
|
4
|
+
* Meta's OAuth flow gives the connector a USER access token. For every
|
|
5
|
+
* surface except `metaWhatsAppConnector`, the actual API calls use a
|
|
6
|
+
* PAGE access token (or an IG-business-account token derived from one)
|
|
7
|
+
* because user tokens can't read Page-owned conversations, posts, or
|
|
8
|
+
* Instagram business inboxes.
|
|
9
|
+
*
|
|
10
|
+
* Why this matters for the connector:
|
|
11
|
+
* - The OAuth callback persists a user token in `af_connector_auths`.
|
|
12
|
+
* - Before the tools can run, we exchange that user token for a list
|
|
13
|
+
* of page tokens (`GET /me/accounts`) and the operator picks one in
|
|
14
|
+
* the connect modal.
|
|
15
|
+
* - We persist the picked page id + token alongside the user token so
|
|
16
|
+
* subsequent API calls can grab it from `ctx.metadata.pageId` /
|
|
17
|
+
* `ctx.getAccessToken()` without a roundtrip every turn.
|
|
18
|
+
*
|
|
19
|
+
* Why one helper instead of one per surface:
|
|
20
|
+
* - The `/me/accounts` payload is the same for Instagram, Messenger,
|
|
21
|
+
* and FB Pages — every Page object includes its `instagram_business_account`
|
|
22
|
+
* edge when the IG account is linked. So one fetch covers all three.
|
|
23
|
+
* - Three of the four connectors share the same Page-selector UX in
|
|
24
|
+
* the dashboard (analogous to Shopify's shop selector); only
|
|
25
|
+
* WhatsApp has its own selector (phone number id, not Page id).
|
|
26
|
+
*
|
|
27
|
+
* Long-lived tokens:
|
|
28
|
+
* - The user token returned by the OAuth callback is short-lived
|
|
29
|
+
* (~1h). Before calling `/me/accounts` we MUST upgrade it via
|
|
30
|
+
* `GET /oauth/access_token?grant_type=fb_exchange_token` — the
|
|
31
|
+
* long-lived form lasts ~60 days.
|
|
32
|
+
* - Page tokens derived from a long-lived user token are themselves
|
|
33
|
+
* **non-expiring** (as long as the user keeps a valid session with
|
|
34
|
+
* Facebook). That's the property we want — no refresh dance ever.
|
|
35
|
+
*/
|
|
36
|
+
export declare class MetaPageSelectionError extends Error {
|
|
37
|
+
readonly raw: string;
|
|
38
|
+
constructor(raw: string, message: string);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Exchange a short-lived user access token for a long-lived one.
|
|
42
|
+
* Meta returns short-lived tokens (~1h) from the OAuth callback even
|
|
43
|
+
* when we asked for `offline` access — you MUST call this helper before
|
|
44
|
+
* deriving page tokens, or the page tokens inherit the short TTL.
|
|
45
|
+
*
|
|
46
|
+
* Endpoint:
|
|
47
|
+
* GET /oauth/access_token?grant_type=fb_exchange_token
|
|
48
|
+
* &client_id=...&client_secret=...&fb_exchange_token=<short-lived>
|
|
49
|
+
*
|
|
50
|
+
* Returns `{ access_token, token_type, expires_in }`. The
|
|
51
|
+
* `expires_in` is in seconds; for production we treat any value above
|
|
52
|
+
* 30 days as "long-lived enough" and don't pre-emptively refresh.
|
|
53
|
+
*/
|
|
54
|
+
export interface LongLivedUserTokenResponse {
|
|
55
|
+
access_token: string;
|
|
56
|
+
token_type: string;
|
|
57
|
+
expires_in?: number;
|
|
58
|
+
}
|
|
59
|
+
export declare function exchangeForLongLivedUserToken(opts: {
|
|
60
|
+
shortLivedUserToken: string;
|
|
61
|
+
clientId: string;
|
|
62
|
+
clientSecret: string;
|
|
63
|
+
}): Promise<LongLivedUserTokenResponse>;
|
|
64
|
+
/**
|
|
65
|
+
* One row from `GET /me/accounts`. Includes the page access token and,
|
|
66
|
+
* when the IG account is linked, the IG business account id used by the
|
|
67
|
+
* Instagram tools.
|
|
68
|
+
*/
|
|
69
|
+
export interface MetaManagedPage {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
access_token: string;
|
|
73
|
+
/** Page roles the calling user has on this Page. We don't filter on
|
|
74
|
+
* this — tools that need a specific role surface a 403 with a clear
|
|
75
|
+
* message at runtime. */
|
|
76
|
+
tasks?: string[];
|
|
77
|
+
category?: string;
|
|
78
|
+
category_list?: Array<{
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
}>;
|
|
82
|
+
/** Present when the Page has an Instagram Business Account linked.
|
|
83
|
+
* This is the id the Instagram Graph API expects, NOT the @-handle. */
|
|
84
|
+
instagram_business_account?: {
|
|
85
|
+
id: string;
|
|
86
|
+
username?: string;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export interface ListManagedPagesResponse {
|
|
90
|
+
data: MetaManagedPage[];
|
|
91
|
+
paging?: {
|
|
92
|
+
cursors?: {
|
|
93
|
+
before?: string;
|
|
94
|
+
after?: string;
|
|
95
|
+
};
|
|
96
|
+
next?: string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Fetch the Pages the operator manages, each with its own page access
|
|
101
|
+
* token. Used at connect-time to populate the page-selector modal.
|
|
102
|
+
*
|
|
103
|
+
* We request a wide-ish field set in one shot to avoid an N+1 (the
|
|
104
|
+
* naive flow without `fields=` only returns id + name, then each Page
|
|
105
|
+
* needs a follow-up for the access_token).
|
|
106
|
+
*
|
|
107
|
+
* The token argument should be a LONG-LIVED user token; passing a
|
|
108
|
+
* short-lived one technically works but the derived page tokens inherit
|
|
109
|
+
* the short TTL.
|
|
110
|
+
*/
|
|
111
|
+
export declare function listManagedPages(longLivedUserToken: string): Promise<MetaManagedPage[]>;
|
|
112
|
+
/**
|
|
113
|
+
* Fetch a specific managed Page by id. Used by the page selector after
|
|
114
|
+
* the operator clicks one to confirm the choice, and at tool-run time
|
|
115
|
+
* if we ever need to re-resolve fresh metadata (e.g. the operator
|
|
116
|
+
* unlinked the IG account between OAuth and first tool call).
|
|
117
|
+
*/
|
|
118
|
+
export declare function getManagedPage(longLivedUserToken: string, pageId: string): Promise<MetaManagedPage | null>;
|
|
119
|
+
/**
|
|
120
|
+
* One WhatsApp Business Account (WABA) the operator can pick. Each WABA
|
|
121
|
+
* owns one or more phone numbers; tools target a phone number id
|
|
122
|
+
* (`/{phone-number-id}/messages`), not the WABA id directly.
|
|
123
|
+
*/
|
|
124
|
+
export interface MetaWhatsAppPhoneNumber {
|
|
125
|
+
id: string;
|
|
126
|
+
display_phone_number: string;
|
|
127
|
+
verified_name?: string;
|
|
128
|
+
quality_rating?: 'GREEN' | 'YELLOW' | 'RED';
|
|
129
|
+
}
|
|
130
|
+
export interface MetaWhatsAppBusinessAccount {
|
|
131
|
+
id: string;
|
|
132
|
+
name?: string;
|
|
133
|
+
phone_numbers: MetaWhatsAppPhoneNumber[];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Fetch the WABAs the operator's Business Manager owns, each with the
|
|
137
|
+
* phone numbers attached. Used by the WhatsApp connector's
|
|
138
|
+
* phone-number selector.
|
|
139
|
+
*
|
|
140
|
+
* Requires `whatsapp_business_management` scope. The endpoint is
|
|
141
|
+
* `/me/businesses/{business-id}/owned_whatsapp_business_accounts` —
|
|
142
|
+
* but to avoid a Business-Manager listing roundtrip we use the
|
|
143
|
+
* `/me?fields=businesses{owned_whatsapp_business_accounts{...}}` shape.
|
|
144
|
+
*/
|
|
145
|
+
export interface ListWabasResponse {
|
|
146
|
+
data: Array<{
|
|
147
|
+
id: string;
|
|
148
|
+
businesses?: {
|
|
149
|
+
data: Array<{
|
|
150
|
+
id: string;
|
|
151
|
+
owned_whatsapp_business_accounts?: {
|
|
152
|
+
data: Array<{
|
|
153
|
+
id: string;
|
|
154
|
+
name?: string;
|
|
155
|
+
phone_numbers?: {
|
|
156
|
+
data: MetaWhatsAppPhoneNumber[];
|
|
157
|
+
};
|
|
158
|
+
}>;
|
|
159
|
+
};
|
|
160
|
+
}>;
|
|
161
|
+
};
|
|
162
|
+
}>;
|
|
163
|
+
}
|
|
164
|
+
export declare function listWhatsAppBusinessAccounts(longLivedUserToken: string): Promise<MetaWhatsAppBusinessAccount[]>;
|
package/dist/page.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Page-token + WhatsApp business helpers.
|
|
4
|
+
*
|
|
5
|
+
* Meta's OAuth flow gives the connector a USER access token. For every
|
|
6
|
+
* surface except `metaWhatsAppConnector`, the actual API calls use a
|
|
7
|
+
* PAGE access token (or an IG-business-account token derived from one)
|
|
8
|
+
* because user tokens can't read Page-owned conversations, posts, or
|
|
9
|
+
* Instagram business inboxes.
|
|
10
|
+
*
|
|
11
|
+
* Why this matters for the connector:
|
|
12
|
+
* - The OAuth callback persists a user token in `af_connector_auths`.
|
|
13
|
+
* - Before the tools can run, we exchange that user token for a list
|
|
14
|
+
* of page tokens (`GET /me/accounts`) and the operator picks one in
|
|
15
|
+
* the connect modal.
|
|
16
|
+
* - We persist the picked page id + token alongside the user token so
|
|
17
|
+
* subsequent API calls can grab it from `ctx.metadata.pageId` /
|
|
18
|
+
* `ctx.getAccessToken()` without a roundtrip every turn.
|
|
19
|
+
*
|
|
20
|
+
* Why one helper instead of one per surface:
|
|
21
|
+
* - The `/me/accounts` payload is the same for Instagram, Messenger,
|
|
22
|
+
* and FB Pages — every Page object includes its `instagram_business_account`
|
|
23
|
+
* edge when the IG account is linked. So one fetch covers all three.
|
|
24
|
+
* - Three of the four connectors share the same Page-selector UX in
|
|
25
|
+
* the dashboard (analogous to Shopify's shop selector); only
|
|
26
|
+
* WhatsApp has its own selector (phone number id, not Page id).
|
|
27
|
+
*
|
|
28
|
+
* Long-lived tokens:
|
|
29
|
+
* - The user token returned by the OAuth callback is short-lived
|
|
30
|
+
* (~1h). Before calling `/me/accounts` we MUST upgrade it via
|
|
31
|
+
* `GET /oauth/access_token?grant_type=fb_exchange_token` — the
|
|
32
|
+
* long-lived form lasts ~60 days.
|
|
33
|
+
* - Page tokens derived from a long-lived user token are themselves
|
|
34
|
+
* **non-expiring** (as long as the user keeps a valid session with
|
|
35
|
+
* Facebook). That's the property we want — no refresh dance ever.
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.MetaPageSelectionError = void 0;
|
|
39
|
+
exports.exchangeForLongLivedUserToken = exchangeForLongLivedUserToken;
|
|
40
|
+
exports.listManagedPages = listManagedPages;
|
|
41
|
+
exports.getManagedPage = getManagedPage;
|
|
42
|
+
exports.listWhatsAppBusinessAccounts = listWhatsAppBusinessAccounts;
|
|
43
|
+
const http_1 = require("./http");
|
|
44
|
+
class MetaPageSelectionError extends Error {
|
|
45
|
+
constructor(raw, message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.raw = raw;
|
|
48
|
+
this.name = 'MetaPageSelectionError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.MetaPageSelectionError = MetaPageSelectionError;
|
|
52
|
+
async function exchangeForLongLivedUserToken(opts) {
|
|
53
|
+
// This endpoint is OAuth-flavored and lives at the same /oauth/...
|
|
54
|
+
// base — but uses query-string params and no Authorization header,
|
|
55
|
+
// so we bypass the standard `metaGet` (which always sends Bearer).
|
|
56
|
+
const url = new URL(`https://graph.facebook.com/${http_1.META_GRAPH_VERSION}/oauth/access_token`);
|
|
57
|
+
url.searchParams.set('grant_type', 'fb_exchange_token');
|
|
58
|
+
url.searchParams.set('client_id', opts.clientId);
|
|
59
|
+
url.searchParams.set('client_secret', opts.clientSecret);
|
|
60
|
+
url.searchParams.set('fb_exchange_token', opts.shortLivedUserToken);
|
|
61
|
+
const res = await fetch(url.toString(), { method: 'GET' });
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
throw new http_1.MetaApiError(res.status, res.statusText, await res.text().catch(() => ''));
|
|
64
|
+
}
|
|
65
|
+
return (await res.json());
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Fetch the Pages the operator manages, each with its own page access
|
|
69
|
+
* token. Used at connect-time to populate the page-selector modal.
|
|
70
|
+
*
|
|
71
|
+
* We request a wide-ish field set in one shot to avoid an N+1 (the
|
|
72
|
+
* naive flow without `fields=` only returns id + name, then each Page
|
|
73
|
+
* needs a follow-up for the access_token).
|
|
74
|
+
*
|
|
75
|
+
* The token argument should be a LONG-LIVED user token; passing a
|
|
76
|
+
* short-lived one technically works but the derived page tokens inherit
|
|
77
|
+
* the short TTL.
|
|
78
|
+
*/
|
|
79
|
+
async function listManagedPages(longLivedUserToken) {
|
|
80
|
+
const res = await (0, http_1.metaGet)({
|
|
81
|
+
accessToken: longLivedUserToken,
|
|
82
|
+
path: '/me/accounts',
|
|
83
|
+
query: {
|
|
84
|
+
fields: 'id,name,access_token,tasks,category,category_list,instagram_business_account{id,username}',
|
|
85
|
+
limit: 100,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return res.data ?? [];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Fetch a specific managed Page by id. Used by the page selector after
|
|
92
|
+
* the operator clicks one to confirm the choice, and at tool-run time
|
|
93
|
+
* if we ever need to re-resolve fresh metadata (e.g. the operator
|
|
94
|
+
* unlinked the IG account between OAuth and first tool call).
|
|
95
|
+
*/
|
|
96
|
+
async function getManagedPage(longLivedUserToken, pageId) {
|
|
97
|
+
try {
|
|
98
|
+
return await (0, http_1.metaGet)({
|
|
99
|
+
accessToken: longLivedUserToken,
|
|
100
|
+
path: `/${encodeURIComponent(pageId)}`,
|
|
101
|
+
query: {
|
|
102
|
+
fields: 'id,name,access_token,tasks,category,category_list,instagram_business_account{id,username}',
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
// 404 / 100-invalid-parameter → the Page no longer exists or the
|
|
108
|
+
// user lost admin access. Treat as "not found" rather than rethrow
|
|
109
|
+
// so the selector UX can show a clean message.
|
|
110
|
+
if (err instanceof http_1.MetaApiError &&
|
|
111
|
+
(err.status === 404 || err.metaCode === 100)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function listWhatsAppBusinessAccounts(longLivedUserToken) {
|
|
118
|
+
// `me` returns a single user object, but we ask for the nested
|
|
119
|
+
// edges in one query so we don't pay an N+1 over Business Manager
|
|
120
|
+
// → WABA → phone numbers.
|
|
121
|
+
const res = await (0, http_1.metaGet)({
|
|
122
|
+
accessToken: longLivedUserToken,
|
|
123
|
+
path: '/me',
|
|
124
|
+
query: {
|
|
125
|
+
fields: 'businesses{id,owned_whatsapp_business_accounts{id,name,phone_numbers{id,display_phone_number,verified_name,quality_rating}}}',
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
const wabas = [];
|
|
129
|
+
for (const business of res.businesses?.data ?? []) {
|
|
130
|
+
for (const waba of business.owned_whatsapp_business_accounts?.data ?? []) {
|
|
131
|
+
wabas.push({
|
|
132
|
+
id: waba.id,
|
|
133
|
+
name: waba.name,
|
|
134
|
+
phone_numbers: waba.phone_numbers?.data ?? [],
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return wabas;
|
|
139
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers every Meta tool needs:
|
|
3
|
+
*
|
|
4
|
+
* - `resolvePageId(ctx)` — pulls the Page id the operator picked at
|
|
5
|
+
* connect-time out of `ctx.metadata.pageId`. Every Page-bound
|
|
6
|
+
* surface (IG / Messenger / FB Pages) needs it.
|
|
7
|
+
*
|
|
8
|
+
* - `resolveIgUserId(ctx)` — pulls the Instagram Business Account id
|
|
9
|
+
* (NOT the @-handle) out of `ctx.metadata.igUserId`. Only Instagram
|
|
10
|
+
* tools call this; Messenger + FB Pages don't.
|
|
11
|
+
*
|
|
12
|
+
* - `resolveWaPhoneId(ctx)` — pulls the WhatsApp phone-number id out
|
|
13
|
+
* of `ctx.metadata.waPhoneNumberId`. WhatsApp tools route by phone
|
|
14
|
+
* number, not by WABA — that's an easy thing to get wrong.
|
|
15
|
+
*
|
|
16
|
+
* Failure mode: every helper throws a descriptive error if the
|
|
17
|
+
* metadata is missing, pointing the operator at the fix ("reconnect
|
|
18
|
+
* the connector from the Directory"). The platform's tool runner
|
|
19
|
+
* surfaces that string back to the agent's turn, which surfaces it to
|
|
20
|
+
* the operator.
|
|
21
|
+
*/
|
|
22
|
+
import type { ConnectorToolContext } from '@agentforge-io/core';
|
|
23
|
+
export declare function resolvePageId(ctx: ConnectorToolContext): string;
|
|
24
|
+
export declare function resolveIgUserId(ctx: ConnectorToolContext): string;
|
|
25
|
+
export declare function resolveWaPhoneId(ctx: ConnectorToolContext): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvePageId = resolvePageId;
|
|
4
|
+
exports.resolveIgUserId = resolveIgUserId;
|
|
5
|
+
exports.resolveWaPhoneId = resolveWaPhoneId;
|
|
6
|
+
const RECONNECT_HINT = 'This usually means the user connected before the per-Page selection ' +
|
|
7
|
+
'was wired. Ask them to disconnect and reconnect the Meta surface ' +
|
|
8
|
+
'from the Directory.';
|
|
9
|
+
function resolvePageId(ctx) {
|
|
10
|
+
const pageId = ctx.metadata?.pageId;
|
|
11
|
+
if (typeof pageId !== 'string' || !pageId) {
|
|
12
|
+
throw new Error(`Meta connector is missing its pageId metadata. ${RECONNECT_HINT}`);
|
|
13
|
+
}
|
|
14
|
+
return pageId;
|
|
15
|
+
}
|
|
16
|
+
function resolveIgUserId(ctx) {
|
|
17
|
+
const igUserId = ctx.metadata?.igUserId;
|
|
18
|
+
if (typeof igUserId !== 'string' || !igUserId) {
|
|
19
|
+
throw new Error('Instagram connector is missing its igUserId metadata. The selected ' +
|
|
20
|
+
'Page may not have an Instagram Business Account linked. Ask the ' +
|
|
21
|
+
'operator to link an IG Business account to the Page and reconnect.');
|
|
22
|
+
}
|
|
23
|
+
return igUserId;
|
|
24
|
+
}
|
|
25
|
+
function resolveWaPhoneId(ctx) {
|
|
26
|
+
const phoneId = ctx.metadata?.waPhoneNumberId;
|
|
27
|
+
if (typeof phoneId !== 'string' || !phoneId) {
|
|
28
|
+
throw new Error(`WhatsApp connector is missing its phone-number id metadata. ${RECONNECT_HINT}`);
|
|
29
|
+
}
|
|
30
|
+
return phoneId;
|
|
31
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facebook Pages tools.
|
|
3
|
+
*
|
|
4
|
+
* Five tools for managing a Page's published content + engagement:
|
|
5
|
+
*
|
|
6
|
+
* 1. fb_list_posts — Page's own posts, newest first
|
|
7
|
+
* 2. fb_get_post — single post with engagement breakdown
|
|
8
|
+
* 3. fb_create_post — publish or schedule a text/link post
|
|
9
|
+
* 4. fb_list_comments — comments on a post
|
|
10
|
+
* 5. fb_reply_comment — reply nested under a comment
|
|
11
|
+
*
|
|
12
|
+
* Token model:
|
|
13
|
+
* - `ctx.getAccessToken()` returns the PAGE access token.
|
|
14
|
+
* - `ctx.metadata.pageId` is the Page id — every endpoint here
|
|
15
|
+
* routes through it.
|
|
16
|
+
*
|
|
17
|
+
* Why `/posts` (Page-authored) and not `/feed` (everything):
|
|
18
|
+
* - `/{page-id}/feed` returns posts the Page made PLUS posts by
|
|
19
|
+
* other people on the Page wall. Agents usually want "what did
|
|
20
|
+
* WE publish?" so `/posts` is the right default; if we ever need
|
|
21
|
+
* the wall, a future `fb_list_feed` can take the same shape.
|
|
22
|
+
*
|
|
23
|
+
* Scheduled posts:
|
|
24
|
+
* - Setting `published: false` + `scheduled_publish_time` (unix
|
|
25
|
+
* seconds) defers publication. Window: 10 minutes to 6 months
|
|
26
|
+
* from now (Meta hard limit; sending outside returns code 100).
|
|
27
|
+
*
|
|
28
|
+
* Media:
|
|
29
|
+
* - This step covers text + link posts only. Photo/video uploads
|
|
30
|
+
* require a separate /photos or /videos endpoint with multipart
|
|
31
|
+
* bodies, which deserves its own tool (`fb_create_photo_post`)
|
|
32
|
+
* and isn't part of the MVP. Posting an external image via the
|
|
33
|
+
* `link` field is supported — Meta scrapes the URL for OG tags
|
|
34
|
+
* and renders the link preview.
|
|
35
|
+
*/
|
|
36
|
+
import type { ConnectorToolFactory } from '@agentforge-io/core';
|
|
37
|
+
export declare const fbListPostsTool: ConnectorToolFactory;
|
|
38
|
+
export declare const fbGetPostTool: ConnectorToolFactory;
|
|
39
|
+
export declare const fbCreatePostTool: ConnectorToolFactory;
|
|
40
|
+
export declare const fbListCommentsTool: ConnectorToolFactory;
|
|
41
|
+
export declare const fbReplyCommentTool: ConnectorToolFactory;
|