samsar-js 0.48.33 → 0.48.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -115,6 +115,20 @@ await samsar.createVideoFromImageList({
115
115
  ],
116
116
  });
117
117
 
118
+ // Create a video and generate the outro with a center logo/CTA image instead of a QR code
119
+ await samsar.createVideoFromImageList({
120
+ image_urls: ['https://example.com/a.jpg', 'https://example.com/b.jpg'],
121
+ prompt: 'Product launch teaser with a branded CTA outro',
122
+ video_model: 'RUNWAYML',
123
+ aspect_ratio: '9:16',
124
+ generate_outro_image: true,
125
+ outro_cta_image: {
126
+ top_text: 'Shop the drop',
127
+ middle_image: { url: 'https://cdn.example.com/drop-logo.png' },
128
+ bottom_text: 'Limited availability',
129
+ },
130
+ });
131
+
118
132
  // Create the same generated QR outro and per-scene footer CTAs from one CTA link
119
133
  await samsar.createVideoFromImageList({
120
134
  image_urls: [
@@ -154,6 +168,20 @@ await samsar.updateVideoOutroImage(
154
168
  { webhookUrl: 'https://example.com/webhook' },
155
169
  );
156
170
 
171
+ // Update an existing outro by generating a new CTA outro with a center logo/CTA image
172
+ await samsar.updateVideoOutroImage(
173
+ {
174
+ videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
175
+ generate_outro_image: true,
176
+ outro_cta_image: {
177
+ top_text: 'Shop the drop',
178
+ middle_image: { url: 'https://cdn.example.com/drop-logo.png' },
179
+ bottom_text: 'Limited availability',
180
+ },
181
+ },
182
+ { webhookUrl: 'https://example.com/webhook' },
183
+ );
184
+
157
185
  // Update the footer CTA on an existing video session
158
186
  await samsar.updateVideoFooterImage(
159
187
  {
@@ -497,13 +525,15 @@ const externalRender = await platform.createExternalVideoFromText(externalUser,
497
525
  enable_subtitles: true,
498
526
  });
499
527
 
500
- // Update an external user's existing outro by generating a new QR CTA outro
528
+ // Update an external user's existing outro by generating a center logo/CTA image outro
501
529
  const externalOutroUpdate = await platform.updateExternalVideoOutroImage(externalUser, {
502
530
  request_id: externalRender.data.request_id,
503
531
  generate_outro_image: true,
504
- cta_url: 'https://example.com/shop',
505
- cta_text_top: 'Scan to shop',
506
- cta_text_bottom: 'Limited drop',
532
+ outro_cta_image: {
533
+ top_text: 'Shop the drop',
534
+ middle_image: { url: 'https://cdn.example.com/drop-logo.png' },
535
+ bottom_text: 'Limited availability',
536
+ },
507
537
  add_outro_animation: true,
508
538
  });
509
539
  console.log(externalOutroUpdate.data.request_id);
@@ -583,15 +613,16 @@ console.log(externalLibrary.data.requests.map((request) => request.request_id));
583
613
  Video model support notes:
584
614
  - `createVideoFromText` image model keys include: `GPTIMAGE2`, `IMAGEN4`, `SEEDREAM`, `NANOBANANA2`, `NANOBANANAPRO`, `CUSTOM_TEXT_TO_IMAGE`.
585
615
  - `createVideoFromText` supports these video models: `RUNWAYML`, `VEO3.1I2V`, `VEO3.1I2VFAST`, `COSMOS3SUPERI2V`, `SEEDANCEI2V` (Seedance 1.5), `KLINGIMGTOVID3PRO`, and `HAPPYHORSEI2V`.
586
- - `createVideoFromText` accepts either a provided outro (`outro_image_url`) or server-generated QR outro (`generate_outro_image: true` with `cta_url`). It can also render bottom CTA footer QR cards with `add_footer_animation` and `footer_metadata`; one footer item applies to every generated scene, while multiple items map by scene index.
616
+ - `createVideoFromText` accepts either a provided outro (`outro_image_url`) or a server-generated CTA outro (`generate_outro_image: true` with `cta_url` for a QR center image, or `outro_cta_image` for a supplied center logo/CTA image). It can also render bottom CTA footer QR cards with `add_footer_animation` and `footer_metadata`; one footer item applies to every generated scene, while multiple items map by scene index.
587
617
  - `createVideoFromImageList` supports `RUNWAYML`, `VEO3.1I2V`, `VEO3.1I2VFAST`, `COSMOS3SUPERI2V`, `SEEDANCEI2V`, `KLINGIMGTOVID3PRO`, and `HAPPYHORSEI2V` via `video_model`; if omitted, it defaults to `RUNWAYML`. It also accepts the same `image_model` keys as text-to-video. Use `aspect_ratio: '16:9'` or `'9:16'`; omitted or invalid values fall back to `16:9`.
588
618
  - Text and image-list video creation both accept optional `backingtrack_model` / `backing_track_model` / `backingTrackModel` / `music_provider` / `musicProvider`, `tts_model` / `ttsModel` / `tts_provider` / `ttsProvider`, `speakerOptions` / `speaker_options`, and `inference_model` / `inferenceModel`. The adapter normalizes these to `backingtrack_model`, `tts_model`, `speakerOptions`, and `inference_model` in the request payload. Omit `inference_model` to use the account default; supported request values are `gpt-5.5` and `gemini-3.1-pro`. When `tts_model` is set, Samsar limits assignment to the matching speaker list (`openAISpeakers`, `elevenLabsSpeakers`, or `googleSpeakers`; Google TTS requests should include `googleSpeakerDetails`).
589
619
  - `video_model_sub_type` is no longer used by the API and is stripped from text and image-list payloads before sending.
590
- - `createVideoFromImageList` accepts either a provided outro (`outro_image_url`) or server-generated QR outro (`generate_outro_image: true` with `cta_url`). Do not combine the two modes in a single request.
620
+ - `createVideoFromImageList` accepts either a provided outro (`outro_image_url`) or a server-generated CTA outro (`generate_outro_image: true` with `cta_url` for a QR center image, or `outro_cta_image` for a supplied center logo/CTA image). Do not combine the two modes in a single request.
621
+ - `outro_cta_image` uses the structured shape `{ top_text, middle_image, bottom_text }`. `middle_image` accepts a public image URL (`{ url }`, `{ image_url }`) or image data (`{ data_url }`, `{ image_data, mime_type }`) and is resized into the same center area used by QR outros without changing aspect ratio.
591
622
  - `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
592
623
  - `createVideoFromImageList` can also generate QR outro CTA text and each scene footer CTA from a single link by setting `express_cta_generation: true` with `cta_url`. CamelCase `expressCtaGeneration` and compatibility aliases `auto_generate_cta_text` / `generate_cta_texts` are normalized to the same API field.
593
624
  - `createVideoFromImageList` accepts `limit_single_narrator: true` to keep all narration under one narrator identity. `add_narrator_avatar: true` automatically enables `limit_single_narrator`, generates an influencer-style human narrator avatar, and overlays it bottom-center or centered in the footer row when footer metadata is present.
594
- - `updateVideoOutroImage` accepts either a replacement outro image URL (`outro_image_url`, `outroImageUrl`, `new_outro_image_url`) or a generated QR CTA outro (`generate_outro_image: true` with `cta_url`, or just `cta_url` when no outro image URL is supplied). Generated outro updates reuse the existing session image layers for tiling and only queue frame/video regeneration.
625
+ - `updateVideoOutroImage` accepts either a replacement outro image URL (`outro_image_url`, `outroImageUrl`, `new_outro_image_url`) or a generated CTA outro (`generate_outro_image: true` with `cta_url` or `outro_cta_image`, or just `cta_url` / `outro_cta_image` when no outro image URL is supplied). Generated outro updates reuse the existing session image layers for tiling and only queue frame/video regeneration.
595
626
  - `updateVideoFooterImage` updates the footer CTA on a cloned session with `cta_text`, `cta_logo`, and/or `cta_url`, or removes all scene footers with `remove_footer: true`. Footer updates queue only frame/video regeneration.
596
627
  - `cloneVideo` creates a deep copy of a completed session and queues only the final video render so the clone receives a new rendered video path and URL. It does not charge credits.
597
628
  - Main video methods and external-user methods accept the same generated outro and footer parameters. The API can resolve either internal session ids or external `extreq_...` ids on repeated video routes, so client code can keep using `translateVideo`, `joinVideos`, `addSubtitles`, `removeSubtitles`, `addVideoOutroImage`, `updateVideoOutroImage`, and `updateVideoFooterImage`; the explicit external variants are available when you want to call `/external_users/*` directly. Do not strip the `extreq_` prefix.
package/dist/index.d.ts CHANGED
@@ -66,6 +66,53 @@ export interface TTSSpeakerOptions {
66
66
  googleSpeakerDetails?: GoogleTTSSpeakerDetail[];
67
67
  [key: string]: unknown;
68
68
  }
69
+ export type OutroCtaImageSource = string | {
70
+ url?: string;
71
+ image_url?: string;
72
+ imageUrl?: string;
73
+ public_url?: string;
74
+ publicUrl?: string;
75
+ source_url?: string;
76
+ sourceUrl?: string;
77
+ source?: string;
78
+ src?: string;
79
+ image?: string;
80
+ data_url?: string;
81
+ dataUrl?: string;
82
+ image_data?: string;
83
+ imageData?: string;
84
+ data?: string;
85
+ mime_type?: string;
86
+ mimeType?: string;
87
+ content_type?: string;
88
+ contentType?: string;
89
+ [key: string]: unknown;
90
+ };
91
+ export interface OutroCtaImagePayload {
92
+ top_text?: string;
93
+ topText?: string;
94
+ cta_text_top?: string;
95
+ ctaTextTop?: string;
96
+ middle_image?: OutroCtaImageSource;
97
+ middleImage?: OutroCtaImageSource;
98
+ center_image?: OutroCtaImageSource;
99
+ centerImage?: OutroCtaImageSource;
100
+ middle?: OutroCtaImageSource;
101
+ center?: OutroCtaImageSource;
102
+ bottom_text?: string;
103
+ bottomText?: string;
104
+ cta_text_bottom?: string;
105
+ ctaTextBottom?: string;
106
+ url?: string;
107
+ image_url?: string;
108
+ imageUrl?: string;
109
+ src?: string;
110
+ data_url?: string;
111
+ dataUrl?: string;
112
+ image_data?: string;
113
+ imageData?: string;
114
+ [key: string]: unknown;
115
+ }
69
116
  export type V2StepGenerationMode = 'one_step' | 'two_step';
70
117
  export interface V2StepGenerationOptions {
71
118
  auto_render_full_video?: boolean;
@@ -127,6 +174,10 @@ export interface CreateVideoFromTextInput extends V2StepGenerationOptions {
127
174
  ctaTextBottom?: string;
128
175
  cta_logo?: string;
129
176
  ctaLogo?: string;
177
+ outro_cta_image?: OutroCtaImagePayload | string;
178
+ outroCtaImage?: OutroCtaImagePayload | string;
179
+ cta_image?: OutroCtaImagePayload | string;
180
+ ctaImage?: OutroCtaImagePayload | string;
130
181
  add_footer_animation?: boolean;
131
182
  addFooterAnimation?: boolean;
132
183
  footer_metadata?: FooterMetadataItem[];
@@ -248,6 +299,10 @@ export interface CreateVideoFromImageListInput extends V2StepGenerationOptions {
248
299
  ctaTextBottom?: string;
249
300
  cta_logo?: string;
250
301
  ctaLogo?: string;
302
+ outro_cta_image?: OutroCtaImagePayload | string;
303
+ outroCtaImage?: OutroCtaImagePayload | string;
304
+ cta_image?: OutroCtaImagePayload | string;
305
+ ctaImage?: OutroCtaImagePayload | string;
251
306
  add_footer_animation?: boolean;
252
307
  addFooterAnimation?: boolean;
253
308
  footer_metadata?: FooterMetadataItem[];
@@ -374,6 +429,10 @@ export interface UpdateVideoOutroImageInput {
374
429
  ctaTextBottom?: string;
375
430
  cta_logo?: string;
376
431
  ctaLogo?: string;
432
+ outro_cta_image?: OutroCtaImagePayload | string;
433
+ outroCtaImage?: OutroCtaImagePayload | string;
434
+ cta_image?: OutroCtaImagePayload | string;
435
+ ctaImage?: OutroCtaImagePayload | string;
377
436
  [key: string]: unknown;
378
437
  }
379
438
  export interface UpdateVideoOutroImageResponse {
@@ -444,6 +503,20 @@ export interface AddVideoOutroImageInput {
444
503
  outro_focus_area?: OutroFocusArea | null;
445
504
  outroFocustArea?: OutroFocusArea | null;
446
505
  outroFocusArea?: OutroFocusArea | null;
506
+ generate_outro_image?: boolean;
507
+ generateOutroImage?: boolean;
508
+ cta_url?: string;
509
+ ctaUrl?: string;
510
+ cta_text_top?: string;
511
+ ctaTextTop?: string;
512
+ cta_text_bottom?: string;
513
+ ctaTextBottom?: string;
514
+ cta_logo?: string;
515
+ ctaLogo?: string;
516
+ outro_cta_image?: OutroCtaImagePayload | string;
517
+ outroCtaImage?: OutroCtaImagePayload | string;
518
+ cta_image?: OutroCtaImagePayload | string;
519
+ ctaImage?: OutroCtaImagePayload | string;
447
520
  [key: string]: unknown;
448
521
  }
449
522
  export interface AddVideoOutroImageResponse {
package/dist/index.js CHANGED
@@ -41,6 +41,58 @@ function assertOptionalBoolean(value, fieldName, context = 'createVideoFromImage
41
41
  throw new Error(`${fieldName} must be a boolean for ${context}`);
42
42
  }
43
43
  }
44
+ function hasOutroCtaImageSource(value) {
45
+ if (typeof value === 'string') {
46
+ return Boolean(value.trim());
47
+ }
48
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
49
+ return false;
50
+ }
51
+ const record = value;
52
+ const middleImage = getFirstDefinedInputValue(record, [
53
+ 'middle_image',
54
+ 'middleImage',
55
+ 'center_image',
56
+ 'centerImage',
57
+ 'middle',
58
+ 'center',
59
+ ]);
60
+ if (middleImage !== undefined) {
61
+ return hasOutroCtaImageSource(middleImage);
62
+ }
63
+ return Boolean(getTrimmedString(record.url) ??
64
+ getTrimmedString(record.image_url) ??
65
+ getTrimmedString(record.imageUrl) ??
66
+ getTrimmedString(record.public_url) ??
67
+ getTrimmedString(record.publicUrl) ??
68
+ getTrimmedString(record.source_url) ??
69
+ getTrimmedString(record.sourceUrl) ??
70
+ getTrimmedString(record.source) ??
71
+ getTrimmedString(record.src) ??
72
+ getTrimmedString(record.image) ??
73
+ getTrimmedString(record.middle_image_url) ??
74
+ getTrimmedString(record.middleImageUrl) ??
75
+ getTrimmedString(record.center_image_url) ??
76
+ getTrimmedString(record.centerImageUrl) ??
77
+ getTrimmedString(record.data_url) ??
78
+ getTrimmedString(record.dataUrl) ??
79
+ getTrimmedString(record.image_data) ??
80
+ getTrimmedString(record.imageData) ??
81
+ getTrimmedString(record.data));
82
+ }
83
+ function normalizeOutroCtaImageInput(raw, context) {
84
+ const value = resolveAliasedInputValue(raw, ['outro_cta_image', 'outroCtaImage', 'cta_image', 'ctaImage'], 'outro_cta_image');
85
+ if (value === undefined || value === null) {
86
+ return undefined;
87
+ }
88
+ if (typeof value !== 'string' && (typeof value !== 'object' || Array.isArray(value))) {
89
+ throw new Error(`outro_cta_image must be a string or object for ${context}`);
90
+ }
91
+ if (!hasOutroCtaImageSource(value)) {
92
+ throw new Error(`outro_cta_image.middle_image is required for ${context}`);
93
+ }
94
+ return value;
95
+ }
44
96
  function getFirstDefinedInputValue(raw, aliases) {
45
97
  for (const alias of aliases) {
46
98
  if (Object.prototype.hasOwnProperty.call(raw, alias)) {
@@ -135,6 +187,7 @@ function normalizeCreateVideoFromTextInput(input) {
135
187
  ['cta_text_top', ['cta_text_top', 'ctaTextTop']],
136
188
  ['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
137
189
  ['cta_logo', ['cta_logo', 'ctaLogo']],
190
+ ['outro_cta_image', ['outro_cta_image', 'outroCtaImage', 'cta_image', 'ctaImage']],
138
191
  ['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
139
192
  ['footer_metadata', ['footer_metadata', 'footerMetadata']],
140
193
  ['backingtrack_model', ['backingtrack_model', 'backing_track_model', 'backingTrackModel', 'music_provider', 'musicProvider']],
@@ -159,11 +212,21 @@ function normalizeCreateVideoFromTextInput(input) {
159
212
  assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation', 'createVideoFromText');
160
213
  if (normalized.generate_outro_image === true) {
161
214
  const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
162
- if (!ctaUrl) {
163
- throw new Error('cta_url is required when generate_outro_image is true for createVideoFromText');
215
+ const outroCtaImage = normalizeOutroCtaImageInput(normalized, 'createVideoFromText');
216
+ if (outroCtaImage !== undefined) {
217
+ normalized.outro_cta_image = outroCtaImage;
218
+ }
219
+ if (!ctaUrl && !outroCtaImage) {
220
+ throw new Error('cta_url or outro_cta_image is required when generate_outro_image is true for createVideoFromText');
164
221
  }
165
222
  }
166
- else if (normalized.add_outro_focus_area === true && normalized.add_outro_animation !== true) {
223
+ else {
224
+ const outroCtaImage = normalizeOutroCtaImageInput(normalized, 'createVideoFromText');
225
+ if (outroCtaImage !== undefined) {
226
+ normalized.outro_cta_image = outroCtaImage;
227
+ }
228
+ }
229
+ if (normalized.generate_outro_image !== true && normalized.add_outro_focus_area === true && normalized.add_outro_animation !== true) {
167
230
  throw new Error('add_outro_focus_area requires add_outro_animation to be true for createVideoFromText');
168
231
  }
169
232
  return normalized;
@@ -197,6 +260,7 @@ function normalizeCreateVideoFromImageListInput(input) {
197
260
  ['cta_text_top', ['cta_text_top', 'ctaTextTop']],
198
261
  ['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
199
262
  ['cta_logo', ['cta_logo', 'ctaLogo']],
263
+ ['outro_cta_image', ['outro_cta_image', 'outroCtaImage', 'cta_image', 'ctaImage']],
200
264
  ['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
201
265
  ['footer_metadata', ['footer_metadata', 'footerMetadata']],
202
266
  ['backingtrack_model', ['backingtrack_model', 'backing_track_model', 'backingTrackModel', 'music_provider', 'musicProvider']],
@@ -224,6 +288,10 @@ function normalizeCreateVideoFromImageListInput(input) {
224
288
  assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation');
225
289
  assertOptionalBoolean(normalized.limit_single_narrator, 'limit_single_narrator');
226
290
  assertOptionalBoolean(normalized.add_narrator_avatar, 'add_narrator_avatar');
291
+ const outroCtaImage = normalizeOutroCtaImageInput(normalized, 'createVideoFromImageList');
292
+ if (outroCtaImage !== undefined) {
293
+ normalized.outro_cta_image = outroCtaImage;
294
+ }
227
295
  if (normalized.add_narrator_avatar === true) {
228
296
  normalized.limit_single_narrator = true;
229
297
  }
@@ -240,8 +308,8 @@ function normalizeCreateVideoFromImageListInput(input) {
240
308
  }
241
309
  if (normalized.generate_outro_image === true) {
242
310
  const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
243
- if (!ctaUrl) {
244
- throw new Error('cta_url is required when generate_outro_image is true for createVideoFromImageList');
311
+ if (!ctaUrl && !outroCtaImage) {
312
+ throw new Error('cta_url or outro_cta_image is required when generate_outro_image is true for createVideoFromImageList');
245
313
  }
246
314
  }
247
315
  else if (normalized.add_outro_focus_area === true && normalized.add_outro_animation !== true) {
@@ -370,8 +438,9 @@ function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroI
370
438
  raw.ctaTextBottom;
371
439
  const ctaLogo = raw.cta_logo ??
372
440
  raw.ctaLogo;
441
+ const outroCtaImage = normalizeOutroCtaImageInput(raw, context);
373
442
  const generateOutroImage = rawGenerateOutroImage === true ||
374
- (rawGenerateOutroImage === undefined && !outroImageUrl && Boolean(ctaUrl));
443
+ (rawGenerateOutroImage === undefined && !outroImageUrl && (Boolean(ctaUrl) || Boolean(outroCtaImage)));
375
444
  if (!videoSessionId) {
376
445
  throw new Error(`videoSessionId is required for ${context}`);
377
446
  }
@@ -384,15 +453,15 @@ function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroI
384
453
  if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
385
454
  throw new Error(`add_outro_focus_area must be a boolean for ${context}`);
386
455
  }
387
- if (generateOutroImage && outroImageUrl) {
388
- throw new Error(`Use either generate_outro_image with cta_url or outro_image_url for ${context}`);
456
+ if ((generateOutroImage || outroCtaImage) && outroImageUrl) {
457
+ throw new Error(`Use either generate_outro_image with cta_url/outro_cta_image or outro_image_url for ${context}`);
389
458
  }
390
459
  if (!generateOutroImage && !outroImageUrl) {
391
460
  throw new Error(`outro_image_url is required for ${context} unless generate_outro_image is true`);
392
461
  }
393
462
  if (generateOutroImage) {
394
- if (!ctaUrl || !String(ctaUrl).trim()) {
395
- throw new Error(`cta_url is required when generate_outro_image is true for ${context}`);
463
+ if ((!ctaUrl || !String(ctaUrl).trim()) && !outroCtaImage) {
464
+ throw new Error(`cta_url or outro_cta_image is required when generate_outro_image is true for ${context}`);
396
465
  }
397
466
  }
398
467
  else if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
@@ -413,7 +482,8 @@ function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroI
413
482
  videoSessionId: String(videoSessionId),
414
483
  ...(outroImageUrl ? { outro_image_url: String(outroImageUrl) } : {}),
415
484
  generate_outro_image: generateOutroImage,
416
- ...(generateOutroImage ? { cta_url: String(ctaUrl).trim() } : {}),
485
+ ...(generateOutroImage && ctaUrl ? { cta_url: String(ctaUrl).trim() } : {}),
486
+ ...(generateOutroImage && outroCtaImage ? { outro_cta_image: outroCtaImage } : {}),
417
487
  ...(ctaTextTop ? { cta_text_top: String(ctaTextTop) } : {}),
418
488
  ...(ctaTextBottom ? { cta_text_bottom: String(ctaTextBottom) } : {}),
419
489
  ...(ctaLogo ? { cta_logo: String(ctaLogo) } : {}),
@@ -879,8 +949,9 @@ export class SamsarClient {
879
949
  }, options);
880
950
  }
881
951
  async addV2VideoOutroImage(input, options) {
952
+ const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'addV2VideoOutroImage');
882
953
  return this.postV2('add_outro_image', {
883
- input,
954
+ input: normalizedInput,
884
955
  webhookUrl: options?.webhookUrl,
885
956
  }, options);
886
957
  }
@@ -1484,61 +1555,9 @@ export class SamsarClient {
1484
1555
  * re-running frame/video generation.
1485
1556
  */
1486
1557
  async addVideoOutroImage(input, options) {
1487
- const raw = input;
1488
- const videoSessionId = raw.videoSessionId ??
1489
- raw.video_session_id ??
1490
- raw.videoSessionID ??
1491
- raw.session_id ??
1492
- raw.sessionId ??
1493
- raw.sessionID ??
1494
- raw.request_id ??
1495
- raw.requestId;
1496
- const outroImageUrl = raw.outro_image_url ??
1497
- raw.outroImageUrl ??
1498
- raw.new_outro_image_url ??
1499
- raw.newOutroImageUrl;
1500
- const rawAddOutroAnimation = raw.add_outro_animation ??
1501
- raw.addOutroAnimation;
1502
- const rawAddOutroFocusArea = raw.add_outro_focus_area ??
1503
- raw.addOutroFocusArea;
1504
- const rawOutroFocusArea = raw.outro_focust_area ??
1505
- raw.outro_focus_area ??
1506
- raw.outroFocustArea ??
1507
- raw.outroFocusArea;
1508
- if (!videoSessionId) {
1509
- throw new Error('videoSessionId is required for addVideoOutroImage');
1510
- }
1511
- if (!outroImageUrl) {
1512
- throw new Error('outro_image_url is required for addVideoOutroImage');
1513
- }
1514
- if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
1515
- throw new Error('add_outro_animation must be a boolean for addVideoOutroImage');
1516
- }
1517
- if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
1518
- throw new Error('add_outro_focus_area must be a boolean for addVideoOutroImage');
1519
- }
1520
- if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
1521
- throw new Error('add_outro_focus_area requires add_outro_animation to be true for addVideoOutroImage');
1522
- }
1523
- if (rawAddOutroFocusArea === true) {
1524
- if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
1525
- throw new Error('outro_focust_area must be an object with x, y, width, height for addVideoOutroImage');
1526
- }
1527
- const { x, y, width, height } = rawOutroFocusArea;
1528
- const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
1529
- if (isInvalid) {
1530
- throw new Error('outro_focust_area x, y, width, height must be valid numbers for addVideoOutroImage');
1531
- }
1532
- }
1558
+ const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'addVideoOutroImage');
1533
1559
  const body = {
1534
- input: {
1535
- ...input,
1536
- videoSessionId: String(videoSessionId),
1537
- outro_image_url: String(outroImageUrl),
1538
- ...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
1539
- ...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
1540
- ...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
1541
- },
1560
+ input: normalizedInput,
1542
1561
  webhookUrl: options?.webhookUrl,
1543
1562
  };
