ugcinc 4.1.49 → 4.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -9,10 +9,10 @@ export { TasksClient } from './tasks';
9
9
  export { PostsClient } from './posts';
10
10
  export { StatsClient } from './stats';
11
11
  export { OrganizationClient } from './org';
12
- export { RenderClient } from './render';
13
12
  export { AutomationsClient } from './automations';
14
13
  export { MediaClient } from './media';
15
14
  export { CommentsClient } from './comments';
15
+ export { submitImageRenderJob, submitVideoRenderJob, getRenderJobStatus, submitDeduplicationJob, submitScreenshotAnimationRenderJob, submitAutoCaptionRenderJob, submitInstagramDmRenderJob, submitIMessageDmRenderJob, } from './render';
16
16
  export { areTypesCompatible, computePortsForNode, computePortsWithPreviews, computeAllNodePorts, computeAllNodePortsWithPreviews, getInputPreviewValue, getAllNodes, getNodeByType, getOutputSchema, createNode, deriveConnections, addConnection, removeConnection, removeNodeConnections, cleanupStaleConnections, getConnectedSource, getForEachContext, checkCrossContextViolation, validateWorkflow, getErrorNodeIds, getPortErrorsForNode, hasMissingTriggerError, hasMissingTerminalError, getWorkflowOutputSchema, resolveNodePreview, computeAllNodePreviews, computePreviewMap, updatePreviewMapForConnection, removePreviewForConnection, getPreviewValue, shuffleNodePreview, type PreviewMap, type NodePreviewOutputs, type Connection, generateNodeName, extractWorkflowConfig, type WorkflowTemplateData, } from './automations/graph-controller';
17
17
  export { nodeDefinitions, internalNodeTypes, isAsyncExecutor, formatPortType, isPortType } from './automations/types';
18
18
  export { getNodeDefinition } from './automations/nodes';
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@
5
5
  * Official TypeScript/JavaScript client for the UGC Inc API
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.isEditModel = exports.getNodeDefinition = exports.isPortType = exports.formatPortType = exports.isAsyncExecutor = exports.internalNodeTypes = exports.nodeDefinitions = exports.extractWorkflowConfig = exports.generateNodeName = exports.shuffleNodePreview = exports.getPreviewValue = exports.removePreviewForConnection = exports.updatePreviewMapForConnection = exports.computePreviewMap = exports.computeAllNodePreviews = exports.resolveNodePreview = exports.getWorkflowOutputSchema = exports.hasMissingTerminalError = exports.hasMissingTriggerError = exports.getPortErrorsForNode = exports.getErrorNodeIds = exports.validateWorkflow = exports.checkCrossContextViolation = exports.getForEachContext = exports.getConnectedSource = exports.cleanupStaleConnections = exports.removeNodeConnections = exports.removeConnection = exports.addConnection = exports.deriveConnections = exports.createNode = exports.getOutputSchema = exports.getNodeByType = exports.getAllNodes = exports.getInputPreviewValue = exports.computeAllNodePortsWithPreviews = exports.computeAllNodePorts = exports.computePortsWithPreviews = exports.computePortsForNode = exports.areTypesCompatible = exports.CommentsClient = exports.MediaClient = exports.AutomationsClient = exports.RenderClient = exports.OrganizationClient = exports.StatsClient = exports.PostsClient = exports.TasksClient = exports.AccountsClient = exports.UGCClient = void 0;
9
- exports.prepareVideoComposerInput = exports.LLMProviders = exports.IfLogicOperators = exports.indexExpressionToIndexes = exports.nodeConfigToCaptionStyle = exports.prepareImageComposerInput = exports.processTemplate = exports.extractTemplateVariables = exports.PortIdSchema = exports.normalizeToPortId = exports.portIdToTitle = exports.isValidPortId = exports.portId = exports.selectFromPool = exports.getModelDurations = exports.getModelAspectRatios = exports.ALL_VIDEO_MODELS = exports.isImageToVideoModel = exports.IMAGE_ASPECT_RATIOS = exports.ALL_IMAGE_MODELS = void 0;
8
+ exports.extractWorkflowConfig = exports.generateNodeName = exports.shuffleNodePreview = exports.getPreviewValue = exports.removePreviewForConnection = exports.updatePreviewMapForConnection = exports.computePreviewMap = exports.computeAllNodePreviews = exports.resolveNodePreview = exports.getWorkflowOutputSchema = exports.hasMissingTerminalError = exports.hasMissingTriggerError = exports.getPortErrorsForNode = exports.getErrorNodeIds = exports.validateWorkflow = exports.checkCrossContextViolation = exports.getForEachContext = exports.getConnectedSource = exports.cleanupStaleConnections = exports.removeNodeConnections = exports.removeConnection = exports.addConnection = exports.deriveConnections = exports.createNode = exports.getOutputSchema = exports.getNodeByType = exports.getAllNodes = exports.getInputPreviewValue = exports.computeAllNodePortsWithPreviews = exports.computeAllNodePorts = exports.computePortsWithPreviews = exports.computePortsForNode = exports.areTypesCompatible = exports.submitIMessageDmRenderJob = exports.submitInstagramDmRenderJob = exports.submitAutoCaptionRenderJob = exports.submitScreenshotAnimationRenderJob = exports.submitDeduplicationJob = exports.getRenderJobStatus = exports.submitVideoRenderJob = exports.submitImageRenderJob = exports.CommentsClient = exports.MediaClient = exports.AutomationsClient = exports.OrganizationClient = exports.StatsClient = exports.PostsClient = exports.TasksClient = exports.AccountsClient = exports.UGCClient = void 0;
9
+ exports.prepareVideoComposerInput = exports.LLMProviders = exports.IfLogicOperators = exports.indexExpressionToIndexes = exports.nodeConfigToCaptionStyle = exports.prepareImageComposerInput = exports.processTemplate = exports.extractTemplateVariables = exports.PortIdSchema = exports.normalizeToPortId = exports.portIdToTitle = exports.isValidPortId = exports.portId = exports.selectFromPool = exports.getModelDurations = exports.getModelAspectRatios = exports.ALL_VIDEO_MODELS = exports.isImageToVideoModel = exports.IMAGE_ASPECT_RATIOS = exports.ALL_IMAGE_MODELS = exports.isEditModel = exports.getNodeDefinition = exports.isPortType = exports.formatPortType = exports.isAsyncExecutor = exports.internalNodeTypes = exports.nodeDefinitions = void 0;
10
10
  // =============================================================================
