ugcinc 3.84.6 → 3.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -1
- package/dist/index.js +6 -1
- package/dist/render/Root.d.ts +12 -0
- package/dist/render/Root.js +508 -0
- package/dist/render/components/CaptionOverlay.d.ts +21 -0
- package/dist/render/components/CaptionOverlay.js +210 -0
- package/dist/render/components/ImageElement.d.ts +26 -0
- package/dist/render/components/ImageElement.js +88 -0
- package/dist/render/components/TextElement.d.ts +30 -0
- package/dist/render/components/TextElement.js +390 -0
- package/dist/render/components/VideoElement.d.ts +30 -0
- package/dist/render/components/VideoElement.js +108 -0
- package/dist/render/components/index.d.ts +7 -0
- package/dist/render/components/index.js +14 -0
- package/dist/render/compositions/AutoCaptionComposition.d.ts +42 -0
- package/dist/render/compositions/AutoCaptionComposition.js +29 -0
- package/dist/render/compositions/DmComposition/BaseDmComposition.d.ts +112 -0
- package/dist/render/compositions/DmComposition/BaseDmComposition.js +212 -0
- package/dist/render/compositions/DmComposition/DebugOverlay.d.ts +20 -0
- package/dist/render/compositions/DmComposition/DebugOverlay.js +258 -0
- package/dist/render/compositions/DmComposition/index.d.ts +6 -0
- package/dist/render/compositions/DmComposition/index.js +10 -0
- package/dist/render/compositions/IMessageDmComposition/convertPropsToElements.d.ts +27 -0
- package/dist/render/compositions/IMessageDmComposition/convertPropsToElements.js +629 -0
- package/dist/render/compositions/IMessageDmComposition/index.d.ts +20 -0
- package/dist/render/compositions/IMessageDmComposition/index.js +485 -0
- package/dist/render/compositions/IMessageDmComposition/types.d.ts +756 -0
- package/dist/render/compositions/IMessageDmComposition/types.js +225 -0
- package/dist/render/compositions/ImageEditorComposition.d.ts +74 -0
- package/dist/render/compositions/ImageEditorComposition.js +351 -0
- package/dist/render/compositions/InstagramDmComposition/convertPropsToElements.d.ts +60 -0
- package/dist/render/compositions/InstagramDmComposition/convertPropsToElements.js +1318 -0
- package/dist/render/compositions/InstagramDmComposition/convertPublicToProps.d.ts +30 -0
- package/dist/render/compositions/InstagramDmComposition/convertPublicToProps.js +131 -0
- package/dist/render/compositions/InstagramDmComposition/index.d.ts +16 -0
- package/dist/render/compositions/InstagramDmComposition/index.js +374 -0
- package/dist/render/compositions/InstagramDmComposition/theme.d.ts +42 -0
- package/dist/render/compositions/InstagramDmComposition/theme.js +55 -0
- package/dist/render/compositions/InstagramDmComposition/types.d.ts +215 -0
- package/dist/render/compositions/InstagramDmComposition/types.js +7 -0
- package/dist/render/compositions/ScreenshotAnimation.d.ts +14 -0
- package/dist/render/compositions/ScreenshotAnimation.js +268 -0
- package/dist/render/compositions/VideoEditorComposition.d.ts +45 -0
- package/dist/render/compositions/VideoEditorComposition.js +307 -0
- package/dist/render/compositions/index.d.ts +12 -0
- package/dist/render/compositions/index.js +43 -0
- package/dist/render/compositions/messaging/components/MediaBubble.d.ts +22 -0
- package/dist/render/compositions/messaging/components/MediaBubble.js +25 -0
- package/dist/render/compositions/messaging/components/MessageBubble.d.ts +35 -0
- package/dist/render/compositions/messaging/components/MessageBubble.js +34 -0
- package/dist/render/compositions/messaging/components/ProfilePic.d.ts +23 -0
- package/dist/render/compositions/messaging/components/ProfilePic.js +37 -0
- package/dist/render/compositions/messaging/components/Reaction.d.ts +23 -0
- package/dist/render/compositions/messaging/components/Reaction.js +19 -0
- package/dist/render/compositions/messaging/components/TypingIndicator.d.ts +25 -0
- package/dist/render/compositions/messaging/components/TypingIndicator.js +66 -0
- package/dist/render/compositions/messaging/index.d.ts +14 -0
- package/dist/render/compositions/messaging/index.js +43 -0
- package/dist/render/compositions/messaging/types.d.ts +148 -0
- package/dist/render/compositions/messaging/types.js +21 -0
- package/dist/render/compositions/messaging/utils/bubbleRadius.d.ts +45 -0
- package/dist/render/compositions/messaging/utils/bubbleRadius.js +84 -0
- package/dist/render/compositions/messaging/utils/groupMessages.d.ts +41 -0
- package/dist/render/compositions/messaging/utils/groupMessages.js +110 -0
- package/dist/render/data/phone-top-nav.d.ts +1 -0
- package/dist/render/data/phone-top-nav.js +4 -0
- package/dist/render/data/screenshot.d.ts +164 -0
- package/dist/render/data/screenshot.js +63 -0
- package/dist/render/hooks/index.d.ts +54 -0
- package/dist/render/hooks/index.js +132 -0
- package/dist/render/index.d.ts +12 -0
- package/dist/render/index.js +36 -0
- package/dist/render/types/base.d.ts +148 -0
- package/dist/render/types/base.js +5 -0
- package/dist/render/types/caption.d.ts +105 -0
- package/dist/render/types/caption.js +8 -0
- package/dist/render/types/crop.d.ts +60 -0
- package/dist/render/types/crop.js +8 -0
- package/dist/render/types/deduplication.d.ts +284 -0
- package/dist/render/types/deduplication.js +240 -0
- package/dist/render/types/editor.d.ts +97 -0
- package/dist/render/types/editor.js +10 -0
- package/dist/render/types/element.d.ts +139 -0
- package/dist/render/types/element.js +19 -0
- package/dist/render/types/index.d.ts +20 -0
- package/dist/render/types/index.js +24 -0
- package/dist/render/types/instagram-dm-public.d.ts +60 -0
- package/dist/render/types/instagram-dm-public.js +8 -0
- package/dist/render/types/position.d.ts +59 -0
- package/dist/render/types/position.js +5 -0
- package/dist/render/types/screenshot.d.ts +57 -0
- package/dist/render/types/screenshot.js +34 -0
- package/dist/render/types/segment.d.ts +163 -0
- package/dist/render/types/segment.js +8 -0
- package/dist/render/types/video.d.ts +192 -0
- package/dist/render/types/video.js +14 -0
- package/dist/render/utils/captionPresets.d.ts +38 -0
- package/dist/render/utils/captionPresets.js +168 -0
- package/dist/render/utils/cropBounds.d.ts +20 -0
- package/dist/render/utils/cropBounds.js +166 -0
- package/dist/render/utils/defaults.d.ts +74 -0
- package/dist/render/utils/defaults.js +91 -0
- package/dist/render/utils/emoji.d.ts +40 -0
- package/dist/render/utils/emoji.js +105 -0
- package/dist/render/utils/fit.d.ts +35 -0
- package/dist/render/utils/fit.js +63 -0
- package/dist/render/utils/fonts.d.ts +55 -0
- package/dist/render/utils/fonts.js +191 -0
- package/dist/render/utils/index.d.ts +14 -0
- package/dist/render/utils/index.js +73 -0
- package/dist/render/utils/positionResolver.d.ts +64 -0
- package/dist/render/utils/positionResolver.js +508 -0
- package/dist/render/utils/text.d.ts +50 -0
- package/dist/render/utils/text.js +177 -0
- package/dist/render/utils/timeline.d.ts +62 -0
- package/dist/render/utils/timeline.js +172 -0
- package/dist/render.d.ts +1 -1
- package/dist/types.d.ts +136 -17
- package/dist/types.js +58 -0
- package/package.json +20 -6
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Text utilities for measuring and wrapping text
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.wrapText = wrapText;
|
|
7
|
+
exports.calculateLineWidth = calculateLineWidth;
|
|
8
|
+
exports.getBorderRadii = getBorderRadii;
|
|
9
|
+
exports.parseHexColor = parseHexColor;
|
|
10
|
+
exports.hexToRgba = hexToRgba;
|
|
11
|
+
exports.getSFProLetterSpacing = getSFProLetterSpacing;
|
|
12
|
+
/**
|
|
13
|
+
* Wrap text to fit within a specific width
|
|
14
|
+
* Accounts for letter spacing when measuring text width
|
|
15
|
+
*/
|
|
16
|
+
function wrapText({ text, maxWidth, letterSpacing = 0, textWrap = 'word', maxLines = 0, measureText, }) {
|
|
17
|
+
const lines = [];
|
|
18
|
+
if (textWrap === 'none') {
|
|
19
|
+
lines.push(text);
|
|
20
|
+
return lines;
|
|
21
|
+
}
|
|
22
|
+
const words = textWrap === 'word' ? text.split(' ') : text.split('');
|
|
23
|
+
let currentLine = '';
|
|
24
|
+
for (let i = 0; i < words.length; i++) {
|
|
25
|
+
const word = words[i];
|
|
26
|
+
if (!word)
|
|
27
|
+
continue;
|
|
28
|
+
const testLine = currentLine + (currentLine ? (textWrap === 'word' ? ' ' : '') : '') + word;
|
|
29
|
+
// Account for letter spacing
|
|
30
|
+
const charCount = [...testLine].length;
|
|
31
|
+
const extraSpacing = charCount > 1 ? (charCount - 1) * letterSpacing : 0;
|
|
32
|
+
const totalWidth = measureText(testLine) + extraSpacing;
|
|
33
|
+
if (totalWidth > maxWidth && currentLine) {
|
|
34
|
+
lines.push(currentLine);
|
|
35
|
+
currentLine = word;
|
|
36
|
+
if (maxLines && lines.length >= maxLines) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
currentLine = testLine;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (currentLine && (!maxLines || lines.length < maxLines)) {
|
|
45
|
+
lines.push(currentLine);
|
|
46
|
+
}
|
|
47
|
+
// Handle overflow
|
|
48
|
+
if (maxLines && lines.length > maxLines) {
|
|
49
|
+
lines.splice(maxLines);
|
|
50
|
+
}
|
|
51
|
+
return lines;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Calculate line width with letter spacing
|
|
55
|
+
*/
|
|
56
|
+
function calculateLineWidth({ line, letterSpacing, measureText, }) {
|
|
57
|
+
const chars = [...line];
|
|
58
|
+
let width = 0;
|
|
59
|
+
for (const char of chars) {
|
|
60
|
+
width += measureText(char) + letterSpacing;
|
|
61
|
+
}
|
|
62
|
+
// Remove extra letter spacing after last character
|
|
63
|
+
if (chars.length > 0) {
|
|
64
|
+
width -= letterSpacing;
|
|
65
|
+
}
|
|
66
|
+
return width;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Convert borderRadius value to array format for roundRect()
|
|
70
|
+
* Returns [topLeft, topRight, bottomRight, bottomLeft] or null if no rounding needed
|
|
71
|
+
*/
|
|
72
|
+
function getBorderRadii(borderRadius) {
|
|
73
|
+
if (!borderRadius)
|
|
74
|
+
return null;
|
|
75
|
+
if (typeof borderRadius === 'number') {
|
|
76
|
+
if (borderRadius <= 0)
|
|
77
|
+
return null;
|
|
78
|
+
return [borderRadius, borderRadius, borderRadius, borderRadius];
|
|
79
|
+
}
|
|
80
|
+
const topLeft = borderRadius.topLeft ?? 0;
|
|
81
|
+
const topRight = borderRadius.topRight ?? 0;
|
|
82
|
+
const bottomRight = borderRadius.bottomRight ?? 0;
|
|
83
|
+
const bottomLeft = borderRadius.bottomLeft ?? 0;
|
|
84
|
+
// Check if any corner has radius
|
|
85
|
+
if (topLeft <= 0 && topRight <= 0 && bottomRight <= 0 && bottomLeft <= 0) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return [topLeft, topRight, bottomRight, bottomLeft];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Parse hex color to RGB values
|
|
92
|
+
*/
|
|
93
|
+
function parseHexColor(hex) {
|
|
94
|
+
const cleanHex = hex.replace('#', '');
|
|
95
|
+
return {
|
|
96
|
+
r: parseInt(cleanHex.substring(0, 2), 16),
|
|
97
|
+
g: parseInt(cleanHex.substring(2, 4), 16),
|
|
98
|
+
b: parseInt(cleanHex.substring(4, 6), 16),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Convert hex color and opacity to rgba string
|
|
103
|
+
*/
|
|
104
|
+
function hexToRgba(hex, opacity = 100) {
|
|
105
|
+
const { r, g, b } = parseHexColor(hex);
|
|
106
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* SF Pro tracking table extracted from the font's `trak` table.
|
|
110
|
+
* Maps font sizes to letter-spacing values in pixels.
|
|
111
|
+
* These values are calculated from the font's FUnits using: (FUnits / 2048) * fontSize
|
|
112
|
+
*/
|
|
113
|
+
const SF_PRO_TRACKING = {
|
|
114
|
+
6: 0.240234,
|
|
115
|
+
9: 0.166992,
|
|
116
|
+
10: 0.117188,
|
|
117
|
+
11: 0.064453,
|
|
118
|
+
12: 0.000000,
|
|
119
|
+
13: -0.076172,
|
|
120
|
+
14: -0.150391,
|
|
121
|
+
15: -0.234375,
|
|
122
|
+
16: -0.312500,
|
|
123
|
+
17: -0.431641,
|
|
124
|
+
20: -0.449219,
|
|
125
|
+
22: -0.257812,
|
|
126
|
+
24: 0.070312,
|
|
127
|
+
28: 0.382812,
|
|
128
|
+
32: 0.406250,
|
|
129
|
+
36: 0.369141,
|
|
130
|
+
50: 0.341797,
|
|
131
|
+
64: 0.218750,
|
|
132
|
+
80: 0.000000,
|
|
133
|
+
100: 0.000000,
|
|
134
|
+
138: 0.000000,
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Get the SF Pro letter-spacing value for a given font size.
|
|
138
|
+
* Uses linear interpolation between known tracking values from the font's trak table.
|
|
139
|
+
* This matches iOS's Core Text rendering behavior.
|
|
140
|
+
*
|
|
141
|
+
* @param fontSize - The font size in pixels
|
|
142
|
+
* @returns The letter-spacing value in pixels
|
|
143
|
+
*/
|
|
144
|
+
function getSFProLetterSpacing(fontSize) {
|
|
145
|
+
const sizes = Object.keys(SF_PRO_TRACKING).map(Number).sort((a, b) => a - b);
|
|
146
|
+
// Ensure we have at least one size
|
|
147
|
+
const firstSize = sizes[0];
|
|
148
|
+
const lastSize = sizes[sizes.length - 1];
|
|
149
|
+
if (firstSize === undefined || lastSize === undefined) {
|
|
150
|
+
return 0; // Fallback if no sizes defined
|
|
151
|
+
}
|
|
152
|
+
// Find bounding sizes for interpolation
|
|
153
|
+
let lower = firstSize;
|
|
154
|
+
let upper = lastSize;
|
|
155
|
+
for (let i = 0; i < sizes.length - 1; i++) {
|
|
156
|
+
const current = sizes[i];
|
|
157
|
+
const next = sizes[i + 1];
|
|
158
|
+
if (current !== undefined && next !== undefined && current <= fontSize && next >= fontSize) {
|
|
159
|
+
lower = current;
|
|
160
|
+
upper = next;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Return exact value if below or above range
|
|
165
|
+
const lowerValue = SF_PRO_TRACKING[lower];
|
|
166
|
+
const upperValue = SF_PRO_TRACKING[upper];
|
|
167
|
+
if (lowerValue === undefined || upperValue === undefined) {
|
|
168
|
+
return 0; // Fallback
|
|
169
|
+
}
|
|
170
|
+
if (fontSize <= lower)
|
|
171
|
+
return lowerValue;
|
|
172
|
+
if (fontSize >= upper)
|
|
173
|
+
return upperValue;
|
|
174
|
+
// Linear interpolation
|
|
175
|
+
const t = (fontSize - lower) / (upper - lower);
|
|
176
|
+
return lowerValue + t * (upperValue - lowerValue);
|
|
177
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeline utility functions for video editor
|
|
3
|
+
*
|
|
4
|
+
* These functions calculate segment positions on the timeline based on
|
|
5
|
+
* the segment/overlay timing model. Used by both the webapp UI and
|
|
6
|
+
* the VideoEditorComposition for rendering.
|
|
7
|
+
*/
|
|
8
|
+
import type { VideoEditorSegment, VideoEditorChannel, SegmentTimelinePosition, TimeMode } from '../types/video';
|
|
9
|
+
import type { TimeValue } from '../types/base';
|
|
10
|
+
/**
|
|
11
|
+
* Create a default TimeValue for segment offsets
|
|
12
|
+
*/
|
|
13
|
+
export declare function defaultOffset(mode?: TimeMode): TimeValue;
|
|
14
|
+
/**
|
|
15
|
+
* Get base segments (no parentId) for a channel
|
|
16
|
+
* Base segments are the primary timeline elements that overlays attach to
|
|
17
|
+
*/
|
|
18
|
+
export declare function getBaseSegments(channel: VideoEditorChannel): VideoEditorSegment[];
|
|
19
|
+
/**
|
|
20
|
+
* Get overlays for a specific parent segment (or global overlays if parentId is null)
|
|
21
|
+
*/
|
|
22
|
+
export declare function getOverlays(channel: VideoEditorChannel, parentId: string | null): VideoEditorSegment[];
|
|
23
|
+
/**
|
|
24
|
+
* Calculate segment position on timeline
|
|
25
|
+
*
|
|
26
|
+
* For base segments:
|
|
27
|
+
* - Position is calculated from offset and previous segments
|
|
28
|
+
* - Duration is from the duration property or default (5 seconds)
|
|
29
|
+
*
|
|
30
|
+
* For overlay segments:
|
|
31
|
+
* - Position is calculated relative to parent using relativeStart/relativeEnd
|
|
32
|
+
* - relativeStart/relativeEnd are fractions (0-1) of parent duration
|
|
33
|
+
*/
|
|
34
|
+
export declare function getSegmentTimelinePosition(segment: VideoEditorSegment, baseSegments: VideoEditorSegment[], channel: VideoEditorChannel): SegmentTimelinePosition;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a segment is visible at a given time
|
|
37
|
+
*/
|
|
38
|
+
export declare function isSegmentVisibleAtTime(segment: VideoEditorSegment, time: number, channel: VideoEditorChannel): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Calculate estimated total duration based on segments
|
|
41
|
+
*/
|
|
42
|
+
export declare function calculateEstimatedDuration(channels: VideoEditorChannel[]): number;
|
|
43
|
+
/**
|
|
44
|
+
* Calculate the timeline content end time (used for both ruler and scroll width)
|
|
45
|
+
*/
|
|
46
|
+
export declare function calculateTimelineContentEnd(channel: VideoEditorChannel): number;
|
|
47
|
+
/**
|
|
48
|
+
* Format time in mm:ss.ms
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatTime(ms: number): string;
|
|
51
|
+
/**
|
|
52
|
+
* Parse time string to milliseconds
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseTime(timeStr: string): number;
|
|
55
|
+
/**
|
|
56
|
+
* Generate a unique segment ID
|
|
57
|
+
*/
|
|
58
|
+
export declare function generateSegmentId(): string;
|
|
59
|
+
/**
|
|
60
|
+
* Generate a unique overlay ID
|
|
61
|
+
*/
|
|
62
|
+
export declare function generateOverlayId(): string;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Timeline utility functions for video editor
|
|
4
|
+
*
|
|
5
|
+
* These functions calculate segment positions on the timeline based on
|
|
6
|
+
* the segment/overlay timing model. Used by both the webapp UI and
|
|
7
|
+
* the VideoEditorComposition for rendering.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.defaultOffset = defaultOffset;
|
|
11
|
+
exports.getBaseSegments = getBaseSegments;
|
|
12
|
+
exports.getOverlays = getOverlays;
|
|
13
|
+
exports.getSegmentTimelinePosition = getSegmentTimelinePosition;
|
|
14
|
+
exports.isSegmentVisibleAtTime = isSegmentVisibleAtTime;
|
|
15
|
+
exports.calculateEstimatedDuration = calculateEstimatedDuration;
|
|
16
|
+
exports.calculateTimelineContentEnd = calculateTimelineContentEnd;
|
|
17
|
+
exports.formatTime = formatTime;
|
|
18
|
+
exports.parseTime = parseTime;
|
|
19
|
+
exports.generateSegmentId = generateSegmentId;
|
|
20
|
+
exports.generateOverlayId = generateOverlayId;
|
|
21
|
+
/**
|
|
22
|
+
* Create a default TimeValue for segment offsets
|
|
23
|
+
*/
|
|
24
|
+
function defaultOffset(mode = 'flexible') {
|
|
25
|
+
return mode === 'flexible'
|
|
26
|
+
? { type: 'relative', value: 0 }
|
|
27
|
+
: { type: 'absolute', value: 0 };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get base segments (no parentId) for a channel
|
|
31
|
+
* Base segments are the primary timeline elements that overlays attach to
|
|
32
|
+
*/
|
|
33
|
+
function getBaseSegments(channel) {
|
|
34
|
+
return channel.segments.filter(s => s.parentId === undefined);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get overlays for a specific parent segment (or global overlays if parentId is null)
|
|
38
|
+
*/
|
|
39
|
+
function getOverlays(channel, parentId) {
|
|
40
|
+
return channel.segments.filter(s => s.parentId === (parentId ?? undefined));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Calculate segment position on timeline
|
|
44
|
+
*
|
|
45
|
+
* For base segments:
|
|
46
|
+
* - Position is calculated from offset and previous segments
|
|
47
|
+
* - Duration is from the duration property or default (5 seconds)
|
|
48
|
+
*
|
|
49
|
+
* For overlay segments:
|
|
50
|
+
* - Position is calculated relative to parent using relativeStart/relativeEnd
|
|
51
|
+
* - relativeStart/relativeEnd are fractions (0-1) of parent duration
|
|
52
|
+
*/
|
|
53
|
+
function getSegmentTimelinePosition(segment, baseSegments, channel) {
|
|
54
|
+
// For overlays, calculate based on parent
|
|
55
|
+
if (segment.parentId) {
|
|
56
|
+
const parent = channel.segments.find(s => s.id === segment.parentId);
|
|
57
|
+
if (parent) {
|
|
58
|
+
const parentPos = getSegmentTimelinePosition(parent, baseSegments, channel);
|
|
59
|
+
const relStart = segment.relativeStart ?? 0;
|
|
60
|
+
const relEnd = segment.relativeEnd ?? 1;
|
|
61
|
+
return {
|
|
62
|
+
startMs: parentPos.startMs + (parentPos.durationMs * relStart),
|
|
63
|
+
durationMs: parentPos.durationMs * (relEnd - relStart),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// For base segments, calculate based on order
|
|
68
|
+
const baseIndex = baseSegments.findIndex(s => s.id === segment.id);
|
|
69
|
+
let accumulatedTime = 0;
|
|
70
|
+
for (let i = 0; i < baseIndex; i++) {
|
|
71
|
+
const prev = baseSegments[i];
|
|
72
|
+
if (prev) {
|
|
73
|
+
accumulatedTime += prev.duration?.type === 'absolute'
|
|
74
|
+
? prev.duration.value
|
|
75
|
+
: 5000; // Default 5 seconds
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const startMs = segment.offset.type === 'absolute'
|
|
79
|
+
? segment.offset.value
|
|
80
|
+
: accumulatedTime;
|
|
81
|
+
const durationMs = segment.duration?.type === 'absolute'
|
|
82
|
+
? segment.duration.value
|
|
83
|
+
: 5000; // Default 5 seconds
|
|
84
|
+
return { startMs, durationMs };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if a segment is visible at a given time
|
|
88
|
+
*/
|
|
89
|
+
function isSegmentVisibleAtTime(segment, time, channel) {
|
|
90
|
+
const baseSegments = getBaseSegments(channel);
|
|
91
|
+
const { startMs, durationMs } = getSegmentTimelinePosition(segment, baseSegments, channel);
|
|
92
|
+
const endMs = startMs + durationMs;
|
|
93
|
+
return time >= startMs && time < endMs;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Calculate estimated total duration based on segments
|
|
97
|
+
*/
|
|
98
|
+
function calculateEstimatedDuration(channels) {
|
|
99
|
+
let maxDuration = 5000; // Minimum 5 seconds
|
|
100
|
+
for (const channel of channels) {
|
|
101
|
+
let channelTime = 0;
|
|
102
|
+
for (const segment of channel.segments) {
|
|
103
|
+
// Skip overlays - they don't extend the timeline
|
|
104
|
+
if (segment.parentId)
|
|
105
|
+
continue;
|
|
106
|
+
// For fixed timing, use the actual offset
|
|
107
|
+
if (segment.offset.type === 'absolute') {
|
|
108
|
+
channelTime = segment.offset.value;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
channelTime += 5000; // Estimate for relative
|
|
112
|
+
}
|
|
113
|
+
if (segment.duration?.type === 'absolute') {
|
|
114
|
+
channelTime += segment.duration.value;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
channelTime += 5000; // Estimate
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
maxDuration = Math.max(maxDuration, channelTime);
|
|
121
|
+
}
|
|
122
|
+
return maxDuration;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Calculate the timeline content end time (used for both ruler and scroll width)
|
|
126
|
+
*/
|
|
127
|
+
function calculateTimelineContentEnd(channel) {
|
|
128
|
+
const baseSegments = getBaseSegments(channel);
|
|
129
|
+
let lastEnd = 0;
|
|
130
|
+
for (const segment of baseSegments) {
|
|
131
|
+
const { startMs, durationMs } = getSegmentTimelinePosition(segment, baseSegments, channel);
|
|
132
|
+
lastEnd = Math.max(lastEnd, startMs + durationMs);
|
|
133
|
+
}
|
|
134
|
+
// Add 2 seconds for "Add Segment" button space, round up to nearest second
|
|
135
|
+
return Math.ceil((lastEnd + 2000) / 1000) * 1000;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Format time in mm:ss.ms
|
|
139
|
+
*/
|
|
140
|
+
function formatTime(ms) {
|
|
141
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
142
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
143
|
+
const seconds = totalSeconds % 60;
|
|
144
|
+
const milliseconds = Math.floor((ms % 1000) / 10);
|
|
145
|
+
return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${milliseconds.toString().padStart(2, '0')}`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Parse time string to milliseconds
|
|
149
|
+
*/
|
|
150
|
+
function parseTime(timeStr) {
|
|
151
|
+
const parts = timeStr.split(':');
|
|
152
|
+
if (parts.length !== 2)
|
|
153
|
+
return 0;
|
|
154
|
+
const [minStr, secPart] = parts;
|
|
155
|
+
const minutes = parseInt(minStr ?? '0', 10) || 0;
|
|
156
|
+
const secParts = (secPart ?? '0').split('.');
|
|
157
|
+
const seconds = parseInt(secParts[0] ?? '0', 10) || 0;
|
|
158
|
+
const ms = parseInt((secParts[1] ?? '0').padEnd(2, '0').slice(0, 2), 10) * 10 || 0;
|
|
159
|
+
return (minutes * 60 + seconds) * 1000 + ms;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate a unique segment ID
|
|
163
|
+
*/
|
|
164
|
+
function generateSegmentId() {
|
|
165
|
+
return `segment-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Generate a unique overlay ID
|
|
169
|
+
*/
|
|
170
|
+
function generateOverlayId() {
|
|
171
|
+
return `overlay-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
172
|
+
}
|
package/dist/render.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiResponse } from './types';
|
|
2
|
-
import type { ImageEditorNodeConfig, VideoEditorNodeConfig, DeduplicationInput } from '
|
|
2
|
+
import type { ImageEditorNodeConfig, VideoEditorNodeConfig, DeduplicationInput } from './render/types';
|
|
3
3
|
export interface RenderJobResponse {
|
|
4
4
|
job_id: string;
|
|
5
5
|
status: string;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageEditorElement, ImageEditorNodeConfig, DimensionPresetKey, VideoEditorNodeConfig, VideoEditorChannel, VideoEditorSegment, VideoEditorVideoSegment, VideoEditorAudioSegment, VideoEditorImageSegment, VideoEditorTextSegment, VideoEditorImageSequenceSegment, VideoEditorVideoSequenceSegment, TimeValue, TimeMode, SegmentTimelinePosition, DeduplicationInput } from '
|
|
1
|
+
import type { ImageEditorElement, ImageEditorNodeConfig, DimensionPresetKey, VideoEditorNodeConfig, VideoEditorChannel, VideoEditorSegment, VideoEditorVideoSegment, VideoEditorAudioSegment, VideoEditorImageSegment, VideoEditorTextSegment, VideoEditorImageSequenceSegment, VideoEditorVideoSequenceSegment, TimeValue, TimeMode, SegmentTimelinePosition, DeduplicationInput } from './render/types';
|
|
2
2
|
/**
|
|
3
3
|
* API response types
|
|
4
4
|
*/
|
|
@@ -471,6 +471,10 @@ export interface ImageEditorNodeOutput extends Record<string, unknown>, NodeOutp
|
|
|
471
471
|
height?: number;
|
|
472
472
|
aspectRatio?: string;
|
|
473
473
|
}
|
|
474
|
+
export interface VideoEditorNodeInput extends Record<string, unknown> {
|
|
475
|
+
type: 'video-composer';
|
|
476
|
+
editor: VideoEditorNodeConfig;
|
|
477
|
+
}
|
|
474
478
|
export interface EditorConfig extends BaseEditorConfig {
|
|
475
479
|
channels: Array<{
|
|
476
480
|
id: string;
|
|
@@ -751,24 +755,24 @@ export type StaticSegment = ImageSegment | TextSegment;
|
|
|
751
755
|
/**
|
|
752
756
|
* Automation types
|
|
753
757
|
*/
|
|
754
|
-
export type MediaType = 'video' | 'image' | 'audio' | 'text'
|
|
758
|
+
export type MediaType = 'video' | 'image' | 'audio' | 'text';
|
|
755
759
|
/**
|
|
756
760
|
* Array types for collections
|
|
757
761
|
*/
|
|
758
|
-
export type ArrayType = 'image[]' | 'video[]' | 'audio[]' | 'text[]' | 'object[]'
|
|
762
|
+
export type ArrayType = 'image[]' | 'video[]' | 'audio[]' | 'text[]' | 'object[]';
|
|
759
763
|
/**
|
|
760
764
|
* Extended port types (includes non-media types for special nodes)
|
|
761
765
|
*/
|
|
762
|
-
export type PortType = MediaType | 'number' | 'boolean' | 'object' | ArrayType;
|
|
766
|
+
export type PortType = MediaType | 'number' | 'boolean' | 'object' | 'account' | 'date' | 'social_audio' | ArrayType;
|
|
763
767
|
/**
|
|
764
768
|
* Selection order configuration for media nodes
|
|
765
769
|
*/
|
|
766
770
|
export type SelectionMode = 'random' | 'sequential';
|
|
767
771
|
export type ExhaustionBehavior = 'restart' | 'error';
|
|
768
772
|
export interface SelectionConfig {
|
|
769
|
-
mode
|
|
770
|
-
enforceUniqueness
|
|
771
|
-
exhaustionBehavior
|
|
773
|
+
mode?: SelectionMode;
|
|
774
|
+
enforceUniqueness?: boolean;
|
|
775
|
+
exhaustionBehavior?: ExhaustionBehavior;
|
|
772
776
|
}
|
|
773
777
|
export interface SelectionState {
|
|
774
778
|
usedIndices: number[];
|
|
@@ -809,14 +813,26 @@ export interface NodePort {
|
|
|
809
813
|
/** Schema of array items (when this port outputs an array) */
|
|
810
814
|
itemSchema?: Record<string, PropertySchema>;
|
|
811
815
|
}
|
|
816
|
+
/**
|
|
817
|
+
* Simplified port definition for database storage.
|
|
818
|
+
* Uses string type since PortType union gets serialized to JSON.
|
|
819
|
+
*/
|
|
820
|
+
export interface ResolvedPort {
|
|
821
|
+
id: string;
|
|
822
|
+
type: string;
|
|
823
|
+
required: boolean;
|
|
824
|
+
/** Schema of array items (when this port outputs an array) */
|
|
825
|
+
itemSchema?: Record<string, PropertySchema>;
|
|
826
|
+
}
|
|
812
827
|
/**
|
|
813
828
|
* Resolved ports for nodes with dynamic inputs/outputs.
|
|
814
829
|
* Stored in node config when the automation is saved, allowing validation
|
|
815
830
|
* without needing to resolve ports at validation time.
|
|
831
|
+
* Note: Uses simplified ResolvedPort type for database compatibility.
|
|
816
832
|
*/
|
|
817
833
|
export interface ResolvedPorts {
|
|
818
|
-
inputs:
|
|
819
|
-
outputs:
|
|
834
|
+
inputs: ResolvedPort[];
|
|
835
|
+
outputs: ResolvedPort[];
|
|
820
836
|
}
|
|
821
837
|
/**
|
|
822
838
|
* Functional category for automation nodes
|
|
@@ -849,7 +865,7 @@ export interface NodeControlConfig {
|
|
|
849
865
|
*/
|
|
850
866
|
isInitializer?: boolean;
|
|
851
867
|
}
|
|
852
|
-
export type NodeTypeEnum = 'social-audio' | 'text' | 'media' | 'video-import' | 'image-composer' | 'video-composer' | 'generate-image' | 'generate-video' | 'custom-model' | 'llm' | 'output' | 'manual-trigger' | 'recurrence' | 'compose-workflow' | 'account' | 'auto-post' | 'save-to-media' | 'deduplicate' | 'for-each' | 'random' | 'random-route' | 'branch' | 'if' | 'not' | 'transcript' | 'auto-caption' | 'screenshot-animation' | 'create-dm' | 'collect' | 'destructure';
|
|
868
|
+
export type NodeTypeEnum = 'social-audio' | 'text' | 'media' | 'video-import' | 'image-composer' | 'video-composer' | 'generate-image' | 'generate-video' | 'custom-model' | 'llm' | 'output' | 'manual-trigger' | 'recurrence' | 'compose-workflow' | 'account' | 'auto-post' | 'save-to-media' | 'deduplicate' | 'for-each' | 'for-each-value' | 'random' | 'random-route' | 'branch' | 'if' | 'not' | 'transcript' | 'auto-caption' | 'screenshot-animation' | 'create-dm' | 'collect' | 'destructure';
|
|
853
869
|
export interface OutputSchemaProperty {
|
|
854
870
|
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
855
871
|
items?: 'string' | 'number' | 'boolean';
|
|
@@ -909,6 +925,10 @@ export interface LLMNodeConfig {
|
|
|
909
925
|
export type ImageGenerationTextModel = 'fal-ai/gemini-3-pro-image-preview' | 'fal-ai/nano-banana-pro' | 'fal-ai/nano-banana' | 'fal-ai/gpt-image-1/text-to-image';
|
|
910
926
|
export type ImageGenerationEditModel = 'fal-ai/gemini-3-pro-image-preview/edit' | 'fal-ai/nano-banana-pro/edit' | 'fal-ai/nano-banana/edit' | 'fal-ai/gpt-image-1/edit-image';
|
|
911
927
|
export type ImageGenerationModel = ImageGenerationTextModel | ImageGenerationEditModel;
|
|
928
|
+
/**
|
|
929
|
+
* Type guard to check if model is an edit/inpaint model
|
|
930
|
+
*/
|
|
931
|
+
export declare function isEditModel(model: ImageGenerationModel): model is ImageGenerationEditModel;
|
|
912
932
|
/**
|
|
913
933
|
* Image Generation Node Configuration
|
|
914
934
|
*/
|
|
@@ -979,13 +999,20 @@ export interface WorkflowNodeDefinition {
|
|
|
979
999
|
}
|
|
980
1000
|
export interface OutputInput {
|
|
981
1001
|
id: string;
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
/**
|
|
985
|
-
|
|
1002
|
+
title: string;
|
|
1003
|
+
type: 'image' | 'video' | 'audio' | 'text';
|
|
1004
|
+
/** Individual tag for this input (overrides global tag) */
|
|
1005
|
+
tag?: string;
|
|
986
1006
|
}
|
|
987
1007
|
export interface OutputNodeConfig {
|
|
988
1008
|
inputs: OutputInput[];
|
|
1009
|
+
/** Which input is the main visual preview for the workflow */
|
|
1010
|
+
mainPreviewInputId?: string;
|
|
1011
|
+
saveToMedia?: boolean;
|
|
1012
|
+
globalTag?: string;
|
|
1013
|
+
makeUnique?: boolean;
|
|
1014
|
+
createPost?: boolean;
|
|
1015
|
+
requireReview?: boolean;
|
|
989
1016
|
}
|
|
990
1017
|
/**
|
|
991
1018
|
* Level 3 (deepest) object schema field - primitives only, no further nesting
|
|
@@ -1222,7 +1249,6 @@ export interface AutoPostNodeConfig {
|
|
|
1222
1249
|
*/
|
|
1223
1250
|
export interface SaveToMediaInput {
|
|
1224
1251
|
id: string;
|
|
1225
|
-
title: string;
|
|
1226
1252
|
type: 'image' | 'video' | 'audio' | 'text';
|
|
1227
1253
|
/** Optional individual tag for this input (overrides global tag) */
|
|
1228
1254
|
tag?: string;
|
|
@@ -1232,11 +1258,11 @@ export interface SaveToMediaInput {
|
|
|
1232
1258
|
*/
|
|
1233
1259
|
export interface SaveToMediaNodeConfig {
|
|
1234
1260
|
/** Dynamic inputs to save */
|
|
1235
|
-
inputs
|
|
1261
|
+
inputs: SaveToMediaInput[];
|
|
1236
1262
|
/** Global tag applied to all saved items */
|
|
1237
1263
|
globalTag?: string;
|
|
1238
1264
|
/** If true, append date in mm-dd-yy format to tag */
|
|
1239
|
-
|
|
1265
|
+
tagWithDate?: boolean;
|
|
1240
1266
|
/** If true, append run ID to make tags unique */
|
|
1241
1267
|
makeUnique?: boolean;
|
|
1242
1268
|
}
|
|
@@ -1617,6 +1643,10 @@ export interface DestructureNodeConfig {
|
|
|
1617
1643
|
export type VideoGenerationTextToVideoModel = 'fal-ai/veo3.1' | 'fal-ai/veo3' | 'fal-ai/veo3/fast' | 'fal-ai/kling-video/v2.6/pro/text-to-video' | 'fal-ai/kling-video/v2.5/pro/text-to-video' | 'fal-ai/luma-dream-machine/ray-2' | 'fal-ai/luma-dream-machine/ray-2-flash' | 'fal-ai/minimax/hailuo-2.3/pro/text-to-video' | 'wan/v2.6/text-to-video' | 'fal-ai/sora-2/text-to-video';
|
|
1618
1644
|
export type VideoGenerationImageToVideoModel = 'fal-ai/veo3.1/image-to-video' | 'fal-ai/veo3/image-to-video' | 'fal-ai/kling-video/v2.6/pro/image-to-video' | 'fal-ai/kling-video/v2.5/pro/image-to-video' | 'fal-ai/luma-dream-machine/ray-2/image-to-video' | 'fal-ai/luma-dream-machine/ray-2-flash/image-to-video' | 'fal-ai/minimax/hailuo-2.3/pro/image-to-video' | 'wan/v2.6/image-to-video' | 'fal-ai/sora-2/image-to-video/pro';
|
|
1619
1645
|
export type VideoGenerationModel = VideoGenerationTextToVideoModel | VideoGenerationImageToVideoModel;
|
|
1646
|
+
/**
|
|
1647
|
+
* Type guard to check if model is an image-to-video model
|
|
1648
|
+
*/
|
|
1649
|
+
export declare function isImageToVideoModel(model: VideoGenerationModel): model is VideoGenerationImageToVideoModel;
|
|
1620
1650
|
/**
|
|
1621
1651
|
* Video Generation node configuration - AI video generation
|
|
1622
1652
|
*/
|
|
@@ -2059,3 +2089,92 @@ export interface AutomationRunExport {
|
|
|
2059
2089
|
edges: ExportedEdge[];
|
|
2060
2090
|
};
|
|
2061
2091
|
}
|
|
2092
|
+
/**
|
|
2093
|
+
* Account object that flows through edges for posting
|
|
2094
|
+
*/
|
|
2095
|
+
export interface AccountData {
|
|
2096
|
+
id: string;
|
|
2097
|
+
username: string;
|
|
2098
|
+
platform: 'tiktok';
|
|
2099
|
+
displayName?: string;
|
|
2100
|
+
profilePicUrl?: string;
|
|
2101
|
+
metadata?: Record<string, unknown>;
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* Output structure for flow control nodes (if, random-route).
|
|
2105
|
+
* Contains values for selected ports and list of skipped port IDs.
|
|
2106
|
+
*/
|
|
2107
|
+
export interface FlowControlOutput {
|
|
2108
|
+
values: Record<string, unknown>;
|
|
2109
|
+
skippedPorts: string[];
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Node types array for runtime use
|
|
2113
|
+
*/
|
|
2114
|
+
export declare const NodeTypes: readonly ["social-audio", "text", "media", "video-import", "image-composer", "video-composer", "generate-image", "generate-video", "custom-model", "llm", "output", "manual-trigger", "recurrence", "compose-workflow", "account", "auto-post", "save-to-media", "deduplicate", "for-each", "for-each-value", "transcript", "auto-caption", "screenshot-animation", "random", "random-route", "branch", "if", "not", "create-dm", "collect", "destructure"];
|
|
2115
|
+
/**
|
|
2116
|
+
* Node type enum derived from NodeTypes const array
|
|
2117
|
+
* This is the canonical type - use this instead of the string union NodeTypeEnum
|
|
2118
|
+
*/
|
|
2119
|
+
export type NodeType = typeof NodeTypes[number];
|
|
2120
|
+
/**
|
|
2121
|
+
* Context passed to executor-based node execution.
|
|
2122
|
+
* Replaces the complex outputMap/iteration/portOffsets pattern with simple inputs.
|
|
2123
|
+
*/
|
|
2124
|
+
export interface ExecutorContext {
|
|
2125
|
+
/** Database ID of this executor */
|
|
2126
|
+
executorId: string;
|
|
2127
|
+
/** Run ID this executor belongs to */
|
|
2128
|
+
runId: string;
|
|
2129
|
+
/** Template node ID this executor was created from */
|
|
2130
|
+
templateNodeId: string;
|
|
2131
|
+
/** Index of this executor (0, 1, 2...) for the same template node */
|
|
2132
|
+
executorIndex: number;
|
|
2133
|
+
/** Node type */
|
|
2134
|
+
type: NodeType;
|
|
2135
|
+
/** Node config (includes assignedValue for source nodes) */
|
|
2136
|
+
config: Record<string, unknown>;
|
|
2137
|
+
/** Input values read from incoming edges (portId -> value) */
|
|
2138
|
+
inputs: Record<string, unknown>;
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Executor for synchronous nodes.
|
|
2142
|
+
* Much simpler than the old NodeControlConfig - just takes context and returns output.
|
|
2143
|
+
*/
|
|
2144
|
+
export interface NodeExecutor<TOutput = unknown> {
|
|
2145
|
+
type: NodeType;
|
|
2146
|
+
/**
|
|
2147
|
+
* Execute the node and return a single output value.
|
|
2148
|
+
* For multi-output nodes (like LLM), return an object with output fields.
|
|
2149
|
+
*/
|
|
2150
|
+
execute: (ctx: ExecutorContext) => Promise<TOutput>;
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Async job status for executor-based async nodes
|
|
2154
|
+
*/
|
|
2155
|
+
export type ExecutorAsyncJobStatus<TOutput = unknown> = {
|
|
2156
|
+
status: 'pending';
|
|
2157
|
+
} | {
|
|
2158
|
+
status: 'completed';
|
|
2159
|
+
output: TOutput;
|
|
2160
|
+
} | {
|
|
2161
|
+
status: 'failed';
|
|
2162
|
+
error: string;
|
|
2163
|
+
};
|
|
2164
|
+
/**
|
|
2165
|
+
* Executor for asynchronous nodes (video-editor, generate-image, workflow).
|
|
2166
|
+
* Uses submit/poll pattern for durable workflows.
|
|
2167
|
+
*/
|
|
2168
|
+
export interface AsyncNodeExecutor<TOutput = unknown> extends Omit<NodeExecutor<TOutput>, 'execute'> {
|
|
2169
|
+
isAsync: true;
|
|
2170
|
+
/** Submit job - returns job ID for polling */
|
|
2171
|
+
submitJob: (ctx: ExecutorContext) => Promise<{
|
|
2172
|
+
jobId: string;
|
|
2173
|
+
}>;
|
|
2174
|
+
/** Check job status - called by orchestrator with workflow sleep between calls */
|
|
2175
|
+
checkStatus: (jobId: string, ctx: ExecutorContext) => Promise<ExecutorAsyncJobStatus<TOutput>>;
|
|
2176
|
+
}
|
|
2177
|
+
/**
|
|
2178
|
+
* Type guard to check if an executor is async
|
|
2179
|
+
*/
|
|
2180
|
+
export declare function isAsyncExecutor<T>(executor: NodeExecutor<T> | AsyncNodeExecutor<T>): executor is AsyncNodeExecutor<T>;
|