samsar-js 0.48.25 → 0.48.27
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 +77 -9
- package/dist/express-video-pricing.d.ts +24 -0
- package/dist/express-video-pricing.js +34 -0
- package/dist/index.d.ts +114 -2
- package/dist/index.js +192 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,7 +77,7 @@ const videoFromImages = await samsar.createVideoFromImageList(
|
|
|
77
77
|
await samsar.createVideoFromImageList({
|
|
78
78
|
image_urls: ['https://example.com/a.jpg', 'https://example.com/b.jpg'],
|
|
79
79
|
prompt: 'Product launch teaser with a clean final CTA',
|
|
80
|
-
video_model: '
|
|
80
|
+
video_model: 'KLINGIMGTOVID3PRO',
|
|
81
81
|
aspect_ratio: '16:9',
|
|
82
82
|
outro_image_url: 'https://cdn.example.com/outro.png',
|
|
83
83
|
add_outro_animation: true,
|
|
@@ -94,6 +94,7 @@ await samsar.createVideoFromImageList({
|
|
|
94
94
|
prompt: 'Travel offer reel with a scannable booking outro',
|
|
95
95
|
video_model: 'RUNWAYML',
|
|
96
96
|
aspect_ratio: '9:16',
|
|
97
|
+
add_narrator_avatar: true,
|
|
97
98
|
generate_outro_image: true,
|
|
98
99
|
cta_url: 'https://example.com/book',
|
|
99
100
|
cta_text_top: 'Scan to book',
|
|
@@ -160,6 +161,14 @@ const translated = await samsar.translateVideo(
|
|
|
160
161
|
{ webhookUrl: 'https://example.com/webhook' },
|
|
161
162
|
);
|
|
162
163
|
|
|
164
|
+
// Deep-clone an existing completed session and render a new final video URL
|
|
165
|
+
const cloned = await samsar.cloneVideo(
|
|
166
|
+
{
|
|
167
|
+
videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
168
|
+
},
|
|
169
|
+
{ webhookUrl: 'https://example.com/webhook' },
|
|
170
|
+
);
|
|
171
|
+
|
|
163
172
|
// Join multiple completed sessions into a single appended video
|
|
164
173
|
const joined = await samsar.joinVideos(
|
|
165
174
|
{
|
|
@@ -426,6 +435,7 @@ const platform = new SamsarClient({
|
|
|
426
435
|
|
|
427
436
|
const externalUser = {
|
|
428
437
|
provider: 'whop',
|
|
438
|
+
unique_key: 'whop:usr_123',
|
|
429
439
|
external_user_id: 'usr_123',
|
|
430
440
|
external_app_id: 'app_abc',
|
|
431
441
|
username: 'roy24x7',
|
|
@@ -536,24 +546,28 @@ console.log(externalLibrary.data.requests.map((request) => request.request_id));
|
|
|
536
546
|
```
|
|
537
547
|
|
|
538
548
|
Video model support notes:
|
|
539
|
-
- `createVideoFromText` image model keys include: `GPTIMAGE2`, `IMAGEN4`, `SEEDREAM`, `
|
|
540
|
-
- `createVideoFromText` supports
|
|
549
|
+
- `createVideoFromText` image model keys include: `GPTIMAGE2`, `IMAGEN4`, `SEEDREAM`, `NANOBANANA2`, `CUSTOM_TEXT_TO_IMAGE`.
|
|
550
|
+
- `createVideoFromText` supports these video models: `VEO3.1I2V`, `VEO3.1I2VFAST`, `SEEDANCEI2V` (Seedance 2.0), `KLINGIMGTOVID3PRO`, `RUNWAYML`, and `CUSTOM_IMAGE_TO_VIDEO`.
|
|
541
551
|
- `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.
|
|
542
|
-
- `createVideoFromImageList` supports `VEO3.1I2V`, `SEEDANCEI2V`, `
|
|
552
|
+
- `createVideoFromImageList` supports `VEO3.1I2V`, `VEO3.1I2VFAST`, `SEEDANCEI2V`, `KLINGIMGTOVID3PRO`, `RUNWAYML`, and `CUSTOM_IMAGE_TO_VIDEO` via `video_model`; if omitted, it defaults to `VEO3.1I2V`. Use `aspect_ratio: '16:9'` or `'9:16'`; omitted or invalid values fall back to `16:9`.
|
|
543
553
|
- `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.
|
|
544
554
|
- `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
|
|
555
|
+
- `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.
|
|
545
556
|
- `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.
|
|
546
557
|
- `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.
|
|
558
|
+
- `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.
|
|
547
559
|
- 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.
|
|
548
560
|
- Completed video status, latest-version, and completed-session list responses expose `has_subtitles` and `result_language` when the session metadata is available.
|
|
549
561
|
- `publishPublication`, `editPublication`, and `revokePublication` manage public feed publications for completed sessions through free `/publications/*` endpoints. They work with account API keys, customer sub-account API keys, and client auth tokens when the session belongs to the authenticated actor.
|
|
550
|
-
-
|
|
562
|
+
- Text-to-video and image-list video pricing use the same per-rendered-second rates for standard express models: `VEO3.1I2V` is 60 credits/sec, `VEO3.1I2VFAST` is 36 credits/sec, `SEEDANCEI2V` is 30 credits/sec, `KLINGIMGTOVID3PRO` is 36 credits/sec, and `RUNWAYML` is 30 credits/sec. Image-list narrator avatar generation adds 4 credits/sec when `add_narrator_avatar` is true.
|
|
563
|
+
- Standard express video models expose a per-second pricing distribution through `EXPRESS_VIDEO_PRICING_DISTRIBUTION_PER_SECOND_BY_MODEL`: pipeline 4, inference 4, image gen/edit 2, speech 2, music 2, effects and lipsync 2, and video as the model-specific remainder.
|
|
551
564
|
|
|
552
565
|
Upcoming `/v2` omni route adapters:
|
|
553
566
|
- `/v2` is additive; `/v1` is not deprecated.
|
|
554
|
-
- `createV2VideoFromText`, `createV2VideoFromImageList`, `translateV2Video`, `updateV2VideoOutroImage`, `updateV2VideoFooterImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
|
|
555
|
-
-
|
|
556
|
-
-
|
|
567
|
+
- `createV2VideoFromText`, `createV2VideoFromImageList`, `translateV2Video`, `cloneV2Video`, `updateV2VideoOutroImage`, `updateV2VideoFooterImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
|
|
568
|
+
- Step-controlled video helpers include `createV2StepVideoFromText`, `createV2StepTextToVideo`, `createV2StepVideoFromImage`, `createV2StepImageToVideo`, `getV2StepVideoStatus`, and `processNextV2StepVideo`.
|
|
569
|
+
- Programmatic user helpers include `createV2ExternalUser`, `createV2UserRechargeCredits`, `refreshV2UserToken`, `createV2UserAppKey`, `refreshV2UserAppKey`, `getV2UserCredits`, `getV2UserUsageLogs`, and `getV2UserPaymentStatus`.
|
|
570
|
+
- Omit `externalUser` for internal account billing, pass `externalUser` to scope an external user with the account API key, or authenticate the client directly with an external-user auth token/API key. V2 external users can be referenced by `unique_key`; if `unique_key` is omitted during creation, the server uses `external_user_id` as the key.
|
|
557
571
|
|
|
558
572
|
```ts
|
|
559
573
|
const v2Video = await platform.createV2VideoFromImageList({
|
|
@@ -567,7 +581,7 @@ const v2Video = await platform.createV2VideoFromImageList({
|
|
|
567
581
|
const v2ExternalVideo = await platform.createV2VideoFromImageList(
|
|
568
582
|
{
|
|
569
583
|
image_urls: ['https://cdn.example.com/a.png', 'https://cdn.example.com/b.png'],
|
|
570
|
-
video_model: '
|
|
584
|
+
video_model: 'KLINGIMGTOVID3PRO',
|
|
571
585
|
},
|
|
572
586
|
{ externalUser },
|
|
573
587
|
);
|
|
@@ -580,10 +594,64 @@ const v2Translated = await platform.translateV2Video({
|
|
|
580
594
|
translate_footer: true,
|
|
581
595
|
});
|
|
582
596
|
|
|
597
|
+
const v2Clone = await platform.cloneV2Video({
|
|
598
|
+
videoSessionId: v2Video.data.request_id!,
|
|
599
|
+
});
|
|
600
|
+
|
|
583
601
|
const v2Status = await platform.getV2Status(v2Video.data.request_id!);
|
|
584
602
|
console.log(v2Status.data.status);
|
|
585
603
|
```
|
|
586
604
|
|
|
605
|
+
Step-controlled video generation pauses after each completed stage until you call `processNextV2StepVideo`:
|
|
606
|
+
|
|
607
|
+
```ts
|
|
608
|
+
const stepVideo = await platform.createV2StepVideoFromText({
|
|
609
|
+
prompt: 'A 20 second launch teaser for a new travel app',
|
|
610
|
+
image_model: 'GPTIMAGE2',
|
|
611
|
+
video_model: 'RUNWAYML',
|
|
612
|
+
duration: 20,
|
|
613
|
+
aspect_ratio: '16:9',
|
|
614
|
+
enable_subtitles: true,
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
let stepStatus = await platform.getV2StepVideoStatus(stepVideo.data.request_id);
|
|
618
|
+
if (stepStatus.data.step_status === 'COMPLETED') {
|
|
619
|
+
console.log(stepStatus.data.current_step, stepStatus.data.current_step_resources);
|
|
620
|
+
stepStatus = await platform.processNextV2StepVideo(stepVideo.data.request_id);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const stepImageVideo = await platform.createV2StepVideoFromImage({
|
|
624
|
+
image_url: 'https://cdn.example.com/product-frame.png',
|
|
625
|
+
prompt: 'Turn this product frame into a cinematic ad',
|
|
626
|
+
video_model: 'KLINGIMGTOVID3PRO',
|
|
627
|
+
aspect_ratio: '16:9',
|
|
628
|
+
});
|
|
629
|
+
console.log(stepImageVideo.data.step?.current_step);
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Create and reference a V2 external user:
|
|
633
|
+
|
|
634
|
+
```ts
|
|
635
|
+
const createdExternalUser = await platform.createV2ExternalUser({
|
|
636
|
+
unique_key: 'wallet:0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
|
|
637
|
+
email: 'member@example.com',
|
|
638
|
+
display_name: 'Member Name',
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
const v2RegisteredExternalVideo = await platform.createV2VideoFromImageList(
|
|
642
|
+
{
|
|
643
|
+
image_urls: ['https://cdn.example.com/a.png', 'https://cdn.example.com/b.png'],
|
|
644
|
+
video_model: 'RUNWAYML',
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
externalUser: {
|
|
648
|
+
unique_key: createdExternalUser.data.unique_key!,
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
);
|
|
652
|
+
console.log(v2RegisteredExternalVideo.data.request_id);
|
|
653
|
+
```
|
|
654
|
+
|
|
587
655
|
Programmatic user recharge and OAuth-style refresh token rotation:
|
|
588
656
|
|
|
589
657
|
```ts
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND: {
|
|
2
|
+
readonly pipeline: 4;
|
|
3
|
+
readonly inference: 4;
|
|
4
|
+
readonly image_gen_edit: 2;
|
|
5
|
+
readonly speech: 2;
|
|
6
|
+
readonly music: 2;
|
|
7
|
+
readonly effects_and_lipsync: 2;
|
|
8
|
+
};
|
|
9
|
+
export type ExpressVideoPricingDistribution = typeof EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND & {
|
|
10
|
+
video: number;
|
|
11
|
+
total: number;
|
|
12
|
+
};
|
|
13
|
+
export declare const EXPRESS_VIDEO_FIXED_COMPONENTS_TOTAL_PER_SECOND: number;
|
|
14
|
+
export declare const EXPRESS_VIDEO_CREDITS_PER_SECOND_BY_MODEL: {
|
|
15
|
+
readonly 'VEO3.1I2V': 60;
|
|
16
|
+
readonly 'VEO3.1I2VFAST': 36;
|
|
17
|
+
readonly SEEDANCEI2V: 30;
|
|
18
|
+
readonly KLINGIMGTOVID3PRO: 36;
|
|
19
|
+
readonly KLINGIMGTOVIDTURBO: 36;
|
|
20
|
+
readonly RUNWAYML: 30;
|
|
21
|
+
};
|
|
22
|
+
export declare const EXPRESS_VIDEO_PRICING_DISTRIBUTION_PER_SECOND_BY_MODEL: Record<string, ExpressVideoPricingDistribution>;
|
|
23
|
+
export declare function getExpressVideoCreditsPerSecond(model: string | null | undefined): 60 | 36 | 30;
|
|
24
|
+
export declare function getExpressVideoPricingDistributionPerSecond(model: string | null | undefined): ExpressVideoPricingDistribution;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND = {
|
|
2
|
+
pipeline: 4,
|
|
3
|
+
inference: 4,
|
|
4
|
+
image_gen_edit: 2,
|
|
5
|
+
speech: 2,
|
|
6
|
+
music: 2,
|
|
7
|
+
effects_and_lipsync: 2,
|
|
8
|
+
};
|
|
9
|
+
export const EXPRESS_VIDEO_FIXED_COMPONENTS_TOTAL_PER_SECOND = Object.values(EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND).reduce((total, value) => total + value, 0);
|
|
10
|
+
export const EXPRESS_VIDEO_CREDITS_PER_SECOND_BY_MODEL = {
|
|
11
|
+
'VEO3.1I2V': 60,
|
|
12
|
+
'VEO3.1I2VFAST': 36,
|
|
13
|
+
SEEDANCEI2V: 30,
|
|
14
|
+
KLINGIMGTOVID3PRO: 36,
|
|
15
|
+
KLINGIMGTOVIDTURBO: 36,
|
|
16
|
+
RUNWAYML: 30,
|
|
17
|
+
};
|
|
18
|
+
export const EXPRESS_VIDEO_PRICING_DISTRIBUTION_PER_SECOND_BY_MODEL = Object.fromEntries(Object.entries(EXPRESS_VIDEO_CREDITS_PER_SECOND_BY_MODEL)
|
|
19
|
+
.map(([model, total]) => [
|
|
20
|
+
model,
|
|
21
|
+
{
|
|
22
|
+
...EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND,
|
|
23
|
+
video: total - EXPRESS_VIDEO_FIXED_COMPONENTS_TOTAL_PER_SECOND,
|
|
24
|
+
total,
|
|
25
|
+
},
|
|
26
|
+
]));
|
|
27
|
+
export function getExpressVideoCreditsPerSecond(model) {
|
|
28
|
+
const modelKey = typeof model === 'string' ? model.trim().toUpperCase() : '';
|
|
29
|
+
return EXPRESS_VIDEO_CREDITS_PER_SECOND_BY_MODEL[modelKey] ?? null;
|
|
30
|
+
}
|
|
31
|
+
export function getExpressVideoPricingDistributionPerSecond(model) {
|
|
32
|
+
const modelKey = typeof model === 'string' ? model.trim().toUpperCase() : '';
|
|
33
|
+
return EXPRESS_VIDEO_PRICING_DISTRIBUTION_PER_SECOND_BY_MODEL[modelKey] ?? null;
|
|
34
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { EXPRESS_VIDEO_CREDITS_PER_SECOND_BY_MODEL, EXPRESS_VIDEO_FIXED_COMPONENTS_TOTAL_PER_SECOND, EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND, EXPRESS_VIDEO_PRICING_DISTRIBUTION_PER_SECOND_BY_MODEL, getExpressVideoCreditsPerSecond, getExpressVideoPricingDistributionPerSecond, } from './express-video-pricing.js';
|
|
2
|
+
export type { ExpressVideoPricingDistribution } from './express-video-pricing.js';
|
|
1
3
|
type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
2
4
|
type QueryValue = string | number | boolean | null | undefined;
|
|
3
5
|
type QueryParams = Record<string, QueryValue>;
|
|
@@ -109,7 +111,7 @@ export interface FooterMetadataItem {
|
|
|
109
111
|
footerLogoImagePath?: string;
|
|
110
112
|
}
|
|
111
113
|
export type ImageListToVideoAspectRatio = '16:9' | '9:16';
|
|
112
|
-
export type ImageListToVideoModel = 'VEO3.1I2V' | '
|
|
114
|
+
export type ImageListToVideoModel = 'VEO3.1I2V' | 'VEO3.1I2VFAST' | 'SEEDANCEI2V' | 'KLINGIMGTOVID3PRO' | 'RUNWAYML' | 'CUSTOM_IMAGE_TO_VIDEO';
|
|
113
115
|
export interface ImageListToVideoItem {
|
|
114
116
|
image_url?: string;
|
|
115
117
|
imageUrl?: string;
|
|
@@ -182,6 +184,10 @@ export interface CreateVideoFromImageListInput {
|
|
|
182
184
|
addFooterAnimation?: boolean;
|
|
183
185
|
footer_metadata?: FooterMetadataItem[];
|
|
184
186
|
footerMetadata?: FooterMetadataItem[];
|
|
187
|
+
limit_single_narrator?: boolean;
|
|
188
|
+
limitSingleNarrator?: boolean;
|
|
189
|
+
add_narrator_avatar?: boolean;
|
|
190
|
+
addNarratorAvatar?: boolean;
|
|
185
191
|
[key: string]: unknown;
|
|
186
192
|
}
|
|
187
193
|
export interface TranscriptBuilderPayload {
|
|
@@ -203,6 +209,12 @@ export interface CreateVideoFromImageListResponse {
|
|
|
203
209
|
remainingCredits?: number | null;
|
|
204
210
|
[key: string]: unknown;
|
|
205
211
|
}
|
|
212
|
+
export interface CreateV2StepImageToVideoInput extends Omit<CreateVideoFromImageListInput, 'image_urls'> {
|
|
213
|
+
image_urls?: Array<string | ImageListToVideoItem>;
|
|
214
|
+
image_url?: string;
|
|
215
|
+
imageUrl?: string;
|
|
216
|
+
image?: string;
|
|
217
|
+
}
|
|
206
218
|
export interface TranslateVideoInput {
|
|
207
219
|
videoSessionId?: string;
|
|
208
220
|
video_session_id?: string;
|
|
@@ -237,6 +249,26 @@ export interface TranslateVideoResponse {
|
|
|
237
249
|
remainingCredits?: number | null;
|
|
238
250
|
[key: string]: unknown;
|
|
239
251
|
}
|
|
252
|
+
export interface CloneVideoInput {
|
|
253
|
+
videoSessionId?: string;
|
|
254
|
+
video_session_id?: string;
|
|
255
|
+
videoSessionID?: string;
|
|
256
|
+
session_id?: string;
|
|
257
|
+
sessionId?: string;
|
|
258
|
+
sessionID?: string;
|
|
259
|
+
request_id?: string;
|
|
260
|
+
requestId?: string;
|
|
261
|
+
source_session_id?: string;
|
|
262
|
+
sourceSessionId?: string;
|
|
263
|
+
source_request_id?: string;
|
|
264
|
+
sourceRequestId?: string;
|
|
265
|
+
[key: string]: unknown;
|
|
266
|
+
}
|
|
267
|
+
export interface CloneVideoResponse extends GlobalStatusResponse {
|
|
268
|
+
sessionID?: string;
|
|
269
|
+
creditsCharged?: number;
|
|
270
|
+
remainingCredits?: number | null;
|
|
271
|
+
}
|
|
240
272
|
export interface UpdateVideoOutroImageInput {
|
|
241
273
|
videoSessionId?: string;
|
|
242
274
|
video_session_id?: string;
|
|
@@ -532,6 +564,7 @@ export interface SupportedTextToVideoModelOption {
|
|
|
532
564
|
label: string;
|
|
533
565
|
value: string;
|
|
534
566
|
basePrice: number | null;
|
|
567
|
+
pricingDistribution?: Record<string, number> | null;
|
|
535
568
|
[key: string]: unknown;
|
|
536
569
|
}
|
|
537
570
|
export interface EnhanceMessageRequest {
|
|
@@ -1177,6 +1210,8 @@ export interface GlobalStatusResponse {
|
|
|
1177
1210
|
}
|
|
1178
1211
|
export interface ExternalUserIdentity {
|
|
1179
1212
|
provider: string;
|
|
1213
|
+
unique_key?: string;
|
|
1214
|
+
uniqueKey?: string;
|
|
1180
1215
|
external_user_id?: string;
|
|
1181
1216
|
externalUserId?: string;
|
|
1182
1217
|
external_app_id?: string;
|
|
@@ -1202,6 +1237,7 @@ export interface ExternalUserSummary {
|
|
|
1202
1237
|
id?: string | null;
|
|
1203
1238
|
provider?: string;
|
|
1204
1239
|
external_user_id?: string;
|
|
1240
|
+
unique_key?: string | null;
|
|
1205
1241
|
external_app_id?: string | null;
|
|
1206
1242
|
external_company_id?: string | null;
|
|
1207
1243
|
email?: string | null;
|
|
@@ -1372,9 +1408,48 @@ export interface ExternalRequestsListResponse {
|
|
|
1372
1408
|
[key: string]: unknown;
|
|
1373
1409
|
}
|
|
1374
1410
|
export interface V2RequestOptions extends SamsarRequestOptions {
|
|
1375
|
-
externalUser?:
|
|
1411
|
+
externalUser?: V2ExternalUserIdentity | null;
|
|
1376
1412
|
webhookUrl?: string;
|
|
1377
1413
|
}
|
|
1414
|
+
export type V2StepVideoStage = 'prompt_generation' | 'image_generation' | 'speech_generation' | 'music_generation' | 'ai_video_generation' | 'lip_sync_generation' | 'sound_effect_generation' | 'video_generation';
|
|
1415
|
+
export type V2StepVideoStatus = 'INIT' | 'PENDING' | 'COMPLETED' | 'FAILED' | string;
|
|
1416
|
+
export interface V2StepVideoState {
|
|
1417
|
+
enabled?: boolean;
|
|
1418
|
+
route_type?: 'text_to_video' | 'image_to_video' | string | null;
|
|
1419
|
+
status?: V2StepVideoStatus;
|
|
1420
|
+
current_step?: V2StepVideoStage | string | null;
|
|
1421
|
+
current_step_label?: string | null;
|
|
1422
|
+
next_step?: V2StepVideoStage | string | null;
|
|
1423
|
+
waiting_for_process_next?: boolean;
|
|
1424
|
+
updated_at?: string | null;
|
|
1425
|
+
[key: string]: unknown;
|
|
1426
|
+
}
|
|
1427
|
+
export interface V2StepVideoResourceBlock {
|
|
1428
|
+
step?: V2StepVideoStage | string;
|
|
1429
|
+
label?: string;
|
|
1430
|
+
status?: V2StepVideoStatus;
|
|
1431
|
+
completed_at?: string | null;
|
|
1432
|
+
resources?: Record<string, unknown>;
|
|
1433
|
+
[key: string]: unknown;
|
|
1434
|
+
}
|
|
1435
|
+
export interface V2StepVideoStatusResponse extends GlobalStatusResponse {
|
|
1436
|
+
step_status?: V2StepVideoStatus;
|
|
1437
|
+
current_step?: V2StepVideoStage | string | null;
|
|
1438
|
+
current_step_label?: string | null;
|
|
1439
|
+
next_step?: V2StepVideoStage | string | null;
|
|
1440
|
+
waiting_for_process_next?: boolean;
|
|
1441
|
+
process_next_url?: string;
|
|
1442
|
+
step?: V2StepVideoState;
|
|
1443
|
+
current_step_resources?: V2StepVideoResourceBlock | null;
|
|
1444
|
+
completed_step_resources?: Record<string, V2StepVideoResourceBlock>;
|
|
1445
|
+
}
|
|
1446
|
+
export interface V2StepVideoCreateResponse extends CreateVideoResponse {
|
|
1447
|
+
status?: V2StepVideoStatus;
|
|
1448
|
+
step?: V2StepVideoState;
|
|
1449
|
+
}
|
|
1450
|
+
export interface V2ExternalUserIdentity extends Omit<ExternalUserIdentity, 'provider'> {
|
|
1451
|
+
provider?: string;
|
|
1452
|
+
}
|
|
1378
1453
|
export interface V2SessionResponse {
|
|
1379
1454
|
account_type?: 'internal' | 'external' | string;
|
|
1380
1455
|
auth_type?: string;
|
|
@@ -1430,6 +1505,27 @@ export interface V2UserTokenResponse {
|
|
|
1430
1505
|
refreshTokenExpiresAt?: string;
|
|
1431
1506
|
[key: string]: unknown;
|
|
1432
1507
|
}
|
|
1508
|
+
export interface V2CreateExternalUserRequest extends V2ExternalUserIdentity {
|
|
1509
|
+
external_user?: V2ExternalUserIdentity | null;
|
|
1510
|
+
externalUser?: V2ExternalUserIdentity | null;
|
|
1511
|
+
}
|
|
1512
|
+
export interface V2CreateExternalUserReference {
|
|
1513
|
+
provider?: string | null;
|
|
1514
|
+
unique_key?: string | null;
|
|
1515
|
+
external_user_id?: string | null;
|
|
1516
|
+
external_app_id?: string | null;
|
|
1517
|
+
[key: string]: unknown;
|
|
1518
|
+
}
|
|
1519
|
+
export interface V2CreateExternalUserResponse {
|
|
1520
|
+
unique_key?: string | null;
|
|
1521
|
+
provider?: string | null;
|
|
1522
|
+
external_user_id?: string | null;
|
|
1523
|
+
external_app_id?: string | null;
|
|
1524
|
+
external_user?: ExternalUserSummary | null;
|
|
1525
|
+
externalUser?: ExternalUserSummary | null;
|
|
1526
|
+
reference?: V2CreateExternalUserReference;
|
|
1527
|
+
[key: string]: unknown;
|
|
1528
|
+
}
|
|
1433
1529
|
export interface V2UserAppKeyRequest {
|
|
1434
1530
|
secret?: string;
|
|
1435
1531
|
appSecret?: string;
|
|
@@ -1572,6 +1668,7 @@ export interface VerifiedClientSessionResponse {
|
|
|
1572
1668
|
avatarUrl?: string | null;
|
|
1573
1669
|
provider?: string | null;
|
|
1574
1670
|
externalUserId?: string | null;
|
|
1671
|
+
uniqueKey?: string | null;
|
|
1575
1672
|
externalAppId?: string | null;
|
|
1576
1673
|
externalCompanyId?: string | null;
|
|
1577
1674
|
generationCredits?: number;
|
|
@@ -1708,6 +1805,7 @@ export declare class SamsarClient {
|
|
|
1708
1805
|
limit?: number;
|
|
1709
1806
|
}): Promise<SamsarResult<UsageLogsResponse>>;
|
|
1710
1807
|
listV2Requests(options?: V2RequestOptions): Promise<SamsarResult<V2RequestsListResponse>>;
|
|
1808
|
+
createV2ExternalUser(payload: V2CreateExternalUserRequest, options?: V2RequestOptions): Promise<SamsarResult<V2CreateExternalUserResponse>>;
|
|
1711
1809
|
createV2UserRechargeCredits(payload: V2UserRechargeCreditsRequest, options?: V2RequestOptions): Promise<SamsarResult<V2UserRechargeCreditsResponse>>;
|
|
1712
1810
|
refreshV2UserToken(payload: string | V2UserTokenRefreshRequest, options?: V2RequestOptions): Promise<SamsarResult<V2UserTokenResponse>>;
|
|
1713
1811
|
refreshV2UserAuthToken(payload: string | V2UserTokenRefreshRequest, options?: V2RequestOptions): Promise<SamsarResult<V2UserTokenResponse>>;
|
|
@@ -1721,7 +1819,14 @@ export declare class SamsarClient {
|
|
|
1721
1819
|
}): Promise<SamsarResult<CreateLoginTokenResponse | ExternalCreateLoginTokenResponse>>;
|
|
1722
1820
|
createV2VideoFromText(input: CreateVideoFromTextInput, options?: V2RequestOptions): Promise<SamsarResult<CreateVideoResponse | ExternalRequestResponse>>;
|
|
1723
1821
|
createV2VideoFromImageList(input: CreateVideoFromImageListInput, options?: V2RequestOptions): Promise<SamsarResult<CreateVideoFromImageListResponse | ExternalRequestResponse>>;
|
|
1822
|
+
createV2StepVideoFromText(input: CreateVideoFromTextInput, options?: V2RequestOptions): Promise<SamsarResult<V2StepVideoCreateResponse>>;
|
|
1823
|
+
createV2StepTextToVideo(input: CreateVideoFromTextInput, options?: V2RequestOptions): Promise<SamsarResult<V2StepVideoCreateResponse>>;
|
|
1824
|
+
createV2StepVideoFromImage(input: CreateV2StepImageToVideoInput, options?: V2RequestOptions): Promise<SamsarResult<V2StepVideoCreateResponse>>;
|
|
1825
|
+
createV2StepImageToVideo(input: CreateV2StepImageToVideoInput, options?: V2RequestOptions): Promise<SamsarResult<V2StepVideoCreateResponse>>;
|
|
1826
|
+
getV2StepVideoStatus(requestId: string, options?: V2RequestOptions): Promise<SamsarResult<V2StepVideoStatusResponse>>;
|
|
1827
|
+
processNextV2StepVideo(requestId: string, options?: V2RequestOptions): Promise<SamsarResult<V2StepVideoStatusResponse>>;
|
|
1724
1828
|
translateV2Video(input: TranslateVideoInput, options?: V2RequestOptions): Promise<SamsarResult<TranslateVideoResponse | ExternalRequestResponse>>;
|
|
1829
|
+
cloneV2Video(input: CloneVideoInput, options?: V2RequestOptions): Promise<SamsarResult<CloneVideoResponse>>;
|
|
1725
1830
|
uploadV2ImageData(imageData: string[], options?: V2RequestOptions): Promise<SamsarResult<{
|
|
1726
1831
|
image_urls: string[];
|
|
1727
1832
|
}>>;
|
|
@@ -1807,6 +1912,13 @@ export declare class SamsarClient {
|
|
|
1807
1912
|
translateVideo(input: TranslateVideoInput, options?: {
|
|
1808
1913
|
webhookUrl?: string;
|
|
1809
1914
|
} & SamsarRequestOptions): Promise<SamsarResult<TranslateVideoResponse>>;
|
|
1915
|
+
/**
|
|
1916
|
+
* Deep-clone a completed video session and queue one final render for the new session.
|
|
1917
|
+
* The clone copies session assets, then regenerates only the final rendered video URL.
|
|
1918
|
+
*/
|
|
1919
|
+
cloneVideo(input: CloneVideoInput, options?: {
|
|
1920
|
+
webhookUrl?: string;
|
|
1921
|
+
} & SamsarRequestOptions): Promise<SamsarResult<CloneVideoResponse>>;
|
|
1810
1922
|
/**
|
|
1811
1923
|
* Join multiple existing video sessions into a single session by appending their timelines.
|
|
1812
1924
|
* Creates a new session_id and queues transcription + frame + video generation.
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const DEFAULT_BASE_URL = 'https://api.samsar.one/v1';
|
|
2
|
+
export { EXPRESS_VIDEO_CREDITS_PER_SECOND_BY_MODEL, EXPRESS_VIDEO_FIXED_COMPONENTS_TOTAL_PER_SECOND, EXPRESS_VIDEO_FIXED_PRICING_COMPONENTS_PER_SECOND, EXPRESS_VIDEO_PRICING_DISTRIBUTION_PER_SECOND_BY_MODEL, getExpressVideoCreditsPerSecond, getExpressVideoPricingDistributionPerSecond, } from './express-video-pricing.js';
|
|
2
3
|
const DEBUG = (() => {
|
|
3
4
|
const env = globalThis?.process?.env;
|
|
4
5
|
return env?.SAMSAR_SDK_DEBUG === '1';
|
|
@@ -101,6 +102,8 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
101
102
|
['cta_logo', ['cta_logo', 'ctaLogo']],
|
|
102
103
|
['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
|
|
103
104
|
['footer_metadata', ['footer_metadata', 'footerMetadata']],
|
|
105
|
+
['limit_single_narrator', ['limit_single_narrator', 'limitSingleNarrator']],
|
|
106
|
+
['add_narrator_avatar', ['add_narrator_avatar', 'addNarratorAvatar']],
|
|
104
107
|
['enable_subtitles', ['enable_subtitles', 'enableSubtitles']],
|
|
105
108
|
['font_key', ['font_key', 'fontKey']],
|
|
106
109
|
];
|
|
@@ -115,6 +118,11 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
115
118
|
assertOptionalBoolean(normalized.add_outro_focus_area, 'add_outro_focus_area');
|
|
116
119
|
assertOptionalBoolean(normalized.generate_outro_image, 'generate_outro_image');
|
|
117
120
|
assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation');
|
|
121
|
+
assertOptionalBoolean(normalized.limit_single_narrator, 'limit_single_narrator');
|
|
122
|
+
assertOptionalBoolean(normalized.add_narrator_avatar, 'add_narrator_avatar');
|
|
123
|
+
if (normalized.add_narrator_avatar === true) {
|
|
124
|
+
normalized.limit_single_narrator = true;
|
|
125
|
+
}
|
|
118
126
|
if (normalized.generate_outro_image === true) {
|
|
119
127
|
const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
|
|
120
128
|
if (!ctaUrl) {
|
|
@@ -126,6 +134,23 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
126
134
|
}
|
|
127
135
|
return normalized;
|
|
128
136
|
}
|
|
137
|
+
function normalizeCreateV2StepImageToVideoInput(input) {
|
|
138
|
+
const raw = input;
|
|
139
|
+
const normalized = { ...input };
|
|
140
|
+
if (!Array.isArray(input.image_urls) || input.image_urls.length === 0) {
|
|
141
|
+
const imageUrl = getTrimmedString(raw.image_url) ??
|
|
142
|
+
getTrimmedString(raw.imageUrl) ??
|
|
143
|
+
getTrimmedString(raw.image);
|
|
144
|
+
if (!imageUrl) {
|
|
145
|
+
throw new Error('image_url or image_urls is required for createV2StepVideoFromImage');
|
|
146
|
+
}
|
|
147
|
+
normalized.image_urls = [imageUrl];
|
|
148
|
+
}
|
|
149
|
+
delete normalized.image_url;
|
|
150
|
+
delete normalized.imageUrl;
|
|
151
|
+
delete normalized.image;
|
|
152
|
+
return normalizeCreateVideoFromImageListInput(normalized);
|
|
153
|
+
}
|
|
129
154
|
function normalizeTranslateVideoInput(input, context = 'translateVideo') {
|
|
130
155
|
const raw = input;
|
|
131
156
|
const videoSessionId = raw.videoSessionId ??
|
|
@@ -170,6 +195,28 @@ function normalizeTranslateVideoInput(input, context = 'translateVideo') {
|
|
|
170
195
|
translate_footer: translateFooter,
|
|
171
196
|
};
|
|
172
197
|
}
|
|
198
|
+
function normalizeCloneVideoInput(input, context = 'cloneVideo') {
|
|
199
|
+
const raw = input;
|
|
200
|
+
const videoSessionId = raw.videoSessionId ??
|
|
201
|
+
raw.video_session_id ??
|
|
202
|
+
raw.videoSessionID ??
|
|
203
|
+
raw.session_id ??
|
|
204
|
+
raw.sessionId ??
|
|
205
|
+
raw.sessionID ??
|
|
206
|
+
raw.request_id ??
|
|
207
|
+
raw.requestId ??
|
|
208
|
+
raw.source_session_id ??
|
|
209
|
+
raw.sourceSessionId ??
|
|
210
|
+
raw.source_request_id ??
|
|
211
|
+
raw.sourceRequestId;
|
|
212
|
+
if (!videoSessionId) {
|
|
213
|
+
throw new Error(`videoSessionId is required for ${context}`);
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
...input,
|
|
217
|
+
videoSessionId: String(videoSessionId),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
173
220
|
function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroImage') {
|
|
174
221
|
const raw = input;
|
|
175
222
|
const videoSessionId = raw.videoSessionId ??
|
|
@@ -394,7 +441,9 @@ export class SamsarClient {
|
|
|
394
441
|
*/
|
|
395
442
|
async getV2(path, options) {
|
|
396
443
|
const query = {
|
|
397
|
-
...(options?.externalUser
|
|
444
|
+
...(options?.externalUser
|
|
445
|
+
? buildExternalUserQuery(options.externalUser, { requireProvider: false })
|
|
446
|
+
: {}),
|
|
398
447
|
...(options?.query ?? {}),
|
|
399
448
|
};
|
|
400
449
|
return this.get(this.buildV2Url(path), { ...(options ?? {}), query });
|
|
@@ -429,6 +478,27 @@ export class SamsarClient {
|
|
|
429
478
|
async listV2Requests(options) {
|
|
430
479
|
return this.getV2('requests', options);
|
|
431
480
|
}
|
|
481
|
+
async createV2ExternalUser(payload, options) {
|
|
482
|
+
const input = payload ?? {};
|
|
483
|
+
const nestedExternalUser = (input.external_user ?? input.externalUser ?? {});
|
|
484
|
+
const uniqueKey = getTrimmedString(nestedExternalUser.unique_key ??
|
|
485
|
+
nestedExternalUser.uniqueKey ??
|
|
486
|
+
input.unique_key ??
|
|
487
|
+
input.uniqueKey);
|
|
488
|
+
const externalUserId = getTrimmedString(nestedExternalUser.external_user_id ??
|
|
489
|
+
nestedExternalUser.externalUserId ??
|
|
490
|
+
input.external_user_id ??
|
|
491
|
+
input.externalUserId);
|
|
492
|
+
const referenceKey = uniqueKey ?? externalUserId;
|
|
493
|
+
if (!referenceKey) {
|
|
494
|
+
throw new Error('unique_key or external_user_id is required');
|
|
495
|
+
}
|
|
496
|
+
return this.postV2('user/create_external_user', {
|
|
497
|
+
...input,
|
|
498
|
+
unique_key: referenceKey,
|
|
499
|
+
...(externalUserId ? { external_user_id: externalUserId } : {}),
|
|
500
|
+
}, options);
|
|
501
|
+
}
|
|
432
502
|
async createV2UserRechargeCredits(payload, options) {
|
|
433
503
|
const amount = Number(payload?.amount);
|
|
434
504
|
if (!Number.isFinite(amount) || amount <= 0) {
|
|
@@ -534,6 +604,40 @@ export class SamsarClient {
|
|
|
534
604
|
webhookUrl: options?.webhookUrl,
|
|
535
605
|
}, options);
|
|
536
606
|
}
|
|
607
|
+
async createV2StepVideoFromText(input, options) {
|
|
608
|
+
const normalizedInput = normalizeCreateVideoFromTextInput(input);
|
|
609
|
+
return this.postV2('video/step/text_to_video', {
|
|
610
|
+
input: normalizedInput,
|
|
611
|
+
webhookUrl: options?.webhookUrl,
|
|
612
|
+
}, options);
|
|
613
|
+
}
|
|
614
|
+
async createV2StepTextToVideo(input, options) {
|
|
615
|
+
return this.createV2StepVideoFromText(input, options);
|
|
616
|
+
}
|
|
617
|
+
async createV2StepVideoFromImage(input, options) {
|
|
618
|
+
const normalizedInput = normalizeCreateV2StepImageToVideoInput(input);
|
|
619
|
+
return this.postV2('video/step/image_to_video', {
|
|
620
|
+
input: normalizedInput,
|
|
621
|
+
webhookUrl: options?.webhookUrl,
|
|
622
|
+
}, options);
|
|
623
|
+
}
|
|
624
|
+
async createV2StepImageToVideo(input, options) {
|
|
625
|
+
return this.createV2StepVideoFromImage(input, options);
|
|
626
|
+
}
|
|
627
|
+
async getV2StepVideoStatus(requestId, options) {
|
|
628
|
+
const normalizedRequestId = getTrimmedString(requestId);
|
|
629
|
+
if (!normalizedRequestId) {
|
|
630
|
+
throw new Error('requestId is required');
|
|
631
|
+
}
|
|
632
|
+
return this.getV2(`video/step/${encodeURIComponent(normalizedRequestId)}/status`, options);
|
|
633
|
+
}
|
|
634
|
+
async processNextV2StepVideo(requestId, options) {
|
|
635
|
+
const normalizedRequestId = getTrimmedString(requestId);
|
|
636
|
+
if (!normalizedRequestId) {
|
|
637
|
+
throw new Error('requestId is required');
|
|
638
|
+
}
|
|
639
|
+
return this.postV2(`video/step/${encodeURIComponent(normalizedRequestId)}/process_next`, {}, options);
|
|
640
|
+
}
|
|
537
641
|
async translateV2Video(input, options) {
|
|
538
642
|
const normalizedInput = normalizeTranslateVideoInput(input, 'translateV2Video');
|
|
539
643
|
return this.postV2('translate_video', {
|
|
@@ -541,6 +645,13 @@ export class SamsarClient {
|
|
|
541
645
|
webhookUrl: options?.webhookUrl,
|
|
542
646
|
}, options);
|
|
543
647
|
}
|
|
648
|
+
async cloneV2Video(input, options) {
|
|
649
|
+
const normalizedInput = normalizeCloneVideoInput(input, 'cloneV2Video');
|
|
650
|
+
return this.postV2('video/clone', {
|
|
651
|
+
input: normalizedInput,
|
|
652
|
+
webhookUrl: options?.webhookUrl,
|
|
653
|
+
}, options);
|
|
654
|
+
}
|
|
544
655
|
async uploadV2ImageData(imageData, options) {
|
|
545
656
|
if (!Array.isArray(imageData) || imageData.length === 0) {
|
|
546
657
|
throw new Error('imageData must be a non-empty array of data URLs');
|
|
@@ -573,7 +684,9 @@ export class SamsarClient {
|
|
|
573
684
|
}
|
|
574
685
|
async getV2Status(requestId, options) {
|
|
575
686
|
const queryParams = {
|
|
576
|
-
...(options?.externalUser
|
|
687
|
+
...(options?.externalUser
|
|
688
|
+
? buildExternalUserQuery(options.externalUser, { requireProvider: false })
|
|
689
|
+
: {}),
|
|
577
690
|
...(options?.queryParams ?? {}),
|
|
578
691
|
};
|
|
579
692
|
return this.getStatus(requestId, {
|
|
@@ -782,6 +895,39 @@ export class SamsarClient {
|
|
|
782
895
|
}
|
|
783
896
|
return response;
|
|
784
897
|
}
|
|
898
|
+
/**
|
|
899
|
+
* Deep-clone a completed video session and queue one final render for the new session.
|
|
900
|
+
* The clone copies session assets, then regenerates only the final rendered video URL.
|
|
901
|
+
*/
|
|
902
|
+
async cloneVideo(input, options) {
|
|
903
|
+
const normalizedInput = normalizeCloneVideoInput(input, 'cloneVideo');
|
|
904
|
+
const body = {
|
|
905
|
+
input: {
|
|
906
|
+
...normalizedInput,
|
|
907
|
+
},
|
|
908
|
+
webhookUrl: options?.webhookUrl,
|
|
909
|
+
};
|
|
910
|
+
const response = await this.post('video/clone', body, options);
|
|
911
|
+
const data = response.data;
|
|
912
|
+
if (data && typeof data === 'object') {
|
|
913
|
+
const sessionId = typeof data.sessionID === 'string'
|
|
914
|
+
? data.sessionID
|
|
915
|
+
: typeof data.session_id === 'string'
|
|
916
|
+
? data.session_id
|
|
917
|
+
: typeof data.request_id === 'string'
|
|
918
|
+
? data.request_id
|
|
919
|
+
: undefined;
|
|
920
|
+
const normalizedSessionId = sessionId ? String(sessionId) : undefined;
|
|
921
|
+
const normalizedData = {
|
|
922
|
+
...data,
|
|
923
|
+
sessionID: data.sessionID ?? normalizedSessionId ?? '',
|
|
924
|
+
session_id: data.session_id ?? normalizedSessionId ?? null,
|
|
925
|
+
request_id: data.request_id ?? normalizedSessionId ?? null,
|
|
926
|
+
};
|
|
927
|
+
return { ...response, data: normalizedData };
|
|
928
|
+
}
|
|
929
|
+
return response;
|
|
930
|
+
}
|
|
785
931
|
/**
|
|
786
932
|
* Join multiple existing video sessions into a single session by appending their timelines.
|
|
787
933
|
* Creates a new session_id and queues transcription + frame + video generation.
|
|
@@ -1953,9 +2099,29 @@ export class SamsarClient {
|
|
|
1953
2099
|
if (!options?.externalUser) {
|
|
1954
2100
|
return body;
|
|
1955
2101
|
}
|
|
2102
|
+
const externalUser = normalizeExternalUserIdentity(options.externalUser, {
|
|
2103
|
+
requireProvider: false,
|
|
2104
|
+
});
|
|
2105
|
+
if (!externalUser.provider) {
|
|
2106
|
+
const referenceKey = externalUser.unique_key ?? externalUser.external_user_id;
|
|
2107
|
+
return {
|
|
2108
|
+
...body,
|
|
2109
|
+
unique_key: referenceKey,
|
|
2110
|
+
...(externalUser.external_user_id ? { external_user_id: externalUser.external_user_id } : {}),
|
|
2111
|
+
...(externalUser.external_app_id ? { external_app_id: externalUser.external_app_id } : {}),
|
|
2112
|
+
...(externalUser.external_company_id ? { external_company_id: externalUser.external_company_id } : {}),
|
|
2113
|
+
...(externalUser.external_account_id ? { external_account_id: externalUser.external_account_id } : {}),
|
|
2114
|
+
...(externalUser.email ? { email: externalUser.email } : {}),
|
|
2115
|
+
...(externalUser.username ? { username: externalUser.username } : {}),
|
|
2116
|
+
...(externalUser.display_name ? { display_name: externalUser.display_name } : {}),
|
|
2117
|
+
...(externalUser.avatar_url ? { avatar_url: externalUser.avatar_url } : {}),
|
|
2118
|
+
...(externalUser.user_type ? { user_type: externalUser.user_type } : {}),
|
|
2119
|
+
...(externalUser.metadata ? { metadata: externalUser.metadata } : {}),
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
1956
2122
|
return {
|
|
1957
2123
|
...body,
|
|
1958
|
-
external_user:
|
|
2124
|
+
external_user: externalUser,
|
|
1959
2125
|
};
|
|
1960
2126
|
}
|
|
1961
2127
|
buildV2Url(path) {
|
|
@@ -2004,6 +2170,13 @@ function parseNumber(value) {
|
|
|
2004
2170
|
const num = value !== undefined ? Number(value) : NaN;
|
|
2005
2171
|
return Number.isFinite(num) ? num : undefined;
|
|
2006
2172
|
}
|
|
2173
|
+
function getTrimmedString(value) {
|
|
2174
|
+
if (typeof value !== 'string') {
|
|
2175
|
+
return undefined;
|
|
2176
|
+
}
|
|
2177
|
+
const trimmed = value.trim();
|
|
2178
|
+
return trimmed || undefined;
|
|
2179
|
+
}
|
|
2007
2180
|
function removeEmptyHeaders(headers) {
|
|
2008
2181
|
const normalized = {};
|
|
2009
2182
|
for (const [key, value] of Object.entries(headers)) {
|
|
@@ -2013,15 +2186,22 @@ function removeEmptyHeaders(headers) {
|
|
|
2013
2186
|
}
|
|
2014
2187
|
return normalized;
|
|
2015
2188
|
}
|
|
2016
|
-
function normalizeExternalUserIdentity(externalUser) {
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2189
|
+
function normalizeExternalUserIdentity(externalUser, { requireProvider = true } = {}) {
|
|
2190
|
+
const provider = getTrimmedString(externalUser.provider);
|
|
2191
|
+
const uniqueKey = getTrimmedString(externalUser.unique_key ??
|
|
2192
|
+
externalUser.uniqueKey);
|
|
2193
|
+
const externalUserId = getTrimmedString(externalUser.external_user_id) ??
|
|
2194
|
+
getTrimmedString(externalUser.externalUserId) ??
|
|
2195
|
+
uniqueKey;
|
|
2196
|
+
if ((requireProvider && !provider) || !externalUserId) {
|
|
2197
|
+
throw new Error(requireProvider
|
|
2198
|
+
? 'externalUser.provider and externalUser.external_user_id or externalUser.unique_key are required'
|
|
2199
|
+
: 'externalUser.external_user_id or externalUser.unique_key is required');
|
|
2021
2200
|
}
|
|
2022
2201
|
return {
|
|
2023
|
-
provider:
|
|
2202
|
+
...(provider ? { provider } : {}),
|
|
2024
2203
|
external_user_id: externalUserId,
|
|
2204
|
+
...(uniqueKey ? { unique_key: uniqueKey } : {}),
|
|
2025
2205
|
...(externalUser.external_app_id || externalUser.externalAppId
|
|
2026
2206
|
? { external_app_id: externalUser.external_app_id ?? externalUser.externalAppId }
|
|
2027
2207
|
: {}),
|
|
@@ -2050,11 +2230,12 @@ function normalizeExternalUserIdentity(externalUser) {
|
|
|
2050
2230
|
...(externalUser.metadata ? { metadata: externalUser.metadata } : {}),
|
|
2051
2231
|
};
|
|
2052
2232
|
}
|
|
2053
|
-
function buildExternalUserQuery(externalUser) {
|
|
2054
|
-
const normalized = normalizeExternalUserIdentity(externalUser);
|
|
2233
|
+
function buildExternalUserQuery(externalUser, { requireProvider = true } = {}) {
|
|
2234
|
+
const normalized = normalizeExternalUserIdentity(externalUser, { requireProvider });
|
|
2055
2235
|
return {
|
|
2056
2236
|
provider: normalized.provider,
|
|
2057
2237
|
external_user_id: normalized.external_user_id,
|
|
2238
|
+
unique_key: normalized.unique_key ?? undefined,
|
|
2058
2239
|
external_app_id: normalized.external_app_id ?? undefined,
|
|
2059
2240
|
external_company_id: normalized.external_company_id ?? undefined,
|
|
2060
2241
|
external_account_id: normalized.external_account_id ?? undefined,
|