posterly-mcp-server 0.8.3 → 0.19.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/README.md +35 -1
- package/dist/generated/platform-manifest.d.ts +392 -0
- package/dist/generated/platform-manifest.js +695 -0
- package/dist/index.js +321 -1
- package/dist/lib/api-client.d.ts +346 -0
- package/dist/lib/api-client.js +173 -0
- package/dist/tools/audit-google-business-profile.d.ts +24 -0
- package/dist/tools/audit-google-business-profile.js +27 -0
- package/dist/tools/create-oauth-client.d.ts +40 -0
- package/dist/tools/create-oauth-client.js +20 -0
- package/dist/tools/create-post.d.ts +7 -20
- package/dist/tools/create-post.js +4 -3
- package/dist/tools/create-posts-batch.d.ts +5 -5
- package/dist/tools/create-signed-upload.d.ts +24 -0
- package/dist/tools/create-signed-upload.js +20 -0
- package/dist/tools/create-webhook.d.ts +36 -0
- package/dist/tools/create-webhook.js +20 -0
- package/dist/tools/delete-google-business-review-reply.d.ts +32 -0
- package/dist/tools/delete-google-business-review-reply.js +17 -0
- package/dist/tools/delete-oauth-client.d.ts +20 -0
- package/dist/tools/delete-oauth-client.js +13 -0
- package/dist/tools/delete-post-group.d.ts +20 -0
- package/dist/tools/delete-post-group.js +13 -0
- package/dist/tools/delete-webhook.d.ts +20 -0
- package/dist/tools/delete-webhook.js +13 -0
- package/dist/tools/disconnect-account.d.ts +20 -0
- package/dist/tools/disconnect-account.js +22 -0
- package/dist/tools/generate-image.d.ts +4 -4
- package/dist/tools/generate-video.d.ts +59 -0
- package/dist/tools/generate-video.js +34 -0
- package/dist/tools/get-connect-link.d.ts +24 -0
- package/dist/tools/get-connect-link.js +46 -0
- package/dist/tools/get-google-business-review-link.d.ts +24 -0
- package/dist/tools/get-google-business-review-link.js +19 -0
- package/dist/tools/get-platform-schema.d.ts +24 -0
- package/dist/tools/get-platform-schema.js +44 -0
- package/dist/tools/get-post-missing.d.ts +16 -0
- package/dist/tools/get-post-missing.js +12 -0
- package/dist/tools/get-video-job.d.ts +24 -0
- package/dist/tools/get-video-job.js +31 -0
- package/dist/tools/get-video-options.d.ts +8 -0
- package/dist/tools/get-video-options.js +26 -0
- package/dist/tools/get-x-posting-quota.d.ts +16 -0
- package/dist/tools/get-x-posting-quota.js +21 -0
- package/dist/tools/list-activity.d.ts +32 -0
- package/dist/tools/list-activity.js +35 -0
- package/dist/tools/list-google-business-reviews.d.ts +32 -0
- package/dist/tools/list-google-business-reviews.js +28 -0
- package/dist/tools/list-oauth-clients.d.ts +8 -0
- package/dist/tools/list-oauth-clients.js +15 -0
- package/dist/tools/list-platforms.d.ts +16 -0
- package/dist/tools/list-platforms.js +20 -0
- package/dist/tools/list-posts.d.ts +3 -3
- package/dist/tools/list-posts.js +3 -2
- package/dist/tools/list-webhooks.d.ts +16 -0
- package/dist/tools/list-webhooks.js +24 -0
- package/dist/tools/reply-google-business-review.d.ts +36 -0
- package/dist/tools/reply-google-business-review.js +18 -0
- package/dist/tools/run-video-function.d.ts +24 -0
- package/dist/tools/run-video-function.js +25 -0
- package/dist/tools/suggest-google-business-review-reply.d.ts +48 -0
- package/dist/tools/suggest-google-business-review-reply.js +27 -0
- package/dist/tools/test-webhook.d.ts +20 -0
- package/dist/tools/test-webhook.js +14 -0
- package/dist/tools/trigger-platform-helper.d.ts +28 -0
- package/dist/tools/trigger-platform-helper.js +22 -0
- package/dist/tools/update-oauth-client.d.ts +44 -0
- package/dist/tools/update-oauth-client.js +21 -0
- package/dist/tools/update-post-release-id.d.ts +28 -0
- package/dist/tools/update-post-release-id.js +18 -0
- package/dist/tools/update-post-status.d.ts +28 -0
- package/dist/tools/update-post-status.js +23 -0
- package/dist/tools/update-post.js +1 -1
- package/dist/tools/update-webhook.d.ts +40 -0
- package/dist/tools/update-webhook.js +21 -0
- package/dist/tools/upload-media-from-url.d.ts +24 -0
- package/dist/tools/upload-media-from-url.js +26 -0
- package/dist/tools/webhook-events.d.ts +3 -0
- package/dist/tools/webhook-events.js +13 -0
- package/package.json +1 -1
- package/src/generated/platform-manifest.ts +695 -0
- package/src/index.ts +481 -1
- package/src/lib/api-client.ts +461 -0
- package/src/tools/audit-google-business-profile.ts +38 -0
- package/src/tools/create-oauth-client.ts +36 -0
- package/src/tools/create-post.ts +5 -17
- package/src/tools/create-signed-upload.ts +27 -0
- package/src/tools/create-webhook.ts +35 -0
- package/src/tools/delete-google-business-review-reply.ts +30 -0
- package/src/tools/delete-oauth-client.ts +23 -0
- package/src/tools/delete-post-group.ts +17 -0
- package/src/tools/delete-webhook.ts +18 -0
- package/src/tools/disconnect-account.ts +30 -0
- package/src/tools/generate-video.ts +38 -0
- package/src/tools/get-connect-link.ts +56 -0
- package/src/tools/get-google-business-review-link.ts +30 -0
- package/src/tools/get-platform-schema.ts +52 -0
- package/src/tools/get-post-missing.ts +17 -0
- package/src/tools/get-video-job.ts +36 -0
- package/src/tools/get-video-options.ts +30 -0
- package/src/tools/get-x-posting-quota.ts +25 -0
- package/src/tools/list-activity.ts +51 -0
- package/src/tools/list-google-business-reviews.ts +43 -0
- package/src/tools/list-oauth-clients.ts +18 -0
- package/src/tools/list-platforms.ts +25 -0
- package/src/tools/list-posts.ts +3 -2
- package/src/tools/list-webhooks.ts +30 -0
- package/src/tools/reply-google-business-review.ts +32 -0
- package/src/tools/run-video-function.ts +32 -0
- package/src/tools/suggest-google-business-review-reply.ts +44 -0
- package/src/tools/test-webhook.ts +18 -0
- package/src/tools/trigger-platform-helper.ts +34 -0
- package/src/tools/update-oauth-client.ts +38 -0
- package/src/tools/update-post-release-id.ts +26 -0
- package/src/tools/update-post-status.ts +31 -0
- package/src/tools/update-post.ts +1 -1
- package/src/tools/update-webhook.ts +37 -0
- package/src/tools/upload-media-from-url.ts +33 -0
- package/src/tools/webhook-events.ts +16 -0
package/src/lib/api-client.ts
CHANGED
|
@@ -211,6 +211,172 @@ export interface PostAnalyticsResponse {
|
|
|
211
211
|
offset: number;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
export interface GoogleBusinessReview {
|
|
215
|
+
name?: string;
|
|
216
|
+
reviewId?: string;
|
|
217
|
+
reviewer?: { displayName?: string; profilePhotoUrl?: string };
|
|
218
|
+
starRating: number;
|
|
219
|
+
comment?: string;
|
|
220
|
+
createTime?: string;
|
|
221
|
+
updateTime?: string;
|
|
222
|
+
reviewReply?: Record<string, unknown>;
|
|
223
|
+
locationId?: string | null;
|
|
224
|
+
locationName?: string | null;
|
|
225
|
+
businessName?: string | null;
|
|
226
|
+
socialAccountId?: number;
|
|
227
|
+
account_id?: number;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface GoogleBusinessReviewsResponse {
|
|
231
|
+
reviews: GoogleBusinessReview[];
|
|
232
|
+
total: number;
|
|
233
|
+
locations: Array<Record<string, unknown>>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface GoogleBusinessReviewLinkResponse {
|
|
237
|
+
reviewLink: string;
|
|
238
|
+
placeId: string;
|
|
239
|
+
businessName: string;
|
|
240
|
+
locationId: string | null;
|
|
241
|
+
account_id: number;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface ActivityItem {
|
|
245
|
+
id: string;
|
|
246
|
+
type: 'activity' | 'publish';
|
|
247
|
+
post_id: number | null;
|
|
248
|
+
action?: string | null;
|
|
249
|
+
description?: string | null;
|
|
250
|
+
platform?: string | null;
|
|
251
|
+
outcome?: string | null;
|
|
252
|
+
error_code?: string | null;
|
|
253
|
+
error_message?: string | null;
|
|
254
|
+
http_status?: number | null;
|
|
255
|
+
retry_number?: number | null;
|
|
256
|
+
duration_ms?: number | null;
|
|
257
|
+
pipeline_step?: string | null;
|
|
258
|
+
metadata?: Record<string, unknown> | null;
|
|
259
|
+
context?: Record<string, unknown> | null;
|
|
260
|
+
created_at: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface ActivityResponse {
|
|
264
|
+
items: ActivityItem[];
|
|
265
|
+
total: number;
|
|
266
|
+
limit: number;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface ApiWebhook {
|
|
270
|
+
id: string;
|
|
271
|
+
workspace_id: string | null;
|
|
272
|
+
url: string;
|
|
273
|
+
description: string | null;
|
|
274
|
+
events: string[];
|
|
275
|
+
is_active: boolean;
|
|
276
|
+
created_at: string;
|
|
277
|
+
updated_at: string | null;
|
|
278
|
+
last_delivery_at: string | null;
|
|
279
|
+
last_delivery_status: number | null;
|
|
280
|
+
last_error: string | null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface WebhookResponse {
|
|
284
|
+
webhook: ApiWebhook;
|
|
285
|
+
secret?: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface PlatformSchema {
|
|
289
|
+
id: string;
|
|
290
|
+
aliases: string[];
|
|
291
|
+
label: string;
|
|
292
|
+
status: 'supported' | 'planned';
|
|
293
|
+
summary: string;
|
|
294
|
+
content_limit: number | null;
|
|
295
|
+
media: Record<string, unknown>;
|
|
296
|
+
post_types: string[];
|
|
297
|
+
analytics_supported: boolean;
|
|
298
|
+
settings_schema: {
|
|
299
|
+
fields: Array<Record<string, unknown>>;
|
|
300
|
+
example: Record<string, unknown>;
|
|
301
|
+
};
|
|
302
|
+
helper_tools: Array<Record<string, unknown>>;
|
|
303
|
+
native_features: string[];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export interface ConnectOption {
|
|
307
|
+
platform: string;
|
|
308
|
+
aliases: string[];
|
|
309
|
+
label: string;
|
|
310
|
+
status: 'supported' | 'planned';
|
|
311
|
+
method: 'dashboard_oauth' | 'manual_credentials' | 'planned';
|
|
312
|
+
provider_platforms: string[];
|
|
313
|
+
dashboard_url: string;
|
|
314
|
+
connection_url: string | null;
|
|
315
|
+
oauth_url: string | null;
|
|
316
|
+
supports_direct_oauth_url: boolean;
|
|
317
|
+
requires_browser_session: boolean;
|
|
318
|
+
configured: boolean | null;
|
|
319
|
+
env_requirements: Array<Record<string, unknown>>;
|
|
320
|
+
missing_env: string[][];
|
|
321
|
+
scopes: string[];
|
|
322
|
+
credential_fields: Array<Record<string, unknown>>;
|
|
323
|
+
notes: string[];
|
|
324
|
+
connected_count?: number;
|
|
325
|
+
connected_accounts?: Account[];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface OAuthDeveloperClient {
|
|
329
|
+
id: string;
|
|
330
|
+
client_id: string;
|
|
331
|
+
client_name: string;
|
|
332
|
+
description?: string | null;
|
|
333
|
+
homepage?: string | null;
|
|
334
|
+
allowed_redirect_uris: string[];
|
|
335
|
+
default_scopes: string[];
|
|
336
|
+
is_active: boolean;
|
|
337
|
+
created_at?: string;
|
|
338
|
+
updated_at?: string;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface VideoJob {
|
|
342
|
+
id: string;
|
|
343
|
+
status: string;
|
|
344
|
+
prompt: string;
|
|
345
|
+
model: string;
|
|
346
|
+
duration_seconds: number;
|
|
347
|
+
aspect_ratio?: string;
|
|
348
|
+
resolution?: string;
|
|
349
|
+
generation_mode?: string | null;
|
|
350
|
+
credit_cost: number;
|
|
351
|
+
included_credit_cost?: number;
|
|
352
|
+
purchased_credit_cost?: number;
|
|
353
|
+
source_image_url?: string | null;
|
|
354
|
+
end_image_url?: string | null;
|
|
355
|
+
source_video_url?: string | null;
|
|
356
|
+
reference_images?: unknown;
|
|
357
|
+
generate_audio?: boolean | null;
|
|
358
|
+
video_url?: string | null;
|
|
359
|
+
error_message?: string | null;
|
|
360
|
+
created_at: string;
|
|
361
|
+
started_at?: string | null;
|
|
362
|
+
completed_at?: string | null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export interface XPostingQuotaResponse {
|
|
366
|
+
workspace_id: string | null;
|
|
367
|
+
tier: string | null;
|
|
368
|
+
base_posts: number;
|
|
369
|
+
addon_posts: number;
|
|
370
|
+
total_posts: number;
|
|
371
|
+
used_posts: number;
|
|
372
|
+
remaining_posts: number;
|
|
373
|
+
current_period_start: string;
|
|
374
|
+
current_period_end: string;
|
|
375
|
+
urls_blocked: boolean;
|
|
376
|
+
addon?: Record<string, unknown>;
|
|
377
|
+
plans?: Array<Record<string, unknown>>;
|
|
378
|
+
}
|
|
379
|
+
|
|
214
380
|
export class PosterlyClient {
|
|
215
381
|
private baseUrl: string;
|
|
216
382
|
private apiKey: string;
|
|
@@ -265,6 +431,58 @@ export class PosterlyClient {
|
|
|
265
431
|
return data.accounts;
|
|
266
432
|
}
|
|
267
433
|
|
|
434
|
+
async disconnectAccount(accountId: string): Promise<Record<string, any>> {
|
|
435
|
+
return this.request('DELETE', `/accounts/${encodeURIComponent(accountId)}`);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async getConnectLink(params?: {
|
|
439
|
+
platform?: string;
|
|
440
|
+
workspace_id?: string;
|
|
441
|
+
include_planned?: boolean;
|
|
442
|
+
}): Promise<{ connect?: ConnectOption; connect_options?: ConnectOption[] }> {
|
|
443
|
+
const searchParams = new URLSearchParams();
|
|
444
|
+
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
445
|
+
if (params?.include_planned) searchParams.set('include_planned', 'true');
|
|
446
|
+
const qs = searchParams.toString();
|
|
447
|
+
const path = params?.platform
|
|
448
|
+
? `/connect/${encodeURIComponent(params.platform)}`
|
|
449
|
+
: '/connect';
|
|
450
|
+
return this.request('GET', `${path}${qs ? `?${qs}` : ''}`);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async listOAuthClients(): Promise<{ clients: OAuthDeveloperClient[] }> {
|
|
454
|
+
return this.request('GET', '/oauth/clients');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async createOAuthClient(data: {
|
|
458
|
+
client_name: string;
|
|
459
|
+
description?: string;
|
|
460
|
+
homepage?: string;
|
|
461
|
+
allowed_redirect_uris: string[];
|
|
462
|
+
default_scopes: string[];
|
|
463
|
+
is_active?: boolean;
|
|
464
|
+
}): Promise<{ client: OAuthDeveloperClient }> {
|
|
465
|
+
return this.request('POST', '/oauth/clients', data);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async updateOAuthClient(
|
|
469
|
+
clientId: string,
|
|
470
|
+
data: {
|
|
471
|
+
client_name?: string;
|
|
472
|
+
description?: string;
|
|
473
|
+
homepage?: string | null;
|
|
474
|
+
allowed_redirect_uris?: string[];
|
|
475
|
+
default_scopes?: string[];
|
|
476
|
+
is_active?: boolean;
|
|
477
|
+
},
|
|
478
|
+
): Promise<{ client: OAuthDeveloperClient }> {
|
|
479
|
+
return this.request('PATCH', `/oauth/clients/${encodeURIComponent(clientId)}`, data);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async deleteOAuthClient(clientId: string): Promise<{ deleted: boolean; client_id: string }> {
|
|
483
|
+
return this.request('DELETE', `/oauth/clients/${encodeURIComponent(clientId)}`);
|
|
484
|
+
}
|
|
485
|
+
|
|
268
486
|
async listBrands(params?: { workspace_id?: string }): Promise<Brand[]> {
|
|
269
487
|
const searchParams = new URLSearchParams();
|
|
270
488
|
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
@@ -318,6 +536,10 @@ export class PosterlyClient {
|
|
|
318
536
|
return this.request('GET', `/posts/${id}`);
|
|
319
537
|
}
|
|
320
538
|
|
|
539
|
+
async getPostMissing(id: number): Promise<Record<string, any>> {
|
|
540
|
+
return this.request('GET', `/posts/${id}/missing`);
|
|
541
|
+
}
|
|
542
|
+
|
|
321
543
|
async updatePost(
|
|
322
544
|
id: number,
|
|
323
545
|
data: {
|
|
@@ -340,6 +562,24 @@ export class PosterlyClient {
|
|
|
340
562
|
return this.request('DELETE', `/posts/${id}`);
|
|
341
563
|
}
|
|
342
564
|
|
|
565
|
+
async updatePostStatus(
|
|
566
|
+
id: number,
|
|
567
|
+
data: { status: 'scheduled' | 'paused' | 'draft'; scheduled_at?: string },
|
|
568
|
+
): Promise<Record<string, any>> {
|
|
569
|
+
return this.request('PUT', `/posts/${id}/status`, data);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
async updatePostReleaseId(
|
|
573
|
+
id: number,
|
|
574
|
+
data: { release_id: string; group_id?: string },
|
|
575
|
+
): Promise<Record<string, any>> {
|
|
576
|
+
return this.request('PUT', `/posts/${id}/release-id`, data);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async deletePostGroup(groupId: string): Promise<Record<string, any>> {
|
|
580
|
+
return this.request('DELETE', `/posts/group/${encodeURIComponent(groupId)}?confirm=true`);
|
|
581
|
+
}
|
|
582
|
+
|
|
343
583
|
async generateImage(data: {
|
|
344
584
|
prompt: string;
|
|
345
585
|
aspect_ratio?: string;
|
|
@@ -364,6 +604,49 @@ export class PosterlyClient {
|
|
|
364
604
|
return this.request('POST', '/ai/generate-image', data);
|
|
365
605
|
}
|
|
366
606
|
|
|
607
|
+
async getVideoOptions(): Promise<Record<string, any>> {
|
|
608
|
+
return this.request('GET', '/ai/video-options');
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
async runVideoFunction(data: {
|
|
612
|
+
identifier: string;
|
|
613
|
+
functionName: string;
|
|
614
|
+
params?: Record<string, unknown>;
|
|
615
|
+
}): Promise<Record<string, any>> {
|
|
616
|
+
return this.request('POST', '/ai/video-function', data);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async generateVideo(data: {
|
|
620
|
+
prompt: string;
|
|
621
|
+
negative_prompt?: string;
|
|
622
|
+
aspect_ratio?: '16:9' | '9:16';
|
|
623
|
+
duration_seconds?: 4 | 6 | 8;
|
|
624
|
+
resolution?: '720p' | '1080p';
|
|
625
|
+
model?: 'fast' | 'standard';
|
|
626
|
+
image_url?: string;
|
|
627
|
+
end_image_url?: string;
|
|
628
|
+
reference_images?: Array<{ url: string; type: 'character' | 'object' | 'scene' }>;
|
|
629
|
+
generate_audio?: boolean;
|
|
630
|
+
source_video_url?: string;
|
|
631
|
+
}): Promise<Record<string, any>> {
|
|
632
|
+
return this.request('POST', '/ai/generate-video', data);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async getVideoJob(params?: {
|
|
636
|
+
job_id?: string;
|
|
637
|
+
status?: string;
|
|
638
|
+
limit?: number;
|
|
639
|
+
}): Promise<{ job?: VideoJob; jobs?: VideoJob[] }> {
|
|
640
|
+
if (params?.job_id) {
|
|
641
|
+
return this.request('GET', `/ai/video-jobs/${encodeURIComponent(params.job_id)}`);
|
|
642
|
+
}
|
|
643
|
+
const searchParams = new URLSearchParams();
|
|
644
|
+
if (params?.status) searchParams.set('status', params.status);
|
|
645
|
+
if (params?.limit) searchParams.set('limit', String(params.limit));
|
|
646
|
+
const qs = searchParams.toString();
|
|
647
|
+
return this.request('GET', `/ai/video-jobs${qs ? `?${qs}` : ''}`);
|
|
648
|
+
}
|
|
649
|
+
|
|
367
650
|
async findAvailableSlots(params?: {
|
|
368
651
|
account_ids?: string[];
|
|
369
652
|
timezone?: string;
|
|
@@ -409,6 +692,172 @@ export class PosterlyClient {
|
|
|
409
692
|
return this.request('GET', `/analytics/posts?${searchParams.toString()}`);
|
|
410
693
|
}
|
|
411
694
|
|
|
695
|
+
async listGoogleBusinessReviews(params?: {
|
|
696
|
+
workspace_id?: string;
|
|
697
|
+
account_id?: number;
|
|
698
|
+
location_id?: string;
|
|
699
|
+
rating?: number;
|
|
700
|
+
unanswered?: boolean;
|
|
701
|
+
}): Promise<GoogleBusinessReviewsResponse> {
|
|
702
|
+
const searchParams = new URLSearchParams();
|
|
703
|
+
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
704
|
+
if (params?.account_id) searchParams.set('account_id', String(params.account_id));
|
|
705
|
+
if (params?.location_id) searchParams.set('location_id', params.location_id);
|
|
706
|
+
if (params?.rating) searchParams.set('rating', String(params.rating));
|
|
707
|
+
if (params?.unanswered) searchParams.set('unanswered', 'true');
|
|
708
|
+
const qs = searchParams.toString();
|
|
709
|
+
return this.request('GET', `/google-business/reviews${qs ? `?${qs}` : ''}`);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
async getGoogleBusinessReviewLink(params: {
|
|
713
|
+
workspace_id?: string;
|
|
714
|
+
account_id?: number;
|
|
715
|
+
location_id?: string;
|
|
716
|
+
}): Promise<GoogleBusinessReviewLinkResponse> {
|
|
717
|
+
const searchParams = new URLSearchParams();
|
|
718
|
+
if (params.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
719
|
+
if (params.account_id) searchParams.set('account_id', String(params.account_id));
|
|
720
|
+
if (params.location_id) searchParams.set('location_id', params.location_id);
|
|
721
|
+
return this.request('GET', `/google-business/review-link?${searchParams.toString()}`);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
async auditGoogleBusinessProfile(params: {
|
|
725
|
+
workspace_id?: string;
|
|
726
|
+
account_id?: number;
|
|
727
|
+
location_id?: string;
|
|
728
|
+
}): Promise<Record<string, any>> {
|
|
729
|
+
const searchParams = new URLSearchParams();
|
|
730
|
+
if (params.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
731
|
+
if (params.account_id) searchParams.set('account_id', String(params.account_id));
|
|
732
|
+
if (params.location_id) searchParams.set('location_id', params.location_id);
|
|
733
|
+
return this.request('GET', `/google-business/audit?${searchParams.toString()}`);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
async suggestGoogleBusinessReviewReply(data: {
|
|
737
|
+
workspace_id?: string;
|
|
738
|
+
account_id?: number;
|
|
739
|
+
location_id?: string;
|
|
740
|
+
review_text?: string;
|
|
741
|
+
star_rating: number;
|
|
742
|
+
reviewer_name?: string;
|
|
743
|
+
business_name?: string;
|
|
744
|
+
tone?: 'professional' | 'friendly' | 'apologetic';
|
|
745
|
+
count?: number;
|
|
746
|
+
}): Promise<Record<string, any>> {
|
|
747
|
+
return this.request('POST', '/google-business/reviews/suggest-reply', data);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
async replyGoogleBusinessReview(data: {
|
|
751
|
+
workspace_id?: string;
|
|
752
|
+
account_id?: number;
|
|
753
|
+
location_id?: string;
|
|
754
|
+
review_name: string;
|
|
755
|
+
comment: string;
|
|
756
|
+
}): Promise<Record<string, any>> {
|
|
757
|
+
return this.request('POST', '/google-business/reviews/reply', data);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
async deleteGoogleBusinessReviewReply(data: {
|
|
761
|
+
workspace_id?: string;
|
|
762
|
+
account_id?: number;
|
|
763
|
+
location_id?: string;
|
|
764
|
+
review_name: string;
|
|
765
|
+
}): Promise<Record<string, any>> {
|
|
766
|
+
return this.request('DELETE', '/google-business/reviews/reply', data);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
async listActivity(params?: {
|
|
770
|
+
workspace_id?: string;
|
|
771
|
+
post_id?: number;
|
|
772
|
+
since?: string;
|
|
773
|
+
type?: 'all' | 'activity' | 'publish';
|
|
774
|
+
limit?: number;
|
|
775
|
+
}): Promise<ActivityResponse> {
|
|
776
|
+
const searchParams = new URLSearchParams();
|
|
777
|
+
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
778
|
+
if (params?.post_id) searchParams.set('post_id', String(params.post_id));
|
|
779
|
+
if (params?.since) searchParams.set('since', params.since);
|
|
780
|
+
if (params?.type) searchParams.set('type', params.type);
|
|
781
|
+
if (params?.limit) searchParams.set('limit', String(params.limit));
|
|
782
|
+
const qs = searchParams.toString();
|
|
783
|
+
return this.request('GET', `/activity${qs ? `?${qs}` : ''}`);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
async listWebhooks(params?: { workspace_id?: string }): Promise<{ webhooks: ApiWebhook[] }> {
|
|
787
|
+
const searchParams = new URLSearchParams();
|
|
788
|
+
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
789
|
+
const qs = searchParams.toString();
|
|
790
|
+
return this.request('GET', `/webhooks${qs ? `?${qs}` : ''}`);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
async createWebhook(data: {
|
|
794
|
+
url: string;
|
|
795
|
+
events?: string[];
|
|
796
|
+
workspace_id?: string;
|
|
797
|
+
description?: string;
|
|
798
|
+
is_active?: boolean;
|
|
799
|
+
}): Promise<WebhookResponse> {
|
|
800
|
+
return this.request('POST', '/webhooks', data);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
async updateWebhook(
|
|
804
|
+
id: string,
|
|
805
|
+
data: {
|
|
806
|
+
url?: string;
|
|
807
|
+
events?: string[];
|
|
808
|
+
workspace_id?: string | null;
|
|
809
|
+
description?: string | null;
|
|
810
|
+
is_active?: boolean;
|
|
811
|
+
},
|
|
812
|
+
): Promise<WebhookResponse> {
|
|
813
|
+
return this.request('PATCH', `/webhooks/${encodeURIComponent(id)}`, data);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
async deleteWebhook(id: string): Promise<{ deleted: boolean; id: string }> {
|
|
817
|
+
return this.request('DELETE', `/webhooks/${encodeURIComponent(id)}`);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
async testWebhook(id: string): Promise<{ delivery: Record<string, unknown> }> {
|
|
821
|
+
return this.request('POST', `/webhooks/${encodeURIComponent(id)}/test`, {});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
async listPlatforms(params?: { include_planned?: boolean }): Promise<{ platforms: PlatformSchema[] }> {
|
|
825
|
+
const searchParams = new URLSearchParams();
|
|
826
|
+
if (params?.include_planned) searchParams.set('include_planned', 'true');
|
|
827
|
+
const qs = searchParams.toString();
|
|
828
|
+
return this.request('GET', `/platforms${qs ? `?${qs}` : ''}`);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
async getPlatformSchema(params: {
|
|
832
|
+
account_id?: string;
|
|
833
|
+
platform?: string;
|
|
834
|
+
include_planned?: boolean;
|
|
835
|
+
}): Promise<{ account?: Record<string, unknown>; schema?: PlatformSchema; platform?: PlatformSchema; platforms?: PlatformSchema[] }> {
|
|
836
|
+
if (params.account_id) {
|
|
837
|
+
return this.request('GET', `/accounts/${encodeURIComponent(params.account_id)}/schema`);
|
|
838
|
+
}
|
|
839
|
+
const searchParams = new URLSearchParams();
|
|
840
|
+
if (params.platform) searchParams.set('platform', params.platform);
|
|
841
|
+
if (params.include_planned) searchParams.set('include_planned', 'true');
|
|
842
|
+
return this.request('GET', `/platforms?${searchParams.toString()}`);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
async triggerPlatformHelper(data: {
|
|
846
|
+
helper: string;
|
|
847
|
+
account_id?: string;
|
|
848
|
+
platform?: string;
|
|
849
|
+
params?: Record<string, unknown>;
|
|
850
|
+
}): Promise<{ helper: string; account: Record<string, unknown> | null; result: unknown }> {
|
|
851
|
+
return this.request('POST', '/platforms/trigger', data);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
async getXPostingQuota(params?: { workspace_id?: string }): Promise<XPostingQuotaResponse> {
|
|
855
|
+
const searchParams = new URLSearchParams();
|
|
856
|
+
if (params?.workspace_id) searchParams.set('workspace_id', params.workspace_id);
|
|
857
|
+
const qs = searchParams.toString();
|
|
858
|
+
return this.request('GET', `/x-posting/quota${qs ? `?${qs}` : ''}`);
|
|
859
|
+
}
|
|
860
|
+
|
|
412
861
|
async getSignedUploadUrl(
|
|
413
862
|
filename: string,
|
|
414
863
|
contentType: string,
|
|
@@ -476,6 +925,18 @@ export class PosterlyClient {
|
|
|
476
925
|
content_type: contentType,
|
|
477
926
|
});
|
|
478
927
|
}
|
|
928
|
+
|
|
929
|
+
async uploadMediaFromUrl(input: {
|
|
930
|
+
url: string;
|
|
931
|
+
filename?: string;
|
|
932
|
+
contentType?: string;
|
|
933
|
+
}): Promise<{ url: string; path: string; source_url: string; content_type: string; size: number }> {
|
|
934
|
+
return this.request('POST', '/media/upload-from-url', {
|
|
935
|
+
url: input.url,
|
|
936
|
+
filename: input.filename,
|
|
937
|
+
content_type: input.contentType,
|
|
938
|
+
});
|
|
939
|
+
}
|
|
479
940
|
}
|
|
480
941
|
|
|
481
942
|
function guessContentType(filename: string): string {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
|
|
4
|
+
export const auditGoogleBusinessProfileTool = {
|
|
5
|
+
name: 'audit_google_business_profile',
|
|
6
|
+
description:
|
|
7
|
+
'Run a live local-profile audit for a connected Google Business Profile location, including completeness, categories, media, attributes, reviews, and recommendations.',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
workspace_id: z.string().optional().describe('Filter to a workspace ID from whoami.'),
|
|
10
|
+
account_id: z.number().int().positive().optional().describe('Google Business account ID from list_accounts.'),
|
|
11
|
+
location_id: z.string().optional().describe('Google Business location/platform_user_id.'),
|
|
12
|
+
}),
|
|
13
|
+
|
|
14
|
+
async execute(
|
|
15
|
+
client: PosterlyClient,
|
|
16
|
+
input: {
|
|
17
|
+
workspace_id?: string;
|
|
18
|
+
account_id?: number;
|
|
19
|
+
location_id?: string;
|
|
20
|
+
},
|
|
21
|
+
) {
|
|
22
|
+
const result = await client.auditGoogleBusinessProfile(input);
|
|
23
|
+
const audit = result.audit || {};
|
|
24
|
+
const recommendations = Array.isArray(audit.recommendations) ? audit.recommendations : [];
|
|
25
|
+
const lines = [
|
|
26
|
+
`Google Business audit: ${audit.businessName || 'Unknown business'}`,
|
|
27
|
+
`Score: ${audit.overallScore ?? 'n/a'} (${audit.overallGrade || 'n/a'})`,
|
|
28
|
+
`Fetched: ${result.fetchedAt || 'unknown'}`,
|
|
29
|
+
];
|
|
30
|
+
if (recommendations.length > 0) {
|
|
31
|
+
lines.push('Top recommendations:');
|
|
32
|
+
for (const rec of recommendations.slice(0, 5)) {
|
|
33
|
+
lines.push(`- ${rec.priority || 'medium'}: ${rec.description || rec.title || 'Recommendation'}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
|
|
4
|
+
const scopeSchema = z.enum(['accounts:read', 'accounts:write', 'posts:read', 'posts:write', 'media:write', 'analytics:read']);
|
|
5
|
+
|
|
6
|
+
export const createOAuthClientTool = {
|
|
7
|
+
name: 'create_oauth_client',
|
|
8
|
+
description:
|
|
9
|
+
'Create a public OAuth 2.1 + PKCE developer client. WRITE: confirm app name, redirect URIs, and scopes with the user before calling.',
|
|
10
|
+
inputSchema: z.object({
|
|
11
|
+
client_name: z.string().min(1).max(120),
|
|
12
|
+
description: z.string().max(500).optional(),
|
|
13
|
+
homepage: z.string().url().optional(),
|
|
14
|
+
allowed_redirect_uris: z.array(z.string().url()).min(1).max(10),
|
|
15
|
+
default_scopes: z.array(scopeSchema).min(1),
|
|
16
|
+
is_active: z.boolean().optional(),
|
|
17
|
+
confirm: z.literal(true).describe('Must be true after explicit user confirmation.'),
|
|
18
|
+
}),
|
|
19
|
+
|
|
20
|
+
async execute(
|
|
21
|
+
client: PosterlyClient,
|
|
22
|
+
input: {
|
|
23
|
+
client_name: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
homepage?: string;
|
|
26
|
+
allowed_redirect_uris: string[];
|
|
27
|
+
default_scopes: string[];
|
|
28
|
+
is_active?: boolean;
|
|
29
|
+
confirm: true;
|
|
30
|
+
},
|
|
31
|
+
) {
|
|
32
|
+
const { confirm: _confirm, ...payload } = input;
|
|
33
|
+
const result = await client.createOAuthClient(payload);
|
|
34
|
+
return `OAuth client created: ${result.client.client_name}\nclient_id: ${result.client.client_id}\nRedirect URIs: ${result.client.allowed_redirect_uris.join(', ')}`;
|
|
35
|
+
},
|
|
36
|
+
};
|
package/src/tools/create-post.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { SUPPORTED_PLATFORM_INPUTS, SUPPORTED_PLATFORM_IDS } from '../generated/platform-manifest.js';
|
|
3
4
|
|
|
4
5
|
export const instagramSettingsSchema = z.object({
|
|
5
6
|
__type: z.enum(['instagram', 'instagram-standalone']).optional(),
|
|
@@ -75,9 +76,9 @@ export const createPostInputSchema = z.object({
|
|
|
75
76
|
account_id: z.string().optional().describe('Social account ID (from list_accounts)'),
|
|
76
77
|
username: z.string().optional().describe('Account username (alternative to account_id)'),
|
|
77
78
|
platform: z
|
|
78
|
-
.
|
|
79
|
+
.enum(SUPPORTED_PLATFORM_INPUTS)
|
|
79
80
|
.optional()
|
|
80
|
-
.describe(
|
|
81
|
+
.describe(`Platform name (required with username). Supported: ${SUPPORTED_PLATFORM_IDS.join(', ')}. Aliases such as x, gmb, and instagram-standalone are accepted.`),
|
|
81
82
|
caption: z.string().optional().describe('The post caption/text content. Ignored when `thread_posts` is provided.'),
|
|
82
83
|
scheduled_at: z
|
|
83
84
|
.string()
|
|
@@ -164,25 +165,12 @@ export const createPostTool = {
|
|
|
164
165
|
'4. If scheduling multiple posts in one turn, list every post first and confirm the batch as a whole, then prefer `create_posts_batch` so they are created in one API request.\n\n' +
|
|
165
166
|
'Provide either account_id OR username+platform to identify the account. If scheduled_at is omitted, the post publishes immediately. If workspace_id is omitted, the server resolves one from the social account, falling back to the caller\'s default (personal) workspace — pass workspace_id explicitly if the user has more than one workspace.\n\n' +
|
|
166
167
|
'THREADS: Pass `thread_posts` (an array of 2+ strings) to schedule a multi-post thread on X (Twitter) or Threads (Meta). The first entry is the lead post; the rest are published as replies in the same chain. X entries are capped at 280 characters each (4000 for verified, 25000 for organization accounts); Threads entries are capped at 500 characters each. When `thread_posts` is set, `caption` is ignored.\n\n' +
|
|
167
|
-
'PLATFORM SETTINGS: Pass `platform_settings` for composer-equivalent controls: Facebook story/reel/backgrounds, YouTube title/privacy/thumbnail/playlist, LinkedIn document titles/mentions/video thumbnails, TikTok direct-post privacy/toggles/commercial disclosure, Pinterest
|
|
168
|
+
'PLATFORM SETTINGS: Pass `platform_settings` for composer-equivalent controls: Facebook story/reel/backgrounds, YouTube title/privacy/thumbnail/playlist, LinkedIn document titles/mentions/video thumbnails, TikTok direct-post privacy/toggles/commercial disclosure, Pinterest post_type (image/video/carousel), board (from pinterest.boards helper), title, link, and cover_image_url (video Pins), GBP event/offer/CTA, X reply settings/polls, Threads reply controls/text attachments, Bluesky languages/alt text, and Instagram feed/story/reel/carousel/collaborators/first comments/trial Reels. `instagram_settings` remains as a backwards-compatible alias.',
|
|
168
169
|
inputSchema: createPostInputSchema,
|
|
169
170
|
|
|
170
171
|
async execute(
|
|
171
172
|
client: PosterlyClient,
|
|
172
|
-
input:
|
|
173
|
-
account_id?: string;
|
|
174
|
-
username?: string;
|
|
175
|
-
platform?: string;
|
|
176
|
-
caption?: string;
|
|
177
|
-
scheduled_at?: string;
|
|
178
|
-
media_url?: string;
|
|
179
|
-
media_urls?: string[];
|
|
180
|
-
post_type?: string;
|
|
181
|
-
thread_posts?: string[];
|
|
182
|
-
instagram_settings?: z.infer<typeof instagramSettingsSchema>;
|
|
183
|
-
platform_settings?: z.infer<typeof platformSettingsSchema>;
|
|
184
|
-
workspace_id?: string;
|
|
185
|
-
}
|
|
173
|
+
input: CreatePostInput,
|
|
186
174
|
) {
|
|
187
175
|
const payload = buildCreatePostPayload(input);
|
|
188
176
|
const { thread_posts, instagram_settings, platform_settings } = input;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
|
|
4
|
+
export const createSignedUploadTool = {
|
|
5
|
+
name: 'create_signed_upload',
|
|
6
|
+
description:
|
|
7
|
+
'Create a signed direct-upload URL for a larger image or video. Upload the binary to upload_url, then use public_url with create_post.',
|
|
8
|
+
inputSchema: z.object({
|
|
9
|
+
filename: z.string().describe('Filename with extension, e.g. launch-video.mp4'),
|
|
10
|
+
content_type: z.string().describe('MIME type, e.g. video/mp4'),
|
|
11
|
+
size: z.number().int().positive().describe('File size in bytes'),
|
|
12
|
+
}),
|
|
13
|
+
|
|
14
|
+
async execute(
|
|
15
|
+
client: PosterlyClient,
|
|
16
|
+
input: { filename: string; content_type: string; size: number },
|
|
17
|
+
) {
|
|
18
|
+
const signed = await client.getSignedUploadUrl(input.filename, input.content_type, input.size);
|
|
19
|
+
return [
|
|
20
|
+
'Signed upload created.',
|
|
21
|
+
`• Upload URL: ${signed.upload_url}`,
|
|
22
|
+
`• Token: ${signed.token}`,
|
|
23
|
+
`• Storage path: ${signed.path}`,
|
|
24
|
+
`• Public URL after upload: ${signed.public_url}`,
|
|
25
|
+
].join('\n');
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { PosterlyClient } from '../lib/api-client.js';
|
|
3
|
+
import { webhookEventSchema } from './webhook-events.js';
|
|
4
|
+
|
|
5
|
+
export const createWebhookTool = {
|
|
6
|
+
name: 'create_webhook',
|
|
7
|
+
description:
|
|
8
|
+
'Create a webhook subscription for post/account/analytics events. WRITE WITH OUTBOUND SIDE EFFECTS: show the user the target URL, workspace, events, and active state, then get explicit confirmation before calling. The response includes the signing secret once.',
|
|
9
|
+
inputSchema: z.object({
|
|
10
|
+
url: z.string().url().describe('HTTPS webhook endpoint URL. Localhost HTTP is allowed by the API for development.'),
|
|
11
|
+
events: z.array(webhookEventSchema).optional().describe('Events to deliver. Defaults to core post lifecycle events.'),
|
|
12
|
+
workspace_id: z.string().optional().describe('Optional workspace filter. Omit for all workspaces owned by the API key user.'),
|
|
13
|
+
description: z.string().max(240).optional(),
|
|
14
|
+
is_active: z.boolean().optional().describe('Defaults to true.'),
|
|
15
|
+
confirm: z.literal(true).describe('Must be true after the user explicitly confirms webhook creation.'),
|
|
16
|
+
}),
|
|
17
|
+
|
|
18
|
+
async execute(
|
|
19
|
+
client: PosterlyClient,
|
|
20
|
+
input: {
|
|
21
|
+
url: string;
|
|
22
|
+
events?: string[];
|
|
23
|
+
workspace_id?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
is_active?: boolean;
|
|
26
|
+
confirm: true;
|
|
27
|
+
},
|
|
28
|
+
) {
|
|
29
|
+
const { confirm: _confirm, ...payload } = input;
|
|
30
|
+
const result = await client.createWebhook(payload);
|
|
31
|
+
const secret = result.secret ? `\nSigning secret: ${result.secret}` : '';
|
|
32
|
+
return `Webhook created: ${result.webhook.id}\nURL: ${result.webhook.url}\nEvents: ${result.webhook.events.join(', ')}${secret}`;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|