samsar-js 0.48.18 → 0.48.20
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 +62 -0
- package/dist/index.d.ts +148 -2
- package/dist/index.js +328 -76
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -423,6 +423,20 @@ const externalRender = await platform.createExternalVideoFromText(externalUser,
|
|
|
423
423
|
enable_subtitles: true,
|
|
424
424
|
});
|
|
425
425
|
|
|
426
|
+
// Update an external user's existing outro by generating a new QR CTA outro
|
|
427
|
+
const externalOutroUpdate = await platform.updateExternalVideoOutroImage(externalUser, {
|
|
428
|
+
request_id: externalRender.data.request_id,
|
|
429
|
+
generate_outro_image: true,
|
|
430
|
+
cta_url: 'https://example.com/shop',
|
|
431
|
+
cta_text_top: 'Scan to shop',
|
|
432
|
+
cta_text_bottom: 'Limited drop',
|
|
433
|
+
add_outro_animation: true,
|
|
434
|
+
});
|
|
435
|
+
console.log(externalOutroUpdate.data.request_id);
|
|
436
|
+
|
|
437
|
+
// Repeated video routes accept the returned extreq_ id or the normalized external id.
|
|
438
|
+
// The API resolves ownership through external request mappings and GlobalSession records.
|
|
439
|
+
|
|
426
440
|
// Run an assistant completion against one of that external user's sessions.
|
|
427
441
|
// Credits are deducted from the external user, while the owning Samsar account model config is used internally.
|
|
428
442
|
const externalAssistant = await platform.createExternalAssistantCompletion(
|
|
@@ -491,9 +505,57 @@ Video model support notes:
|
|
|
491
505
|
- `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.
|
|
492
506
|
- `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
|
|
493
507
|
- `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.
|
|
508
|
+
- 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`, `addVideoOutroImage`, and `updateVideoOutroImage`; the explicit external variants are available when you want to call `/external_users/*` directly. Do not strip the `extreq_` prefix.
|
|
494
509
|
- `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.
|
|
495
510
|
- Image-list video pricing is per rendered second: `VEO3.1I2V` and `SEEDANCEI2V` are 75 credits/sec, `KLING3.0` is 50 credits/sec, and `RUNWAYML` is 25 credits/sec.
|
|
496
511
|
|
|
512
|
+
Upcoming `/v2` omni route adapters:
|
|
513
|
+
- `/v2` is additive; `/v1` is not deprecated.
|
|
514
|
+
- `createV2VideoFromText`, `createV2VideoFromImageList`, `updateV2VideoOutroImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
|
|
515
|
+
- Programmatic user billing helpers include `createV2UserRechargeCredits`, `refreshV2UserToken`, `getV2UserCredits`, `getV2UserUsageLogs`, and `getV2UserPaymentStatus`.
|
|
516
|
+
- 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.
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
const v2Video = await platform.createV2VideoFromImageList({
|
|
520
|
+
image_urls: ['https://cdn.example.com/a.png', 'https://cdn.example.com/b.png'],
|
|
521
|
+
video_model: 'RUNWAYML',
|
|
522
|
+
generate_outro_image: true,
|
|
523
|
+
cta_url: 'https://example.com/book',
|
|
524
|
+
cta_text_top: 'Scan to book',
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
const v2ExternalVideo = await platform.createV2VideoFromImageList(
|
|
528
|
+
{
|
|
529
|
+
image_urls: ['https://cdn.example.com/a.png', 'https://cdn.example.com/b.png'],
|
|
530
|
+
video_model: 'KLING3.0',
|
|
531
|
+
},
|
|
532
|
+
{ externalUser },
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
const v2Status = await platform.getV2Status(v2Video.data.request_id!);
|
|
536
|
+
console.log(v2Status.data.status);
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
Programmatic user recharge and OAuth-style refresh token rotation:
|
|
540
|
+
|
|
541
|
+
```ts
|
|
542
|
+
const publicClient = new SamsarClient({});
|
|
543
|
+
|
|
544
|
+
const checkout = await publicClient.createV2UserRechargeCredits({
|
|
545
|
+
amount: 25,
|
|
546
|
+
email: 'customer@example.com',
|
|
547
|
+
redirect_url: 'https://example.com/samsar/callback',
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// After the Stripe webhook calls your redirect_url with authToken, refreshToken, and expiryDate:
|
|
551
|
+
const userClient = new SamsarClient({ apiKey: authToken });
|
|
552
|
+
const refreshed = await userClient.refreshV2UserToken(refreshToken);
|
|
553
|
+
|
|
554
|
+
localStorage.setItem('authToken', refreshed.data.authToken);
|
|
555
|
+
localStorage.setItem('refreshToken', refreshed.data.refreshToken);
|
|
556
|
+
localStorage.setItem('expiryDate', refreshed.data.expiryDate);
|
|
557
|
+
```
|
|
558
|
+
|
|
497
559
|
Each method returns `{ data, status, headers, creditsCharged, creditsRemaining, raw }`. Non-2xx responses throw `SamsarRequestError` containing status, body, and credit headers (if present).
|
|
498
560
|
|
|
499
561
|
## Billing notes
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Respo
|
|
|
2
2
|
type QueryValue = string | number | boolean | null | undefined;
|
|
3
3
|
type QueryParams = Record<string, QueryValue>;
|
|
4
4
|
export interface SamsarClientOptions {
|
|
5
|
-
apiKey
|
|
5
|
+
apiKey?: string;
|
|
6
6
|
baseUrl?: string;
|
|
7
7
|
timeoutMs?: number;
|
|
8
8
|
fetch?: FetchLike;
|
|
@@ -224,6 +224,12 @@ export interface UpdateVideoOutroImageInput {
|
|
|
224
224
|
sessionID?: string;
|
|
225
225
|
request_id?: string;
|
|
226
226
|
requestId?: string;
|
|
227
|
+
source_request_id?: string;
|
|
228
|
+
sourceRequestId?: string;
|
|
229
|
+
external_request_id?: string;
|
|
230
|
+
externalRequestId?: string;
|
|
231
|
+
external_session_id?: string;
|
|
232
|
+
externalSessionId?: string;
|
|
227
233
|
outro_image_url?: string;
|
|
228
234
|
outroImageUrl?: string;
|
|
229
235
|
new_outro_image_url?: string;
|
|
@@ -265,6 +271,12 @@ export interface AddVideoOutroImageInput {
|
|
|
265
271
|
sessionID?: string;
|
|
266
272
|
request_id?: string;
|
|
267
273
|
requestId?: string;
|
|
274
|
+
source_request_id?: string;
|
|
275
|
+
sourceRequestId?: string;
|
|
276
|
+
external_request_id?: string;
|
|
277
|
+
externalRequestId?: string;
|
|
278
|
+
external_session_id?: string;
|
|
279
|
+
externalSessionId?: string;
|
|
268
280
|
outro_image_url?: string;
|
|
269
281
|
outroImageUrl?: string;
|
|
270
282
|
new_outro_image_url?: string;
|
|
@@ -1294,6 +1306,89 @@ export interface ExternalRequestsListResponse {
|
|
|
1294
1306
|
externalUser?: ExternalUserSummary | null;
|
|
1295
1307
|
[key: string]: unknown;
|
|
1296
1308
|
}
|
|
1309
|
+
export interface V2RequestOptions extends SamsarRequestOptions {
|
|
1310
|
+
externalUser?: ExternalUserIdentity | null;
|
|
1311
|
+
webhookUrl?: string;
|
|
1312
|
+
}
|
|
1313
|
+
export interface V2SessionResponse {
|
|
1314
|
+
account_type?: 'internal' | 'external' | string;
|
|
1315
|
+
auth_type?: string;
|
|
1316
|
+
user?: {
|
|
1317
|
+
id?: string;
|
|
1318
|
+
email?: string | null;
|
|
1319
|
+
displayName?: string | null;
|
|
1320
|
+
username?: string | null;
|
|
1321
|
+
pfpUrl?: string | null;
|
|
1322
|
+
preferredLanguage?: string | null;
|
|
1323
|
+
[key: string]: unknown;
|
|
1324
|
+
};
|
|
1325
|
+
external_api_key?: string | null;
|
|
1326
|
+
external_user?: ExternalUserSummary | null;
|
|
1327
|
+
externalUser?: ExternalUserSummary | null;
|
|
1328
|
+
remainingCredits?: number | null;
|
|
1329
|
+
[key: string]: unknown;
|
|
1330
|
+
}
|
|
1331
|
+
export interface V2RequestsListResponse {
|
|
1332
|
+
requests: Array<ExternalRequestSummary | Record<string, unknown>>;
|
|
1333
|
+
external_user?: ExternalUserSummary | null;
|
|
1334
|
+
externalUser?: ExternalUserSummary | null;
|
|
1335
|
+
[key: string]: unknown;
|
|
1336
|
+
}
|
|
1337
|
+
export interface V2UserRechargeCreditsRequest {
|
|
1338
|
+
amount: number;
|
|
1339
|
+
email: string;
|
|
1340
|
+
redirect_url?: string;
|
|
1341
|
+
redirectUrl?: string;
|
|
1342
|
+
[key: string]: unknown;
|
|
1343
|
+
}
|
|
1344
|
+
export interface V2UserRechargeCreditsResponse {
|
|
1345
|
+
url: string;
|
|
1346
|
+
checkoutSessionId?: string | null;
|
|
1347
|
+
paymentStatusEndpoint?: string;
|
|
1348
|
+
amount: number;
|
|
1349
|
+
amountCents: number;
|
|
1350
|
+
credits: number;
|
|
1351
|
+
currency: string;
|
|
1352
|
+
redirectUrl?: string;
|
|
1353
|
+
[key: string]: unknown;
|
|
1354
|
+
}
|
|
1355
|
+
export interface V2UserTokenRefreshRequest {
|
|
1356
|
+
refreshToken?: string;
|
|
1357
|
+
refresh_token?: string;
|
|
1358
|
+
}
|
|
1359
|
+
export interface V2UserTokenResponse {
|
|
1360
|
+
tokenType?: 'Bearer' | string;
|
|
1361
|
+
authToken: string;
|
|
1362
|
+
refreshToken: string;
|
|
1363
|
+
expiryDate: string;
|
|
1364
|
+
expiresInSeconds?: number;
|
|
1365
|
+
refreshTokenExpiresAt?: string;
|
|
1366
|
+
[key: string]: unknown;
|
|
1367
|
+
}
|
|
1368
|
+
export interface UsageLogItem {
|
|
1369
|
+
id?: string;
|
|
1370
|
+
source?: string;
|
|
1371
|
+
credits?: number;
|
|
1372
|
+
balanceAfter?: number | null;
|
|
1373
|
+
metadata?: Record<string, unknown>;
|
|
1374
|
+
direction?: string;
|
|
1375
|
+
createdAt?: string;
|
|
1376
|
+
updatedAt?: string;
|
|
1377
|
+
[key: string]: unknown;
|
|
1378
|
+
}
|
|
1379
|
+
export interface UsageLogsResponse {
|
|
1380
|
+
items: UsageLogItem[];
|
|
1381
|
+
pagination?: {
|
|
1382
|
+
page?: number;
|
|
1383
|
+
pageSize?: number;
|
|
1384
|
+
totalItems?: number;
|
|
1385
|
+
totalPages?: number;
|
|
1386
|
+
hasNextPage?: boolean;
|
|
1387
|
+
hasPreviousPage?: boolean;
|
|
1388
|
+
[key: string]: unknown;
|
|
1389
|
+
};
|
|
1390
|
+
[key: string]: unknown;
|
|
1391
|
+
}
|
|
1297
1392
|
export interface ExternalArchiveResponse {
|
|
1298
1393
|
request?: ExternalRequestSummary | null;
|
|
1299
1394
|
external_user?: ExternalUserSummary | null;
|
|
@@ -1476,13 +1571,49 @@ export declare class SamsarRequestError extends Error {
|
|
|
1476
1571
|
constructor(message: string, init: SamsarErrorInit);
|
|
1477
1572
|
}
|
|
1478
1573
|
export declare class SamsarClient {
|
|
1479
|
-
private readonly apiKey
|
|
1574
|
+
private readonly apiKey?;
|
|
1480
1575
|
private readonly baseUrl;
|
|
1481
1576
|
private readonly timeoutMs;
|
|
1482
1577
|
private readonly fetchFn;
|
|
1483
1578
|
private readonly defaultHeaders;
|
|
1484
1579
|
private readonly externalUserApiKey?;
|
|
1485
1580
|
constructor(options: SamsarClientOptions);
|
|
1581
|
+
/**
|
|
1582
|
+
* Low-level POST adapter for the upcoming /v2 omni routes.
|
|
1583
|
+
* Pass options.externalUser to include an external_user payload; omit it for internal-account calls
|
|
1584
|
+
* or when authenticating directly with an external-user auth token/API key.
|
|
1585
|
+
*/
|
|
1586
|
+
postV2<T = Record<string, unknown>>(path: string, payload?: Record<string, unknown>, options?: V2RequestOptions): Promise<SamsarResult<T>>;
|
|
1587
|
+
/**
|
|
1588
|
+
* Low-level GET adapter for the upcoming /v2 omni routes.
|
|
1589
|
+
*/
|
|
1590
|
+
getV2<T = Record<string, unknown>>(path: string, options?: V2RequestOptions): Promise<SamsarResult<T>>;
|
|
1591
|
+
createV2Session(options?: V2RequestOptions): Promise<SamsarResult<V2SessionResponse>>;
|
|
1592
|
+
getV2Credits(options?: V2RequestOptions): Promise<SamsarResult<CreditsBalanceResponse | ExternalCreditsBalanceResponse>>;
|
|
1593
|
+
getV2UserCredits(options?: V2RequestOptions): Promise<SamsarResult<CreditsBalanceResponse>>;
|
|
1594
|
+
getV2UserUsageLogs(options?: V2RequestOptions & {
|
|
1595
|
+
page?: number;
|
|
1596
|
+
pageSize?: number;
|
|
1597
|
+
limit?: number;
|
|
1598
|
+
}): Promise<SamsarResult<UsageLogsResponse>>;
|
|
1599
|
+
listV2Requests(options?: V2RequestOptions): Promise<SamsarResult<V2RequestsListResponse>>;
|
|
1600
|
+
createV2UserRechargeCredits(payload: V2UserRechargeCreditsRequest, options?: V2RequestOptions): Promise<SamsarResult<V2UserRechargeCreditsResponse>>;
|
|
1601
|
+
refreshV2UserToken(payload: string | V2UserTokenRefreshRequest, options?: V2RequestOptions): Promise<SamsarResult<V2UserTokenResponse>>;
|
|
1602
|
+
refreshV2UserAuthToken(payload: string | V2UserTokenRefreshRequest, options?: V2RequestOptions): Promise<SamsarResult<V2UserTokenResponse>>;
|
|
1603
|
+
getV2UserPaymentStatus(payload: PaymentStatusRequest, options?: V2RequestOptions): Promise<SamsarResult<PaymentStatusResponse>>;
|
|
1604
|
+
createV2LoginToken(options?: V2RequestOptions & {
|
|
1605
|
+
redirect?: string;
|
|
1606
|
+
}): Promise<SamsarResult<CreateLoginTokenResponse | ExternalCreateLoginTokenResponse>>;
|
|
1607
|
+
createV2VideoFromText(input: CreateVideoFromTextInput, options?: V2RequestOptions): Promise<SamsarResult<CreateVideoResponse | ExternalRequestResponse>>;
|
|
1608
|
+
createV2VideoFromImageList(input: CreateVideoFromImageListInput, options?: V2RequestOptions): Promise<SamsarResult<CreateVideoFromImageListResponse | ExternalRequestResponse>>;
|
|
1609
|
+
uploadV2ImageData(imageData: string[], options?: V2RequestOptions): Promise<SamsarResult<{
|
|
1610
|
+
image_urls: string[];
|
|
1611
|
+
}>>;
|
|
1612
|
+
updateV2VideoOutroImage(input: UpdateVideoOutroImageInput, options?: V2RequestOptions): Promise<SamsarResult<UpdateVideoOutroImageResponse | ExternalRequestResponse>>;
|
|
1613
|
+
addV2VideoOutroImage(input: AddVideoOutroImageInput, options?: V2RequestOptions): Promise<SamsarResult<AddVideoOutroImageResponse | ExternalRequestResponse>>;
|
|
1614
|
+
getV2Status(requestId: string, options?: V2RequestOptions & {
|
|
1615
|
+
queryParams?: QueryParams;
|
|
1616
|
+
}): Promise<SamsarResult<GlobalStatusResponse | ExternalStatusResponse>>;
|
|
1486
1617
|
/**
|
|
1487
1618
|
* Create a new video generation job from text.
|
|
1488
1619
|
*/
|
|
@@ -1584,6 +1715,13 @@ export declare class SamsarClient {
|
|
|
1584
1715
|
updateVideoOutroImage(input: UpdateVideoOutroImageInput, options?: {
|
|
1585
1716
|
webhookUrl?: string;
|
|
1586
1717
|
} & SamsarRequestOptions): Promise<SamsarResult<UpdateVideoOutroImageResponse>>;
|
|
1718
|
+
/**
|
|
1719
|
+
* Update the outro image for an external-user video request by resolving the external request id
|
|
1720
|
+
* through /external_users/update_outro_image.
|
|
1721
|
+
*/
|
|
1722
|
+
updateExternalVideoOutroImage(externalUser: ExternalUserIdentity, input: UpdateVideoOutroImageInput, options?: {
|
|
1723
|
+
webhookUrl?: string;
|
|
1724
|
+
} & SamsarRequestOptions): Promise<SamsarResult<ExternalRequestResponse>>;
|
|
1587
1725
|
/**
|
|
1588
1726
|
* Add or replace the outro image for an existing video session by cloning it into a new session and
|
|
1589
1727
|
* re-running frame/video generation.
|
|
@@ -1591,6 +1729,12 @@ export declare class SamsarClient {
|
|
|
1591
1729
|
addVideoOutroImage(input: AddVideoOutroImageInput, options?: {
|
|
1592
1730
|
webhookUrl?: string;
|
|
1593
1731
|
} & SamsarRequestOptions): Promise<SamsarResult<AddVideoOutroImageResponse>>;
|
|
1732
|
+
/**
|
|
1733
|
+
* Add or replace an outro image for an external-user video request by resolving the external request id.
|
|
1734
|
+
*/
|
|
1735
|
+
addExternalVideoOutroImage(externalUser: ExternalUserIdentity, input: AddVideoOutroImageInput, options?: {
|
|
1736
|
+
webhookUrl?: string;
|
|
1737
|
+
} & SamsarRequestOptions): Promise<SamsarResult<ExternalRequestResponse>>;
|
|
1594
1738
|
/**
|
|
1595
1739
|
* Fetch the latest available render URL for a given video session id.
|
|
1596
1740
|
* Maps to GET /video/fetch_latest_version?session_id={sessionId}.
|
|
@@ -1826,5 +1970,7 @@ export declare class SamsarClient {
|
|
|
1826
1970
|
private buildHeaders;
|
|
1827
1971
|
private buildUrl;
|
|
1828
1972
|
private buildRootUrl;
|
|
1973
|
+
private withV2ExternalUser;
|
|
1974
|
+
private buildV2Url;
|
|
1829
1975
|
}
|
|
1830
1976
|
export default SamsarClient;
|
package/dist/index.js
CHANGED
|
@@ -126,6 +126,96 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
126
126
|
}
|
|
127
127
|
return normalized;
|
|
128
128
|
}
|
|
129
|
+
function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroImage') {
|
|
130
|
+
const raw = input;
|
|
131
|
+
const videoSessionId = raw.videoSessionId ??
|
|
132
|
+
raw.video_session_id ??
|
|
133
|
+
raw.videoSessionID ??
|
|
134
|
+
raw.session_id ??
|
|
135
|
+
raw.sessionId ??
|
|
136
|
+
raw.sessionID ??
|
|
137
|
+
raw.request_id ??
|
|
138
|
+
raw.requestId ??
|
|
139
|
+
raw.source_request_id ??
|
|
140
|
+
raw.sourceRequestId ??
|
|
141
|
+
raw.external_request_id ??
|
|
142
|
+
raw.externalRequestId ??
|
|
143
|
+
raw.external_session_id ??
|
|
144
|
+
raw.externalSessionId;
|
|
145
|
+
const outroImageUrl = raw.outro_image_url ??
|
|
146
|
+
raw.outroImageUrl ??
|
|
147
|
+
raw.new_outro_image_url ??
|
|
148
|
+
raw.newOutroImageUrl;
|
|
149
|
+
const rawGenerateOutroImage = raw.generate_outro_image ??
|
|
150
|
+
raw.generateOutroImage;
|
|
151
|
+
const rawAddOutroAnimation = raw.add_outro_animation ??
|
|
152
|
+
raw.addOutroAnimation;
|
|
153
|
+
const rawAddOutroFocusArea = raw.add_outro_focus_area ??
|
|
154
|
+
raw.addOutroFocusArea;
|
|
155
|
+
const rawOutroFocusArea = raw.outro_focust_area ??
|
|
156
|
+
raw.outro_focus_area ??
|
|
157
|
+
raw.outroFocustArea ??
|
|
158
|
+
raw.outroFocusArea;
|
|
159
|
+
const ctaUrl = raw.cta_url ??
|
|
160
|
+
raw.ctaUrl;
|
|
161
|
+
const ctaTextTop = raw.cta_text_top ??
|
|
162
|
+
raw.ctaTextTop;
|
|
163
|
+
const ctaTextBottom = raw.cta_text_bottom ??
|
|
164
|
+
raw.ctaTextBottom;
|
|
165
|
+
const ctaLogo = raw.cta_logo ??
|
|
166
|
+
raw.ctaLogo;
|
|
167
|
+
const generateOutroImage = rawGenerateOutroImage === true ||
|
|
168
|
+
(rawGenerateOutroImage === undefined && !outroImageUrl && Boolean(ctaUrl));
|
|
169
|
+
if (!videoSessionId) {
|
|
170
|
+
throw new Error(`videoSessionId is required for ${context}`);
|
|
171
|
+
}
|
|
172
|
+
if (rawGenerateOutroImage !== undefined && typeof rawGenerateOutroImage !== 'boolean') {
|
|
173
|
+
throw new Error(`generate_outro_image must be a boolean for ${context}`);
|
|
174
|
+
}
|
|
175
|
+
if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
|
|
176
|
+
throw new Error(`add_outro_animation must be a boolean for ${context}`);
|
|
177
|
+
}
|
|
178
|
+
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
179
|
+
throw new Error(`add_outro_focus_area must be a boolean for ${context}`);
|
|
180
|
+
}
|
|
181
|
+
if (generateOutroImage && outroImageUrl) {
|
|
182
|
+
throw new Error(`Use either generate_outro_image with cta_url or outro_image_url for ${context}`);
|
|
183
|
+
}
|
|
184
|
+
if (!generateOutroImage && !outroImageUrl) {
|
|
185
|
+
throw new Error(`outro_image_url is required for ${context} unless generate_outro_image is true`);
|
|
186
|
+
}
|
|
187
|
+
if (generateOutroImage) {
|
|
188
|
+
if (!ctaUrl || !String(ctaUrl).trim()) {
|
|
189
|
+
throw new Error(`cta_url is required when generate_outro_image is true for ${context}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
193
|
+
throw new Error(`add_outro_focus_area requires add_outro_animation to be true for ${context}`);
|
|
194
|
+
}
|
|
195
|
+
if (!generateOutroImage && rawAddOutroFocusArea === true) {
|
|
196
|
+
if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
|
|
197
|
+
throw new Error(`outro_focust_area must be an object with x, y, width, height for ${context}`);
|
|
198
|
+
}
|
|
199
|
+
const { x, y, width, height } = rawOutroFocusArea;
|
|
200
|
+
const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
|
|
201
|
+
if (isInvalid) {
|
|
202
|
+
throw new Error(`outro_focust_area x, y, width, height must be valid numbers for ${context}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
...input,
|
|
207
|
+
videoSessionId: String(videoSessionId),
|
|
208
|
+
...(outroImageUrl ? { outro_image_url: String(outroImageUrl) } : {}),
|
|
209
|
+
generate_outro_image: generateOutroImage,
|
|
210
|
+
...(generateOutroImage ? { cta_url: String(ctaUrl).trim() } : {}),
|
|
211
|
+
...(ctaTextTop ? { cta_text_top: String(ctaTextTop) } : {}),
|
|
212
|
+
...(ctaTextBottom ? { cta_text_bottom: String(ctaTextBottom) } : {}),
|
|
213
|
+
...(ctaLogo ? { cta_logo: String(ctaLogo) } : {}),
|
|
214
|
+
...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
|
|
215
|
+
...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
|
|
216
|
+
...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
129
219
|
function normalizeSessionPublicationInput(input, context) {
|
|
130
220
|
if (typeof input !== 'string' && (!input || typeof input !== 'object' || Array.isArray(input))) {
|
|
131
221
|
throw new Error(`input must be a session id or object for ${context}`);
|
|
@@ -180,10 +270,7 @@ function normalizeSessionPublicationInput(input, context) {
|
|
|
180
270
|
}
|
|
181
271
|
export class SamsarClient {
|
|
182
272
|
constructor(options) {
|
|
183
|
-
|
|
184
|
-
throw new Error('apiKey is required to initialize SamsarClient');
|
|
185
|
-
}
|
|
186
|
-
this.apiKey = options.apiKey;
|
|
273
|
+
this.apiKey = options?.apiKey?.trim() || undefined;
|
|
187
274
|
this.baseUrl = trimTrailingSlash(options.baseUrl ?? DEFAULT_BASE_URL);
|
|
188
275
|
this.timeoutMs = options.timeoutMs ?? 30000;
|
|
189
276
|
this.fetchFn = options.fetch ?? globalThis.fetch;
|
|
@@ -193,6 +280,155 @@ export class SamsarClient {
|
|
|
193
280
|
throw new Error('A fetch implementation is required. Provide one via the "fetch" option when running outside environments with global fetch.');
|
|
194
281
|
}
|
|
195
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Low-level POST adapter for the upcoming /v2 omni routes.
|
|
285
|
+
* Pass options.externalUser to include an external_user payload; omit it for internal-account calls
|
|
286
|
+
* or when authenticating directly with an external-user auth token/API key.
|
|
287
|
+
*/
|
|
288
|
+
async postV2(path, payload = {}, options) {
|
|
289
|
+
return this.post(this.buildV2Url(path), this.withV2ExternalUser(payload, options), options);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Low-level GET adapter for the upcoming /v2 omni routes.
|
|
293
|
+
*/
|
|
294
|
+
async getV2(path, options) {
|
|
295
|
+
const query = {
|
|
296
|
+
...(options?.externalUser ? buildExternalUserQuery(options.externalUser) : {}),
|
|
297
|
+
...(options?.query ?? {}),
|
|
298
|
+
};
|
|
299
|
+
return this.get(this.buildV2Url(path), { ...(options ?? {}), query });
|
|
300
|
+
}
|
|
301
|
+
async createV2Session(options) {
|
|
302
|
+
return this.postV2('session', {}, options);
|
|
303
|
+
}
|
|
304
|
+
async getV2Credits(options) {
|
|
305
|
+
return this.getV2('credits', options);
|
|
306
|
+
}
|
|
307
|
+
async getV2UserCredits(options) {
|
|
308
|
+
return this.getV2('user/credits', options);
|
|
309
|
+
}
|
|
310
|
+
async getV2UserUsageLogs(options) {
|
|
311
|
+
const query = {
|
|
312
|
+
...(options?.query ?? {}),
|
|
313
|
+
};
|
|
314
|
+
if (options?.page !== undefined) {
|
|
315
|
+
query.page = options.page;
|
|
316
|
+
}
|
|
317
|
+
if (options?.pageSize !== undefined) {
|
|
318
|
+
query.pageSize = options.pageSize;
|
|
319
|
+
}
|
|
320
|
+
if (options?.limit !== undefined) {
|
|
321
|
+
query.limit = options.limit;
|
|
322
|
+
}
|
|
323
|
+
return this.getV2('user/usage/logs', {
|
|
324
|
+
...(options ?? {}),
|
|
325
|
+
query,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
async listV2Requests(options) {
|
|
329
|
+
return this.getV2('requests', options);
|
|
330
|
+
}
|
|
331
|
+
async createV2UserRechargeCredits(payload, options) {
|
|
332
|
+
const amount = Number(payload?.amount);
|
|
333
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
334
|
+
throw new Error('amount must be a positive dollar amount');
|
|
335
|
+
}
|
|
336
|
+
if (!payload?.email || typeof payload.email !== 'string') {
|
|
337
|
+
throw new Error('email is required');
|
|
338
|
+
}
|
|
339
|
+
const redirectUrl = payload.redirect_url ?? payload.redirectUrl;
|
|
340
|
+
if (!redirectUrl || typeof redirectUrl !== 'string') {
|
|
341
|
+
throw new Error('redirect_url is required');
|
|
342
|
+
}
|
|
343
|
+
return this.postV2('user/recharge_credits', {
|
|
344
|
+
...payload,
|
|
345
|
+
amount,
|
|
346
|
+
email: payload.email.trim(),
|
|
347
|
+
redirect_url: redirectUrl.trim(),
|
|
348
|
+
}, options);
|
|
349
|
+
}
|
|
350
|
+
async refreshV2UserToken(payload, options) {
|
|
351
|
+
const refreshToken = typeof payload === 'string'
|
|
352
|
+
? payload
|
|
353
|
+
: (payload?.refreshToken ?? payload?.refresh_token);
|
|
354
|
+
if (!refreshToken || typeof refreshToken !== 'string') {
|
|
355
|
+
throw new Error('refreshToken is required');
|
|
356
|
+
}
|
|
357
|
+
return this.postV2('user/refresh_token', { refreshToken: refreshToken.trim() }, options);
|
|
358
|
+
}
|
|
359
|
+
async refreshV2UserAuthToken(payload, options) {
|
|
360
|
+
return this.refreshV2UserToken(payload, options);
|
|
361
|
+
}
|
|
362
|
+
async getV2UserPaymentStatus(payload, options) {
|
|
363
|
+
const query = {
|
|
364
|
+
...(options?.query ?? {}),
|
|
365
|
+
};
|
|
366
|
+
if (payload?.checkoutSessionId) {
|
|
367
|
+
query.checkoutSessionId = payload.checkoutSessionId;
|
|
368
|
+
}
|
|
369
|
+
if (payload?.paymentIntentId) {
|
|
370
|
+
query.paymentIntentId = payload.paymentIntentId;
|
|
371
|
+
}
|
|
372
|
+
if (payload?.setupIntentId) {
|
|
373
|
+
query.setupIntentId = payload.setupIntentId;
|
|
374
|
+
}
|
|
375
|
+
return this.getV2('user/payment_status', {
|
|
376
|
+
...(options ?? {}),
|
|
377
|
+
query,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
async createV2LoginToken(options) {
|
|
381
|
+
const body = options?.redirect ? { redirect: options.redirect } : {};
|
|
382
|
+
return this.postV2('create_login_token', body, options);
|
|
383
|
+
}
|
|
384
|
+
async createV2VideoFromText(input, options) {
|
|
385
|
+
const normalizedInput = normalizeCreateVideoFromTextInput(input);
|
|
386
|
+
return this.postV2('text_to_video', {
|
|
387
|
+
input: normalizedInput,
|
|
388
|
+
webhookUrl: options?.webhookUrl,
|
|
389
|
+
}, options);
|
|
390
|
+
}
|
|
391
|
+
async createV2VideoFromImageList(input, options) {
|
|
392
|
+
const normalizedInput = normalizeCreateVideoFromImageListInput(input);
|
|
393
|
+
return this.postV2('image_list_to_video', {
|
|
394
|
+
input: normalizedInput,
|
|
395
|
+
webhookUrl: options?.webhookUrl,
|
|
396
|
+
}, options);
|
|
397
|
+
}
|
|
398
|
+
async uploadV2ImageData(imageData, options) {
|
|
399
|
+
if (!Array.isArray(imageData) || imageData.length === 0) {
|
|
400
|
+
throw new Error('imageData must be a non-empty array of data URLs');
|
|
401
|
+
}
|
|
402
|
+
return this.postV2('upload_image_data', {
|
|
403
|
+
input: {
|
|
404
|
+
image_data: imageData,
|
|
405
|
+
},
|
|
406
|
+
}, options);
|
|
407
|
+
}
|
|
408
|
+
async updateV2VideoOutroImage(input, options) {
|
|
409
|
+
const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'updateV2VideoOutroImage');
|
|
410
|
+
return this.postV2('update_outro_image', {
|
|
411
|
+
input: normalizedInput,
|
|
412
|
+
webhookUrl: options?.webhookUrl,
|
|
413
|
+
}, options);
|
|
414
|
+
}
|
|
415
|
+
async addV2VideoOutroImage(input, options) {
|
|
416
|
+
return this.postV2('add_outro_image', {
|
|
417
|
+
input,
|
|
418
|
+
webhookUrl: options?.webhookUrl,
|
|
419
|
+
}, options);
|
|
420
|
+
}
|
|
421
|
+
async getV2Status(requestId, options) {
|
|
422
|
+
const queryParams = {
|
|
423
|
+
...(options?.externalUser ? buildExternalUserQuery(options.externalUser) : {}),
|
|
424
|
+
...(options?.queryParams ?? {}),
|
|
425
|
+
};
|
|
426
|
+
return this.getStatus(requestId, {
|
|
427
|
+
...options,
|
|
428
|
+
path: this.buildV2Url('status'),
|
|
429
|
+
queryParams,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
196
432
|
/**
|
|
197
433
|
* Create a new video generation job from text.
|
|
198
434
|
*/
|
|
@@ -563,6 +799,50 @@ export class SamsarClient {
|
|
|
563
799
|
* only the final video render step.
|
|
564
800
|
*/
|
|
565
801
|
async updateVideoOutroImage(input, options) {
|
|
802
|
+
const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'updateVideoOutroImage');
|
|
803
|
+
const body = {
|
|
804
|
+
input: normalizedInput,
|
|
805
|
+
webhookUrl: options?.webhookUrl,
|
|
806
|
+
};
|
|
807
|
+
const response = await this.post('video/update_outro_image', body, options);
|
|
808
|
+
const data = response.data;
|
|
809
|
+
if (data && typeof data === 'object') {
|
|
810
|
+
const sessionId = typeof data.sessionID === 'string'
|
|
811
|
+
? data.sessionID
|
|
812
|
+
: typeof data.session_id === 'string'
|
|
813
|
+
? data.session_id
|
|
814
|
+
: typeof data.request_id === 'string'
|
|
815
|
+
? data.request_id
|
|
816
|
+
: undefined;
|
|
817
|
+
const normalizedSessionId = sessionId ? String(sessionId) : undefined;
|
|
818
|
+
const normalizedData = {
|
|
819
|
+
...data,
|
|
820
|
+
sessionID: data.sessionID ?? normalizedSessionId ?? '',
|
|
821
|
+
session_id: data.session_id ?? normalizedSessionId,
|
|
822
|
+
request_id: data.request_id ?? normalizedSessionId,
|
|
823
|
+
};
|
|
824
|
+
return { ...response, data: normalizedData };
|
|
825
|
+
}
|
|
826
|
+
return response;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Update the outro image for an external-user video request by resolving the external request id
|
|
830
|
+
* through /external_users/update_outro_image.
|
|
831
|
+
*/
|
|
832
|
+
async updateExternalVideoOutroImage(externalUser, input, options) {
|
|
833
|
+
const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'updateExternalVideoOutroImage');
|
|
834
|
+
const body = {
|
|
835
|
+
external_user: normalizeExternalUserIdentity(externalUser),
|
|
836
|
+
input: normalizedInput,
|
|
837
|
+
webhookUrl: options?.webhookUrl,
|
|
838
|
+
};
|
|
839
|
+
return this.post('external_users/update_outro_image', body, options);
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Add or replace the outro image for an existing video session by cloning it into a new session and
|
|
843
|
+
* re-running frame/video generation.
|
|
844
|
+
*/
|
|
845
|
+
async addVideoOutroImage(input, options) {
|
|
566
846
|
const raw = input;
|
|
567
847
|
const videoSessionId = raw.videoSessionId ??
|
|
568
848
|
raw.video_session_id ??
|
|
@@ -576,8 +856,6 @@ export class SamsarClient {
|
|
|
576
856
|
raw.outroImageUrl ??
|
|
577
857
|
raw.new_outro_image_url ??
|
|
578
858
|
raw.newOutroImageUrl;
|
|
579
|
-
const rawGenerateOutroImage = raw.generate_outro_image ??
|
|
580
|
-
raw.generateOutroImage;
|
|
581
859
|
const rawAddOutroAnimation = raw.add_outro_animation ??
|
|
582
860
|
raw.addOutroAnimation;
|
|
583
861
|
const rawAddOutroFocusArea = raw.add_outro_focus_area ??
|
|
@@ -586,69 +864,43 @@ export class SamsarClient {
|
|
|
586
864
|
raw.outro_focus_area ??
|
|
587
865
|
raw.outroFocustArea ??
|
|
588
866
|
raw.outroFocusArea;
|
|
589
|
-
const ctaUrl = raw.cta_url ??
|
|
590
|
-
raw.ctaUrl;
|
|
591
|
-
const ctaTextTop = raw.cta_text_top ??
|
|
592
|
-
raw.ctaTextTop;
|
|
593
|
-
const ctaTextBottom = raw.cta_text_bottom ??
|
|
594
|
-
raw.ctaTextBottom;
|
|
595
|
-
const ctaLogo = raw.cta_logo ??
|
|
596
|
-
raw.ctaLogo;
|
|
597
|
-
const generateOutroImage = rawGenerateOutroImage === true ||
|
|
598
|
-
(rawGenerateOutroImage === undefined && !outroImageUrl && Boolean(ctaUrl));
|
|
599
867
|
if (!videoSessionId) {
|
|
600
|
-
throw new Error('videoSessionId is required for
|
|
868
|
+
throw new Error('videoSessionId is required for addVideoOutroImage');
|
|
601
869
|
}
|
|
602
|
-
if (
|
|
603
|
-
throw new Error('
|
|
870
|
+
if (!outroImageUrl) {
|
|
871
|
+
throw new Error('outro_image_url is required for addVideoOutroImage');
|
|
604
872
|
}
|
|
605
873
|
if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
|
|
606
|
-
throw new Error('add_outro_animation must be a boolean for
|
|
874
|
+
throw new Error('add_outro_animation must be a boolean for addVideoOutroImage');
|
|
607
875
|
}
|
|
608
876
|
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
609
|
-
throw new Error('add_outro_focus_area must be a boolean for
|
|
610
|
-
}
|
|
611
|
-
if (generateOutroImage && outroImageUrl) {
|
|
612
|
-
throw new Error('Use either generate_outro_image with cta_url or outro_image_url for updateVideoOutroImage');
|
|
613
|
-
}
|
|
614
|
-
if (!generateOutroImage && !outroImageUrl) {
|
|
615
|
-
throw new Error('outro_image_url is required for updateVideoOutroImage unless generate_outro_image is true');
|
|
616
|
-
}
|
|
617
|
-
if (generateOutroImage) {
|
|
618
|
-
if (!ctaUrl || !String(ctaUrl).trim()) {
|
|
619
|
-
throw new Error('cta_url is required when generate_outro_image is true for updateVideoOutroImage');
|
|
620
|
-
}
|
|
877
|
+
throw new Error('add_outro_focus_area must be a boolean for addVideoOutroImage');
|
|
621
878
|
}
|
|
622
|
-
|
|
623
|
-
throw new Error('add_outro_focus_area requires add_outro_animation to be true for
|
|
879
|
+
if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
880
|
+
throw new Error('add_outro_focus_area requires add_outro_animation to be true for addVideoOutroImage');
|
|
624
881
|
}
|
|
625
|
-
if (
|
|
882
|
+
if (rawAddOutroFocusArea === true) {
|
|
626
883
|
if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
|
|
627
|
-
throw new Error('outro_focust_area must be an object with x, y, width, height for
|
|
884
|
+
throw new Error('outro_focust_area must be an object with x, y, width, height for addVideoOutroImage');
|
|
628
885
|
}
|
|
629
886
|
const { x, y, width, height } = rawOutroFocusArea;
|
|
630
887
|
const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
|
|
631
888
|
if (isInvalid) {
|
|
632
|
-
throw new Error('outro_focust_area x, y, width, height must be valid numbers for
|
|
889
|
+
throw new Error('outro_focust_area x, y, width, height must be valid numbers for addVideoOutroImage');
|
|
633
890
|
}
|
|
634
891
|
}
|
|
635
892
|
const body = {
|
|
636
893
|
input: {
|
|
637
894
|
...input,
|
|
638
895
|
videoSessionId: String(videoSessionId),
|
|
639
|
-
|
|
640
|
-
generate_outro_image: generateOutroImage,
|
|
641
|
-
...(generateOutroImage ? { cta_url: String(ctaUrl).trim() } : {}),
|
|
642
|
-
...(ctaTextTop ? { cta_text_top: String(ctaTextTop) } : {}),
|
|
643
|
-
...(ctaTextBottom ? { cta_text_bottom: String(ctaTextBottom) } : {}),
|
|
644
|
-
...(ctaLogo ? { cta_logo: String(ctaLogo) } : {}),
|
|
896
|
+
outro_image_url: String(outroImageUrl),
|
|
645
897
|
...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
|
|
646
898
|
...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
|
|
647
899
|
...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
|
|
648
900
|
},
|
|
649
901
|
webhookUrl: options?.webhookUrl,
|
|
650
902
|
};
|
|
651
|
-
const response = await this.post('video/
|
|
903
|
+
const response = await this.post('video/add_outro_image', body, options);
|
|
652
904
|
const data = response.data;
|
|
653
905
|
if (data && typeof data === 'object') {
|
|
654
906
|
const sessionId = typeof data.sessionID === 'string'
|
|
@@ -670,10 +922,9 @@ export class SamsarClient {
|
|
|
670
922
|
return response;
|
|
671
923
|
}
|
|
672
924
|
/**
|
|
673
|
-
* Add or replace
|
|
674
|
-
* re-running frame/video generation.
|
|
925
|
+
* Add or replace an outro image for an external-user video request by resolving the external request id.
|
|
675
926
|
*/
|
|
676
|
-
async
|
|
927
|
+
async addExternalVideoOutroImage(externalUser, input, options) {
|
|
677
928
|
const raw = input;
|
|
678
929
|
const videoSessionId = raw.videoSessionId ??
|
|
679
930
|
raw.video_session_id ??
|
|
@@ -682,7 +933,13 @@ export class SamsarClient {
|
|
|
682
933
|
raw.sessionId ??
|
|
683
934
|
raw.sessionID ??
|
|
684
935
|
raw.request_id ??
|
|
685
|
-
raw.requestId
|
|
936
|
+
raw.requestId ??
|
|
937
|
+
raw.source_request_id ??
|
|
938
|
+
raw.sourceRequestId ??
|
|
939
|
+
raw.external_request_id ??
|
|
940
|
+
raw.externalRequestId ??
|
|
941
|
+
raw.external_session_id ??
|
|
942
|
+
raw.externalSessionId;
|
|
686
943
|
const outroImageUrl = raw.outro_image_url ??
|
|
687
944
|
raw.outroImageUrl ??
|
|
688
945
|
raw.new_outro_image_url ??
|
|
@@ -696,31 +953,32 @@ export class SamsarClient {
|
|
|
696
953
|
raw.outroFocustArea ??
|
|
697
954
|
raw.outroFocusArea;
|
|
698
955
|
if (!videoSessionId) {
|
|
699
|
-
throw new Error('videoSessionId is required for
|
|
956
|
+
throw new Error('videoSessionId is required for addExternalVideoOutroImage');
|
|
700
957
|
}
|
|
701
958
|
if (!outroImageUrl) {
|
|
702
|
-
throw new Error('outro_image_url is required for
|
|
959
|
+
throw new Error('outro_image_url is required for addExternalVideoOutroImage');
|
|
703
960
|
}
|
|
704
961
|
if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
|
|
705
|
-
throw new Error('add_outro_animation must be a boolean for
|
|
962
|
+
throw new Error('add_outro_animation must be a boolean for addExternalVideoOutroImage');
|
|
706
963
|
}
|
|
707
964
|
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
708
|
-
throw new Error('add_outro_focus_area must be a boolean for
|
|
965
|
+
throw new Error('add_outro_focus_area must be a boolean for addExternalVideoOutroImage');
|
|
709
966
|
}
|
|
710
967
|
if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
711
|
-
throw new Error('add_outro_focus_area requires add_outro_animation to be true for
|
|
968
|
+
throw new Error('add_outro_focus_area requires add_outro_animation to be true for addExternalVideoOutroImage');
|
|
712
969
|
}
|
|
713
970
|
if (rawAddOutroFocusArea === true) {
|
|
714
971
|
if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
|
|
715
|
-
throw new Error('outro_focust_area must be an object with x, y, width, height for
|
|
972
|
+
throw new Error('outro_focust_area must be an object with x, y, width, height for addExternalVideoOutroImage');
|
|
716
973
|
}
|
|
717
974
|
const { x, y, width, height } = rawOutroFocusArea;
|
|
718
975
|
const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
|
|
719
976
|
if (isInvalid) {
|
|
720
|
-
throw new Error('outro_focust_area x, y, width, height must be valid numbers for
|
|
977
|
+
throw new Error('outro_focust_area x, y, width, height must be valid numbers for addExternalVideoOutroImage');
|
|
721
978
|
}
|
|
722
979
|
}
|
|
723
980
|
const body = {
|
|
981
|
+
external_user: normalizeExternalUserIdentity(externalUser),
|
|
724
982
|
input: {
|
|
725
983
|
...input,
|
|
726
984
|
videoSessionId: String(videoSessionId),
|
|
@@ -731,26 +989,7 @@ export class SamsarClient {
|
|
|
731
989
|
},
|
|
732
990
|
webhookUrl: options?.webhookUrl,
|
|
733
991
|
};
|
|
734
|
-
|
|
735
|
-
const data = response.data;
|
|
736
|
-
if (data && typeof data === 'object') {
|
|
737
|
-
const sessionId = typeof data.sessionID === 'string'
|
|
738
|
-
? data.sessionID
|
|
739
|
-
: typeof data.session_id === 'string'
|
|
740
|
-
? data.session_id
|
|
741
|
-
: typeof data.request_id === 'string'
|
|
742
|
-
? data.request_id
|
|
743
|
-
: undefined;
|
|
744
|
-
const normalizedSessionId = sessionId ? String(sessionId) : undefined;
|
|
745
|
-
const normalizedData = {
|
|
746
|
-
...data,
|
|
747
|
-
sessionID: data.sessionID ?? normalizedSessionId ?? '',
|
|
748
|
-
session_id: data.session_id ?? normalizedSessionId,
|
|
749
|
-
request_id: data.request_id ?? normalizedSessionId,
|
|
750
|
-
};
|
|
751
|
-
return { ...response, data: normalizedData };
|
|
752
|
-
}
|
|
753
|
-
return response;
|
|
992
|
+
return this.post('external_users/add_outro_image', body, options);
|
|
754
993
|
}
|
|
755
994
|
/**
|
|
756
995
|
* Fetch the latest available render URL for a given video session id.
|
|
@@ -1448,7 +1687,7 @@ export class SamsarClient {
|
|
|
1448
1687
|
}
|
|
1449
1688
|
buildHeaders(options) {
|
|
1450
1689
|
const headers = {
|
|
1451
|
-
Authorization: `Bearer ${this.apiKey}
|
|
1690
|
+
Authorization: this.apiKey ? `Bearer ${this.apiKey}` : undefined,
|
|
1452
1691
|
'Content-Type': options.body ? 'application/json' : undefined,
|
|
1453
1692
|
'x-external-user-api-key': options.externalUserApiKey ?? this.externalUserApiKey,
|
|
1454
1693
|
...this.defaultHeaders,
|
|
@@ -1478,6 +1717,19 @@ export class SamsarClient {
|
|
|
1478
1717
|
const rootUrl = baseUrl.endsWith('/v1') ? baseUrl.slice(0, -3) : baseUrl;
|
|
1479
1718
|
return `${rootUrl}/${cleanedPath}`;
|
|
1480
1719
|
}
|
|
1720
|
+
withV2ExternalUser(body, options) {
|
|
1721
|
+
if (!options?.externalUser) {
|
|
1722
|
+
return body;
|
|
1723
|
+
}
|
|
1724
|
+
return {
|
|
1725
|
+
...body,
|
|
1726
|
+
external_user: normalizeExternalUserIdentity(options.externalUser),
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
buildV2Url(path) {
|
|
1730
|
+
const cleanedPath = path.replace(/^\/+/, '');
|
|
1731
|
+
return this.buildRootUrl(`v2/${cleanedPath}`);
|
|
1732
|
+
}
|
|
1481
1733
|
}
|
|
1482
1734
|
function trimTrailingSlash(url) {
|
|
1483
1735
|
return url.replace(/\/+$/, '');
|