posterly-mcp-server 0.8.2 → 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.
Files changed (121) hide show
  1. package/README.md +38 -3
  2. package/dist/generated/platform-manifest.d.ts +392 -0
  3. package/dist/generated/platform-manifest.js +695 -0
  4. package/dist/index.js +331 -1
  5. package/dist/lib/api-client.d.ts +391 -24
  6. package/dist/lib/api-client.js +176 -0
  7. package/dist/tools/audit-google-business-profile.d.ts +24 -0
  8. package/dist/tools/audit-google-business-profile.js +27 -0
  9. package/dist/tools/create-oauth-client.d.ts +40 -0
  10. package/dist/tools/create-oauth-client.js +20 -0
  11. package/dist/tools/create-post.d.ts +399 -20
  12. package/dist/tools/create-post.js +81 -78
  13. package/dist/tools/create-posts-batch.d.ts +567 -0
  14. package/dist/tools/create-posts-batch.js +38 -0
  15. package/dist/tools/create-signed-upload.d.ts +24 -0
  16. package/dist/tools/create-signed-upload.js +20 -0
  17. package/dist/tools/create-webhook.d.ts +36 -0
  18. package/dist/tools/create-webhook.js +20 -0
  19. package/dist/tools/delete-google-business-review-reply.d.ts +32 -0
  20. package/dist/tools/delete-google-business-review-reply.js +17 -0
  21. package/dist/tools/delete-oauth-client.d.ts +20 -0
  22. package/dist/tools/delete-oauth-client.js +13 -0
  23. package/dist/tools/delete-post-group.d.ts +20 -0
  24. package/dist/tools/delete-post-group.js +13 -0
  25. package/dist/tools/delete-webhook.d.ts +20 -0
  26. package/dist/tools/delete-webhook.js +13 -0
  27. package/dist/tools/disconnect-account.d.ts +20 -0
  28. package/dist/tools/disconnect-account.js +22 -0
  29. package/dist/tools/generate-image.d.ts +4 -4
  30. package/dist/tools/generate-video.d.ts +59 -0
  31. package/dist/tools/generate-video.js +34 -0
  32. package/dist/tools/get-connect-link.d.ts +24 -0
  33. package/dist/tools/get-connect-link.js +46 -0
  34. package/dist/tools/get-google-business-review-link.d.ts +24 -0
  35. package/dist/tools/get-google-business-review-link.js +19 -0
  36. package/dist/tools/get-platform-schema.d.ts +24 -0
  37. package/dist/tools/get-platform-schema.js +44 -0
  38. package/dist/tools/get-post-missing.d.ts +16 -0
  39. package/dist/tools/get-post-missing.js +12 -0
  40. package/dist/tools/get-video-job.d.ts +24 -0
  41. package/dist/tools/get-video-job.js +31 -0
  42. package/dist/tools/get-video-options.d.ts +8 -0
  43. package/dist/tools/get-video-options.js +26 -0
  44. package/dist/tools/get-x-posting-quota.d.ts +16 -0
  45. package/dist/tools/get-x-posting-quota.js +21 -0
  46. package/dist/tools/list-activity.d.ts +32 -0
  47. package/dist/tools/list-activity.js +35 -0
  48. package/dist/tools/list-google-business-reviews.d.ts +32 -0
  49. package/dist/tools/list-google-business-reviews.js +28 -0
  50. package/dist/tools/list-oauth-clients.d.ts +8 -0
  51. package/dist/tools/list-oauth-clients.js +15 -0
  52. package/dist/tools/list-platforms.d.ts +16 -0
  53. package/dist/tools/list-platforms.js +20 -0
  54. package/dist/tools/list-posts.d.ts +3 -3
  55. package/dist/tools/list-posts.js +3 -2
  56. package/dist/tools/list-webhooks.d.ts +16 -0
  57. package/dist/tools/list-webhooks.js +24 -0
  58. package/dist/tools/reply-google-business-review.d.ts +36 -0
  59. package/dist/tools/reply-google-business-review.js +18 -0
  60. package/dist/tools/run-video-function.d.ts +24 -0
  61. package/dist/tools/run-video-function.js +25 -0
  62. package/dist/tools/suggest-google-business-review-reply.d.ts +48 -0
  63. package/dist/tools/suggest-google-business-review-reply.js +27 -0
  64. package/dist/tools/test-webhook.d.ts +20 -0
  65. package/dist/tools/test-webhook.js +14 -0
  66. package/dist/tools/trigger-platform-helper.d.ts +28 -0
  67. package/dist/tools/trigger-platform-helper.js +22 -0
  68. package/dist/tools/update-oauth-client.d.ts +44 -0
  69. package/dist/tools/update-oauth-client.js +21 -0
  70. package/dist/tools/update-post-release-id.d.ts +28 -0
  71. package/dist/tools/update-post-release-id.js +18 -0
  72. package/dist/tools/update-post-status.d.ts +28 -0
  73. package/dist/tools/update-post-status.js +23 -0
  74. package/dist/tools/update-post.js +1 -1
  75. package/dist/tools/update-webhook.d.ts +40 -0
  76. package/dist/tools/update-webhook.js +21 -0
  77. package/dist/tools/upload-media-from-url.d.ts +24 -0
  78. package/dist/tools/upload-media-from-url.js +26 -0
  79. package/dist/tools/webhook-events.d.ts +3 -0
  80. package/dist/tools/webhook-events.js +13 -0
  81. package/package.json +1 -1
  82. package/src/generated/platform-manifest.ts +695 -0
  83. package/src/index.ts +496 -1
  84. package/src/lib/api-client.ts +497 -19
  85. package/src/tools/audit-google-business-profile.ts +38 -0
  86. package/src/tools/create-oauth-client.ts +36 -0
  87. package/src/tools/create-post.ts +91 -94
  88. package/src/tools/create-posts-batch.ts +48 -0
  89. package/src/tools/create-signed-upload.ts +27 -0
  90. package/src/tools/create-webhook.ts +35 -0
  91. package/src/tools/delete-google-business-review-reply.ts +30 -0
  92. package/src/tools/delete-oauth-client.ts +23 -0
  93. package/src/tools/delete-post-group.ts +17 -0
  94. package/src/tools/delete-webhook.ts +18 -0
  95. package/src/tools/disconnect-account.ts +30 -0
  96. package/src/tools/generate-video.ts +38 -0
  97. package/src/tools/get-connect-link.ts +56 -0
  98. package/src/tools/get-google-business-review-link.ts +30 -0
  99. package/src/tools/get-platform-schema.ts +52 -0
  100. package/src/tools/get-post-missing.ts +17 -0
  101. package/src/tools/get-video-job.ts +36 -0
  102. package/src/tools/get-video-options.ts +30 -0
  103. package/src/tools/get-x-posting-quota.ts +25 -0
  104. package/src/tools/list-activity.ts +51 -0
  105. package/src/tools/list-google-business-reviews.ts +43 -0
  106. package/src/tools/list-oauth-clients.ts +18 -0
  107. package/src/tools/list-platforms.ts +25 -0
  108. package/src/tools/list-posts.ts +3 -2
  109. package/src/tools/list-webhooks.ts +30 -0
  110. package/src/tools/reply-google-business-review.ts +32 -0
  111. package/src/tools/run-video-function.ts +32 -0
  112. package/src/tools/suggest-google-business-review-reply.ts +44 -0
  113. package/src/tools/test-webhook.ts +18 -0
  114. package/src/tools/trigger-platform-helper.ts +34 -0
  115. package/src/tools/update-oauth-client.ts +38 -0
  116. package/src/tools/update-post-release-id.ts +26 -0
  117. package/src/tools/update-post-status.ts +31 -0
  118. package/src/tools/update-post.ts +1 -1
  119. package/src/tools/update-webhook.ts +37 -0
  120. package/src/tools/upload-media-from-url.ts +33 -0
  121. package/src/tools/webhook-events.ts +16 -0
