ugcinc 4.18.0 → 4.19.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 CHANGED
@@ -43,7 +43,7 @@ if (res.ok) {
43
43
 
44
44
  - `client.accounts`: list, create, update, troubleshoot, quarantine/release, and manage account lifecycle
45
45
  - `client.posts`: create video/slideshow posts, update them, retry failures, and preview schedule conflicts
46
- - `client.media`: upload media, create media records, search profile-picture candidates, search images and videos by keyword (`media.imageSearch`, cursor-paged), manage tags/names, and work with social audio
46
+ - `client.media`: upload media, create media records, manage tags/names, and work with social audio
47
47
  - `client.stats`: fetch account/post analytics, daily aggregates, top performers, and refresh stats
48
48
  - `client.org`: manage organizations, API keys, and integration keys
49
49
  - `client.billing`: inspect subscription state and handle account deactivation, replacements, and refunds
@@ -74,20 +74,6 @@ if (posts.ok) {
74
74
  }
75
75
  ```
76
76
 
77
- ## Posting failure quick reference
78
-
79
- `posts.getStatus()` returns `failure`; both `getPosts()` and `getPostsPage()` include it on each post. It is `null` when there is no current posting issue. A successful lookup still returns HTTP 200 even if the post failed.
80
-
81
- ```typescript
82
- const result = await client.posts.getStatus({ postId: "post_123" });
83
- if (result.ok && result.data.failure) {
84
- const { code, message, recovery, next_action } = result.data.failure;
85
- console.log(code, message, recovery, next_action);
86
- }
87
- ```
88
-
89
- See the posting failure reference below for recovery states and messages.
90
-
91
77
  ## Pagination
92
78
 
93
79
  `accounts.getAccounts()` and `posts.getPosts()` support keyset pagination via `limit`/`cursor`.
@@ -107,28 +93,6 @@ do {
107
93
  } while (cursor);
108
94
  ```
109
95
 
110
- For interactive tables, `posts.getPostsPage()` keeps filtering and sorting on the server and
111
- returns page-scoped latest stats plus `totalCount`, organization-wide `postTags`,
112
- `anyHasTitle`, and `matchingAccountIds`. It supports caption/title/account search; platform,
113
- post type, status, account, account-tag, post-tag, social-audio, and phone-type filters; and
114
- sorting by account, status, title, caption, tag, audio presence, scheduled time, or engagement:
115
-
116
- ```typescript
117
- const page = await client.posts.getPostsPage({
118
- search: "launch",
119
- statuses: ["complete"],
120
- postTags: ["fall-campaign"],
121
- sortBy: "views",
122
- sortDirection: "desc",
123
- limit: 200,
124
- });
125
-
126
- if (page.ok) {
127
- console.log(page.data.posts, page.data.stats, page.data.totalCount);
128
- const next = page.data.nextCursor;
129
- }
130
- ```
131
-
132
96
  ## Caption Overlays
133
97
 
134
98
  Video posts can carry text overlays to display on the video. Pass `captionOverlays` to
@@ -180,28 +144,6 @@ await client.posts.createVideo({
180
144
  await client.posts.updatePost({ postId: "post_123", post_tag: "campaign-august" });
181
145
  ```
182
146
 
183
- When a post fails, its category is appended to the tag as `fail reason: <fail_category>` (for
184
- example `campaign-july fail reason: device_error`), so a post list shows why without a status call
185
- per post. The suffix is removed again when the post is retried.
186
-
187
- ## Backup Audio
188
-
189
- A post can carry a second sound. If the platform refuses the primary sound at posting time, the
190
- backup becomes the post's `social_audio_id`, the post is re-attempted once, ` switched to backup
191
- audio` is appended to its `tag`, and `backup_audio_used_at` is set. With no backup left the post
192
- fails as `audio_unavailable` and is not retried. Set it with `backupSocialAudioId` on
193
- `posts.createVideo()`, `posts.createSlideshow()`, `posts.createDraft()`, and `posts.updatePost()`
194
- (`null` clears it on update).
195
-
196
- ```typescript
197
- await client.posts.createSlideshow({
198
- accountId: "acc_123",
199
- imageUrls: ["https://example.com/img1.jpg"],
200
- socialAudioId: "audio_primary",
201
- backupSocialAudioId: "audio_fallback",
202
- });
203
- ```
204
-
205
147
  ## Useful Exports
206
148
 
207
149
  - `UGCClient` for API access
@@ -220,33 +162,6 @@ For the full endpoint reference, all method signatures, data structures, and wor
220
162
 
221
163
  MIT
222
164
 
223
- ## Posting failure reference
224
-
225
- The same `failure` object is returned by status and list responses. It contains a stable `code`, a fixed `message`, a `recovery` state, and `next_action`.
226
-
227
- | Recovery | Meaning |
228
- |---|---|
229
- | `retry_pending` | The existing post is waiting for another attempt; no execution time is guaranteed. |
230
- | `waiting` | The existing post is paused until a publishing issue is resolved. |
231
- | `verifying_publication` | Publication is being checked before another attempt is allowed. |
232
- | `stopped` | No automatic recovery is indicated. Follow `next_action`. |
233
-
234
- `next_action` is `wait`, `change_audio`, `change_audio_or_contact_support`, or `contact_support`. When it is `wait`, do not submit another copy. Account and publishing operations are handled by the service; these messages never ask customers to manage them.
235
-
236
- | Code | Message |
237
- |---|---|
238
- | `AUDIO_UNAVAILABLE` | The selected sound is unavailable. Choose another sound and retry. |
239
- | `BACKUP_AUDIO_RETRY_PENDING` | The selected sound was unavailable. Your post is waiting to be retried with its backup sound. |
240
- | `AUDIO_RETRY_PENDING` | The selected sound could not be loaded. Your post is waiting to be retried. |
241
- | `AUDIO_PREPARATION_FAILED` | The selected sound could not be prepared for this post. Choose another sound or contact support before retrying. |
242
- | `PUBLISHING_RETRY_PENDING` | Publishing was temporarily interrupted. Your post is waiting to be retried. No action is needed. |
243
- | `PUBLISHING_BLOCKED` | A publishing issue prevented this post from proceeding. Contact support for help with this post. |
244
- | `POST_PROCESSING_FAILED` | A processing error prevented this posting attempt from completing. Contact support before retrying. |
245
- | `PUBLICATION_CHECK_IN_PROGRESS` | We’re checking whether your post published. Please wait before submitting it again to avoid a duplicate. |
246
- | `PUBLICATION_UNCONFIRMED` | We couldn’t confirm whether your post published. Contact support before submitting it again to avoid a duplicate. |
247
- | `POST_RETRY_PENDING` | The previous posting attempt did not complete. Your post is waiting to be retried. No action is needed. |
248
- | `POST_FAILED` | The posting attempt failed, but we couldn’t determine the cause. Contact support before submitting it again. |
249
-
250
165
  ### Render a supplied Remotion composition
251
166
 
252
167
  `remotion-composition` accepts a TSX module whose default export is a React
@@ -280,3 +195,12 @@ status/logs to inspect failures and the returned video for preview.
280
195
 
281
196
  Server integrations can also call `submitRemotionCompositionRenderJob` and
282
197
  `getRenderJobStatus` with the configured render-worker origin.
198
+
199
+ ### Remotion composition PNG output
200
+
201
+ The `remotion-composition` workflow node accepts `outputType: "image"` to render
202
+ the first composition frame as a PNG. Its output port becomes `image`; video
203
+ remains the default for existing workflows. Pass sound assets separately for
204
+ photo posts because PNG files contain no audio. The public render helper
205
+ `submitRemotionCompositionRenderJob({...composition, outputType: "image"})`
206
+ supports the same option.
@@ -336,6 +336,7 @@ export declare const nodeDefinitions: {
336
336
  source: string;
337
337
  outputMode: "per-input" | "single";
338
338
  selectionMode: null;
339
+ outputType: "video" | "image";
339
340
  inputs: {
340
341
  type: "number" | "boolean" | "object" | "video" | "audio" | "image" | "text";
341
342
  id: string;
@@ -7,6 +7,7 @@ declare const defaults: {
7
7
  source: string;
8
8
  outputMode: "per-input" | "single";
9
9
  selectionMode: null;
10
+ outputType: "video" | "image";
10
11
  inputs: {
11
12
  type: "number" | "boolean" | "object" | "video" | "audio" | "image" | "text";
12
13
  id: string;
@@ -23,6 +24,7 @@ declare const _default: import("./types").NodeDefinition<"remotion-composition",
23
24
  source: string;
24
25
  outputMode: "per-input" | "single";
25
26
  selectionMode: null;
27
+ outputType: "video" | "image";
26
28
  inputs: {
27
29
  type: "number" | "boolean" | "object" | "video" | "audio" | "image" | "text";
28
30
  id: string;
@@ -14,12 +14,12 @@ export default function Video({title}: {title: string}) {
14
14
  });
15
15
  const definition = (0, types_1.defineNode)({
16
16
  nodeId: 'remotion-composition', label: 'Remotion Composition',
17
- description: 'Render a React/TSX composition with UGC components',
18
- guide: 'Supply a TSX module with a default-exported React component. UGC registers and bundles it. Import react, remotion or ugcinc/render (including its utils/types subpaths). Configure dimensions, fps, frame count and default inputProps. Add typed input ports whose IDs match component props; connected values override defaults. Media props retain their {url} shape. Source is browser code: no local files, npm installs, require or dynamic imports. Output is a rendered video; use Save to Media or Pass Through. Run preview uses the same renderer as the final output.',
17
+ description: 'Render a React/TSX composition as a video or PNG',
18
+ guide: 'Supply a TSX module with a default-exported React component. UGC registers and bundles it. Import react, remotion or ugcinc/render (including its utils/types subpaths). Configure dimensions, fps, frame count and default inputProps. Add typed input ports whose IDs match component props; connected values override defaults. Media props retain their {url} shape. Source is browser code: no local files, npm installs, require or dynamic imports. Set outputType to video (default) or image (first-frame PNG); use Save to Media or Pass Through. Image output does not embed audio. Run preview uses the same renderer as the final output.',
19
19
  type: 'generator', category: 'Generation', outputModes: ['per-input', 'single'], selectionModes: null,
20
20
  defaults,
21
21
  computePorts: ({ config }) => ({ inputs: config.inputs,
22
- outputs: [{ id: 'output', type: 'video', isArray: false, required: true }] }),
22
+ outputs: [{ id: 'output', type: config.outputType === 'image' ? 'image' : 'video', isArray: false, required: true }] }),
23
23
  generatePreview: (_config, _ctx, cached) => (0, types_1.preview)({ output: cached?.output ?? null }),
24
24
  validate: config => {
25
25
  const result = remotion_composition_1.remotionCompositionNodeSchema.safeParse(config);
@@ -47,6 +47,7 @@ export declare const remotionCompositionNodeSchema: z.ZodObject<{
47
47
  durationInFrames: z.ZodNumber;
48
48
  inputProps: z.ZodRecord<z.ZodString, z.ZodUnknown>;
49
49
  } & {
50
+ outputType: z.ZodDefault<z.ZodEnum<["video", "image"]>>;
50
51
  inputs: z.ZodEffects<z.ZodArray<z.ZodObject<{
51
52
  id: z.ZodEffects<z.ZodString, string, string>;
52
53
  type: z.ZodEnum<["text", "number", "boolean", "image", "video", "audio", "object"]>;
@@ -79,6 +80,7 @@ export declare const remotionCompositionNodeSchema: z.ZodObject<{
79
80
  source: string;
80
81
  outputMode: "per-input" | "single";
81
82
  selectionMode: null;
83
+ outputType: "video" | "image";
82
84
  inputs: {
83
85
  type: "number" | "boolean" | "object" | "video" | "audio" | "image" | "text";
84
86
  id: string;
@@ -105,6 +107,7 @@ export declare const remotionCompositionNodeSchema: z.ZodObject<{
105
107
  fps: number;
106
108
  durationInFrames: number;
107
109
  inputProps: Record<string, unknown>;
110
+ outputType?: "video" | "image" | undefined;
108
111
  }>;
109
112
  export declare const REMOTION_COMPOSITION_IMPORTS: string[];
110
113
  export declare function parseRemotionPropsJson({ text }: {
@@ -19,6 +19,7 @@ exports.remotionCompositionPortSchema = zod_1.z.object({
19
19
  required: zod_1.z.boolean(),
20
20
  }).strict();
21
21
  exports.remotionCompositionNodeSchema = exports.remotionCompositionSchema.extend({
22
+ outputType: zod_1.z.enum(['video', 'image']).default('video'),
22
23
  inputs: zod_1.z.array(exports.remotionCompositionPortSchema).max(64).refine(ports => new Set(ports.map(port => port.id)).size === ports.length, 'Prop names must be unique'),
23
24
  outputMode: zod_1.z.enum(['single', 'per-input']),
24
25
  selectionMode: zod_1.z.null(),
package/dist/render.d.ts CHANGED
@@ -14,7 +14,9 @@ import type { ImageEditorNodeConfig } from './automations/nodes/image-composer';
14
14
  import type { CreateDmMessage } from './automations/nodes/create-dm';
15
15
  import { type RemotionCompositionInput } from './render/types/remotion-composition';
16
16
  /** Submit TSX source and props; UGC owns registration and bundling. */
17
- export declare function submitRemotionCompositionRenderJob(params: RemotionCompositionInput): Promise<ApiResponse<RenderJobResponse>>;
17
+ export declare function submitRemotionCompositionRenderJob(params: RemotionCompositionInput & {
18
+ outputType?: 'video' | 'image';
19
+ }): Promise<ApiResponse<RenderJobResponse>>;
18
20
  export interface RenderJobResponse {
19
21
  job_id: string;
20
22
  status: string;
package/dist/render.js CHANGED
@@ -31,13 +31,16 @@ function renderBaseUrl() {
31
31
  const MAX_RETRIES = 3;
32
32
  /** Submit TSX source and props; UGC owns registration and bundling. */
33
33
  async function submitRemotionCompositionRenderJob(params) {
34
- const parsed = remotion_composition_1.remotionCompositionSchema.safeParse(params);
34
+ const { outputType = 'video', ...composition } = params;
35
+ if (outputType !== 'video' && outputType !== 'image')
36
+ return { ok: false, code: 400, message: 'Output type must be video or image' };
37
+ const parsed = remotion_composition_1.remotionCompositionSchema.safeParse(composition);
35
38
  if (!parsed.success)
36
39
  return { ok: false, code: 400, message: parsed.error.message };
37
40
  const response = await renderFetch('/submit-job', {
38
41
  method: 'POST', headers: { 'Content-Type': 'application/json' },
39
42
  body: JSON.stringify({ config: { _compositionType: 'remotion-composition', ...parsed.data },
40
- output_type: 'video', video_codec: 'h264' }),
43
+ output_type: outputType, video_codec: 'h264', image_format: 'png' }),
41
44
  });
42
45
  const data = await response.json();
43
46
  const result = zod_1.z.object({ job_id: zod_1.z.string(), status: zod_1.z.string(), output_type: zod_1.z.string(), message: zod_1.z.string() }).safeParse(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc",
3
- "version": "4.18.0",
3
+ "version": "4.19.1",
4
4
  "description": "TypeScript/JavaScript client for the UGC Inc API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",