ugcinc 4.14.0 → 4.15.1
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 +22 -0
- package/dist/index.d.ts +2 -2
- package/dist/media.d.ts +13 -12
- package/dist/media.js +6 -9
- package/dist/posts.d.ts +17 -1
- package/dist/render/Root.js +3 -3
- package/dist/render/compositions/IMessageDmComposition/index.js +3 -3
- package/dist/render/compositions/InstagramDmComposition/index.js +4 -4
- package/dist/render.d.ts +16 -11
- package/dist/render.js +48 -75
- package/dist/tools/posts.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -166,6 +166,28 @@ await client.posts.createVideo({
|
|
|
166
166
|
await client.posts.updatePost({ postId: "post_123", post_tag: "campaign-august" });
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
+
When a post fails, its category is appended to the tag as `fail reason: <fail_category>` (for
|
|
170
|
+
example `campaign-july fail reason: device_error`), so a post list shows why without a status call
|
|
171
|
+
per post. The suffix is removed again when the post is retried.
|
|
172
|
+
|
|
173
|
+
## Backup Audio
|
|
174
|
+
|
|
175
|
+
A post can carry a second sound. If the platform refuses the primary sound at posting time, the
|
|
176
|
+
backup becomes the post's `social_audio_id`, the post is re-attempted once, ` switched to backup
|
|
177
|
+
audio` is appended to its `tag`, and `backup_audio_used_at` is set. With no backup left the post
|
|
178
|
+
fails as `audio_unavailable` and is not retried. Set it with `backupSocialAudioId` on
|
|
179
|
+
`posts.createVideo()`, `posts.createSlideshow()`, `posts.createDraft()`, and `posts.updatePost()`
|
|
180
|
+
(`null` clears it on update).
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
await client.posts.createSlideshow({
|
|
184
|
+
accountId: "acc_123",
|
|
185
|
+
imageUrls: ["https://example.com/img1.jpg"],
|
|
186
|
+
socialAudioId: "audio_primary",
|
|
187
|
+
backupSocialAudioId: "audio_fallback",
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
169
191
|
## Useful Exports
|
|
170
192
|
|
|
171
193
|
- `UGCClient` for API access
|
package/dist/index.d.ts
CHANGED
|
@@ -27,10 +27,10 @@ export type { InputType } from './automations/nodes/types';
|
|
|
27
27
|
export type { ClientConfig } from './base';
|
|
28
28
|
export type { Account, AccountStatus, AccountStat, AccountTask, QuarantineAccountParams, ReleaseAccountParams, QuarantineAccountResponse, EditProfileInfo, GetAccountsParams, GetAccountStatsParams, GetAccountStatusParams, AccountInfoUpdate, UpdateAccountInfoParams, AccountInfoUpdateResult, UpdateAccountInfoResponse, AccountSocialUpdate, UpdateAccountSocialParams, AccountSocialUpdateResult, UpdateAccountSocialResponse, DeleteAccountPostsParams, DeleteAccountPostsResponse, ResetWarmupParams, ResetWarmupResponse, NicheSwitchUpdate, NicheSwitchParams, NicheSwitchResult, NicheSwitchResponse, CreateAccountInput, CreateAccountsParams, CreateAccountResult, CreateAccountsResponse, TroubleshootFailReason, TroubleshootAccount, TroubleshootParams, } from './accounts';
|
|
29
29
|
export type { TaskType, Task, GetTasksParams } from './tasks';
|
|
30
|
-
export type { PostType, PostStatus, Post, PostStat, CaptionOverlay, GetPostsParams, CreateDraftParams, CreateSlideshowParams, GetPostStatsParams, GetPostStatusParams, CreateVideoParams, UpdatePostParams, DeletePostsParams, DeletePostsResponse, RetryPostsParams, SetPostStatusParams, SetPostStatusResponse, PreviewScheduleEntry, PreviewScheduleParams, PreviewScheduleResult, } from './posts';
|
|
30
|
+
export type { PostType, PostStatus, Post, PostStat, CaptionOverlay, GetPostsParams, GetPostsPageParams, PostsPage, PostSortField, PostSortDirection, CreateDraftParams, CreateSlideshowParams, GetPostStatsParams, GetPostStatusParams, CreateVideoParams, UpdatePostParams, DeletePostsParams, DeletePostsResponse, RetryPostsParams, SetPostStatusParams, SetPostStatusResponse, PreviewScheduleEntry, PreviewScheduleParams, PreviewScheduleResult, } from './posts';
|
|
31
31
|
export type { RefreshStatsParams, RefreshStatsError, RefreshStatsResponse, RefreshStatsProgressResponse, RefreshStartEvent, RefreshProgressEvent, RefreshDoneEvent, RefreshStreamEvent, DailyAggregatedStat, GetDailyAggregatedStatsParams, DailyAccountStat, GetDailyAccountStatsParams, DailyPostStat, GetDailyPostStatsParams, DashboardDailyStat, GetDashboardDailyStatsParams, TopAccount, GetTopAccountsParams, TopPost, GetTopPostsParams, } from './stats';
|
|
32
32
|
export type { Org, ApiKey, DeleteApiKeyParams, EditApiKeyParams, IntegrationKey, IntegrationProvider, UpsertIntegrationKeyParams, DeleteIntegrationKeyParams } from './org';
|
|
33
|
-
export type { UserMedia, MediaUse, SocialAudio, Media, GetMediaParams, GetSocialAudioParams, UploadMediaParams, UploadMediaResponse, MediaTagUpdate, UpdateMediaTagsParams, MediaTagUpdateResult, UpdateMediaTagsResponse, UpdateMediaTagParams, UpdateMediaNameParams, DeleteMediaParams, DeleteMediaResponse, CreateSocialAudioParams, ImportTextParams, ImportTextResponse, CreateMediaFromUrlParams, GetMediaUseParams, GetMediaUseResponse, FilterMediaParams, FilterMediaResponse, PfpSearchParams, PfpSearchResponse, PfpCandidate,
|
|
33
|
+
export type { UserMedia, MediaUse, SocialAudio, Media, GetMediaParams, GetSocialAudioParams, UploadMediaParams, UploadMediaResponse, MediaTagUpdate, UpdateMediaTagsParams, MediaTagUpdateResult, UpdateMediaTagsResponse, UpdateMediaTagParams, UpdateMediaNameParams, DeleteMediaParams, DeleteMediaResponse, CreateSocialAudioParams, ImportTextParams, ImportTextResponse, CreateMediaFromUrlParams, GetMediaUseParams, GetMediaUseResponse, FilterMediaParams, FilterMediaResponse, PfpSearchParams, PfpSearchResponse, PfpCandidate, } from './media';
|
|
34
34
|
export type { CommentStatus, Comment, CreateCommentParams, CreateCommentResponse, GetCommentsParams, } from './comments';
|
|
35
35
|
export type { BillingInfo, PortalUrlResponse, CancelAccountParams, CancelAccountResponse, ReactivateAccountParams, ReactivateAccountResponse, CancelSubscriptionResponse, RequestReplacementParams, RequestReplacementResponse, RequestRefundParams, RequestRefundResponse, BillingRequestInfo, PortalParams, } from './billing';
|
|
36
36
|
export type { RenderJobResponse, RenderJobStatus, SubmitImageRenderJobParams, SubmitVideoRenderJobParams, SubmitScreenshotAnimationRenderJobParams, SubmitAutoCaptionRenderJobParams, SubmitSceneSplitJobParams, SceneSplitDetectorConfig, SubmitInstagramDmRenderJobParams, SubmitIMessageDmRenderJobParams, IgDmMessage, ImDmMessage, RenderVideoEditorConfig, } from './render';
|
package/dist/media.d.ts
CHANGED
|
@@ -150,13 +150,17 @@ export interface PfpSearchResponse {
|
|
|
150
150
|
search_term: string;
|
|
151
151
|
count: number;
|
|
152
152
|
}
|
|
153
|
-
export interface
|
|
153
|
+
export interface OwnedUploadParams {
|
|
154
154
|
filename: string;
|
|
155
|
-
contentType
|
|
155
|
+
contentType: string;
|
|
156
|
+
size: number;
|
|
156
157
|
}
|
|
157
|
-
export interface
|
|
158
|
-
|
|
158
|
+
export interface OwnedUploadResponse {
|
|
159
|
+
url: string;
|
|
160
|
+
fields: Record<string, string>;
|
|
159
161
|
pathname: string;
|
|
162
|
+
publicUrl: string;
|
|
163
|
+
expiresAt: string;
|
|
160
164
|
}
|
|
161
165
|
/**
|
|
162
166
|
* Client for managing media files
|
|
@@ -175,15 +179,12 @@ export declare class MediaClient extends BaseClient {
|
|
|
175
179
|
getSocialAudio(params?: GetSocialAudioParams): Promise<ApiResponse<SocialAudio[]>>;
|
|
176
180
|
/**
|
|
177
181
|
* Create media from URL(s)
|
|
178
|
-
* Creates media records from files already uploaded to
|
|
182
|
+
* Creates media records from files already uploaded to owned media storage
|
|
183
|
+
* (see getOwnedUpload() for the upload policy)
|
|
179
184
|
*/
|
|
180
185
|
create(params: CreateMediaFromUrlParams): Promise<ApiResponse<UploadMediaResponse>>;
|
|
181
|
-
/**
|
|
182
|
-
|
|
183
|
-
* Use this with the `put` function from @vercel/blob/client
|
|
184
|
-
* After uploading, call create() with the resulting blob URL
|
|
185
|
-
*/
|
|
186
|
-
getUploadToken(params: GetUploadTokenParams): Promise<ApiResponse<UploadTokenResponse>>;
|
|
186
|
+
/** Request a short-lived Wasabi POST policy for an owned media upload. */
|
|
187
|
+
getOwnedUpload(params: OwnedUploadParams): Promise<ApiResponse<OwnedUploadResponse>>;
|
|
187
188
|
/**
|
|
188
189
|
* Update tags on multiple media items in a single request
|
|
189
190
|
* Works for both user_media and social_audio
|
|
@@ -203,7 +204,7 @@ export declare class MediaClient extends BaseClient {
|
|
|
203
204
|
updateTag(params: UpdateMediaTagParams): Promise<ApiResponse<UpdateMediaTagsResponse>>;
|
|
204
205
|
/**
|
|
205
206
|
* Delete one or more media items
|
|
206
|
-
* Also deletes the files from
|
|
207
|
+
* Also deletes the files from owned media storage
|
|
207
208
|
*/
|
|
208
209
|
delete(params: DeleteMediaParams): Promise<ApiResponse<DeleteMediaResponse>>;
|
|
209
210
|
/**
|
package/dist/media.js
CHANGED
|
@@ -23,18 +23,15 @@ class MediaClient extends base_1.BaseClient {
|
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Create media from URL(s)
|
|
26
|
-
* Creates media records from files already uploaded to
|
|
26
|
+
* Creates media records from files already uploaded to owned media storage
|
|
27
|
+
* (see getOwnedUpload() for the upload policy)
|
|
27
28
|
*/
|
|
28
29
|
async create(params) {
|
|
29
30
|
return this.post('/media/create', params);
|
|
30
31
|
}
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* After uploading, call create() with the resulting blob URL
|
|
35
|
-
*/
|
|
36
|
-
async getUploadToken(params) {
|
|
37
|
-
return this.post('/media/create/url', params);
|
|
32
|
+
/** Request a short-lived Wasabi POST policy for an owned media upload. */
|
|
33
|
+
async getOwnedUpload(params) {
|
|
34
|
+
return this.post('/media/create/owned-upload', params);
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
40
37
|
* Update tags on multiple media items in a single request
|
|
@@ -61,7 +58,7 @@ class MediaClient extends base_1.BaseClient {
|
|
|
61
58
|
}
|
|
62
59
|
/**
|
|
63
60
|
* Delete one or more media items
|
|
64
|
-
* Also deletes the files from
|
|
61
|
+
* Also deletes the files from owned media storage
|
|
65
62
|
*/
|
|
66
63
|
async delete(params) {
|
|
67
64
|
return this.post('/media/delete', params);
|
package/dist/posts.d.ts
CHANGED
|
@@ -10,9 +10,13 @@ import type { ApiResponse } from './types';
|
|
|
10
10
|
* - `capacity_deferred` — no posting capacity was available; the post will be retried
|
|
11
11
|
* - `platform_change` — the social app's interface changed and the post could not complete
|
|
12
12
|
* - `unconfirmed` — posting finished but publication could not be confirmed
|
|
13
|
+
* - `audio_unavailable` — the chosen sound was not available on the platform and no backup audio was left
|
|
13
14
|
* - `unknown` — the post failed for an unrecognized reason
|
|
15
|
+
*
|
|
16
|
+
* A failed post also carries its category on its `tag`, as a trailing
|
|
17
|
+
* `fail reason: <category>` (removed again when the post is retried).
|
|
14
18
|
*/
|
|
15
|
-
export type PostFailCategory = 'device_error' | 'network_error' | 'upload_interrupted' | 'account_issue' | 'capacity_deferred' | 'platform_change' | 'unconfirmed' | 'unknown';
|
|
19
|
+
export type PostFailCategory = 'device_error' | 'network_error' | 'upload_interrupted' | 'account_issue' | 'capacity_deferred' | 'platform_change' | 'unconfirmed' | 'audio_unavailable' | 'unknown';
|
|
16
20
|
export type PostType = 'video' | 'slideshow';
|
|
17
21
|
export type PostStatus = 'draft' | 'scheduled' | 'pending' | 'complete' | 'failed' | 'retrying' | 'deleting' | 'deleted' | 'hidden' | 'require-approval';
|
|
18
22
|
/**
|
|
@@ -42,6 +46,10 @@ export interface Post {
|
|
|
42
46
|
thumbnail_url: string | null;
|
|
43
47
|
music_post_id: string | null;
|
|
44
48
|
social_audio_id: string | null;
|
|
49
|
+
/** Fallback sound. Moved into `social_audio_id` (and cleared) if the platform refuses the primary sound. */
|
|
50
|
+
backup_social_audio_id: string | null;
|
|
51
|
+
/** When the backup sound was swapped in (ISO 8601), or null if it never was. */
|
|
52
|
+
backup_audio_used_at: string | null;
|
|
45
53
|
scheduled_at: string | null;
|
|
46
54
|
postUrl?: string;
|
|
47
55
|
}
|
|
@@ -101,6 +109,8 @@ export interface CreateSlideshowParams {
|
|
|
101
109
|
caption?: string;
|
|
102
110
|
title?: string;
|
|
103
111
|
socialAudioId?: string;
|
|
112
|
+
/** Fallback sound, used once if the platform refuses the primary sound at posting time */
|
|
113
|
+
backupSocialAudioId?: string;
|
|
104
114
|
postTime?: string;
|
|
105
115
|
imageUrls: string[];
|
|
106
116
|
strict?: boolean;
|
|
@@ -126,6 +136,8 @@ export interface CreateVideoParams {
|
|
|
126
136
|
caption?: string;
|
|
127
137
|
captionOverlays?: CaptionOverlay[];
|
|
128
138
|
socialAudioId?: string;
|
|
139
|
+
/** Fallback sound, used once if the platform refuses the primary sound at posting time */
|
|
140
|
+
backupSocialAudioId?: string;
|
|
129
141
|
postTime?: string;
|
|
130
142
|
videoUrl: string;
|
|
131
143
|
strict?: boolean;
|
|
@@ -158,6 +170,8 @@ export interface UpdatePostParams {
|
|
|
158
170
|
caption?: string;
|
|
159
171
|
title?: string;
|
|
160
172
|
socialAudioId?: string;
|
|
173
|
+
/** Fallback sound, used once if the platform refuses the primary sound at posting time; `null` clears it */
|
|
174
|
+
backupSocialAudioId?: string | null;
|
|
161
175
|
postTime?: string;
|
|
162
176
|
accountId?: string;
|
|
163
177
|
mediaUrls?: string[];
|
|
@@ -184,6 +198,8 @@ export interface CreateDraftParams {
|
|
|
184
198
|
caption?: string;
|
|
185
199
|
title?: string;
|
|
186
200
|
socialAudioId?: string;
|
|
201
|
+
/** Fallback sound, used once if the platform refuses the primary sound at posting time */
|
|
202
|
+
backupSocialAudioId?: string;
|
|
187
203
|
/** Tag stored on the created POST itself (returned as `tag` on the Post object) */
|
|
188
204
|
post_tag?: string;
|
|
189
205
|
}
|
package/dist/render/Root.js
CHANGED
|
@@ -59,7 +59,7 @@ const defaultAutoCaptionProps = {
|
|
|
59
59
|
},
|
|
60
60
|
};
|
|
61
61
|
const defaultScreenshotAnimationProps = {
|
|
62
|
-
imageUrl: 'https://
|
|
62
|
+
imageUrl: 'https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/IMG_3163-RY0CFNrbnSnqZpaJzi9VdslzfYLLKf.png',
|
|
63
63
|
width: 1206,
|
|
64
64
|
height: 2622,
|
|
65
65
|
pauseDurationMs: 1000,
|
|
@@ -213,7 +213,7 @@ const instagramDmSchema = zod_1.z.object({
|
|
|
213
213
|
// Debug overlay
|
|
214
214
|
showDebugOverlay: zod_1.z.boolean().optional().default(true).describe('Show debug overlay with mouse coordinates'),
|
|
215
215
|
// Reference overlay
|
|
216
|
-
referenceImageUrl: zod_1.z.string().optional().default('https://
|
|
216
|
+
referenceImageUrl: zod_1.z.string().optional().default('https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/IMG_3153-TiJrpzJKKvsTsjmP9zIX5LpoT8s2hF.png').describe('Reference screenshot URL'),
|
|
217
217
|
showReferenceImage: zod_1.z.boolean().optional().default(true).describe('Show/hide reference image'),
|
|
218
218
|
referenceOpacity: zod_1.z.number().min(0).max(100).optional().default(50).describe('Reference overlay opacity (0-100)'),
|
|
219
219
|
// Canvas
|
|
@@ -326,7 +326,7 @@ const instagramDmSchema = zod_1.z.object({
|
|
|
326
326
|
backArrowLeft: zod_1.z.number().optional().default(78).describe('Back arrow left X'),
|
|
327
327
|
backArrowRight: zod_1.z.number().optional().default(111).describe('Back arrow right X'),
|
|
328
328
|
// Header - User profile picture
|
|
329
|
-
userPfpUrl: zod_1.z.string().optional().default('https://
|
|
329
|
+
userPfpUrl: zod_1.z.string().optional().default('https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/884a81ce74fa88e229f6be5f76f29385-3P4rjQqfbLidxtZ7OmvgaDQNMSSIGi.jpg').describe('User profile picture URL'),
|
|
330
330
|
userPfpTop: zod_1.z.number().optional().default(220).describe('User pfp top Y'),
|
|
331
331
|
userPfpBottom: zod_1.z.number().optional().default(320).describe('User pfp bottom Y'),
|
|
332
332
|
userPfpLeft: zod_1.z.number().optional().default(179).describe('User pfp left X'),
|
|
@@ -25,7 +25,7 @@ Object.defineProperty(exports, "convertPropsToElements", { enumerable: true, get
|
|
|
25
25
|
*/
|
|
26
26
|
exports.defaultIMessageDmProps = {
|
|
27
27
|
showDebugOverlay: false,
|
|
28
|
-
referenceImageUrl: 'https://
|
|
28
|
+
referenceImageUrl: 'https://media.ugc.inc/media/06c3ed1c-eefb-4a60-b0c4-5fb872811ba0/IMG_3189-hUoucNOmBoT8fihIL7ybuEXwoRrngz.png',
|
|
29
29
|
showReferenceImage: false,
|
|
30
30
|
referenceOpacity: 50,
|
|
31
31
|
lightMode: false,
|
|
@@ -38,7 +38,7 @@ exports.defaultIMessageDmProps = {
|
|
|
38
38
|
headerBottom: 424,
|
|
39
39
|
headerBackgroundColor: '#171717',
|
|
40
40
|
// Profile section defaults
|
|
41
|
-
profilePicUrl: 'https://
|
|
41
|
+
profilePicUrl: 'https://media.ugc.inc/media/06c3ed1c-eefb-4a60-b0c4-5fb872811ba0/pinterest-1766175215011-3-ftQGbunlgHOFdfFtr1PdxxmHD9TAf9.jpg',
|
|
42
42
|
profilePicTop: 195,
|
|
43
43
|
profilePicBottom: 347,
|
|
44
44
|
profilePicLeft: 528,
|
|
@@ -225,7 +225,7 @@ exports.defaultIMessageDmProps = {
|
|
|
225
225
|
readReceiptRight: 1158,
|
|
226
226
|
// Example messages
|
|
227
227
|
messages: [
|
|
228
|
-
{ id: 'msg-1', sender: 'user', text: 'heyyy fae, help me slide on this baddie pls 🙏', imageUrl: 'https://
|
|
228
|
+
{ id: 'msg-1', sender: 'user', text: 'heyyy fae, help me slide on this baddie pls 🙏', imageUrl: 'https://media.ugc.inc/media/06c3ed1c-eefb-4a60-b0c4-5fb872811ba0/pinterest-1766175214139-0-JpXmGIxVWdjEJ3qxGyoC4DAi2KAZrg.jpg' },
|
|
229
229
|
{ id: 'msg-2', sender: 'recipient', text: 'don\'t worry king, i gotchu' },
|
|
230
230
|
{ id: 'msg-3', sender: 'recipient', text: 'that is indeed a cute kitty', groupWithPrevious: true },
|
|
231
231
|
{ id: 'msg-4', sender: 'recipient', text: 'try this line out for speed: are you a kitty? because you deserve pets', groupWithPrevious: true },
|
|
@@ -26,7 +26,7 @@ Object.defineProperty(exports, "convertPropsToElements", { enumerable: true, get
|
|
|
26
26
|
*/
|
|
27
27
|
exports.defaultInstagramDmProps = {
|
|
28
28
|
showDebugOverlay: false,
|
|
29
|
-
referenceImageUrl: 'https://
|
|
29
|
+
referenceImageUrl: 'https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/IMG_3186-L1M2HgmhYFpnI5uKDrhcKYpRQSzwoz.png',
|
|
30
30
|
showReferenceImage: false,
|
|
31
31
|
referenceOpacity: 50,
|
|
32
32
|
width: 1206,
|
|
@@ -89,7 +89,7 @@ exports.defaultInstagramDmProps = {
|
|
|
89
89
|
// Message defaults
|
|
90
90
|
messages: [
|
|
91
91
|
// Sender group 1 (with story reply)
|
|
92
|
-
{ id: '1', sender: 'user', text: "if you were a disney princess you'd be jasmine", storyReplyImageUrl: 'https://
|
|
92
|
+
{ id: '1', sender: 'user', text: "if you were a disney princess you'd be jasmine", storyReplyImageUrl: 'https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/ddafc0af3ae404d8223d191bcd424a4a-IMBUblDJvuj2g8LkUZXQ3pJZzfBSTc.jpg' },
|
|
93
93
|
// Receiver group 1
|
|
94
94
|
{ id: '2', sender: 'recipient', text: 'aww ur sweet' },
|
|
95
95
|
{ id: '3', sender: 'recipient', text: "but i'm clearly more of a mulan 🙄", groupWithPrevious: true },
|
|
@@ -131,7 +131,7 @@ exports.defaultInstagramDmProps = {
|
|
|
131
131
|
recipientBubbleLeft: 168,
|
|
132
132
|
senderBubbleRight: 1182,
|
|
133
133
|
bubbleMaxWidth: 866,
|
|
134
|
-
profilePicUrl: 'https://
|
|
134
|
+
profilePicUrl: 'https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/884a81ce74fa88e229f6be5f76f29385-3P4rjQqfbLidxtZ7OmvgaDQNMSSIGi.jpg',
|
|
135
135
|
profilePicSize: 83,
|
|
136
136
|
profilePicGap: 37,
|
|
137
137
|
// Header - Back arrow
|
|
@@ -140,7 +140,7 @@ exports.defaultInstagramDmProps = {
|
|
|
140
140
|
backArrowLeft: 78,
|
|
141
141
|
backArrowRight: 111,
|
|
142
142
|
// Header - User profile picture
|
|
143
|
-
userPfpUrl: 'https://
|
|
143
|
+
userPfpUrl: 'https://media.ugc.inc/media/8ff1462b-13d7-4abe-9325-0a6ad19004f0/884a81ce74fa88e229f6be5f76f29385-3P4rjQqfbLidxtZ7OmvgaDQNMSSIGi.jpg',
|
|
144
144
|
userPfpTop: 220,
|
|
145
145
|
userPfpBottom: 320,
|
|
146
146
|
userPfpLeft: 179,
|
package/dist/render.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Render functions
|
|
3
|
-
*
|
|
2
|
+
* Render functions: submit image, video, deduplication, scene-split and DM
|
|
3
|
+
* jobs to the UGC render worker and poll them.
|
|
4
|
+
*
|
|
5
|
+
* The worker's origin is read from `UGC_RENDER_URL` at call time. It is a
|
|
6
|
+
* private origin (the owned render worker is reachable only from the UGC API's
|
|
7
|
+
* network); there is no public default, so calling these functions without the
|
|
8
|
+
* variable set fails fast.
|
|
4
9
|
*/
|
|
5
10
|
import type { ApiResponse } from './types';
|
|
6
11
|
import type { VideoEditorNodeConfig, DeduplicationInput } from './render/types';
|
|
@@ -156,45 +161,45 @@ export interface SubmitIMessageDmRenderJobParams {
|
|
|
156
161
|
dynamicCrop?: import('./render/types/crop').DynamicCropConfig;
|
|
157
162
|
}
|
|
158
163
|
/**
|
|
159
|
-
* Submit an image render job to the
|
|
164
|
+
* Submit an image render job to the render worker.
|
|
160
165
|
* Uses the element-based format for single-source-of-truth rendering.
|
|
161
166
|
*/
|
|
162
167
|
export declare function submitImageRenderJob(params: SubmitImageRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
163
168
|
/**
|
|
164
|
-
* Submit a video render job to the
|
|
169
|
+
* Submit a video render job to the render worker.
|
|
165
170
|
*/
|
|
166
171
|
export declare function submitVideoRenderJob(params: SubmitVideoRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
167
172
|
/**
|
|
168
|
-
* Get render job status from the
|
|
173
|
+
* Get render job status from the render worker.
|
|
169
174
|
*/
|
|
170
175
|
export declare function getRenderJobStatus(jobId: string): Promise<ApiResponse<RenderJobStatus>>;
|
|
171
176
|
/**
|
|
172
|
-
* Submit a deduplication job to the
|
|
177
|
+
* Submit a deduplication job to the render worker.
|
|
173
178
|
* Applies hash-breaking, metadata injection, and trace removal to a video.
|
|
174
179
|
*/
|
|
175
180
|
export declare function submitDeduplicationJob(params: SubmitDeduplicationJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
176
181
|
/**
|
|
177
|
-
* Submit a scene split job to the
|
|
182
|
+
* Submit a scene split job to the render worker.
|
|
178
183
|
* Detects scene boundaries and splits a video into individual clips.
|
|
179
184
|
*/
|
|
180
185
|
export declare function submitSceneSplitJob(params: SubmitSceneSplitJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
181
186
|
/**
|
|
182
|
-
* Submit a screenshot animation render job to the
|
|
187
|
+
* Submit a screenshot animation render job to the render worker.
|
|
183
188
|
* Renders an iPhone screenshot animation video from a source image.
|
|
184
189
|
*/
|
|
185
190
|
export declare function submitScreenshotAnimationRenderJob(params: SubmitScreenshotAnimationRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
186
191
|
/**
|
|
187
|
-
* Submit an auto-caption render job to the
|
|
192
|
+
* Submit an auto-caption render job to the render worker.
|
|
188
193
|
* Renders a video with captions overlaid.
|
|
189
194
|
*/
|
|
190
195
|
export declare function submitAutoCaptionRenderJob(params: SubmitAutoCaptionRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
191
196
|
/**
|
|
192
|
-
* Submit an Instagram DM render job to the
|
|
197
|
+
* Submit an Instagram DM render job to the render worker.
|
|
193
198
|
* Renders a fake Instagram DM conversation image.
|
|
194
199
|
*/
|
|
195
200
|
export declare function submitInstagramDmRenderJob(params: SubmitInstagramDmRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
|
196
201
|
/**
|
|
197
|
-
* Submit an iMessage DM render job to the
|
|
202
|
+
* Submit an iMessage DM render job to the render worker.
|
|
198
203
|
* Renders a fake iMessage conversation image.
|
|
199
204
|
*/
|
|
200
205
|
export declare function submitIMessageDmRenderJob(params: SubmitIMessageDmRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
|
package/dist/render.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Render functions
|
|
4
|
-
*
|
|
3
|
+
* Render functions: submit image, video, deduplication, scene-split and DM
|
|
4
|
+
* jobs to the UGC render worker and poll them.
|
|
5
|
+
*
|
|
6
|
+
* The worker's origin is read from `UGC_RENDER_URL` at call time. It is a
|
|
7
|
+
* private origin (the owned render worker is reachable only from the UGC API's
|
|
8
|
+
* network); there is no public default, so calling these functions without the
|
|
9
|
+
* variable set fails fast.
|
|
5
10
|
*/
|
|
6
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
12
|
exports.submitImageRenderJob = submitImageRenderJob;
|
|
@@ -13,72 +18,40 @@ exports.submitScreenshotAnimationRenderJob = submitScreenshotAnimationRenderJob;
|
|
|
13
18
|
exports.submitAutoCaptionRenderJob = submitAutoCaptionRenderJob;
|
|
14
19
|
exports.submitInstagramDmRenderJob = submitInstagramDmRenderJob;
|
|
15
20
|
exports.submitIMessageDmRenderJob = submitIMessageDmRenderJob;
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// =============================================================================
|
|
21
|
-
// Rate Limiting & Retry (Modal workspace limit: 200 req/s)
|
|
22
|
-
// =============================================================================
|
|
23
|
-
const MODAL_RATE_LIMIT = 150; // per second, safety margin below 200
|
|
24
|
-
const MAX_RETRIES = 3;
|
|
25
|
-
// Sliding window: timestamps of recent requests within the last second
|
|
26
|
-
const requestTimestamps = [];
|
|
27
|
-
function acquireRateSlot() {
|
|
28
|
-
const now = Date.now();
|
|
29
|
-
// Evict timestamps older than 1 second
|
|
30
|
-
while (requestTimestamps.length > 0 && requestTimestamps[0] < now - 1000) {
|
|
31
|
-
requestTimestamps.shift();
|
|
32
|
-
}
|
|
33
|
-
if (requestTimestamps.length < MODAL_RATE_LIMIT) {
|
|
34
|
-
requestTimestamps.push(now);
|
|
35
|
-
return 0; // no wait needed
|
|
36
|
-
}
|
|
37
|
-
// Calculate ms until the oldest request exits the window
|
|
38
|
-
return 1000 - (now - requestTimestamps[0]) + 10;
|
|
39
|
-
}
|
|
40
|
-
async function waitForRateSlot() {
|
|
41
|
-
let waitMs = acquireRateSlot();
|
|
42
|
-
while (waitMs > 0) {
|
|
43
|
-
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
44
|
-
waitMs = acquireRateSlot();
|
|
21
|
+
function renderBaseUrl() {
|
|
22
|
+
const url = process.env.UGC_RENDER_URL?.trim();
|
|
23
|
+
if (!url) {
|
|
24
|
+
throw new Error('UGC_RENDER_URL is not set: the render functions need the render worker origin');
|
|
45
25
|
}
|
|
26
|
+
return url.replace(/\/+$/, '');
|
|
46
27
|
}
|
|
28
|
+
const MAX_RETRIES = 3;
|
|
47
29
|
/**
|
|
48
|
-
* Fetch wrapper for
|
|
49
|
-
*
|
|
30
|
+
* Fetch wrapper for every render worker call: retries network errors, 429 and
|
|
31
|
+
* 5xx with exponential backoff; returns 4xx responses to the caller unchanged.
|
|
50
32
|
*/
|
|
51
|
-
async function
|
|
33
|
+
async function renderFetch(path, options) {
|
|
34
|
+
const url = `${renderBaseUrl()}${path}`;
|
|
35
|
+
let response;
|
|
52
36
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
53
|
-
await waitForRateSlot();
|
|
54
|
-
let response;
|
|
55
37
|
try {
|
|
56
38
|
response = await fetch(url, options);
|
|
57
39
|
}
|
|
58
40
|
catch (error) {
|
|
59
|
-
// Network error — retry with backoff
|
|
60
41
|
if (attempt < MAX_RETRIES) {
|
|
61
|
-
|
|
62
|
-
await new Promise(resolve => setTimeout(resolve, backoff));
|
|
42
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 500 + Math.random() * 500));
|
|
63
43
|
continue;
|
|
64
44
|
}
|
|
65
45
|
throw error;
|
|
66
46
|
}
|
|
67
|
-
// Success or non-retryable client error (400, 401, 403, 404, etc.)
|
|
68
47
|
if (response.ok || (response.status >= 400 && response.status < 500 && response.status !== 429)) {
|
|
69
48
|
return response;
|
|
70
49
|
}
|
|
71
|
-
// Retryable: 429 (rate limit) or 5xx (server error)
|
|
72
50
|
if (attempt < MAX_RETRIES) {
|
|
73
|
-
|
|
74
|
-
await new Promise(resolve => setTimeout(resolve, backoff));
|
|
75
|
-
continue;
|
|
51
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 500 + Math.random() * 500));
|
|
76
52
|
}
|
|
77
|
-
return response; // Return error response on final attempt
|
|
78
53
|
}
|
|
79
|
-
|
|
80
|
-
await waitForRateSlot();
|
|
81
|
-
return fetch(url, options);
|
|
54
|
+
return response;
|
|
82
55
|
}
|
|
83
56
|
// =============================================================================
|
|
84
57
|
// DM Message Transformation Helpers
|
|
@@ -131,12 +104,12 @@ function transformToIMessageMessages(messages, imageAttachmentUrl) {
|
|
|
131
104
|
// Render Functions
|
|
132
105
|
// =============================================================================
|
|
133
106
|
/**
|
|
134
|
-
* Submit an image render job to the
|
|
107
|
+
* Submit an image render job to the render worker.
|
|
135
108
|
* Uses the element-based format for single-source-of-truth rendering.
|
|
136
109
|
*/
|
|
137
110
|
async function submitImageRenderJob(params) {
|
|
138
111
|
try {
|
|
139
|
-
const response = await
|
|
112
|
+
const response = await renderFetch('/submit-job', {
|
|
140
113
|
method: 'POST',
|
|
141
114
|
headers: { 'Content-Type': 'application/json' },
|
|
142
115
|
body: JSON.stringify({
|
|
@@ -164,7 +137,7 @@ async function submitImageRenderJob(params) {
|
|
|
164
137
|
data = JSON.parse(text);
|
|
165
138
|
}
|
|
166
139
|
catch {
|
|
167
|
-
return { ok: false, code: response.status || 500, message: `
|
|
140
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
168
141
|
}
|
|
169
142
|
if (data.status === 'error' || !response.ok) {
|
|
170
143
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit render job' };
|
|
@@ -177,11 +150,11 @@ async function submitImageRenderJob(params) {
|
|
|
177
150
|
}
|
|
178
151
|
}
|
|
179
152
|
/**
|
|
180
|
-
* Submit a video render job to the
|
|
153
|
+
* Submit a video render job to the render worker.
|
|
181
154
|
*/
|
|
182
155
|
async function submitVideoRenderJob(params) {
|
|
183
156
|
try {
|
|
184
|
-
const response = await
|
|
157
|
+
const response = await renderFetch('/submit-job', {
|
|
185
158
|
method: 'POST',
|
|
186
159
|
headers: { 'Content-Type': 'application/json' },
|
|
187
160
|
body: JSON.stringify({
|
|
@@ -202,7 +175,7 @@ async function submitVideoRenderJob(params) {
|
|
|
202
175
|
data = JSON.parse(text);
|
|
203
176
|
}
|
|
204
177
|
catch {
|
|
205
|
-
return { ok: false, code: response.status || 500, message: `
|
|
178
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
206
179
|
}
|
|
207
180
|
if (data.status === 'error' || !response.ok) {
|
|
208
181
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit render job' };
|
|
@@ -215,11 +188,11 @@ async function submitVideoRenderJob(params) {
|
|
|
215
188
|
}
|
|
216
189
|
}
|
|
217
190
|
/**
|
|
218
|
-
* Get render job status from the
|
|
191
|
+
* Get render job status from the render worker.
|
|
219
192
|
*/
|
|
220
193
|
async function getRenderJobStatus(jobId) {
|
|
221
194
|
try {
|
|
222
|
-
const response = await
|
|
195
|
+
const response = await renderFetch('/get-status', {
|
|
223
196
|
method: 'POST',
|
|
224
197
|
headers: { 'Content-Type': 'application/json' },
|
|
225
198
|
body: JSON.stringify({ job_id: jobId }),
|
|
@@ -230,7 +203,7 @@ async function getRenderJobStatus(jobId) {
|
|
|
230
203
|
data = JSON.parse(text);
|
|
231
204
|
}
|
|
232
205
|
catch {
|
|
233
|
-
return { ok: false, code: response.status || 500, message: `
|
|
206
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
234
207
|
}
|
|
235
208
|
if (data.status === 'error' || !response.ok) {
|
|
236
209
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to get job status' };
|
|
@@ -247,12 +220,12 @@ async function getRenderJobStatus(jobId) {
|
|
|
247
220
|
}
|
|
248
221
|
}
|
|
249
222
|
/**
|
|
250
|
-
* Submit a deduplication job to the
|
|
223
|
+
* Submit a deduplication job to the render worker.
|
|
251
224
|
* Applies hash-breaking, metadata injection, and trace removal to a video.
|
|
252
225
|
*/
|
|
253
226
|
async function submitDeduplicationJob(params) {
|
|
254
227
|
try {
|
|
255
|
-
const response = await
|
|
228
|
+
const response = await renderFetch('/submit-job', {
|
|
256
229
|
method: 'POST',
|
|
257
230
|
headers: { 'Content-Type': 'application/json' },
|
|
258
231
|
body: JSON.stringify({
|
|
@@ -267,7 +240,7 @@ async function submitDeduplicationJob(params) {
|
|
|
267
240
|
data = JSON.parse(text);
|
|
268
241
|
}
|
|
269
242
|
catch {
|
|
270
|
-
return { ok: false, code: response.status || 500, message: `
|
|
243
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
271
244
|
}
|
|
272
245
|
if (data.status === 'error' || !response.ok) {
|
|
273
246
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit deduplication job' };
|
|
@@ -280,12 +253,12 @@ async function submitDeduplicationJob(params) {
|
|
|
280
253
|
}
|
|
281
254
|
}
|
|
282
255
|
/**
|
|
283
|
-
* Submit a scene split job to the
|
|
256
|
+
* Submit a scene split job to the render worker.
|
|
284
257
|
* Detects scene boundaries and splits a video into individual clips.
|
|
285
258
|
*/
|
|
286
259
|
async function submitSceneSplitJob(params) {
|
|
287
260
|
try {
|
|
288
|
-
const response = await
|
|
261
|
+
const response = await renderFetch('/submit-job', {
|
|
289
262
|
method: 'POST',
|
|
290
263
|
headers: { 'Content-Type': 'application/json' },
|
|
291
264
|
body: JSON.stringify({
|
|
@@ -300,7 +273,7 @@ async function submitSceneSplitJob(params) {
|
|
|
300
273
|
data = JSON.parse(text);
|
|
301
274
|
}
|
|
302
275
|
catch {
|
|
303
|
-
return { ok: false, code: response.status || 500, message: `
|
|
276
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
304
277
|
}
|
|
305
278
|
if (data.status === 'error' || !response.ok) {
|
|
306
279
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit scene split job' };
|
|
@@ -313,12 +286,12 @@ async function submitSceneSplitJob(params) {
|
|
|
313
286
|
}
|
|
314
287
|
}
|
|
315
288
|
/**
|
|
316
|
-
* Submit a screenshot animation render job to the
|
|
289
|
+
* Submit a screenshot animation render job to the render worker.
|
|
317
290
|
* Renders an iPhone screenshot animation video from a source image.
|
|
318
291
|
*/
|
|
319
292
|
async function submitScreenshotAnimationRenderJob(params) {
|
|
320
293
|
try {
|
|
321
|
-
const response = await
|
|
294
|
+
const response = await renderFetch('/submit-job', {
|
|
322
295
|
method: 'POST',
|
|
323
296
|
headers: { 'Content-Type': 'application/json' },
|
|
324
297
|
body: JSON.stringify({
|
|
@@ -337,7 +310,7 @@ async function submitScreenshotAnimationRenderJob(params) {
|
|
|
337
310
|
data = JSON.parse(text);
|
|
338
311
|
}
|
|
339
312
|
catch {
|
|
340
|
-
return { ok: false, code: response.status || 500, message: `
|
|
313
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
341
314
|
}
|
|
342
315
|
if (data.status === 'error' || !response.ok) {
|
|
343
316
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit screenshot animation job' };
|
|
@@ -350,12 +323,12 @@ async function submitScreenshotAnimationRenderJob(params) {
|
|
|
350
323
|
}
|
|
351
324
|
}
|
|
352
325
|
/**
|
|
353
|
-
* Submit an auto-caption render job to the
|
|
326
|
+
* Submit an auto-caption render job to the render worker.
|
|
354
327
|
* Renders a video with captions overlaid.
|
|
355
328
|
*/
|
|
356
329
|
async function submitAutoCaptionRenderJob(params) {
|
|
357
330
|
try {
|
|
358
|
-
const response = await
|
|
331
|
+
const response = await renderFetch('/submit-job', {
|
|
359
332
|
method: 'POST',
|
|
360
333
|
headers: { 'Content-Type': 'application/json' },
|
|
361
334
|
body: JSON.stringify({
|
|
@@ -379,7 +352,7 @@ async function submitAutoCaptionRenderJob(params) {
|
|
|
379
352
|
data = JSON.parse(text);
|
|
380
353
|
}
|
|
381
354
|
catch {
|
|
382
|
-
return { ok: false, code: response.status || 500, message: `
|
|
355
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
383
356
|
}
|
|
384
357
|
if (data.status === 'error' || !response.ok) {
|
|
385
358
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit auto-caption job' };
|
|
@@ -392,14 +365,14 @@ async function submitAutoCaptionRenderJob(params) {
|
|
|
392
365
|
}
|
|
393
366
|
}
|
|
394
367
|
/**
|
|
395
|
-
* Submit an Instagram DM render job to the
|
|
368
|
+
* Submit an Instagram DM render job to the render worker.
|
|
396
369
|
* Renders a fake Instagram DM conversation image.
|
|
397
370
|
*/
|
|
398
371
|
async function submitInstagramDmRenderJob(params) {
|
|
399
372
|
try {
|
|
400
373
|
const transformedMessages = transformToInstagramMessages(params.messages, params.imageAttachmentUrl);
|
|
401
374
|
const hasStoryReply = params.messages.some(msg => msg.hasImage);
|
|
402
|
-
const response = await
|
|
375
|
+
const response = await renderFetch('/submit-job', {
|
|
403
376
|
method: 'POST',
|
|
404
377
|
headers: { 'Content-Type': 'application/json' },
|
|
405
378
|
body: JSON.stringify({
|
|
@@ -424,7 +397,7 @@ async function submitInstagramDmRenderJob(params) {
|
|
|
424
397
|
data = JSON.parse(text);
|
|
425
398
|
}
|
|
426
399
|
catch {
|
|
427
|
-
return { ok: false, code: response.status || 500, message: `
|
|
400
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
428
401
|
}
|
|
429
402
|
if (data.status === 'error' || !response.ok) {
|
|
430
403
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit Instagram DM job' };
|
|
@@ -437,13 +410,13 @@ async function submitInstagramDmRenderJob(params) {
|
|
|
437
410
|
}
|
|
438
411
|
}
|
|
439
412
|
/**
|
|
440
|
-
* Submit an iMessage DM render job to the
|
|
413
|
+
* Submit an iMessage DM render job to the render worker.
|
|
441
414
|
* Renders a fake iMessage conversation image.
|
|
442
415
|
*/
|
|
443
416
|
async function submitIMessageDmRenderJob(params) {
|
|
444
417
|
try {
|
|
445
418
|
const transformedMessages = transformToIMessageMessages(params.messages, params.imageAttachmentUrl);
|
|
446
|
-
const response = await
|
|
419
|
+
const response = await renderFetch('/submit-job', {
|
|
447
420
|
method: 'POST',
|
|
448
421
|
headers: { 'Content-Type': 'application/json' },
|
|
449
422
|
body: JSON.stringify({
|
|
@@ -473,7 +446,7 @@ async function submitIMessageDmRenderJob(params) {
|
|
|
473
446
|
data = JSON.parse(text);
|
|
474
447
|
}
|
|
475
448
|
catch {
|
|
476
|
-
return { ok: false, code: response.status || 500, message: `
|
|
449
|
+
return { ok: false, code: response.status || 500, message: `Render endpoint error: ${text.substring(0, 100)}` };
|
|
477
450
|
}
|
|
478
451
|
if (data.status === 'error' || !response.ok) {
|
|
479
452
|
return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit iMessage DM job' };
|
package/dist/tools/posts.js
CHANGED
|
@@ -26,6 +26,7 @@ exports.postTools = [
|
|
|
26
26
|
videoUrl: zod_1.z.string().describe('URL of the video file'),
|
|
27
27
|
caption: zod_1.z.string().optional().describe('Post caption'),
|
|
28
28
|
socialAudioId: zod_1.z.string().optional().describe('Social audio ID to use'),
|
|
29
|
+
backupSocialAudioId: zod_1.z.string().optional().describe('Fallback social audio ID, used once if the platform refuses the primary sound'),
|
|
29
30
|
postTime: zod_1.z.string().optional().describe('Scheduled time (ISO 8601). Omit for next available slot.'),
|
|
30
31
|
strict: zod_1.z.boolean().optional().describe('If true with auto-selection, must post at exact time or error'),
|
|
31
32
|
mustPostBy: zod_1.z.string().optional().describe('Latest allowed scheduled time (ISO 8601). Errors if no slot is available before this deadline.'),
|
|
@@ -47,6 +48,7 @@ exports.postTools = [
|
|
|
47
48
|
caption: zod_1.z.string().optional().describe('Post caption'),
|
|
48
49
|
title: zod_1.z.string().optional().describe('Slideshow title'),
|
|
49
50
|
socialAudioId: zod_1.z.string().optional().describe('Social audio ID to use'),
|
|
51
|
+
backupSocialAudioId: zod_1.z.string().optional().describe('Fallback social audio ID, used once if the platform refuses the primary sound'),
|
|
50
52
|
postTime: zod_1.z.string().optional().describe('Scheduled time (ISO 8601)'),
|
|
51
53
|
strict: zod_1.z.boolean().optional().describe('If true with auto-selection, must post at exact time or error'),
|
|
52
54
|
mustPostBy: zod_1.z.string().optional().describe('Latest allowed scheduled time (ISO 8601). Errors if no slot is available before this deadline.'),
|
|
@@ -68,6 +70,7 @@ exports.postTools = [
|
|
|
68
70
|
caption: zod_1.z.string().optional().describe('Post caption'),
|
|
69
71
|
title: zod_1.z.string().optional().describe('Slideshow title'),
|
|
70
72
|
socialAudioId: zod_1.z.string().optional().describe('Social audio ID'),
|
|
73
|
+
backupSocialAudioId: zod_1.z.string().optional().describe('Fallback social audio ID, used once if the platform refuses the primary sound'),
|
|
71
74
|
post_tag: zod_1.z.string().optional().describe('Tag stored on the created post'),
|
|
72
75
|
}),
|
|
73
76
|
execute: async (client, params) => {
|
|
@@ -92,6 +95,7 @@ exports.postTools = [
|
|
|
92
95
|
caption: zod_1.z.string().optional().describe('New caption'),
|
|
93
96
|
title: zod_1.z.string().optional().describe('New title (slideshows only)'),
|
|
94
97
|
socialAudioId: zod_1.z.string().optional().describe('New social audio ID'),
|
|
98
|
+
backupSocialAudioId: zod_1.z.string().nullable().optional().describe('Fallback social audio ID, used once if the platform refuses the primary sound; null clears it'),
|
|
95
99
|
postTime: zod_1.z.string().optional().describe('New scheduled time (ISO 8601)'),
|
|
96
100
|
accountId: zod_1.z.string().optional().describe('Move post to different account'),
|
|
97
101
|
mediaUrls: zod_1.z.array(zod_1.z.string()).optional().describe('New media URLs'),
|