11
11
  // Client Exports
12
12
  // =============================================================================
@@ -22,14 +22,22 @@ var stats_1 = require("./stats");
22
22
  Object.defineProperty(exports, "StatsClient", { enumerable: true, get: function () { return stats_1.StatsClient; } });
23
23
  var org_1 = require("./org");
24
24
  Object.defineProperty(exports, "OrganizationClient", { enumerable: true, get: function () { return org_1.OrganizationClient; } });
25
- var render_1 = require("./render");
26
- Object.defineProperty(exports, "RenderClient", { enumerable: true, get: function () { return render_1.RenderClient; } });
27
25
  var automations_1 = require("./automations");
28
26
  Object.defineProperty(exports, "AutomationsClient", { enumerable: true, get: function () { return automations_1.AutomationsClient; } });
29
27
  var media_1 = require("./media");
30
28
  Object.defineProperty(exports, "MediaClient", { enumerable: true, get: function () { return media_1.MediaClient; } });
31
29
  var comments_1 = require("./comments");
32
30
  Object.defineProperty(exports, "CommentsClient", { enumerable: true, get: function () { return comments_1.CommentsClient; } });
31
+ // Render functions
32
+ var render_1 = require("./render");
33
+ Object.defineProperty(exports, "submitImageRenderJob", { enumerable: true, get: function () { return render_1.submitImageRenderJob; } });
34
+ Object.defineProperty(exports, "submitVideoRenderJob", { enumerable: true, get: function () { return render_1.submitVideoRenderJob; } });
35
+ Object.defineProperty(exports, "getRenderJobStatus", { enumerable: true, get: function () { return render_1.getRenderJobStatus; } });
36
+ Object.defineProperty(exports, "submitDeduplicationJob", { enumerable: true, get: function () { return render_1.submitDeduplicationJob; } });
37
+ Object.defineProperty(exports, "submitScreenshotAnimationRenderJob", { enumerable: true, get: function () { return render_1.submitScreenshotAnimationRenderJob; } });
38
+ Object.defineProperty(exports, "submitAutoCaptionRenderJob", { enumerable: true, get: function () { return render_1.submitAutoCaptionRenderJob; } });
39
+ Object.defineProperty(exports, "submitInstagramDmRenderJob", { enumerable: true, get: function () { return render_1.submitInstagramDmRenderJob; } });
40
+ Object.defineProperty(exports, "submitIMessageDmRenderJob", { enumerable: true, get: function () { return render_1.submitIMessageDmRenderJob; } });
33
41
  // =============================================================================
34
42
  // Graph Controller Exports
35
43
  // =============================================================================
package/dist/render.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Render functions for submitting jobs to the Modal renderer.
3
+ * These functions call Modal endpoints directly, not the UGC Inc API.
4
+ */
1
5
  import type { ApiResponse } from './types';
2
6
  import type { VideoEditorNodeConfig, DeduplicationInput } from './render/types';
3
7
  import type { CaptionWord, CaptionStyle } from './render/types/caption';
@@ -130,47 +134,41 @@ export interface SubmitIMessageDmRenderJobParams {
130
134
  messageHeaderTimestampText?: string;
131
135
  }
132
136
  /**
133
- * Client for rendering operations
134
- * Note: This calls Modal endpoints directly, not the UGC Inc API
137
+ * Submit an image render job to the Modal renderer.
138
+ * Uses the element-based format for single-source-of-truth rendering.
135
139
  */