1544
1563
  const response = await this.post('video/add_outro_image', body, options);
@@ -1566,68 +1585,10 @@ export class SamsarClient {
1566
1585
  * Add or replace an outro image for an external-user video request by resolving the external request id.
1567
1586
  */
1568
1587
  async addExternalVideoOutroImage(externalUser, input, options) {
1569
- const raw = input;
1570
- const videoSessionId = raw.videoSessionId ??
1571
- raw.video_session_id ??
1572
- raw.videoSessionID ??
1573
- raw.session_id ??
1574
- raw.sessionId ??
1575
- raw.sessionID ??
1576
- raw.request_id ??
1577
- raw.requestId ??
1578
- raw.source_request_id ??
1579
- raw.sourceRequestId ??
1580
- raw.external_request_id ??
1581
- raw.externalRequestId ??
1582
- raw.external_session_id ??
1583
- raw.externalSessionId;
1584
- const outroImageUrl = raw.outro_image_url ??
1585
- raw.outroImageUrl ??
1586
- raw.new_outro_image_url ??
1587
- raw.newOutroImageUrl;
1588
- const rawAddOutroAnimation = raw.add_outro_animation ??
1589
- raw.addOutroAnimation;
1590
- const rawAddOutroFocusArea = raw.add_outro_focus_area ??
1591
- raw.addOutroFocusArea;
1592
- const rawOutroFocusArea = raw.outro_focust_area ??
1593
- raw.outro_focus_area ??
1594
- raw.outroFocustArea ??
1595
- raw.outroFocusArea;
1596
- if (!videoSessionId) {
1597
- throw new Error('videoSessionId is required for addExternalVideoOutroImage');
1598
- }
1599
- if (!outroImageUrl) {
1600
- throw new Error('outro_image_url is required for addExternalVideoOutroImage');
1601
- }
1602
- if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
1603
- throw new Error('add_outro_animation must be a boolean for addExternalVideoOutroImage');
1604
- }
1605
- if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
1606
- throw new Error('add_outro_focus_area must be a boolean for addExternalVideoOutroImage');
1607
- }
1608
- if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
1609
- throw new Error('add_outro_focus_area requires add_outro_animation to be true for addExternalVideoOutroImage');
1610
- }
1611
- if (rawAddOutroFocusArea === true) {
1612
- if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
1613
- throw new Error('outro_focust_area must be an object with x, y, width, height for addExternalVideoOutroImage');
1614
- }
1615
- const { x, y, width, height } = rawOutroFocusArea;
1616
- const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
1617
- if (isInvalid) {
1618
- throw new Error('outro_focust_area x, y, width, height must be valid numbers for addExternalVideoOutroImage');
1619
- }
1620
- }
1588
+ const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'addExternalVideoOutroImage');
1621
1589
  const body = {
1622
1590
  external_user: normalizeExternalUserIdentity(externalUser),
1623
- input: {
1624
- ...input,
1625
- videoSessionId: String(videoSessionId),
1626
- outro_image_url: String(outroImageUrl),
1627
- ...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
1628
- ...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
1629
- ...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
1630
- },
1591
+ input: normalizedInput,
1631
1592
  webhookUrl: options?.webhookUrl,
1632
1593
  };
1633
1594
  return this.post('external_users/add_outro_image', body, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "samsar-js",
3
- "version": "0.48.33",
3
+ "version": "0.48.34",
4
4
  "description": "TypeScript client for the Samsar Processor API routes.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",