ugcinc 4.26.0 → 4.27.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/README.md +220 -0
- package/dist/automations/nodes/create-dm.d.ts +7 -2
- package/dist/automations/nodes/create-dm.js +26 -2
- package/dist/automations/nodes/index.d.ts +6 -3
- package/dist/automations/nodes/remotion-composition.d.ts +6 -6
- package/dist/cli.js +49 -8
- package/dist/content-skills.d.ts +1 -0
- package/dist/content-skills.js +10 -0
- package/dist/imessage-conversation.d.ts +907 -0
- package/dist/imessage-conversation.js +331 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -3
- package/dist/media-analysis.d.ts +272 -272
- package/dist/media.d.ts +11 -0
- package/dist/media.js +12 -0
- package/dist/render/compositions/IMessageDmComposition/types.d.ts +20 -20
- package/dist/render/types/remotion-composition.d.ts +16 -16
- package/dist/skills.js +2 -61
- package/dist/types.d.ts +1 -0
- package/package.json +8 -3
- package/skills/content-automation/SKILL.md +82 -0
- package/skills/content-automation/references/build-review.md +66 -0
- package/skills/media/SKILL.md +83 -0
- package/skills/media/references/tools.md +64 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.iMessageConversationJobSchema = exports.iMessageConversationSchema = exports.IMESSAGE_MAX_REQUEST_BYTES = void 0;
|
|
4
|
+
exports.compileIMessageConversation = compileIMessageConversation;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
exports.IMESSAGE_MAX_REQUEST_BYTES = 16 * 1024 * 1024;
|
|
7
|
+
const avatarPng = zod_1.z.string().max(65536).regex(/^iVBORw0KGgo[A-Za-z0-9+/]*={0,2}$/)
|
|
8
|
+
.refine(value => value.length % 4 === 0, 'Expected a base64 PNG, without a data URL prefix.');
|
|
9
|
+
const attachmentPng = zod_1.z.string().max(8 * 1024 * 1024).regex(/^iVBORw0KGgo[A-Za-z0-9+/]*={0,2}$/)
|
|
10
|
+
.refine(value => value.length % 4 === 0, 'Expected a base64 PNG, without a data URL prefix.');
|
|
11
|
+
const timingFields = {
|
|
12
|
+
charactersPerSecond: zod_1.z.number().finite().min(0.5).max(60),
|
|
13
|
+
pauseBeforeMs: zod_1.z.number().int().min(0).max(30000),
|
|
14
|
+
pauseBeforeSendMs: zod_1.z.number().int().min(0).max(10000),
|
|
15
|
+
punctuationPauseMs: zod_1.z.number().int().min(0).max(2000),
|
|
16
|
+
variation: zod_1.z.number().finite().min(0).max(0.75),
|
|
17
|
+
incomingTypingDurationMs: zod_1.z.number().int().min(0).max(30000),
|
|
18
|
+
keyboardSwitchPauseMs: zod_1.z.number().int().min(350).max(10000),
|
|
19
|
+
emojiSelectionDelayMs: zod_1.z.number().int().min(100).max(10000),
|
|
20
|
+
};
|
|
21
|
+
const timingOverrides = zod_1.z.object(timingFields).partial().strict();
|
|
22
|
+
const displayText = zod_1.z.string().refine(text => !/[\p{Surrogate}\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/u.test(text), 'Text must contain valid, printable Unicode.');
|
|
23
|
+
const reactionSchema = zod_1.z.object({
|
|
24
|
+
actor: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/),
|
|
25
|
+
action: zod_1.z.enum(['set', 'remove']).default('set'),
|
|
26
|
+
reaction: zod_1.z.enum(['love', 'like', 'dislike', 'laugh', 'emphasize', 'question']).optional(),
|
|
27
|
+
emoji: displayText.pipe(zod_1.z.string().min(1).max(32)).optional(),
|
|
28
|
+
delayMs: zod_1.z.number().int().min(0).max(60000).default(700),
|
|
29
|
+
menuDurationMs: zod_1.z.number().int().min(400).max(10000).default(700),
|
|
30
|
+
}).strict().superRefine((value, ctx) => {
|
|
31
|
+
if (value.action === 'set' && (value.reaction === undefined) === (value.emoji === undefined))
|
|
32
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Set requires exactly one classic reaction or emoji.' });
|
|
33
|
+
if (value.action === 'remove' && (value.reaction !== undefined || value.emoji !== undefined))
|
|
34
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Remove identifies the actor, without a reaction value.' });
|
|
35
|
+
if (value.emoji !== undefined && (Array.from(new Intl.Segmenter('und', { granularity: 'grapheme' }).segment(value.emoji)).length !== 1 ||
|
|
36
|
+
!/\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20e3/u.test(value.emoji)))
|
|
37
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['emoji'], message: 'Expected one complete emoji.' });
|
|
38
|
+
});
|
|
39
|
+
const statusBarSchema = zod_1.z.object({
|
|
40
|
+
time: zod_1.z.string().regex(/^(?:[01]?\d|2[0-3]):[0-5]\d$/).default('9:41'),
|
|
41
|
+
wifiBars: zod_1.z.number().int().min(0).max(3).default(3),
|
|
42
|
+
wifiEnabled: zod_1.z.boolean().default(true),
|
|
43
|
+
cellularBars: zod_1.z.number().int().min(0).max(4).default(4),
|
|
44
|
+
cellularEnabled: zod_1.z.boolean().default(true),
|
|
45
|
+
batteryPercent: zod_1.z.number().int().min(0).max(100).default(100),
|
|
46
|
+
charging: zod_1.z.boolean().default(false),
|
|
47
|
+
lowPowerMode: zod_1.z.boolean().default(false),
|
|
48
|
+
}).strict();
|
|
49
|
+
const messageSchema = zod_1.z.object({
|
|
50
|
+
id: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/).optional(),
|
|
51
|
+
sender: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/),
|
|
52
|
+
text: displayText.pipe(zod_1.z.string().min(1).max(2000)).optional(),
|
|
53
|
+
imagePngBase64: attachmentPng.optional(),
|
|
54
|
+
initial: zod_1.z.boolean().default(false),
|
|
55
|
+
showTyping: zod_1.z.boolean().optional(),
|
|
56
|
+
receipt: zod_1.z.enum(['none', 'delivered', 'read']).default('none'),
|
|
57
|
+
readAt: zod_1.z.string().datetime({ offset: true }).optional(),
|
|
58
|
+
receiptDelayMs: zod_1.z.number().int().min(0).max(30000).default(500),
|
|
59
|
+
timing: timingOverrides.optional(),
|
|
60
|
+
replyTo: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/).optional(),
|
|
61
|
+
sentAt: zod_1.z.string().datetime({ offset: true }).optional(),
|
|
62
|
+
timestampText: displayText.pipe(zod_1.z.string().trim().min(1).max(80)).optional(),
|
|
63
|
+
reactions: zod_1.z.array(reactionSchema).max(20).default([]),
|
|
64
|
+
}).strict().superRefine((value, ctx) => {
|
|
65
|
+
if ((value.text === undefined) === (value.imagePngBase64 === undefined))
|
|
66
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Provide exactly one text or imagePngBase64 message body; image captions are not supported.' });
|
|
67
|
+
});
|
|
68
|
+
const outputSchema = zod_1.z.discriminatedUnion('kind', [
|
|
69
|
+
zod_1.z.object({ kind: zod_1.z.literal('video') }).strict(),
|
|
70
|
+
zod_1.z.object({ kind: zod_1.z.literal('png'), atMs: zod_1.z.number().int().min(0).max(120000).optional() }).strict(),
|
|
71
|
+
]);
|
|
72
|
+
/** Native iMessage video or PNG authoring. Typing speed counts visible grapheme clusters. */
|
|
73
|
+
exports.iMessageConversationSchema = zod_1.z.object({
|
|
74
|
+
idempotencyKey: zod_1.z.string().min(1).max(128).optional(),
|
|
75
|
+
profile: zod_1.z.literal('iphone-xs-ios18.6.2').default('iphone-xs-ios18.6.2'),
|
|
76
|
+
contact: zod_1.z.object({
|
|
77
|
+
name: displayText.pipe(zod_1.z.string().trim().min(1).max(80)),
|
|
78
|
+
avatarPngBase64: avatarPng.optional(),
|
|
79
|
+
}).strict().optional(),
|
|
80
|
+
group: zod_1.z.object({
|
|
81
|
+
name: displayText.pipe(zod_1.z.string().trim().min(1).max(80)),
|
|
82
|
+
avatarPngBase64: avatarPng.optional(),
|
|
83
|
+
localParticipantId: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/).default('user'),
|
|
84
|
+
participants: zod_1.z.array(zod_1.z.object({
|
|
85
|
+
id: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/),
|
|
86
|
+
name: displayText.pipe(zod_1.z.string().trim().min(1).max(80)),
|
|
87
|
+
avatarPngBase64: avatarPng.optional(),
|
|
88
|
+
}).strict()).min(3).max(20),
|
|
89
|
+
}).strict().optional(),
|
|
90
|
+
statusBar: statusBarSchema.default({}),
|
|
91
|
+
unreadCount: zod_1.z.number().int().min(0).max(9999).default(0),
|
|
92
|
+
timestampText: displayText.pipe(zod_1.z.string().trim().min(1).max(80)).optional(),
|
|
93
|
+
theme: zod_1.z.enum(['light', 'dark']).default('dark'),
|
|
94
|
+
fps: zod_1.z.literal(60).default(60),
|
|
95
|
+
output: outputSchema.default({ kind: 'video' }),
|
|
96
|
+
keyboard: zod_1.z.boolean().default(true),
|
|
97
|
+
seed: zod_1.z.number().int().min(0).max(4294967295).default(0),
|
|
98
|
+
timing: timingOverrides.default({}),
|
|
99
|
+
showIncomingTyping: zod_1.z.boolean().default(true),
|
|
100
|
+
endHoldMs: zod_1.z.number().int().min(350).max(10000).default(1500),
|
|
101
|
+
messages: zod_1.z.array(messageSchema).min(1).max(30),
|
|
102
|
+
threads: zod_1.z.array(zod_1.z.object({
|
|
103
|
+
messageId: zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,80}$/),
|
|
104
|
+
openAtMs: zod_1.z.number().int().min(0).max(120000),
|
|
105
|
+
durationMs: zod_1.z.number().int().min(600).max(30000),
|
|
106
|
+
}).strict()).max(10).default([]),
|
|
107
|
+
}).strict().superRefine((value, ctx) => {
|
|
108
|
+
if (new TextEncoder().encode(JSON.stringify(value)).byteLength > exports.IMESSAGE_MAX_REQUEST_BYTES)
|
|
109
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Conversation request exceeds the 16 MiB limit.' });
|
|
110
|
+
if (!!value.contact === !!value.group)
|
|
111
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Provide a contact or a group, exclusively.' });
|
|
112
|
+
const localId = value.group?.localParticipantId ?? 'user';
|
|
113
|
+
const participantIds = new Set(value.group?.participants.map(person => person.id) ?? ['user', 'recipient']);
|
|
114
|
+
if (value.group && (participantIds.size !== value.group.participants.length || !participantIds.has(localId)))
|
|
115
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['group'], message: 'Group participants need unique IDs and must include the local participant.' });
|
|
116
|
+
let animated = false;
|
|
117
|
+
const ids = new Set();
|
|
118
|
+
const usesSentAt = value.messages.some(message => message.sentAt !== undefined);
|
|
119
|
+
let previousSentAt = -Infinity;
|
|
120
|
+
value.messages.forEach((message, index) => {
|
|
121
|
+
const isLocal = message.sender === localId;
|
|
122
|
+
if (!participantIds.has(message.sender))
|
|
123
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'sender'], message: 'Unknown participant ID.' });
|
|
124
|
+
if (isLocal && !message.initial && !value.keyboard && /\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20e3/u.test(message.text ?? ''))
|
|
125
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['keyboard'], message: 'Outgoing emoji selection requires the visible native keyboard.' });
|
|
126
|
+
if (isLocal && !message.initial && message.replyTo !== undefined && !value.keyboard)
|
|
127
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['keyboard'], message: 'Outgoing reply interaction requires the visible native keyboard.' });
|
|
128
|
+
const id = message.id ?? `message-${index + 1}`;
|
|
129
|
+
if (message.replyTo !== undefined && !ids.has(message.replyTo))
|
|
130
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'replyTo'], message: 'Reply target must identify an earlier message.' });
|
|
131
|
+
if (ids.has(id))
|
|
132
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'id'], message: 'Message IDs must be unique.' });
|
|
133
|
+
ids.add(id);
|
|
134
|
+
if (usesSentAt && message.sentAt === undefined)
|
|
135
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'sentAt'], message: 'Provide sentAt for every message when setting conversation dates.' });
|
|
136
|
+
if (message.sentAt !== undefined) {
|
|
137
|
+
const sentAt = Date.parse(message.sentAt);
|
|
138
|
+
if (sentAt < previousSentAt)
|
|
139
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'sentAt'], message: 'Message dates must be chronological.' });
|
|
140
|
+
previousSentAt = sentAt;
|
|
141
|
+
}
|
|
142
|
+
if (!message.initial)
|
|
143
|
+
animated = true;
|
|
144
|
+
else if (animated)
|
|
145
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'initial'], message: 'Initial history must precede animated messages.' });
|
|
146
|
+
if (isLocal && message.showTyping !== undefined)
|
|
147
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'showTyping'], message: 'showTyping controls incoming indicators; outgoing text is shown in the composer.' });
|
|
148
|
+
if (isLocal && message.timing?.incomingTypingDurationMs !== undefined)
|
|
149
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'timing', 'incomingTypingDurationMs'], message: 'incomingTypingDurationMs controls remote participants; outgoing composer speed uses charactersPerSecond.' });
|
|
150
|
+
if (!isLocal && message.receipt !== 'none')
|
|
151
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'receipt'], message: 'Receipts belong to outgoing messages.' });
|
|
152
|
+
if ((message.receipt === 'read') !== (message.readAt !== undefined))
|
|
153
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'readAt'], message: 'A read receipt requires readAt; other states do not accept readAt.' });
|
|
154
|
+
const active = new Set();
|
|
155
|
+
for (const reaction of [...message.reactions].sort((a, b) => a.delayMs - b.delayMs)) {
|
|
156
|
+
if (reaction.actor === localId && reaction.emoji !== undefined)
|
|
157
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'reactions'], message: 'Local reactions currently support the six classic picker options; custom emoji reactions are supported for remote participants.' });
|
|
158
|
+
if (!participantIds.has(reaction.actor))
|
|
159
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'reactions'], message: 'Unknown reaction participant.' });
|
|
160
|
+
if (reaction.action === 'set')
|
|
161
|
+
active.add(reaction.actor);
|
|
162
|
+
else if (!active.delete(reaction.actor))
|
|
163
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['messages', index, 'reactions'], message: 'Cannot remove an actor’s reaction before it is set.' });
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
let closesAt = -1;
|
|
167
|
+
for (const thread of [...value.threads].sort((a, b) => a.openAtMs - b.openAtMs)) {
|
|
168
|
+
if (!ids.has(thread.messageId))
|
|
169
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['threads'], message: 'Thread target must identify a message.' });
|
|
170
|
+
if (thread.openAtMs < closesAt)
|
|
171
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['threads'], message: 'Thread views cannot overlap.' });
|
|
172
|
+
closesAt = thread.openAtMs + thread.durationMs;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
const defaults = { charactersPerSecond: 8, pauseBeforeMs: 450, pauseBeforeSendMs: 180, punctuationPauseMs: 160, variation: 0.15 };
|
|
176
|
+
/** Compile high-level pacing to explicit, reproducible native events. No network calls. */
|
|
177
|
+
function compileIMessageConversation(input) {
|
|
178
|
+
const value = exports.iMessageConversationSchema.parse(input);
|
|
179
|
+
const localId = value.group?.localParticipantId ?? 'user';
|
|
180
|
+
const segmenter = new Intl.Segmenter('und', { granularity: 'grapheme' });
|
|
181
|
+
let randomState = value.seed;
|
|
182
|
+
function random() {
|
|
183
|
+
randomState = (randomState + 0x6D2B79F5) >>> 0;
|
|
184
|
+
let t = randomState;
|
|
185
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
186
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
187
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
188
|
+
}
|
|
189
|
+
const messages = value.messages.map((m, i) => ({ id: m.id ?? `message-${i + 1}`, sender: m.sender, text: m.text ?? '', imagePngBase64: m.imagePngBase64, initial: m.initial, receipt: m.receipt, readAt: m.readAt, replyTo: m.replyTo, sentAt: m.sentAt, timestampText: m.timestampText }));
|
|
190
|
+
const events = [];
|
|
191
|
+
const schedule = [];
|
|
192
|
+
let cursor = 0;
|
|
193
|
+
let totalCharacters = 0;
|
|
194
|
+
let keyboardMode = 'letters';
|
|
195
|
+
value.messages.forEach((message, index) => {
|
|
196
|
+
const isLocal = message.sender === localId;
|
|
197
|
+
const resolved = messages[index];
|
|
198
|
+
if (!resolved)
|
|
199
|
+
throw new Error('Invalid message index.');
|
|
200
|
+
const addReactions = (arrivalMs) => {
|
|
201
|
+
for (const reaction of [...message.reactions].sort((a, b) => a.delayMs - b.delayMs)) {
|
|
202
|
+
let atMs = arrivalMs + reaction.delayMs;
|
|
203
|
+
if (reaction.actor === localId) {
|
|
204
|
+
// Local actions consume the same user's interaction timeline: open
|
|
205
|
+
// the real picker, choose an item, finish dismissal, then type again.
|
|
206
|
+
const opensAt = Math.max(atMs, cursor, arrivalMs + (message.initial ? 0 : 600));
|
|
207
|
+
events.push({ type: 'picker.open', atMs: opensAt, messageId: resolved.id });
|
|
208
|
+
atMs = opensAt + reaction.menuDurationMs;
|
|
209
|
+
cursor = atMs + 600;
|
|
210
|
+
}
|
|
211
|
+
events.push({ type: reaction.action === 'set' ? 'reaction.set' : 'reaction.remove',
|
|
212
|
+
atMs, messageId: resolved.id, actor: reaction.actor, reaction: reaction.reaction, emoji: reaction.emoji });
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
if (message.initial) {
|
|
216
|
+
addReactions(0);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const timing = {
|
|
220
|
+
charactersPerSecond: message.timing?.charactersPerSecond ?? value.timing.charactersPerSecond ?? defaults.charactersPerSecond,
|
|
221
|
+
pauseBeforeMs: message.timing?.pauseBeforeMs ?? value.timing.pauseBeforeMs ?? defaults.pauseBeforeMs,
|
|
222
|
+
pauseBeforeSendMs: message.timing?.pauseBeforeSendMs ?? value.timing.pauseBeforeSendMs ?? defaults.pauseBeforeSendMs,
|
|
223
|
+
punctuationPauseMs: message.timing?.punctuationPauseMs ?? value.timing.punctuationPauseMs ?? defaults.punctuationPauseMs,
|
|
224
|
+
variation: message.timing?.variation ?? value.timing.variation ?? defaults.variation,
|
|
225
|
+
incomingTypingDurationMs: message.timing?.incomingTypingDurationMs ?? value.timing.incomingTypingDurationMs,
|
|
226
|
+
keyboardSwitchPauseMs: message.timing?.keyboardSwitchPauseMs ?? value.timing.keyboardSwitchPauseMs ?? 450,
|
|
227
|
+
emojiSelectionDelayMs: message.timing?.emojiSelectionDelayMs ?? value.timing.emojiSelectionDelayMs ?? 350,
|
|
228
|
+
};
|
|
229
|
+
const clusters = Array.from(segmenter.segment(message.text ?? ''), part => part.segment);
|
|
230
|
+
totalCharacters += clusters.length;
|
|
231
|
+
if (totalCharacters > 6000)
|
|
232
|
+
throw new Error('Conversation exceeds 6000 animated visible characters.');
|
|
233
|
+
cursor += timing.pauseBeforeMs;
|
|
234
|
+
const localReply = isLocal && message.replyTo !== undefined;
|
|
235
|
+
if (isLocal && message.replyTo !== undefined) {
|
|
236
|
+
events.push({ type: 'reply.begin', atMs: cursor, messageId: message.replyTo });
|
|
237
|
+
// Long press, native menu selection, and reply-pane presentation finish before typing.
|
|
238
|
+
cursor += 1400;
|
|
239
|
+
}
|
|
240
|
+
const typingStartMs = cursor;
|
|
241
|
+
if (isLocal && message.imagePngBase64 !== undefined) {
|
|
242
|
+
events.push({ type: 'composer.attach', atMs: cursor, messageId: resolved.id });
|
|
243
|
+
cursor += 1000;
|
|
244
|
+
}
|
|
245
|
+
else if (isLocal)
|
|
246
|
+
events.push({ type: 'composer.set', atMs: cursor, text: '' });
|
|
247
|
+
else if (message.showTyping ?? value.showIncomingTyping)
|
|
248
|
+
events.push({ type: 'typing.start', atMs: cursor, messageId: resolved.id });
|
|
249
|
+
let prefix = '';
|
|
250
|
+
for (const cluster of clusters) {
|
|
251
|
+
const emoji = /\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20e3/u.test(cluster);
|
|
252
|
+
if (isLocal) {
|
|
253
|
+
const mode = emoji ? 'emoji' : 'letters';
|
|
254
|
+
if (mode !== keyboardMode) {
|
|
255
|
+
events.push({ type: 'keyboard.mode', atMs: cursor, mode });
|
|
256
|
+
cursor += timing.keyboardSwitchPauseMs;
|
|
257
|
+
keyboardMode = mode;
|
|
258
|
+
}
|
|
259
|
+
if (emoji) {
|
|
260
|
+
events.push({ type: 'emoji.focus', atMs: cursor, emoji: cluster });
|
|
261
|
+
cursor += timing.emojiSelectionDelayMs;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const delay = 1000 / timing.charactersPerSecond * (1 + (random() * 2 - 1) * timing.variation);
|
|
265
|
+
cursor += Math.max(1, Math.round(delay));
|
|
266
|
+
prefix += cluster;
|
|
267
|
+
if (isLocal)
|
|
268
|
+
events.push(emoji ? { type: 'emoji.select', atMs: cursor, emoji: cluster, text: prefix } : { type: 'composer.set', atMs: cursor, text: prefix });
|
|
269
|
+
if (isLocal && emoji)
|
|
270
|
+
cursor += 120;
|
|
271
|
+
if (/[.!?,;:\n]/u.test(cluster))
|
|
272
|
+
cursor += timing.punctuationPauseMs;
|
|
273
|
+
}
|
|
274
|
+
cursor += timing.pauseBeforeSendMs;
|
|
275
|
+
// Explicit incoming duration covers the complete indicator-to-arrival
|
|
276
|
+
// window, independently of outgoing composer speed and punctuation delays.
|
|
277
|
+
if (!isLocal && timing.incomingTypingDurationMs !== undefined) {
|
|
278
|
+
cursor = typingStartMs + timing.incomingTypingDurationMs;
|
|
279
|
+
}
|
|
280
|
+
events.push({ type: isLocal ? 'message.send' : 'message.receive', atMs: cursor, messageId: resolved.id });
|
|
281
|
+
if (message.receipt !== 'none')
|
|
282
|
+
events.push({ type: 'receipt.show', atMs: cursor + message.receiptDelayMs, messageId: resolved.id });
|
|
283
|
+
schedule.push({ messageId: resolved.id, typingStartMs, arrivalMs: cursor, visibleCharacters: clusters.length });
|
|
284
|
+
const arrivalMs = cursor;
|
|
285
|
+
if (localReply) {
|
|
286
|
+
cursor += 600;
|
|
287
|
+
events.push({ type: 'reply.end', atMs: cursor });
|
|
288
|
+
cursor += 600;
|
|
289
|
+
}
|
|
290
|
+
addReactions(arrivalMs);
|
|
291
|
+
// Reserve the pinned native transition before starting the next message.
|
|
292
|
+
// Local replies already reserve their send and dismissal transitions above.
|
|
293
|
+
if (!localReply)
|
|
294
|
+
cursor += isLocal ? 350 : 300;
|
|
295
|
+
});
|
|
296
|
+
const settledAt = Math.max(cursor, ...events.map(event => event.atMs + 600));
|
|
297
|
+
for (const thread of value.threads) {
|
|
298
|
+
if (thread.openAtMs < settledAt)
|
|
299
|
+
throw new Error('Thread views must open after conversation events and native transitions finish.');
|
|
300
|
+
events.push({ type: 'thread.open', atMs: thread.openAtMs, messageId: thread.messageId }, { type: 'thread.close', atMs: thread.openAtMs + thread.durationMs });
|
|
301
|
+
}
|
|
302
|
+
if (events.length > 6100)
|
|
303
|
+
throw new Error('Conversation exceeds the 6100 event limit.');
|
|
304
|
+
events.sort((a, b) => a.atMs - b.atMs);
|
|
305
|
+
const durationMs = Math.max(cursor, events.at(-1)?.atMs ?? 0) + value.endHoldMs;
|
|
306
|
+
if (durationMs > 120000)
|
|
307
|
+
throw new Error('Conversation exceeds the 120 second render limit; shorten it or increase typing speed.');
|
|
308
|
+
const output = value.output.kind === 'png'
|
|
309
|
+
? { kind: 'png', atMs: value.output.atMs ?? durationMs }
|
|
310
|
+
: { kind: 'video' };
|
|
311
|
+
if (output.kind === 'png' && output.atMs > durationMs)
|
|
312
|
+
throw new Error('PNG snapshot time exceeds the conversation duration.');
|
|
313
|
+
const contact = value.contact ?? { name: value.group?.name ?? '' };
|
|
314
|
+
return { version: 1, profile: value.profile, contact, group: value.group, theme: value.theme,
|
|
315
|
+
statusBar: value.statusBar, unreadCount: value.unreadCount, timestampText: value.timestampText,
|
|
316
|
+
fps: value.fps, output, keyboard: value.keyboard, messages, events, schedule,
|
|
317
|
+
durationMs, durationInFrames: Math.ceil(durationMs * value.fps / 1000) + 1 };
|
|
318
|
+
}
|
|
319
|
+
exports.iMessageConversationJobSchema = zod_1.z.object({
|
|
320
|
+
jobId: zod_1.z.string().uuid(),
|
|
321
|
+
status: zod_1.z.enum(['pending', 'processing', 'completed', 'failed', 'cancelled']),
|
|
322
|
+
cancelRequested: zod_1.z.boolean().optional(),
|
|
323
|
+
progress: zod_1.z.number().min(0).max(100),
|
|
324
|
+
fps: zod_1.z.literal(60),
|
|
325
|
+
output: outputSchema.optional(),
|
|
326
|
+
contentType: zod_1.z.enum(['image/png', 'video/mp4']).optional(),
|
|
327
|
+
durationInFrames: zod_1.z.number().int().positive(),
|
|
328
|
+
durationMs: zod_1.z.number().int().positive(),
|
|
329
|
+
url: zod_1.z.string().url().optional(),
|
|
330
|
+
error: zod_1.z.object({ code: zod_1.z.string(), message: zod_1.z.string(), retryable: zod_1.z.boolean() }).optional(),
|
|
331
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export { AutomationsClient } from './automations';
|
|
|
13
13
|
export { MediaClient } from './media';
|
|
14
14
|
export { CommentsClient } from './comments';
|
|
15
15
|
export { BillingClient } from './billing';
|
|
16
|
+
export { iMessageConversationSchema, compileIMessageConversation, iMessageConversationJobSchema } from './imessage-conversation';
|
|
17
|
+
export type { IMessageConversationInput, IMessageConversationSettings, IMessageTiming, IMessageConversationEvent, IMessageConversationPlan, IMessageConversationJob } from './imessage-conversation';
|
|
16
18
|
export { submitImageRenderJob, submitVideoRenderJob, getRenderJobStatus, submitDeduplicationJob, submitSceneSplitJob, submitScreenshotAnimationRenderJob, submitRemotionCompositionRenderJob, submitNativeTextStickerRenderJob, nativeTextStickerSchema, submitAutoCaptionRenderJob, submitInstagramDmRenderJob, submitIMessageDmRenderJob, } from './render';
|
|
17
19
|
export { remotionCompositionSchema, remotionCompositionNodeSchema, remotionCompositionPortSchema, REMOTION_COMPOSITION_IMPORTS, parseRemotionPropsJson } from './render/types/remotion-composition';
|
|
18
20
|
export type { RemotionCompositionInput } from './render/types/remotion-composition';
|
package/dist/index.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* Official TypeScript/JavaScript client for the UGC Inc API
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
9
|
-
exports.
|
|
10
|
-
exports.mediaAnalysisResultSchema = exports.mediaAnalysisStatusSchema = exports.detectScenesSchema = exports.extractFramesSchema = exports.videoTextResultSchema = exports.imageTextResultSchema = exports.readVideoTextSchema = exports.readImageTextSchema = exports.audioLevelsResultSchema = exports.audioTranscriptResultSchema = exports.measureAudioLevelsSchema = exports.transcribeAudioSchema = exports.binaryMaskSchema = exports.measureLayoutResultSchema = exports.sampleColorsResultSchema = exports.measureLayoutSchema = exports.sampleColorsSchema = exports.matchTextStyleResultSchema = exports.matchTextStyleSchema = exports.prepareVideoComposerInput = exports.formatDateTag = exports.outputFieldsToZod = exports.outputFieldToZod = exports.LLMProviders = exports.applyLogicOperator = exports.IfLogicOperators = exports.resolvePath = exports.indexExpressionToString = exports.indexExpressionToIndexes = exports.resolveUnknownPath = exports.getOutputTypeFromCategory = exports.parseOpenAPIOutputPath = exports.parseOpenAPIInputs = void 0;
|
|
8
|
+
exports.getNodesDownstreamOfSet = exports.getDownstreamNodes = 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.parseRemotionPropsJson = exports.REMOTION_COMPOSITION_IMPORTS = exports.remotionCompositionPortSchema = exports.remotionCompositionNodeSchema = exports.remotionCompositionSchema = exports.submitIMessageDmRenderJob = exports.submitInstagramDmRenderJob = exports.submitAutoCaptionRenderJob = exports.nativeTextStickerSchema = exports.submitNativeTextStickerRenderJob = exports.submitRemotionCompositionRenderJob = exports.submitScreenshotAnimationRenderJob = exports.submitSceneSplitJob = exports.submitDeduplicationJob = exports.getRenderJobStatus = exports.submitVideoRenderJob = exports.submitImageRenderJob = exports.iMessageConversationJobSchema = exports.compileIMessageConversation = exports.iMessageConversationSchema = exports.BillingClient = exports.CommentsClient = exports.MediaClient = exports.AutomationsClient = exports.OrganizationClient = exports.StatsClient = exports.PostsClient = exports.TasksClient = exports.AccountsClient = exports.UGCClient = void 0;
|
|
9
|
+
exports.prepareImageComposerInput = exports.substituteVariables = 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.getAvailableInputModes = exports.hasReferenceVariant = exports.getReferenceModelId = exports.hasFirstLastFrameVariant = exports.getFirstLastFrameModelId = exports.hasImageToVideoVariant = exports.getImageToVideoModelId = exports.isImageToVideoModel = exports.IMAGE_ASPECT_RATIOS = exports.ALL_IMAGE_MODELS = exports.getEditModelId = exports.isEditModel = exports.getCapturedSourceNodeTypes = exports.getFlowControlNodeTypes = exports.getAllNodeDefinitions = 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.getCapturedNodes = void 0;
|
|
10
|
+
exports.mediaAnalysisResultSchema = exports.mediaAnalysisStatusSchema = exports.detectScenesSchema = exports.extractFramesSchema = exports.videoTextResultSchema = exports.imageTextResultSchema = exports.readVideoTextSchema = exports.readImageTextSchema = exports.audioLevelsResultSchema = exports.audioTranscriptResultSchema = exports.measureAudioLevelsSchema = exports.transcribeAudioSchema = exports.binaryMaskSchema = exports.measureLayoutResultSchema = exports.sampleColorsResultSchema = exports.measureLayoutSchema = exports.sampleColorsSchema = exports.matchTextStyleResultSchema = exports.matchTextStyleSchema = exports.prepareVideoComposerInput = exports.formatDateTag = exports.outputFieldsToZod = exports.outputFieldToZod = exports.LLMProviders = exports.applyLogicOperator = exports.IfLogicOperators = exports.resolvePath = exports.indexExpressionToString = exports.indexExpressionToIndexes = exports.resolveUnknownPath = exports.getOutputTypeFromCategory = exports.parseOpenAPIOutputPath = exports.parseOpenAPIInputs = exports.mapOpenAPIType = exports.nodeConfigToCaptionStyle = exports.HttpMethods = void 0;
|
|
11
11
|
// =============================================================================
|
|
12
12
|
// Client Exports
|
|
13
13
|
// =============================================================================
|
|
@@ -31,6 +31,10 @@ var comments_1 = require("./comments");
|
|
|
31
31
|
Object.defineProperty(exports, "CommentsClient", { enumerable: true, get: function () { return comments_1.CommentsClient; } });
|
|
32
32
|
var billing_1 = require("./billing");
|
|
33
33
|
Object.defineProperty(exports, "BillingClient", { enumerable: true, get: function () { return billing_1.BillingClient; } });
|
|
34
|
+
var imessage_conversation_1 = require("./imessage-conversation");
|
|
35
|
+
Object.defineProperty(exports, "iMessageConversationSchema", { enumerable: true, get: function () { return imessage_conversation_1.iMessageConversationSchema; } });
|
|
36
|
+
Object.defineProperty(exports, "compileIMessageConversation", { enumerable: true, get: function () { return imessage_conversation_1.compileIMessageConversation; } });
|
|
37
|
+
Object.defineProperty(exports, "iMessageConversationJobSchema", { enumerable: true, get: function () { return imessage_conversation_1.iMessageConversationJobSchema; } });
|
|
34
38
|
// Render functions
|
|
35
39
|
var render_1 = require("./render");
|
|
36
40
|
Object.defineProperty(exports, "submitImageRenderJob", { enumerable: true, get: function () { return render_1.submitImageRenderJob; } });
|