ugcinc 4.1.54 → 4.1.56

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.
@@ -7,17 +7,58 @@ export interface CustomModelNodeOutputs {
7
7
  output: ImageValue | VideoValue | AudioValue;
8
8
  }
9
9
  export type CustomModelOutputType = 'image' | 'video' | 'audio';
10
+ export type CustomModelParamType = 'string' | 'number' | 'boolean' | 'image' | 'video' | 'audio';
10
11
  export interface CustomModelInputParam {
11
12
  name: string;
12
- type: string;
13
+ type: CustomModelParamType;
13
14
  required: boolean;
14
15
  description?: string;
15
16
  default?: unknown;
16
17
  }
18
+ export interface OpenAPIProperty {
19
+ type?: string;
20
+ format?: string;
21
+ description?: string;
22
+ default?: unknown;
23
+ enum?: string[];
24
+ items?: {
25
+ type?: string;
26
+ $ref?: string;
27
+ };
28
+ $ref?: string;
29
+ }
30
+ interface OpenAPISchemaDefinition {
31
+ properties?: Record<string, OpenAPIProperty>;
32
+ required?: string[];
33
+ 'x-fal-order-properties'?: string[];
34
+ }
35
+ export interface OpenAPISchema {
36
+ components?: {
37
+ schemas?: Record<string, OpenAPISchemaDefinition>;
38
+ };
39
+ }
40
+ /**
41
+ * Map OpenAPI type to our param type
42
+ */
43
+ export declare function mapOpenAPIType(prop: OpenAPIProperty, name: string): CustomModelParamType;
44
+ /**
45
+ * Parse OpenAPI schema to get input parameters
46
+ */
47
+ export declare function parseOpenAPIInputs(schema: OpenAPISchema): CustomModelInputParam[];
48
+ /**
49
+ * Parse OpenAPI schema to determine the output URL path.
50
+ * Returns a path like "images[0].url", "video.url", "audio.url", etc.
51
+ */
52
+ export declare function parseOpenAPIOutputPath(schema: OpenAPISchema, outputType: CustomModelOutputType): string | null;
53
+ /**
54
+ * Determine output type from fal.ai category string
55
+ */
56
+ export declare function getOutputTypeFromCategory(category?: string): CustomModelOutputType;
17
57
  declare const definition: import("./types").NodeDefinition<"generator", {
18
58
  modelId: string;
19
59
  modelName: string;
20
60
  outputType: CustomModelOutputType;
61
+ outputUrlPath: string | null;
21
62
  inputParams: CustomModelInputParam[];
22
63
  apiKey: string | undefined;
23
64
  outputMode: OutputMode;
@@ -1,7 +1,180 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapOpenAPIType = mapOpenAPIType;
4
+ exports.parseOpenAPIInputs = parseOpenAPIInputs;
5
+ exports.parseOpenAPIOutputPath = parseOpenAPIOutputPath;
6
+ exports.getOutputTypeFromCategory = getOutputTypeFromCategory;
3
7
  const types_1 = require("./types");
4
8
  // =============================================================================
9
+ // OpenAPI Parsing Functions
10
+ // =============================================================================
11
+ /** Helper types that should be excluded when searching for Input/Output schemas */
12
+ const HELPER_TYPES = ['File', 'QueueStatus', 'HTTPValidationError', 'ValidationError', 'Image', 'Video', 'Audio'];
13
+ /**
14
+ * Find the input schema from OpenAPI components.
15
+ * fal.ai names input schemas like "WanProImageToVideoInput" not just "Input"
16
+ */
17
+ function findInputSchema(schemas) {
18
+ if (!schemas)
19
+ return null;
20
+ // First try exact "Input" name
21
+ if (schemas.Input)
22
+ return schemas.Input;
23
+ // Find schema that ends with "Input" (excluding helper types)
24
+ for (const [name, schema] of Object.entries(schemas)) {
25
+ if (name.endsWith('Input') && !HELPER_TYPES.includes(name)) {
26
+ return schema;
27
+ }
28
+ }
29
+ return null;
30
+ }
31
+ /**
32
+ * Find the output schema from OpenAPI components.
33
+ * fal.ai names output schemas like "WanProImageToVideoOutput" not just "Output"
34
+ */
35
+ function findOutputSchema(schemas) {
36
+ if (!schemas)
37
+ return null;
38
+ // First try exact "Output" name
39
+ if (schemas.Output)
40
+ return schemas.Output;
41
+ // Find schema that ends with "Output" (excluding helper types)
42
+ for (const [name, schema] of Object.entries(schemas)) {
43
+ if (name.endsWith('Output') && !HELPER_TYPES.includes(name)) {
44
+ return schema;
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ /**
50
+ * Map OpenAPI type to our param type
51
+ */
52
+ function mapOpenAPIType(prop, name) {
53
+ // Check for common image/video/audio input patterns
54
+ const nameLower = name.toLowerCase();
55
+ const descLower = (prop.description ?? '').toLowerCase();
56
+ if (nameLower.includes('image') || descLower.includes('image url')) {
57
+ return 'image';
58
+ }
59
+ if (nameLower.includes('video') || descLower.includes('video url')) {
60
+ return 'video';
61
+ }
62
+ if (nameLower.includes('audio') || descLower.includes('audio url')) {
63
+ return 'audio';
64
+ }
65
+ // Check format
66
+ if (prop.format === 'uri' || prop.format === 'binary') {
67
+ // Generic file input - assume image
68
+ return 'image';
69
+ }
70
+ // Map basic types
71
+ if (prop.type === 'integer' || prop.type === 'number') {
72
+ return 'number';
73
+ }
74
+ if (prop.type === 'boolean') {
75
+ return 'boolean';
76
+ }
77
+ return 'string';
78
+ }
79
+ /**
80
+ * Parse OpenAPI schema to get input parameters
81
+ */
82
+ function parseOpenAPIInputs(schema) {
83
+ const schemas = schema.components?.schemas;
84
+ const inputSchema = findInputSchema(schemas);
85
+ if (!inputSchema?.properties) {
86
+ return [];
87
+ }
88
+ const params = [];
89
+ for (const [name, prop] of Object.entries(inputSchema.properties)) {
90
+ // Skip complex nested objects and arrays (for now)
91
+ if (prop.type === 'object' || (prop.type === 'array' && !prop.items)) {
92
+ continue;
93
+ }
94
+ params.push({
95
+ name,
96
+ type: mapOpenAPIType(prop, name),
97
+ required: inputSchema.required?.includes(name) ?? false,
98
+ description: prop.description,
99
+ default: prop.default,
100
+ });
101
+ }
102
+ // Sort: required first, then prompt/text inputs, then others
103
+ return params.sort((a, b) => {
104
+ if (a.required !== b.required)
105
+ return a.required ? -1 : 1;
106
+ if (a.name === 'prompt')
107
+ return -1;
108
+ if (b.name === 'prompt')
109
+ return 1;
110
+ return a.name.localeCompare(b.name);
111
+ });
112
+ }
113
+ /**
114
+ * Parse OpenAPI schema to determine the output URL path.
115
+ * Returns a path like "images[0].url", "video.url", "audio.url", etc.
116
+ */
117
+ function parseOpenAPIOutputPath(schema, outputType) {
118
+ const schemas = schema.components?.schemas;
119
+ const outputSchema = findOutputSchema(schemas);
120
+ if (!outputSchema?.properties) {
121
+ return null;
122
+ }
123
+ const props = outputSchema.properties;
124
+ // Check for common output patterns based on output type
125
+ if (outputType === 'image') {
126
+ // Array patterns: images, outputs
127
+ if (props.images?.type === 'array')
128
+ return 'images[0].url';
129
+ if (props.outputs?.type === 'array')
130
+ return 'outputs[0].url';
131
+ // Object patterns: image, output
132
+ if (props.image)
133
+ return 'image.url';
134
+ if (props.output?.type === 'string')
135
+ return 'output';
136
+ }
137
+ if (outputType === 'video') {
138
+ // Object patterns: video
139
+ if (props.video)
140
+ return 'video.url';
141
+ // Array patterns: videos
142
+ if (props.videos?.type === 'array')
143
+ return 'videos[0].url';
144
+ if (props.output?.type === 'string')
145
+ return 'output';
146
+ }
147
+ if (outputType === 'audio') {
148
+ // Object patterns: audio, audio_file
149
+ if (props.audio)
150
+ return 'audio.url';
151
+ if (props.audio_file)
152
+ return 'audio_file.url';
153
+ // String patterns: audio_url
154
+ if (props.audio_url?.type === 'string')
155
+ return 'audio_url';
156
+ if (props.output?.type === 'string')
157
+ return 'output';
158
+ }
159
+ // Fallback: check for generic url property
160
+ if (props.url?.type === 'string')
161
+ return 'url';
162
+ return null;
163
+ }
164
+ /**
165
+ * Determine output type from fal.ai category string
166
+ */
167
+ function getOutputTypeFromCategory(category) {
168
+ if (!category)
169
+ return 'image';
170
+ const catLower = category.toLowerCase();
171
+ if (catLower.includes('video'))
172
+ return 'video';
173
+ if (catLower.includes('audio') || catLower.includes('speech'))
174
+ return 'audio';
175
+ return 'image';
176
+ }
177
+ // =============================================================================
5
178
  // Node Definition
6
179
  // =============================================================================
7
180
  const definition = (0, types_1.defineNode)({
@@ -16,6 +189,7 @@ const definition = (0, types_1.defineNode)({
16
189
  modelId: '',
17
190
  modelName: '',
18
191
  outputType: 'image',
192
+ outputUrlPath: null,
19
193
  inputParams: [],
20
194
  apiKey: undefined,
21
195
  outputMode: 'per-input',
@@ -37,3 +37,12 @@ export type DestructureNodeConfig = typeof definition.defaults;
37
37
  * Convert a structured IndexExpression to an array of indexes.
38
38
  */
39
39
  export declare function indexExpressionToIndexes(expr: IndexExpression): number[];
40
+ /**
41
+ * Resolve a path within an object to get a nested value.
42
+ * Supports:
43
+ * - Simple property: "messages" -> obj.messages
44
+ * - Nested property: "data.items" -> obj.data.items
45
+ * - Array index: "[0]" -> obj[0]
46
+ * - Mixed: "acts[0].messages" -> obj.acts[0].messages
47
+ */
48
+ export declare function resolvePath(obj: PortValue, path: string): PortValue | undefined;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.indexExpressionToIndexes = indexExpressionToIndexes;
4
+ exports.resolvePath = resolvePath;
4
5
  const types_1 = require("./types");
5
6
  // =============================================================================
6
7
  // Node Definition
@@ -108,9 +109,7 @@ const definition = (0, types_1.defineNode)({
108
109
  result[selection.portId] = null;
109
110
  }
110
111
  else if (selection.propertyPath) {
111
- // TODO: Add discriminator field to value types to enable proper narrowing without casts
112
- // For now, cast to access property - returns undefined if property doesn't exist
113
- const value = item[selection.propertyPath];
112
+ const value = resolvePath(item, selection.propertyPath);
114
113
  result[selection.portId] = value ?? null;
115
114
  }
116
115
  else {
@@ -125,8 +124,7 @@ const definition = (0, types_1.defineNode)({
125
124
  if (item === undefined)
126
125
  return undefined;
127
126
  if (selection.propertyPath) {
128
- // TODO: Add discriminator field to value types to enable proper narrowing
129
- return item[selection.propertyPath];
127
+ return resolvePath(item, selection.propertyPath);
130
128
  }
131
129
  return item;
132
130
  })
@@ -161,3 +159,60 @@ function indexExpressionToIndexes(expr) {
161
159
  return [];
162
160
  }
163
161
  }
162
+ /**
163
+ * Resolve a path within an object to get a nested value.
164
+ * Supports:
165
+ * - Simple property: "messages" -> obj.messages
166
+ * - Nested property: "data.items" -> obj.data.items
167
+ * - Array index: "[0]" -> obj[0]
168
+ * - Mixed: "acts[0].messages" -> obj.acts[0].messages
169
+ */
170
+ function resolvePath(obj, path) {
171
+ if (!path || path.trim() === '')
172
+ return obj;
173
+ // Parse path into segments: "acts[0].messages" -> ["acts", "0", "messages"]
174
+ const segments = [];
175
+ let current = '';
176
+ for (const char of path) {
177
+ if (char === '.') {
178
+ if (current)
179
+ segments.push(current);
180
+ current = '';
181
+ }
182
+ else if (char === '[') {
183
+ if (current)
184
+ segments.push(current);
185
+ current = '';
186
+ }
187
+ else if (char === ']') {
188
+ if (current)
189
+ segments.push(current);
190
+ current = '';
191
+ }
192
+ else {
193
+ current += char;
194
+ }
195
+ }
196
+ if (current)
197
+ segments.push(current);
198
+ // Navigate through the object
199
+ let result = obj;
200
+ for (const segment of segments) {
201
+ if (result === null || result === undefined)
202
+ return undefined;
203
+ if (typeof result !== 'object')
204
+ return undefined;
205
+ // Check if segment is a number (array index)
206
+ const index = parseInt(segment, 10);
207
+ if (!isNaN(index) && Array.isArray(result)) {
208
+ result = result[index];
209
+ }
210
+ else if (!Array.isArray(result)) {
211
+ result = result[segment];
212
+ }
213
+ else {
214
+ return undefined;
215
+ }
216
+ }
217
+ return result;
218
+ }
@@ -120,6 +120,7 @@ export declare const nodeDefinitions: {
120
120
  modelId: string;
121
121
  modelName: string;
122
122
  outputType: import("./custom-model").CustomModelOutputType;
123
+ outputUrlPath: string | null;
123
124
  inputParams: import("./custom-model").CustomModelInputParam[];
124
125
  apiKey: string | undefined;
125
126
  outputMode: import("./types").OutputMode;
package/dist/index.d.ts CHANGED
@@ -43,10 +43,11 @@ export type { BranchNodeConfig, BranchDefinition, BranchPassthroughInput, Branch
43
43
  export type { CollectNodeConfig, CollectedValues } from './automations/nodes/collect';
44
44
  export type { ComposeWorkflowNodeConfig } from './automations/nodes/compose-workflow';
45
45
  export type { CreateDmNodeConfig, CreateDmMessage, DmPlatform, } from './automations/nodes/create-dm';
46
- export type { CustomModelNodeConfig, CustomModelOutputType, CustomModelInputParam, } from './automations/nodes/custom-model';
46
+ export type { CustomModelNodeConfig, CustomModelOutputType, CustomModelInputParam, CustomModelParamType, OpenAPISchema, OpenAPIProperty, } from './automations/nodes/custom-model';
47
+ export { mapOpenAPIType, parseOpenAPIInputs, parseOpenAPIOutputPath, getOutputTypeFromCategory, } from './automations/nodes/custom-model';
47
48
  export type { DeduplicateNodeConfig } from './automations/nodes/deduplicate';
48
49
  export type { DestructureNodeConfig, DestructureNodeInputs, DestructureNodeOutputs, DestructureSelection, IndexExpression, } from './automations/nodes/destructure';
49
- export { indexExpressionToIndexes } from './automations/nodes/destructure';
50
+ export { indexExpressionToIndexes, resolvePath } from './automations/nodes/destructure';
50
51
  export type { ForEachNodeConfig, ForEachNodeInputs, ForEachNodeOutputs, ForEachOutputProperty, } from './automations/nodes/for-each';
51
52
  export type { GenerateImageNodeConfig, ImageGenerationTextModel, ImageGenerationEditModel, ImageGenerationModel, ImageModelProvider, ImageModelOption, AspectRatioOption, } from './automations/nodes/generate-image';
52
53
  export type { GenerateVideoNodeConfig, VideoGenerationTextToVideoModel, VideoGenerationImageToVideoModel, VideoGenerationModel, VideoModelProvider, VideoModelTier, VideoAspectRatioOption, VideoDurationOption, VideoModelOption, } from './automations/nodes/generate-video';
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
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;
9
+ exports.prepareVideoComposerInput = exports.LLMProviders = exports.IfLogicOperators = exports.resolvePath = exports.indexExpressionToIndexes = exports.getOutputTypeFromCategory = exports.parseOpenAPIOutputPath = exports.parseOpenAPIInputs = exports.mapOpenAPIType = 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
  // =============================================================================
@@ -124,8 +124,14 @@ var image_composer_1 = require("./automations/nodes/image-composer");
124
124
  Object.defineProperty(exports, "prepareImageComposerInput", { enumerable: true, get: function () { return image_composer_1.prepareImageComposerInput; } });
125
125
  var auto_caption_1 = require("./automations/nodes/auto-caption");
126
126
  Object.defineProperty(exports, "nodeConfigToCaptionStyle", { enumerable: true, get: function () { return auto_caption_1.nodeConfigToCaptionStyle; } });
127
+ var custom_model_1 = require("./automations/nodes/custom-model");
128
+ Object.defineProperty(exports, "mapOpenAPIType", { enumerable: true, get: function () { return custom_model_1.mapOpenAPIType; } });
129
+ Object.defineProperty(exports, "parseOpenAPIInputs", { enumerable: true, get: function () { return custom_model_1.parseOpenAPIInputs; } });
130
+ Object.defineProperty(exports, "parseOpenAPIOutputPath", { enumerable: true, get: function () { return custom_model_1.parseOpenAPIOutputPath; } });
131
+ Object.defineProperty(exports, "getOutputTypeFromCategory", { enumerable: true, get: function () { return custom_model_1.getOutputTypeFromCategory; } });
127
132
  var destructure_1 = require("./automations/nodes/destructure");
128
133
  Object.defineProperty(exports, "indexExpressionToIndexes", { enumerable: true, get: function () { return destructure_1.indexExpressionToIndexes; } });
134
+ Object.defineProperty(exports, "resolvePath", { enumerable: true, get: function () { return destructure_1.resolvePath; } });
129
135
  var if_1 = require("./automations/nodes/if");
130
136
  Object.defineProperty(exports, "IfLogicOperators", { enumerable: true, get: function () { return if_1.IfLogicOperators; } });
131
137
  var llm_1 = require("./automations/nodes/llm");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc",
3
- "version": "4.1.54",
3
+ "version": "4.1.56",
4
4
  "description": "TypeScript/JavaScript client for the UGC Inc API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",