@@ -0,0 +1,567 @@
1
+ import { z } from 'zod';
2
+ import type { PosterlyClient } from '../lib/api-client.js';
3
+ import { type CreatePostInput } from './create-post.js';
4
+ export declare const createPostsBatchTool: {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: z.ZodObject<{
8
+ posts: z.ZodArray<z.ZodObject<{
9
+ account_id: z.ZodOptional<z.ZodString>;
10
+ username: z.ZodOptional<z.ZodString>;
11
+ platform: z.ZodOptional<z.ZodEnum<["bluesky", "facebook", "gmb", "google-business", "google_business", "google_business_profile", "instagram", "instagram-standalone", "linkedin", "pinterest", "telegram", "threads", "tiktok", "twitter", "x", "youtube"]>>;
12
+ caption: z.ZodOptional<z.ZodString>;
13
+ scheduled_at: z.ZodOptional<z.ZodString>;
14
+ media_url: z.ZodOptional<z.ZodString>;
15
+ media_urls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
16
+ post_type: z.ZodOptional<z.ZodString>;
17
+ thread_posts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
18
+ instagram_settings: z.ZodOptional<z.ZodObject<{
19
+ __type: z.ZodOptional<z.ZodEnum<["instagram", "instagram-standalone"]>>;
20
+ post_type: z.ZodOptional<z.ZodEnum<["post", "feed", "story", "reel", "carousel"]>>;
21
+ is_trial_reel: z.ZodOptional<z.ZodBoolean>;
22
+ graduation_strategy: z.ZodOptional<z.ZodEnum<["MANUAL", "SS_PERFORMANCE"]>>;
23
+ collaborators: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
24
+ label: z.ZodOptional<z.ZodString>;
25
+ username: z.ZodOptional<z.ZodString>;
26
+ handle: z.ZodOptional<z.ZodString>;
27
+ }, "strip", z.ZodTypeAny, {
28
+ label?: string | undefined;
29
+ username?: string | undefined;
30
+ handle?: string | undefined;
31
+ }, {
32
+ label?: string | undefined;
33
+ username?: string | undefined;
34
+ handle?: string | undefined;
35
+ }>]>, "many">>;
36
+ user_tags: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
37
+ username: z.ZodOptional<z.ZodString>;
38
+ label: z.ZodOptional<z.ZodString>;
39
+ handle: z.ZodOptional<z.ZodString>;
40
+ }, "strip", z.ZodTypeAny, {
41
+ label?: string | undefined;
42
+ username?: string | undefined;
43
+ handle?: string | undefined;
44
+ }, {
45
+ label?: string | undefined;
46
+ username?: string | undefined;
47
+ handle?: string | undefined;
48
+ }>]>, "many">>;
49
+ first_comment: z.ZodOptional<z.ZodString>;
50
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
51
+ reel_cover_url: z.ZodOptional<z.ZodString>;
52
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
53
+ }, "strip", z.ZodTypeAny, {
54
+ __type?: "instagram" | "instagram-standalone" | undefined;
55
+ post_type?: "post" | "feed" | "story" | "reel" | "carousel" | undefined;
56
+ is_trial_reel?: boolean | undefined;
57
+ graduation_strategy?: "MANUAL" | "SS_PERFORMANCE" | undefined;
58
+ collaborators?: (string | {
59
+ label?: string | undefined;
60
+ username?: string | undefined;
61
+ handle?: string | undefined;
62
+ })[] | undefined;
63
+ user_tags?: (string | {
64
+ label?: string | undefined;
65
+ username?: string | undefined;
66
+ handle?: string | undefined;
67
+ })[] | undefined;
68
+ first_comment?: string | undefined;
69
+ media_alt_texts?: Record<string, string> | undefined;
70
+ reel_cover_url?: string | undefined;
71
+ reel_thumb_offset?: number | undefined;
72
+ }, {
73
+ __type?: "instagram" | "instagram-standalone" | undefined;
74
+ post_type?: "post" | "feed" | "story" | "reel" | "carousel" | undefined;
75
+ is_trial_reel?: boolean | undefined;
76
+ graduation_strategy?: "MANUAL" | "SS_PERFORMANCE" | undefined;
77
+ collaborators?: (string | {
78
+ label?: string | undefined;
79
+ username?: string | undefined;
80
+ handle?: string | undefined;
81
+ })[] | undefined;
82
+ user_tags?: (string | {
83
+ label?: string | undefined;
84
+ username?: string | undefined;
85
+ handle?: string | undefined;
86
+ })[] | undefined;
87
+ first_comment?: string | undefined;
88
+ media_alt_texts?: Record<string, string> | undefined;
89
+ reel_cover_url?: string | undefined;
90
+ reel_thumb_offset?: number | undefined;
91
+ }>>;
92
+ platform_settings: z.ZodOptional<z.ZodObject<{
93
+ __type: z.ZodOptional<z.ZodString>;
94
+ post_type: z.ZodOptional<z.ZodString>;
95
+ content_type: z.ZodOptional<z.ZodString>;
96
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
97
+ reel_cover_url: z.ZodOptional<z.ZodString>;
98
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
99
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
100
+ poll: z.ZodOptional<z.ZodObject<{
101
+ options: z.ZodArray<z.ZodString, "many">;
102
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
103
+ }, "strip", z.ZodTypeAny, {
104
+ options: string[];
105
+ duration_minutes?: number | undefined;
106
+ }, {
107
+ options: string[];
108
+ duration_minutes?: number | undefined;
109
+ }>>;
110
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
111
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
112
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
113
+ document_title: z.ZodOptional<z.ZodString>;
114
+ document_filename: z.ZodOptional<z.ZodString>;
115
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
116
+ thumbnail_url: z.ZodOptional<z.ZodString>;
117
+ thumbnail_method: z.ZodOptional<z.ZodString>;
118
+ privacy_level: z.ZodOptional<z.ZodString>;
119
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
120
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
121
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
122
+ title: z.ZodOptional<z.ZodString>;
123
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
124
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
125
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
126
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
127
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
128
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
129
+ category_id: z.ZodOptional<z.ZodString>;
130
+ playlist_id: z.ZodOptional<z.ZodString>;
131
+ board_id: z.ZodOptional<z.ZodString>;
132
+ link: z.ZodOptional<z.ZodString>;
133
+ cover_image_url: z.ZodOptional<z.ZodString>;
134
+ video_cover_url: z.ZodOptional<z.ZodString>;
135
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
136
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
137
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
138
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
139
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
140
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
141
+ __type: z.ZodOptional<z.ZodString>;
142
+ post_type: z.ZodOptional<z.ZodString>;
143
+ content_type: z.ZodOptional<z.ZodString>;
144
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
145
+ reel_cover_url: z.ZodOptional<z.ZodString>;
146
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
147
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
148
+ poll: z.ZodOptional<z.ZodObject<{
149
+ options: z.ZodArray<z.ZodString, "many">;
150
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
151
+ }, "strip", z.ZodTypeAny, {
152
+ options: string[];
153
+ duration_minutes?: number | undefined;
154
+ }, {
155
+ options: string[];
156
+ duration_minutes?: number | undefined;
157
+ }>>;
158
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
159
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
160
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
161
+ document_title: z.ZodOptional<z.ZodString>;
162
+ document_filename: z.ZodOptional<z.ZodString>;
163
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
164
+ thumbnail_url: z.ZodOptional<z.ZodString>;
165
+ thumbnail_method: z.ZodOptional<z.ZodString>;
166
+ privacy_level: z.ZodOptional<z.ZodString>;
167
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
168
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
169
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
170
+ title: z.ZodOptional<z.ZodString>;
171
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
172
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
173
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
174
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
175
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
176
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
177
+ category_id: z.ZodOptional<z.ZodString>;
178
+ playlist_id: z.ZodOptional<z.ZodString>;
179
+ board_id: z.ZodOptional<z.ZodString>;
180
+ link: z.ZodOptional<z.ZodString>;
181
+ cover_image_url: z.ZodOptional<z.ZodString>;
182
+ video_cover_url: z.ZodOptional<z.ZodString>;
183
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
184
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
185
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
186
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
187
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
188
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
189
+ __type: z.ZodOptional<z.ZodString>;
190
+ post_type: z.ZodOptional<z.ZodString>;
191
+ content_type: z.ZodOptional<z.ZodString>;
192
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
193
+ reel_cover_url: z.ZodOptional<z.ZodString>;
194
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
195
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
196
+ poll: z.ZodOptional<z.ZodObject<{
197
+ options: z.ZodArray<z.ZodString, "many">;
198
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
199
+ }, "strip", z.ZodTypeAny, {
200
+ options: string[];
201
+ duration_minutes?: number | undefined;
202
+ }, {
203
+ options: string[];
204
+ duration_minutes?: number | undefined;
205
+ }>>;
206
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
207
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
208
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
209
+ document_title: z.ZodOptional<z.ZodString>;
210
+ document_filename: z.ZodOptional<z.ZodString>;
211
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
212
+ thumbnail_url: z.ZodOptional<z.ZodString>;
213
+ thumbnail_method: z.ZodOptional<z.ZodString>;
214
+ privacy_level: z.ZodOptional<z.ZodString>;
215
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
216
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
217
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
218
+ title: z.ZodOptional<z.ZodString>;
219
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
220
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
221
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
222
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
223
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
224
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
225
+ category_id: z.ZodOptional<z.ZodString>;
226
+ playlist_id: z.ZodOptional<z.ZodString>;
227
+ board_id: z.ZodOptional<z.ZodString>;
228
+ link: z.ZodOptional<z.ZodString>;
229
+ cover_image_url: z.ZodOptional<z.ZodString>;
230
+ video_cover_url: z.ZodOptional<z.ZodString>;
231
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
232
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
233
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
234
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
235
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
236
+ }, z.ZodTypeAny, "passthrough">>>;
237
+ workspace_id: z.ZodOptional<z.ZodString>;
238
+ }, "strip", z.ZodTypeAny, {
239
+ workspace_id?: string | undefined;
240
+ platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "linkedin" | "youtube" | "pinterest" | "threads" | "google_business" | "telegram" | "bluesky" | "gmb" | "google-business" | "google_business_profile" | "x" | undefined;
241
+ account_id?: string | undefined;
242
+ post_type?: string | undefined;
243
+ username?: string | undefined;
244
+ caption?: string | undefined;
245
+ scheduled_at?: string | undefined;
246
+ media_url?: string | undefined;
247
+ media_urls?: string[] | undefined;
248
+ thread_posts?: string[] | undefined;
249
+ instagram_settings?: {
250
+ __type?: "instagram" | "instagram-standalone" | undefined;
251
+ post_type?: "post" | "feed" | "story" | "reel" | "carousel" | undefined;
252
+ is_trial_reel?: boolean | undefined;
253
+ graduation_strategy?: "MANUAL" | "SS_PERFORMANCE" | undefined;
254
+ collaborators?: (string | {
255
+ label?: string | undefined;
256
+ username?: string | undefined;
257
+ handle?: string | undefined;
258
+ })[] | undefined;
259
+ user_tags?: (string | {
260
+ label?: string | undefined;
261
+ username?: string | undefined;
262
+ handle?: string | undefined;
263
+ })[] | undefined;
264
+ first_comment?: string | undefined;
265
+ media_alt_texts?: Record<string, string> | undefined;
266
+ reel_cover_url?: string | undefined;
267
+ reel_thumb_offset?: number | undefined;
268
+ } | undefined;
269
+ platform_settings?: z.objectOutputType<{
270
+ __type: z.ZodOptional<z.ZodString>;
271
+ post_type: z.ZodOptional<z.ZodString>;
272
+ content_type: z.ZodOptional<z.ZodString>;
273
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
274
+ reel_cover_url: z.ZodOptional<z.ZodString>;
275
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
276
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
277
+ poll: z.ZodOptional<z.ZodObject<{
278
+ options: z.ZodArray<z.ZodString, "many">;
279
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
280
+ }, "strip", z.ZodTypeAny, {
281
+ options: string[];
282
+ duration_minutes?: number | undefined;
283
+ }, {
284
+ options: string[];
285
+ duration_minutes?: number | undefined;
286
+ }>>;
287
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
288
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
289
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
290
+ document_title: z.ZodOptional<z.ZodString>;
291
+ document_filename: z.ZodOptional<z.ZodString>;
292
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
293
+ thumbnail_url: z.ZodOptional<z.ZodString>;
294
+ thumbnail_method: z.ZodOptional<z.ZodString>;
295
+ privacy_level: z.ZodOptional<z.ZodString>;
296
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
297
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
298
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
299
+ title: z.ZodOptional<z.ZodString>;
300
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
301
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
302
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
303
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
304
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
305
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
306
+ category_id: z.ZodOptional<z.ZodString>;
307
+ playlist_id: z.ZodOptional<z.ZodString>;
308
+ board_id: z.ZodOptional<z.ZodString>;
309
+ link: z.ZodOptional<z.ZodString>;
310
+ cover_image_url: z.ZodOptional<z.ZodString>;
311
+ video_cover_url: z.ZodOptional<z.ZodString>;
312
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
313
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
314
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
315
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
316
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
317
+ }, z.ZodTypeAny, "passthrough"> | undefined;
318
+ }, {
319
+ workspace_id?: string | undefined;
320
+ platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "linkedin" | "youtube" | "pinterest" | "threads" | "google_business" | "telegram" | "bluesky" | "gmb" | "google-business" | "google_business_profile" | "x" | undefined;
321
+ account_id?: string | undefined;
322
+ post_type?: string | undefined;
323
+ username?: string | undefined;
324
+ caption?: string | undefined;
325
+ scheduled_at?: string | undefined;
326
+ media_url?: string | undefined;
327
+ media_urls?: string[] | undefined;
328
+ thread_posts?: string[] | undefined;
329
+ instagram_settings?: {
330
+ __type?: "instagram" | "instagram-standalone" | undefined;
331
+ post_type?: "post" | "feed" | "story" | "reel" | "carousel" | undefined;
332
+ is_trial_reel?: boolean | undefined;
333
+ graduation_strategy?: "MANUAL" | "SS_PERFORMANCE" | undefined;
334
+ collaborators?: (string | {
335
+ label?: string | undefined;
336
+ username?: string | undefined;
337
+ handle?: string | undefined;
338
+ })[] | undefined;
339
+ user_tags?: (string | {
340
+ label?: string | undefined;
341
+ username?: string | undefined;
342
+ handle?: string | undefined;
343
+ })[] | undefined;
344
+ first_comment?: string | undefined;
345
+ media_alt_texts?: Record<string, string> | undefined;
346
+ reel_cover_url?: string | undefined;
347
+ reel_thumb_offset?: number | undefined;
348
+ } | undefined;
349
+ platform_settings?: z.objectInputType<{
350
+ __type: z.ZodOptional<z.ZodString>;
351
+ post_type: z.ZodOptional<z.ZodString>;
352
+ content_type: z.ZodOptional<z.ZodString>;
353
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
354
+ reel_cover_url: z.ZodOptional<z.ZodString>;
355
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
356
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
357
+ poll: z.ZodOptional<z.ZodObject<{
358
+ options: z.ZodArray<z.ZodString, "many">;
359
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
360
+ }, "strip", z.ZodTypeAny, {
361
+ options: string[];
362
+ duration_minutes?: number | undefined;
363
+ }, {
364
+ options: string[];
365
+ duration_minutes?: number | undefined;
366
+ }>>;
367
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
368
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
369
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
370
+ document_title: z.ZodOptional<z.ZodString>;
371
+ document_filename: z.ZodOptional<z.ZodString>;
372
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
373
+ thumbnail_url: z.ZodOptional<z.ZodString>;
374
+ thumbnail_method: z.ZodOptional<z.ZodString>;
375
+ privacy_level: z.ZodOptional<z.ZodString>;
376
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
377
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
378
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
379
+ title: z.ZodOptional<z.ZodString>;
380
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
381
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
382
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
383
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
384
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
385
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
386
+ category_id: z.ZodOptional<z.ZodString>;
387
+ playlist_id: z.ZodOptional<z.ZodString>;
388
+ board_id: z.ZodOptional<z.ZodString>;
389
+ link: z.ZodOptional<z.ZodString>;
390
+ cover_image_url: z.ZodOptional<z.ZodString>;
391
+ video_cover_url: z.ZodOptional<z.ZodString>;
392
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
393
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
394
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
395
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
396
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
397
+ }, z.ZodTypeAny, "passthrough"> | undefined;
398
+ }>, "many">;
399
+ }, "strip", z.ZodTypeAny, {
400
+ posts: {
401
+ workspace_id?: string | undefined;
402
+ platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "linkedin" | "youtube" | "pinterest" | "threads" | "google_business" | "telegram" | "bluesky" | "gmb" | "google-business" | "google_business_profile" | "x" | undefined;
403
+ account_id?: string | undefined;
404
+ post_type?: string | undefined;
405
+ username?: string | undefined;
406
+ caption?: string | undefined;
407
+ scheduled_at?: string | undefined;
408
+ media_url?: string | undefined;
409
+ media_urls?: string[] | undefined;
410
+ thread_posts?: string[] | undefined;
411
+ instagram_settings?: {
412
+ __type?: "instagram" | "instagram-standalone" | undefined;
413
+ post_type?: "post" | "feed" | "story" | "reel" | "carousel" | undefined;
414
+ is_trial_reel?: boolean | undefined;
415
+ graduation_strategy?: "MANUAL" | "SS_PERFORMANCE" | undefined;
416
+ collaborators?: (string | {
417
+ label?: string | undefined;
418
+ username?: string | undefined;
419
+ handle?: string | undefined;
420
+ })[] | undefined;
421
+ user_tags?: (string | {
422
+ label?: string | undefined;
423
+ username?: string | undefined;
424
+ handle?: string | undefined;
425
+ })[] | undefined;
426
+ first_comment?: string | undefined;
427
+ media_alt_texts?: Record<string, string> | undefined;
428
+ reel_cover_url?: string | undefined;
429
+ reel_thumb_offset?: number | undefined;
430
+ } | undefined;
431
+ platform_settings?: z.objectOutputType<{
432
+ __type: z.ZodOptional<z.ZodString>;
433
+ post_type: z.ZodOptional<z.ZodString>;
434
+ content_type: z.ZodOptional<z.ZodString>;
435
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
436
+ reel_cover_url: z.ZodOptional<z.ZodString>;
437
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
438
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
439
+ poll: z.ZodOptional<z.ZodObject<{
440
+ options: z.ZodArray<z.ZodString, "many">;
441
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
442
+ }, "strip", z.ZodTypeAny, {
443
+ options: string[];
444
+ duration_minutes?: number | undefined;
445
+ }, {
446
+ options: string[];
447
+ duration_minutes?: number | undefined;
448
+ }>>;
449
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
450
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
451
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
452
+ document_title: z.ZodOptional<z.ZodString>;
453
+ document_filename: z.ZodOptional<z.ZodString>;
454
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
455
+ thumbnail_url: z.ZodOptional<z.ZodString>;
456
+ thumbnail_method: z.ZodOptional<z.ZodString>;
457
+ privacy_level: z.ZodOptional<z.ZodString>;
458
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
459
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
460
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
461
+ title: z.ZodOptional<z.ZodString>;
462
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
463
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
464
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
465
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
466
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
467
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
468
+ category_id: z.ZodOptional<z.ZodString>;
469
+ playlist_id: z.ZodOptional<z.ZodString>;
470
+ board_id: z.ZodOptional<z.ZodString>;
471
+ link: z.ZodOptional<z.ZodString>;
472
+ cover_image_url: z.ZodOptional<z.ZodString>;
473
+ video_cover_url: z.ZodOptional<z.ZodString>;
474
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
475
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
476
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
477
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
478
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
479
+ }, z.ZodTypeAny, "passthrough"> | undefined;
480
+ }[];
481
+ }, {
482
+ posts: {
483
+ workspace_id?: string | undefined;
484
+ platform?: "instagram" | "instagram-standalone" | "facebook" | "tiktok" | "twitter" | "linkedin" | "youtube" | "pinterest" | "threads" | "google_business" | "telegram" | "bluesky" | "gmb" | "google-business" | "google_business_profile" | "x" | undefined;
485
+ account_id?: string | undefined;
486
+ post_type?: string | undefined;
487
+ username?: string | undefined;
488
+ caption?: string | undefined;
489
+ scheduled_at?: string | undefined;
490
+ media_url?: string | undefined;
491
+ media_urls?: string[] | undefined;
492
+ thread_posts?: string[] | undefined;
493
+ instagram_settings?: {
494
+ __type?: "instagram" | "instagram-standalone" | undefined;
495
+ post_type?: "post" | "feed" | "story" | "reel" | "carousel" | undefined;
496
+ is_trial_reel?: boolean | undefined;
497
+ graduation_strategy?: "MANUAL" | "SS_PERFORMANCE" | undefined;
498
+ collaborators?: (string | {
499
+ label?: string | undefined;
500
+ username?: string | undefined;
501
+ handle?: string | undefined;
502
+ })[] | undefined;
503
+ user_tags?: (string | {
504
+ label?: string | undefined;
505
+ username?: string | undefined;
506
+ handle?: string | undefined;
507
+ })[] | undefined;
508
+ first_comment?: string | undefined;
509
+ media_alt_texts?: Record<string, string> | undefined;
510
+ reel_cover_url?: string | undefined;
511
+ reel_thumb_offset?: number | undefined;
512
+ } | undefined;
513
+ platform_settings?: z.objectInputType<{
514
+ __type: z.ZodOptional<z.ZodString>;
515
+ post_type: z.ZodOptional<z.ZodString>;
516
+ content_type: z.ZodOptional<z.ZodString>;
517
+ media_alt_texts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
518
+ reel_cover_url: z.ZodOptional<z.ZodString>;
519
+ reel_thumb_offset: z.ZodOptional<z.ZodNumber>;
520
+ reply_settings: z.ZodOptional<z.ZodEnum<["everyone", "following", "mentionedUsers"]>>;
521
+ poll: z.ZodOptional<z.ZodObject<{
522
+ options: z.ZodArray<z.ZodString, "many">;
523
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
524
+ }, "strip", z.ZodTypeAny, {
525
+ options: string[];
526
+ duration_minutes?: number | undefined;
527
+ }, {
528
+ options: string[];
529
+ duration_minutes?: number | undefined;
530
+ }>>;
531
+ reply_control: z.ZodOptional<z.ZodEnum<["everyone", "accounts_you_follow", "mentioned_only"]>>;
532
+ text_attachment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
533
+ text_format_preset_id: z.ZodOptional<z.ZodString>;
534
+ document_title: z.ZodOptional<z.ZodString>;
535
+ document_filename: z.ZodOptional<z.ZodString>;
536
+ mentions: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">>;
537
+ thumbnail_url: z.ZodOptional<z.ZodString>;
538
+ thumbnail_method: z.ZodOptional<z.ZodString>;
539
+ privacy_level: z.ZodOptional<z.ZodString>;
540
+ allow_comment: z.ZodOptional<z.ZodBoolean>;
541
+ allow_duet: z.ZodOptional<z.ZodBoolean>;
542
+ allow_stitch: z.ZodOptional<z.ZodBoolean>;
543
+ title: z.ZodOptional<z.ZodString>;
544
+ is_commercial_content: z.ZodOptional<z.ZodBoolean>;
545
+ is_your_brand: z.ZodOptional<z.ZodBoolean>;
546
+ is_branded_content: z.ZodOptional<z.ZodBoolean>;
547
+ privacy_status: z.ZodOptional<z.ZodEnum<["public", "unlisted", "private"]>>;
548
+ made_for_kids: z.ZodOptional<z.ZodBoolean>;
549
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
550
+ category_id: z.ZodOptional<z.ZodString>;
551
+ playlist_id: z.ZodOptional<z.ZodString>;
552
+ board_id: z.ZodOptional<z.ZodString>;
553
+ link: z.ZodOptional<z.ZodString>;
554
+ cover_image_url: z.ZodOptional<z.ZodString>;
555
+ video_cover_url: z.ZodOptional<z.ZodString>;
556
+ cover_image_method: z.ZodOptional<z.ZodEnum<["upload", "frame", "api"]>>;
557
+ event: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
558
+ offer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
559
+ cta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
560
+ langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
561
+ }, z.ZodTypeAny, "passthrough"> | undefined;
562
+ }[];
563
+ }>;
564
+ execute(client: PosterlyClient, input: {
565
+ posts: CreatePostInput[];
566
+ }): Promise<string>;
567
+ };
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ import { buildCreatePostPayload, createPostInputSchema } from './create-post.js';
3
+ export const createPostsBatchTool = {
4
+ name: 'create_posts_batch',
5
+ description: 'Create 1-25 scheduled or immediate social posts in one API request. This is a DESTRUCTIVE WRITE that creates content on the user\'s real social accounts — once scheduled_at passes, posts may go public and cannot be un-posted.\n\n' +
6
+ 'REQUIRED BEFORE CALLING:\n' +
7
+ '1. Call `whoami` at the start of any new session to confirm which workspace and user you are acting for.\n' +
8
+ '2. Show the user a preview of EVERY post: account/platform, final caption or thread text, scheduled time in their timezone, media, platform settings, and workspace.\n' +
9
+ '3. Get explicit confirmation for the whole batch before calling. Do not infer consent from an earlier content plan.\n\n' +
10
+ 'Each item accepts the same fields as `create_post`, including `thread_posts`, `platform_settings`, `instagram_settings`, media URLs, and workspace_id. The endpoint may partially succeed; failed items are returned with their index.',
11
+ inputSchema: z.object({
12
+ posts: z
13
+ .array(createPostInputSchema)
14
+ .min(1)
15
+ .max(25)
16
+ .describe('Posts to create. Each item uses the same schema as create_post.'),
17
+ }),
18
+ async execute(client, input) {
19
+ const payloads = input.posts.map((post) => buildCreatePostPayload(post));
20
+ const result = await client.createPostsBatch({ posts: payloads });
21
+ const lines = [
22
+ 'Batch create completed.',
23
+ `• Total: ${result.total}`,
24
+ `• Created: ${result.created}`,
25
+ `• Replayed: ${result.replayed}`,
26
+ `• Failed: ${result.failed}`,
27
+ ];
28
+ for (const item of result.posts.slice(0, 25)) {
29
+ const post = item.post;
30
+ const when = post.scheduled_at ? new Date(post.scheduled_at).toLocaleString() : 'now';
31
+ lines.push(`• [${item.index}] ID ${post.id} ${post.platform || 'unknown'} ${post.post_type || 'post'} ${post.status || 'created'} at ${when}${item.replayed ? ' (replayed)' : ''}`);
32
+ }
33
+ for (const error of result.errors.slice(0, 25)) {
34
+ lines.push(`• [${error.index}] ERROR ${error.status}: ${error.error}`);
35
+ }
36
+ return lines.join('\n');
37
+ },
38
+ };
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ import type { PosterlyClient } from '../lib/api-client.js';
3
+ export declare const createSignedUploadTool: {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: z.ZodObject<{
7
+ filename: z.ZodString;
8
+ content_type: z.ZodString;
9
+ size: z.ZodNumber;
10
+ }, "strip", z.ZodTypeAny, {
11
+ content_type: string;
12
+ filename: string;
13
+ size: number;
14
+ }, {
15
+ content_type: string;
16
+ filename: string;
17
+ size: number;
18
+ }>;
19
+ execute(client: PosterlyClient, input: {
20
+ filename: string;
21
+ content_type: string;
22
+ size: number;
23
+ }): Promise<string>;
24
+ };
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ export const createSignedUploadTool = {
3
+ name: 'create_signed_upload',
4
+ description: '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.',
5
+ inputSchema: z.object({
6
+ filename: z.string().describe('Filename with extension, e.g. launch-video.mp4'),
7
+ content_type: z.string().describe('MIME type, e.g. video/mp4'),
8
+ size: z.number().int().positive().describe('File size in bytes'),
9
+ }),
10
+ async execute(client, input) {
11
+ const signed = await client.getSignedUploadUrl(input.filename, input.content_type, input.size);
12
+ return [
13
+ 'Signed upload created.',
14
+ `• Upload URL: ${signed.upload_url}`,
15
+ `• Token: ${signed.token}`,
16
+ `• Storage path: ${signed.path}`,
17
+ `• Public URL after upload: ${signed.public_url}`,
18
+ ].join('\n');
19
+ },
20
+ };