136
- export declare class RenderClient {
137
- /**
138
- * Submit an image render job to the Modal renderer
139
- * Uses the new element-based format for single-source-of-truth rendering
140
- */
141
- submitImageRenderJob(params: SubmitImageRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
142
- /**
143
- * Submit a render job to the Modal renderer
144
- */
145
- submitVideoRenderJob(params: SubmitVideoRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
146
- /**
147
- * Get render job status from the Modal renderer
148
- */
149
- getRenderJobStatus(jobId: string): Promise<ApiResponse<RenderJobStatus>>;
150
- /**
151
- * Submit a deduplication job to the Modal renderer
152
- * Applies hash-breaking, metadata injection, and trace removal to a video
153
- */
154
- submitDeduplicationJob(params: SubmitDeduplicationJobParams): Promise<ApiResponse<RenderJobResponse>>;
155
- /**
156
- * Submit a screenshot animation render job to the Modal renderer
157
- * Renders an iPhone screenshot animation video from a source image
158
- */
159
- submitScreenshotAnimationRenderJob(params: SubmitScreenshotAnimationRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
160
- /**
161
- * Submit an auto-caption render job to the Modal renderer
162
- * Renders a video with captions overlaid
163
- */
164
- submitAutoCaptionRenderJob(params: SubmitAutoCaptionRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
165
- /**
166
- * Submit an Instagram DM render job to the Modal renderer
167
- * Renders a fake Instagram DM conversation image
168
- */
169
- submitInstagramDmRenderJob(params: SubmitInstagramDmRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
170
- /**
171
- * Submit an iMessage DM render job to the Modal renderer
172
- * Renders a fake iMessage conversation image
173
- */
174
- submitIMessageDmRenderJob(params: SubmitIMessageDmRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
175
- }
140
+ export declare function submitImageRenderJob(params: SubmitImageRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
141
+ /**
142
+ * Submit a video render job to the Modal renderer.
143
+ */
144
+ export declare function submitVideoRenderJob(params: SubmitVideoRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
145
+ /**
146
+ * Get render job status from the Modal renderer.
147
+ */
148
+ export declare function getRenderJobStatus(jobId: string): Promise<ApiResponse<RenderJobStatus>>;
149
+ /**
150
+ * Submit a deduplication job to the Modal renderer.
151
+ * Applies hash-breaking, metadata injection, and trace removal to a video.
152
+ */
153
+ export declare function submitDeduplicationJob(params: SubmitDeduplicationJobParams): Promise<ApiResponse<RenderJobResponse>>;
154
+ /**
155
+ * Submit a screenshot animation render job to the Modal renderer.
156
+ * Renders an iPhone screenshot animation video from a source image.
157
+ */
158
+ export declare function submitScreenshotAnimationRenderJob(params: SubmitScreenshotAnimationRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
159
+ /**
160
+ * Submit an auto-caption render job to the Modal renderer.
161
+ * Renders a video with captions overlaid.
162
+ */
163
+ export declare function submitAutoCaptionRenderJob(params: SubmitAutoCaptionRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
164
+ /**
165
+ * Submit an Instagram DM render job to the Modal renderer.
166
+ * Renders a fake Instagram DM conversation image.
167
+ */
168
+ export declare function submitInstagramDmRenderJob(params: SubmitInstagramDmRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
169
+ /**
170
+ * Submit an iMessage DM render job to the Modal renderer.
171
+ * Renders a fake iMessage conversation image.
172
+ */
173
+ export declare function submitIMessageDmRenderJob(params: SubmitIMessageDmRenderJobParams): Promise<ApiResponse<RenderJobResponse>>;
176
174
  export {};
package/dist/render.js CHANGED
@@ -1,6 +1,17 @@
1
1
  "use strict";
2
+ /**
3
+ * Render functions for submitting jobs to the Modal renderer.
4
+ * These functions call Modal endpoints directly, not the UGC Inc API.
5
+ */
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RenderClient = void 0;
7
+ exports.submitImageRenderJob = submitImageRenderJob;
8
+ exports.submitVideoRenderJob = submitVideoRenderJob;
9
+ exports.getRenderJobStatus = getRenderJobStatus;
10
+ exports.submitDeduplicationJob = submitDeduplicationJob;
11
+ exports.submitScreenshotAnimationRenderJob = submitScreenshotAnimationRenderJob;
12
+ exports.submitAutoCaptionRenderJob = submitAutoCaptionRenderJob;
13
+ exports.submitInstagramDmRenderJob = submitInstagramDmRenderJob;
14
+ exports.submitIMessageDmRenderJob = submitIMessageDmRenderJob;
4
15
  // Modal renderer endpoints
5
16
  const RENDER_SUBMIT_URL = "https://aidangollan--ugcinc-render-renderer-submit-job.modal.run";
6
17
  const RENDER_STATUS_URL = "https://aidangollan--ugcinc-render-renderer-get-status.modal.run";
@@ -52,507 +63,325 @@ function transformToIMessageMessages(messages, imageAttachmentUrl) {
52
63
  }));
53
64
  }
54
65
  // =============================================================================
55
- // Render Client
66
+ // Render Functions
56
67
  // =============================================================================
57
68
  /**
58
- * Client for rendering operations
59
- * Note: This calls Modal endpoints directly, not the UGC Inc API
69
+ * Submit an image render job to the Modal renderer.
70
+ * Uses the element-based format for single-source-of-truth rendering.
60
71
  */
61
- class RenderClient {
62
- /**
63
- * Submit an image render job to the Modal renderer
64
- * Uses the new element-based format for single-source-of-truth rendering
65
- */
66
- async submitImageRenderJob(params) {
67
- try {
68
- const response = await fetch(RENDER_SUBMIT_URL, {
69
- method: 'POST',
70
- headers: {
71
- 'Content-Type': 'application/json',
72
+ async function submitImageRenderJob(params) {
73
+ try {
74
+ const response = await fetch(RENDER_SUBMIT_URL, {
75
+ method: 'POST',
76
+ headers: { 'Content-Type': 'application/json' },
77
+ body: JSON.stringify({
78
+ config: {
79
+ width: params.config.width,
80
+ height: params.config.height,
81
+ elements: params.config.elements,
82
+ backgroundType: params.config.backgroundType ?? 'image',
83
+ backgroundColor: params.config.backgroundColor,
84
+ backgroundFit: params.config.backgroundFit ?? 'cover',
85
+ dynamicCrop: params.config.dynamicCrop,
86
+ imageUrls: params.imageUrls,
87
+ textValues: params.textValues,
72
88
  },
73
- body: JSON.stringify({
74
- config: {
75
- // New element-based format
76
- width: params.config.width,
77
- height: params.config.height,
78
- elements: params.config.elements,
79
- backgroundType: params.config.backgroundType ?? 'image',
80
- backgroundColor: params.config.backgroundColor,
81
- backgroundFit: params.config.backgroundFit ?? 'cover',
82
- dynamicCrop: params.config.dynamicCrop,
83
- // Inject imageUrls and textValues as sources for the renderer
84
- imageUrls: params.imageUrls,
85
- textValues: params.textValues,
86
- },
87
- output_type: params.output_type ?? 'image',
88
- image_format: params.image_format ?? 'png',
89
- // CapCut metadata injection options
90
- inject_capcut_metadata: params.injectCapcutMetadata ?? false,
91
- capcut_os: params.capcutOs ?? 'ios',
92
- capcut_region: params.capcutRegion ?? 'US',
93
- })
94
- });
95
- const text = await response.text();
96
- let data;
97
- try {
98
- data = JSON.parse(text);
99
- }
100
- catch (jsonError) {
101
- console.error('[Render] JSON parse error:', text.substring(0, 200));
102
- return {
103
- ok: false,
104
- code: response.status || 500,
105
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
106
- };
107
- }
108
- if (data.status === 'error' || !response.ok) {
109
- return {
110
- ok: false,
111
- code: response.status,
112
- message: data.error ?? data.message ?? 'Failed to submit render job',
113
- };
114
- }
115
- return {
116
- ok: true,
117
- code: 200,
118
- message: "Render job submitted",
119
- data,
120
- };
89
+ output_type: params.output_type ?? 'image',
90
+ image_format: params.image_format ?? 'png',
91
+ inject_capcut_metadata: params.injectCapcutMetadata ?? false,
92
+ capcut_os: params.capcutOs ?? 'ios',
93
+ capcut_region: params.capcutRegion ?? 'US',
94
+ })
95
+ });
96
+ const text = await response.text();
97
+ let data;
98
+ try {
99
+ data = JSON.parse(text);
100
+ }
101
+ catch {
102
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
121
103
  }
122
- catch (error) {
123
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
124
- console.error('[Render] Submit error:', error);
125
- return {
126
- ok: false,
127
- code: 500,
128
- message: `Failed to submit render job: ${errorMessage}`,
129
- };
104
+ if (data.status === 'error' || !response.ok) {
105
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit render job' };
130
106
  }
107
+ return { ok: true, code: 200, message: "Render job submitted", data };
131
108
  }
132
- /**
133
- * Submit a render job to the Modal renderer
134
- */
135
- async submitVideoRenderJob(params) {
109
+ catch (error) {
110
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
111
+ return { ok: false, code: 500, message: `Failed to submit render job: ${errorMessage}` };
112
+ }
113
+ }
114
+ /**
115
+ * Submit a video render job to the Modal renderer.
116
+ */
117
+ async function submitVideoRenderJob(params) {
118
+ try {
119
+ const response = await fetch(RENDER_SUBMIT_URL, {
120
+ method: 'POST',
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify({
123
+ config: params.config,
124
+ sources: params.sources,
125
+ output_type: params.output_type,
126
+ image_format: params.image_format,
127
+ video_codec: params.video_codec,
128
+ inject_capcut_metadata: params.injectCapcutMetadata ?? false,
129
+ capcut_os: params.capcutOs ?? 'ios',
130
+ capcut_region: params.capcutRegion ?? 'US',
131
+ reencode_h265: params.reencodeH265 ?? false,
132
+ })
133
+ });
134
+ const text = await response.text();
135
+ let data;
136
136
  try {
137
- const response = await fetch(RENDER_SUBMIT_URL, {
138
- method: 'POST',
139
- headers: {
140
- 'Content-Type': 'application/json',
141
- },
142
- body: JSON.stringify({
143
- config: params.config,
144
- sources: params.sources,
145
- output_type: params.output_type,
146
- image_format: params.image_format,
147
- video_codec: params.video_codec,
148
- // CapCut metadata injection options
149
- inject_capcut_metadata: params.injectCapcutMetadata ?? false,
150
- capcut_os: params.capcutOs ?? 'ios',
151
- capcut_region: params.capcutRegion ?? 'US',
152
- reencode_h265: params.reencodeH265 ?? false,
153
- })
154
- });
155
- const text = await response.text();
156
- let data;
157
- try {
158
- data = JSON.parse(text);
159
- }
160
- catch (jsonError) {
161
- console.error('[Render] JSON parse error:', text.substring(0, 200));
162
- return {
163
- ok: false,
164
- code: response.status || 500,
165
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
166
- };
167
- }
168
- if (data.status === 'error' || !response.ok) {
169
- return {
170
- ok: false,
171
- code: response.status,
172
- message: data.error ?? data.message ?? 'Failed to submit render job',
173
- };
174
- }
175
- return {
176
- ok: true,
177
- code: 200,
178
- message: "Render job submitted",
179
- data,
180
- };
137
+ data = JSON.parse(text);
138
+ }
139
+ catch {
140
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
181
141
  }
182
- catch (error) {
183
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
184
- console.error('[Render] Submit error:', error);
185
- return {
186
- ok: false,
187
- code: 500,
188
- message: `Failed to submit render job: ${errorMessage}`,
189
- };
142
+ if (data.status === 'error' || !response.ok) {
143
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit render job' };
190
144
  }
145
+ return { ok: true, code: 200, message: "Render job submitted", data };
191
146
  }
192
- /**
193
- * Get render job status from the Modal renderer
194
- */
195
- async getRenderJobStatus(jobId) {
147
+ catch (error) {
148
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
149
+ return { ok: false, code: 500, message: `Failed to submit render job: ${errorMessage}` };
150
+ }
151
+ }
152
+ /**
153
+ * Get render job status from the Modal renderer.
154
+ */
155
+ async function getRenderJobStatus(jobId) {
156
+ try {
157
+ const response = await fetch(RENDER_STATUS_URL, {
158
+ method: 'POST',
159
+ headers: { 'Content-Type': 'application/json' },
160
+ body: JSON.stringify({ job_id: jobId }),
161
+ });
162
+ const text = await response.text();
163
+ let data;
196
164
  try {
197
- const response = await fetch(RENDER_STATUS_URL, {
198
- method: 'POST',
199
- headers: {
200
- 'Content-Type': 'application/json',
201
- },
202
- body: JSON.stringify({ job_id: jobId }),
203
- });
204
- const text = await response.text();
205
- let data;
206
- try {
207
- data = JSON.parse(text);
208
- }
209
- catch (jsonError) {
210
- console.error('[Render] JSON parse error:', text.substring(0, 200));
211
- return {
212
- ok: false,
213
- code: response.status || 500,
214
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
215
- };
216
- }
217
- if (data.status === 'error' || !response.ok) {
218
- return {
219
- ok: false,
220
- code: response.status,
221
- message: data.error ?? data.message ?? 'Failed to get job status',
222
- };
223
- }
224
- // Modal returns Vercel Blob URL as download_url (fast CDN access)
225
- // Fallback to download endpoint if not provided
226
- if (data.status === 'completed' && !data.download_url) {
227
- data.download_url = `https://aidangollan--ugcinc-render-renderer-download.modal.run?job_id=${jobId}`;
228
- }
229
- return {
230
- ok: true,
231
- code: 200,
232
- message: "Job status retrieved",
233
- data,
234
- };
165
+ data = JSON.parse(text);
166
+ }
167
+ catch {
168
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
169
+ }
170
+ if (data.status === 'error' || !response.ok) {
171
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to get job status' };
235
172
  }
236
- catch (error) {
237
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
238
- console.error('[Render] Status error:', error);
239
- return {
240
- ok: false,
241
- code: 500,
242
- message: `Failed to get job status: ${errorMessage}`,
243
- };
173
+ // Fallback to download endpoint if Modal didn't provide a URL
174
+ if (data.status === 'completed' && !data.download_url) {
175
+ data.download_url = `https://aidangollan--ugcinc-render-renderer-download.modal.run?job_id=${jobId}`;
244
176
  }
177
+ return { ok: true, code: 200, message: "Job status retrieved", data };
245
178
  }
246
- /**
247
- * Submit a deduplication job to the Modal renderer
248
- * Applies hash-breaking, metadata injection, and trace removal to a video
249
- */
250
- async submitDeduplicationJob(params) {
179
+ catch (error) {
180
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
181
+ return { ok: false, code: 500, message: `Failed to get job status: ${errorMessage}` };
182
+ }
183
+ }
184
+ /**
185
+ * Submit a deduplication job to the Modal renderer.
186
+ * Applies hash-breaking, metadata injection, and trace removal to a video.
187
+ */
188
+ async function submitDeduplicationJob(params) {
189
+ try {
190
+ const response = await fetch(RENDER_SUBMIT_URL, {
191
+ method: 'POST',
192
+ headers: { 'Content-Type': 'application/json' },
193
+ body: JSON.stringify({
194
+ video_url: params.video_url,
195
+ deduplication: params.deduplication,
196
+ output_type: 'video',
197
+ })
198
+ });
199
+ const text = await response.text();
200
+ let data;
251
201
  try {
252
- const response = await fetch(RENDER_SUBMIT_URL, {
253
- method: 'POST',
254
- headers: {
255
- 'Content-Type': 'application/json',
256
- },
257
- body: JSON.stringify({
258
- video_url: params.video_url,
259
- deduplication: params.deduplication,
260
- output_type: 'video',
261
- })
262
- });
263
- const text = await response.text();
264
- let data;
265
- try {
266
- data = JSON.parse(text);
267
- }
268
- catch (jsonError) {
269
- console.error('[Render] JSON parse error:', text.substring(0, 200));
270
- return {
271
- ok: false,
272
- code: response.status || 500,
273
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
274
- };
275
- }
276
- if (data.status === 'error' || !response.ok) {
277
- return {
278
- ok: false,
279
- code: response.status,
280
- message: data.error ?? data.message ?? 'Failed to submit deduplication job',
281
- };
282
- }
283
- return {
284
- ok: true,
285
- code: 200,
286
- message: "Deduplication job submitted",
287
- data,
288
- };
202
+ data = JSON.parse(text);
203
+ }
204
+ catch {
205
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
289
206
  }
290
- catch (error) {
291
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
292
- console.error('[Render] Submit deduplication error:', error);
293
- return {
294
- ok: false,
295
- code: 500,
296
- message: `Failed to submit deduplication job: ${errorMessage}`,
297
- };
207
+ if (data.status === 'error' || !response.ok) {
208
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit deduplication job' };
298
209
  }
210
+ return { ok: true, code: 200, message: "Deduplication job submitted", data };
299
211
  }
300
- /**
301
- * Submit a screenshot animation render job to the Modal renderer
302
- * Renders an iPhone screenshot animation video from a source image
303
- */
304
- async submitScreenshotAnimationRenderJob(params) {
305
- try {
306
- const response = await fetch(RENDER_SUBMIT_URL, {
307
- method: 'POST',
308
- headers: {
309
- 'Content-Type': 'application/json',
212
+ catch (error) {
213
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
214
+ return { ok: false, code: 500, message: `Failed to submit deduplication job: ${errorMessage}` };
215
+ }
216
+ }
217
+ /**
218
+ * Submit a screenshot animation render job to the Modal renderer.
219
+ * Renders an iPhone screenshot animation video from a source image.
220
+ */
221
+ async function submitScreenshotAnimationRenderJob(params) {
222
+ try {
223
+ const response = await fetch(RENDER_SUBMIT_URL, {
224
+ method: 'POST',
225
+ headers: { 'Content-Type': 'application/json' },
226
+ body: JSON.stringify({
227
+ config: {
228
+ _compositionType: 'screenshot-animation',
229
+ imageUrl: params.imageUrl,
230
+ holdDurationMs: params.holdDurationMs,
310
231
  },
311
- body: JSON.stringify({
312
- config: {
313
- _compositionType: 'screenshot-animation',
314
- imageUrl: params.imageUrl,
315
- holdDurationMs: params.holdDurationMs,
316
- },
317
- output_type: 'video',
318
- video_codec: 'h264',
319
- })
320
- });
321
- const text = await response.text();
322
- let data;
323
- try {
324
- data = JSON.parse(text);
325
- }
326
- catch (jsonError) {
327
- console.error('[Render] JSON parse error:', text.substring(0, 200));
328
- return {
329
- ok: false,
330
- code: response.status || 500,
331
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
332
- };
333
- }
334
- if (data.status === 'error' || !response.ok) {
335
- return {
336
- ok: false,
337
- code: response.status,
338
- message: data.error ?? data.message ?? 'Failed to submit screenshot animation job',
339
- };
340
- }
341
- return {
342
- ok: true,
343
- code: 200,
344
- message: "Screenshot animation job submitted",
345
- data,
346
- };
232
+ output_type: 'video',
233
+ video_codec: 'h264',
234
+ })
235
+ });
236
+ const text = await response.text();
237
+ let data;
238
+ try {
239
+ data = JSON.parse(text);
347
240
  }
348
- catch (error) {
349
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
350
- console.error('[Render] Submit screenshot animation error:', error);
351
- return {
352
- ok: false,
353
- code: 500,
354
- message: `Failed to submit screenshot animation job: ${errorMessage}`,
355
- };
241
+ catch {
242
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
356
243
  }
244
+ if (data.status === 'error' || !response.ok) {
245
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit screenshot animation job' };
246
+ }
247
+ return { ok: true, code: 200, message: "Screenshot animation job submitted", data };
357
248
  }
358
- /**
359
- * Submit an auto-caption render job to the Modal renderer
360
- * Renders a video with captions overlaid
361
- */
362
- async submitAutoCaptionRenderJob(params) {
363
- try {
364
- const response = await fetch(RENDER_SUBMIT_URL, {
365
- method: 'POST',
366
- headers: {
367
- 'Content-Type': 'application/json',
249
+ catch (error) {
250
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
251
+ return { ok: false, code: 500, message: `Failed to submit screenshot animation job: ${errorMessage}` };
252
+ }
253
+ }
254
+ /**
255
+ * Submit an auto-caption render job to the Modal renderer.
256
+ * Renders a video with captions overlaid.
257
+ */
258
+ async function submitAutoCaptionRenderJob(params) {
259
+ try {
260
+ const response = await fetch(RENDER_SUBMIT_URL, {
261
+ method: 'POST',
262
+ headers: { 'Content-Type': 'application/json' },
263
+ body: JSON.stringify({
264
+ config: {
265
+ _compositionType: 'auto-caption',
266
+ videoUrl: params.videoUrl,
267
+ width: params.width,
268
+ height: params.height,
269
+ durationMs: params.durationMs,
270
+ fps: params.fps,
271
+ captions: params.captions,
272
+ style: params.style,
368
273
  },
369
- body: JSON.stringify({
370
- config: {
371
- _compositionType: 'auto-caption',
372
- videoUrl: params.videoUrl,
373
- width: params.width,
374
- height: params.height,
375
- durationMs: params.durationMs,
376
- fps: params.fps,
377
- captions: params.captions,
378
- style: params.style,
379
- },
380
- output_type: 'video',
381
- video_codec: 'h264',
382
- })
383
- });
384
- const text = await response.text();
385
- let data;
386
- try {
387
- data = JSON.parse(text);
388
- }
389
- catch (jsonError) {
390
- console.error('[Render] JSON parse error:', text.substring(0, 200));
391
- return {
392
- ok: false,
393
- code: response.status || 500,
394
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
395
- };
396
- }
397
- if (data.status === 'error' || !response.ok) {
398
- return {
399
- ok: false,
400
- code: response.status,
401
- message: data.error ?? data.message ?? 'Failed to submit auto-caption job',
402
- };
403
- }
404
- return {
405
- ok: true,
406
- code: 200,
407
- message: "Auto-caption job submitted",
408
- data,
409
- };
274
+ output_type: 'video',
275
+ video_codec: 'h264',
276
+ })
277
+ });
278
+ const text = await response.text();
279
+ let data;
280
+ try {
281
+ data = JSON.parse(text);
410
282
  }
411
- catch (error) {
412
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
413
- console.error('[Render] Submit auto-caption error:', error);
414
- return {
415
- ok: false,
416
- code: 500,
417
- message: `Failed to submit auto-caption job: ${errorMessage}`,
418
- };
283
+ catch {
284
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
419
285
  }
286
+ if (data.status === 'error' || !response.ok) {
287
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit auto-caption job' };
288
+ }
289
+ return { ok: true, code: 200, message: "Auto-caption job submitted", data };
420
290
  }
421
- /**
422
- * Submit an Instagram DM render job to the Modal renderer
423
- * Renders a fake Instagram DM conversation image
424
- */
425
- async submitInstagramDmRenderJob(params) {
426
- try {
427
- // Transform CreateDmMessage[] to internal format
428
- const transformedMessages = transformToInstagramMessages(params.messages, params.imageAttachmentUrl);
429
- const hasStoryReply = params.messages.some(msg => msg.hasImage);
430
- const response = await fetch(RENDER_SUBMIT_URL, {
431
- method: 'POST',
432
- headers: {
433
- 'Content-Type': 'application/json',
434
- },
435
- body: JSON.stringify({
436
- config: {
437
- _compositionType: 'instagram-dm',
438
- input: {
439
- receiverUsername: params.receiverUsername,
440
- receiverProfilePicUrl: params.receiverProfilePicUrl,
441
- theme: params.theme,
442
- messages: transformedMessages,
443
- storyImageUrl: hasStoryReply ? params.imageAttachmentUrl : undefined,
444
- },
291
+ catch (error) {
292
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
293
+ return { ok: false, code: 500, message: `Failed to submit auto-caption job: ${errorMessage}` };
294
+ }
295
+ }
296
+ /**
297
+ * Submit an Instagram DM render job to the Modal renderer.
298
+ * Renders a fake Instagram DM conversation image.
299
+ */
300
+ async function submitInstagramDmRenderJob(params) {
301
+ try {
302
+ const transformedMessages = transformToInstagramMessages(params.messages, params.imageAttachmentUrl);
303
+ const hasStoryReply = params.messages.some(msg => msg.hasImage);
304
+ const response = await fetch(RENDER_SUBMIT_URL, {
305
+ method: 'POST',
306
+ headers: { 'Content-Type': 'application/json' },
307
+ body: JSON.stringify({
308
+ config: {
309
+ _compositionType: 'instagram-dm',
310
+ input: {
311
+ receiverUsername: params.receiverUsername,
312
+ receiverProfilePicUrl: params.receiverProfilePicUrl,
313
+ theme: params.theme,
314
+ messages: transformedMessages,
315
+ storyImageUrl: hasStoryReply ? params.imageAttachmentUrl : undefined,
445
316
  },
446
- output_type: 'image',
447
- image_format: 'png',
448
- })
449
- });
450
- const text = await response.text();
451
- let data;
452
- try {
453
- data = JSON.parse(text);
454
- }
455
- catch (jsonError) {
456
- console.error('[Render] JSON parse error:', text.substring(0, 200));
457
- return {
458
- ok: false,
459
- code: response.status || 500,
460
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
461
- };
462
- }
463
- if (data.status === 'error' || !response.ok) {
464
- return {
465
- ok: false,
466
- code: response.status,
467
- message: data.error ?? data.message ?? 'Failed to submit Instagram DM job',
468
- };
469
- }
470
- return {
471
- ok: true,
472
- code: 200,
473
- message: "Instagram DM job submitted",
474
- data,
475
- };
317
+ },
318
+ output_type: 'image',
319
+ image_format: 'png',
320
+ })
321
+ });
322
+ const text = await response.text();
323
+ let data;
324
+ try {
325
+ data = JSON.parse(text);
476
326
  }
477
- catch (error) {
478
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
479
- console.error('[Render] Submit Instagram DM error:', error);
480
- return {
481
- ok: false,
482
- code: 500,
483
- message: `Failed to submit Instagram DM job: ${errorMessage}`,
484
- };
327
+ catch {
328
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
485
329
  }
330
+ if (data.status === 'error' || !response.ok) {
331
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit Instagram DM job' };
332
+ }
333
+ return { ok: true, code: 200, message: "Instagram DM job submitted", data };
486
334
  }
487
- /**
488
- * Submit an iMessage DM render job to the Modal renderer
489
- * Renders a fake iMessage conversation image
490
- */
491
- async submitIMessageDmRenderJob(params) {
492
- try {
493
- // Transform CreateDmMessage[] to internal format
494
- const transformedMessages = transformToIMessageMessages(params.messages, params.imageAttachmentUrl);
495
- const response = await fetch(RENDER_SUBMIT_URL, {
496
- method: 'POST',
497
- headers: {
498
- 'Content-Type': 'application/json',
499
- },
500
- body: JSON.stringify({
501
- config: {
502
- _compositionType: 'imessage-dm',
503
- input: {
504
- username: params.username,
505
- profilePicUrl: params.profilePicUrl,
506
- theme: params.theme,
507
- time: params.time,
508
- messages: transformedMessages,
509
- senderBubbleColor: params.senderBubbleColor,
510
- showReadReceipt: params.showReadReceipt,
511
- readReceiptText: params.readReceiptText,
512
- unreadBadgeText: params.unreadBadgeText,
513
- messageHeaderTimestampText: params.messageHeaderTimestampText,
514
- },
335
+ catch (error) {
336
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
337
+ return { ok: false, code: 500, message: `Failed to submit Instagram DM job: ${errorMessage}` };
338
+ }
339
+ }
340
+ /**
341
+ * Submit an iMessage DM render job to the Modal renderer.
342
+ * Renders a fake iMessage conversation image.
343
+ */
344
+ async function submitIMessageDmRenderJob(params) {
345
+ try {
346
+ const transformedMessages = transformToIMessageMessages(params.messages, params.imageAttachmentUrl);
347
+ const response = await fetch(RENDER_SUBMIT_URL, {
348
+ method: 'POST',
349
+ headers: { 'Content-Type': 'application/json' },
350
+ body: JSON.stringify({
351
+ config: {
352
+ _compositionType: 'imessage-dm',
353
+ input: {
354
+ username: params.username,
355
+ profilePicUrl: params.profilePicUrl,
356
+ theme: params.theme,
357
+ time: params.time,
358
+ messages: transformedMessages,
359
+ senderBubbleColor: params.senderBubbleColor,
360
+ showReadReceipt: params.showReadReceipt,
361
+ readReceiptText: params.readReceiptText,
362
+ unreadBadgeText: params.unreadBadgeText,
363
+ messageHeaderTimestampText: params.messageHeaderTimestampText,
515
364
  },
516
- output_type: 'image',
517
- image_format: 'png',
518
- })
519
- });
520
- const text = await response.text();
521
- let data;
522
- try {
523
- data = JSON.parse(text);
524
- }
525
- catch (jsonError) {
526
- console.error('[Render] JSON parse error:', text.substring(0, 200));
527
- return {
528
- ok: false,
529
- code: response.status || 500,
530
- message: `Modal endpoint error: ${text.substring(0, 100)}`,
531
- };
532
- }
533
- if (data.status === 'error' || !response.ok) {
534
- return {
535
- ok: false,
536
- code: response.status,
537
- message: data.error ?? data.message ?? 'Failed to submit iMessage DM job',
538
- };
539
- }
540
- return {
541
- ok: true,
542
- code: 200,
543
- message: "iMessage DM job submitted",
544
- data,
545
- };
365
+ },
366
+ output_type: 'image',
367
+ image_format: 'png',
368
+ })
369
+ });
370
+ const text = await response.text();
371
+ let data;
372
+ try {
373
+ data = JSON.parse(text);
374
+ }
375
+ catch {
376
+ return { ok: false, code: response.status || 500, message: `Modal endpoint error: ${text.substring(0, 100)}` };
546
377
  }
547
- catch (error) {
548
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
549
- console.error('[Render] Submit iMessage DM error:', error);
550
- return {
551
- ok: false,
552
- code: 500,
553
- message: `Failed to submit iMessage DM job: ${errorMessage}`,
554
- };
378
+ if (data.status === 'error' || !response.ok) {
379
+ return { ok: false, code: response.status, message: data.error ?? data.message ?? 'Failed to submit iMessage DM job' };
555
380
  }
381
+ return { ok: true, code: 200, message: "iMessage DM job submitted", data };
382
+ }
383
+ catch (error) {
384
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
385
+ return { ok: false, code: 500, message: `Failed to submit iMessage DM job: ${errorMessage}` };
556
386
  }
557
387
  }
558
- exports.RenderClient = RenderClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc",
3
- "version": "4.1.49",
3
+ "version": "4.1.51",
4
4
  "description": "TypeScript/JavaScript client for the UGC Inc API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",