samsar-js 0.48.30 → 0.48.31

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
@@ -346,6 +346,24 @@ const images = await samsar.extendImageList({
346
346
  aspect_ratio: '16:9',
347
347
  });
348
348
 
349
+ // Assign a short SEO-friendly image title
350
+ const imageTitle = await samsar.assignImageTitle({
351
+ image_url: 'https://example.com/product-photo.png',
352
+ metadata: {
353
+ product: 'linen travel shirt',
354
+ collection: 'spring essentials',
355
+ },
356
+ });
357
+ console.log(imageTitle.data.content); // "Linen Travel Shirt"
358
+
359
+ // Binary uploads are also supported in browser/Node 18+ runtimes
360
+ const fileTitle = await samsar.assignImageTitle({
361
+ image: fileOrBlob,
362
+ fileName: 'product-photo.png',
363
+ mimeType: 'image/png',
364
+ metadata: { product: 'linen travel shirt' },
365
+ });
366
+
349
367
  // Create a reusable receipt template from one sample receipt image (free endpoint)
350
368
  const receiptTemplate = await samsar.createReceiptTemplate({
351
369
  image_url: 'https://example.com/receipt-template.png',
@@ -579,7 +597,7 @@ Video model support notes:
579
597
 
580
598
  Upcoming `/v2` omni route adapters:
581
599
  - `/v2` is additive; `/v1` is not deprecated.
582
- - `createV2VideoFromText`, `createV2VideoFromImageList`, `translateV2Video`, `cloneV2Video`, `regenerateV2VideoAvatar`, `updateV2VideoOutroImage`, `updateV2VideoFooterImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2StatusDetailed`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
600
+ - `createV2VideoFromText`, `createV2VideoFromImageList`, `assignV2ImageTitle`, `translateV2Video`, `cloneV2Video`, `regenerateV2VideoAvatar`, `updateV2VideoOutroImage`, `updateV2VideoFooterImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2StatusDetailed`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
583
601
  - Step-controlled video helpers include `createV2StepVideoFromText`, `createV2StepTextToVideo`, `createV2StepVideoFromImage`, `createV2StepImageToVideo`, `getV2StepVideoStatus`, `getV2StepVideoStatusDetailed`, and `processNextV2StepVideo`. They default to 1-step express rendering by sending `auto_render_full_video: true` and `manual_step_stages: []`; pass `{ stepMode: 'two_step' }` or `manual_step_stages: ['ai_video_generation']` to require an explicit second-step approval before image-to-video generation.
584
602
  - Programmatic user helpers include `createV2ExternalUser`, `createV2UserRechargeCredits`, `refreshV2UserToken`, `createV2UserAppKey`, `refreshV2UserAppKey`, `getV2UserCredits`, `getV2UserUsageLogs`, and `getV2UserPaymentStatus`.
585
603
  - 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.
@@ -601,6 +619,12 @@ const v2ExternalVideo = await platform.createV2VideoFromImageList(
601
619
  { externalUser },
602
620
  );
603
621
 
622
+ const v2ImageTitle = await platform.assignV2ImageTitle({
623
+ image_url: 'https://cdn.example.com/product-frame.png',
624
+ metadata: { product: 'travel shirt', channel: 'marketplace' },
625
+ });
626
+ console.log(v2ImageTitle.data.content);
627
+
604
628
  const v2Translated = await platform.translateV2Video({
605
629
  videoSessionId: v2Video.data.request_id!,
606
630
  language: 'es',
package/dist/index.d.ts CHANGED
@@ -975,6 +975,33 @@ export interface EnhanceImageResponse {
975
975
  remainingCredits?: number;
976
976
  [key: string]: unknown;
977
977
  }
978
+ export type AssignImageTitleMimeType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';
979
+ export type AssignImageTitleBinaryInput = Blob | ArrayBuffer | Uint8Array;
980
+ export interface AssignImageTitleRequest {
981
+ image?: string | AssignImageTitleBinaryInput;
982
+ file?: AssignImageTitleBinaryInput;
983
+ image_file?: AssignImageTitleBinaryInput;
984
+ imageFile?: AssignImageTitleBinaryInput;
985
+ image_url?: string;
986
+ imageUrl?: string;
987
+ url?: string;
988
+ image_data?: string;
989
+ imageData?: string;
990
+ image_data_url?: string;
991
+ imageDataUrl?: string;
992
+ metadata?: Record<string, unknown> | string;
993
+ metadata_json?: Record<string, unknown> | string;
994
+ metadataJson?: Record<string, unknown> | string;
995
+ fileName?: string;
996
+ filename?: string;
997
+ mimeType?: AssignImageTitleMimeType | string;
998
+ [key: string]: unknown;
999
+ }
1000
+ export interface AssignImageTitleResponse {
1001
+ content: string;
1002
+ title?: string;
1003
+ [key: string]: unknown;
1004
+ }
978
1005
  export interface ExtendImageListRequest {
979
1006
  image_urls: string[];
980
1007
  num_images: number;
@@ -1978,6 +2005,12 @@ export declare class SamsarClient {
1978
2005
  uploadV2ImageData(imageData: string[], options?: V2RequestOptions): Promise<SamsarResult<{
1979
2006
  image_urls: string[];
1980
2007
  }>>;
2008
+ /**
2009
+ * Assign a short SEO-friendly title to an image using the /v2 image route.
2010
+ * Supports image_url/image_data JSON payloads or binary image/FormData uploads.
2011
+ */
2012
+ assignV2ImageTitle(payload: AssignImageTitleRequest | FormData, options?: V2RequestOptions): Promise<SamsarResult<AssignImageTitleResponse>>;
2013
+ assignV2TitleToImage(payload: AssignImageTitleRequest | FormData, options?: V2RequestOptions): Promise<SamsarResult<AssignImageTitleResponse>>;
1981
2014
  updateV2VideoOutroImage(input: UpdateVideoOutroImageInput, options?: V2RequestOptions): Promise<SamsarResult<UpdateVideoOutroImageResponse | ExternalRequestResponse>>;
1982
2015
  updateV2VideoFooterImage(input: UpdateVideoFooterImageInput, options?: V2RequestOptions): Promise<SamsarResult<UpdateVideoFooterImageResponse | ExternalRequestResponse>>;
1983
2016
  addV2VideoOutroImage(input: AddVideoOutroImageInput, options?: V2RequestOptions): Promise<SamsarResult<AddVideoOutroImageResponse | ExternalRequestResponse>>;
@@ -2263,6 +2296,12 @@ export declare class SamsarClient {
2263
2296
  * Enhance an image by upscaling it with the specified resolution.
2264
2297
  */
2265
2298
  enhanceImage(payload: EnhanceImageRequest, options?: SamsarRequestOptions): Promise<SamsarResult<EnhanceImageResponse>>;
2299
+ /**
2300
+ * Assign a short SEO-friendly title to an image.
2301
+ * Supports image_url/image_data JSON payloads or binary image/FormData uploads.
2302
+ */
2303
+ assignImageTitle(payload: AssignImageTitleRequest | FormData, options?: SamsarRequestOptions): Promise<SamsarResult<AssignImageTitleResponse>>;
2304
+ assignTitleToImage(payload: AssignImageTitleRequest | FormData, options?: SamsarRequestOptions): Promise<SamsarResult<AssignImageTitleResponse>>;
2266
2305
  /**
2267
2306
  * Add or extend a saved image list for the authenticated API key.
2268
2307
  */
@@ -2379,6 +2418,7 @@ export declare class SamsarClient {
2379
2418
  }): Promise<SamsarResult<GlobalStatusResponse>>;
2380
2419
  private get;
2381
2420
  private post;
2421
+ private postForm;
2382
2422
  private request;
2383
2423
  private buildHeaders;
2384
2424
  private buildUrl;
package/dist/index.js CHANGED
@@ -792,6 +792,22 @@ export class SamsarClient {
792
792
  },
793
793
  }, options);
794
794
  }
795
+ /**
796
+ * Assign a short SEO-friendly title to an image using the /v2 image route.
797
+ * Supports image_url/image_data JSON payloads or binary image/FormData uploads.
798
+ */
799
+ async assignV2ImageTitle(payload, options) {
800
+ const body = buildAssignImageTitleBody(payload);
801
+ if (isFormDataBody(body)) {
802
+ return this.postForm(this.buildV2Url('image/assign_title'), body, options);
803
+ }
804
+ return this.postV2('image/assign_title', {
805
+ input: body,
806
+ }, options);
807
+ }
808
+ async assignV2TitleToImage(payload, options) {
809
+ return this.assignV2ImageTitle(payload, options);
810
+ }
795
811
  async updateV2VideoOutroImage(input, options) {
796
812
  const normalizedInput = normalizeUpdateVideoOutroImageInput(input, 'updateV2VideoOutroImage');
797
813
  return this.postV2('update_outro_image', {
@@ -1758,6 +1774,20 @@ export class SamsarClient {
1758
1774
  async enhanceImage(payload, options) {
1759
1775
  return this.post('image/enhance', payload, options);
1760
1776
  }
1777
+ /**
1778
+ * Assign a short SEO-friendly title to an image.
1779
+ * Supports image_url/image_data JSON payloads or binary image/FormData uploads.
1780
+ */
1781
+ async assignImageTitle(payload, options) {
1782
+ const body = buildAssignImageTitleBody(payload);
1783
+ if (isFormDataBody(body)) {
1784
+ return this.postForm('image/assign_title', body, options);
1785
+ }
1786
+ return this.post('image/assign_title', body, options);
1787
+ }
1788
+ async assignTitleToImage(payload, options) {
1789
+ return this.assignImageTitle(payload, options);
1790
+ }
1761
1791
  /**
1762
1792
  * Add or extend a saved image list for the authenticated API key.
1763
1793
  */
@@ -2132,6 +2162,13 @@ export class SamsarClient {
2132
2162
  body: JSON.stringify(body),
2133
2163
  });
2134
2164
  }
2165
+ async postForm(path, body, options) {
2166
+ return this.request(path, {
2167
+ ...(options ?? {}),
2168
+ method: 'POST',
2169
+ body,
2170
+ });
2171
+ }
2135
2172
  async request(path, options) {
2136
2173
  const url = this.buildUrl(path, options.query);
2137
2174
  const controller = new AbortController();
@@ -2221,7 +2258,7 @@ export class SamsarClient {
2221
2258
  : this.apiKey
2222
2259
  ? `Bearer ${this.apiKey}`
2223
2260
  : undefined,
2224
- 'Content-Type': options.body ? 'application/json' : undefined,
2261
+ 'Content-Type': options.body && !isFormDataBody(options.body) ? 'application/json' : undefined,
2225
2262
  'x-external-user-api-key': options.externalUserApiKey ?? this.externalUserApiKey,
2226
2263
  'x-app-secret': resolvedAppKey ? resolvedAppSecret : undefined,
2227
2264
  ...this.defaultHeaders,
@@ -2288,6 +2325,104 @@ export class SamsarClient {
2288
2325
  function trimTrailingSlash(url) {
2289
2326
  return url.replace(/\/+$/, '');
2290
2327
  }
2328
+ function buildAssignImageTitleBody(payload) {
2329
+ if (isFormDataBody(payload)) {
2330
+ return payload;
2331
+ }
2332
+ const input = (payload ?? {});
2333
+ const image = input.image ??
2334
+ input.file ??
2335
+ input.image_file ??
2336
+ input.imageFile;
2337
+ if (isBinaryAssignImageTitleInput(image)) {
2338
+ return buildAssignImageTitleFormData(input, image);
2339
+ }
2340
+ const stringImage = getTrimmedString(image);
2341
+ const imageData = stringImage?.startsWith('data:image/')
2342
+ ? stringImage
2343
+ : getTrimmedString(input.image_data) ??
2344
+ getTrimmedString(input.imageData) ??
2345
+ getTrimmedString(input.image_data_url) ??
2346
+ getTrimmedString(input.imageDataUrl);
2347
+ const imageUrl = stringImage && !stringImage.startsWith('data:image/')
2348
+ ? stringImage
2349
+ : getTrimmedString(input.image_url) ??
2350
+ getTrimmedString(input.imageUrl) ??
2351
+ getTrimmedString(input.url);
2352
+ const metadata = input.metadata ?? input.metadata_json ?? input.metadataJson;
2353
+ if (!imageData && !imageUrl) {
2354
+ throw new Error('image, image_data, or image_url is required for assignImageTitle');
2355
+ }
2356
+ return {
2357
+ ...(imageData ? { image_data: imageData } : {}),
2358
+ ...(imageUrl ? { image_url: imageUrl } : {}),
2359
+ ...(metadata !== undefined ? { metadata } : {}),
2360
+ };
2361
+ }
2362
+ function buildAssignImageTitleFormData(input, image) {
2363
+ if (typeof FormData === 'undefined') {
2364
+ throw new Error('FormData is required for binary assignImageTitle uploads');
2365
+ }
2366
+ const metadata = input.metadata ?? input.metadata_json ?? input.metadataJson;
2367
+ const mimeType = getTrimmedString(input.mimeType) ?? getBlobType(image);
2368
+ if (!mimeType || !isSupportedAssignImageTitleMimeType(mimeType)) {
2369
+ throw new Error('mimeType must be image/png, image/jpeg, image/webp, or image/gif for binary assignImageTitle uploads');
2370
+ }
2371
+ const blob = toAssignImageTitleBlob(image, mimeType);
2372
+ const fileName = getTrimmedString(input.fileName) ??
2373
+ getTrimmedString(input.filename) ??
2374
+ `image.${mimeTypeToExtension(mimeType)}`;
2375
+ const formData = new FormData();
2376
+ formData.append('image', blob, fileName);
2377
+ if (metadata !== undefined) {
2378
+ formData.append('metadata', typeof metadata === 'string' ? metadata : JSON.stringify(metadata));
2379
+ }
2380
+ return formData;
2381
+ }
2382
+ function isBinaryAssignImageTitleInput(value) {
2383
+ return (isBlobValue(value) ||
2384
+ value instanceof ArrayBuffer ||
2385
+ value instanceof Uint8Array);
2386
+ }
2387
+ function toAssignImageTitleBlob(value, mimeType) {
2388
+ if (isBlobValue(value)) {
2389
+ if (value.type === mimeType) {
2390
+ return value;
2391
+ }
2392
+ return new Blob([value], { type: mimeType });
2393
+ }
2394
+ if (value instanceof Uint8Array) {
2395
+ const arrayBuffer = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
2396
+ return new Blob([arrayBuffer], { type: mimeType });
2397
+ }
2398
+ return new Blob([value], { type: mimeType });
2399
+ }
2400
+ function getBlobType(value) {
2401
+ return isBlobValue(value) ? getTrimmedString(value.type) : undefined;
2402
+ }
2403
+ function isBlobValue(value) {
2404
+ return typeof Blob !== 'undefined' && value instanceof Blob;
2405
+ }
2406
+ function isFormDataBody(body) {
2407
+ return typeof FormData !== 'undefined' && body instanceof FormData;
2408
+ }
2409
+ function isSupportedAssignImageTitleMimeType(value) {
2410
+ const normalized = value.trim().toLowerCase();
2411
+ return ['image/png', 'image/jpeg', 'image/jpg', 'image/webp', 'image/gif'].includes(normalized);
2412
+ }
2413
+ function mimeTypeToExtension(value) {
2414
+ const normalized = value.trim().toLowerCase();
2415
+ if (normalized === 'image/jpeg' || normalized === 'image/jpg') {
2416
+ return 'jpg';
2417
+ }
2418
+ if (normalized === 'image/webp') {
2419
+ return 'webp';
2420
+ }
2421
+ if (normalized === 'image/gif') {
2422
+ return 'gif';
2423
+ }
2424
+ return 'png';
2425
+ }
2291
2426
  function parseMaybeJson(value) {
2292
2427
  try {
2293
2428
  return JSON.parse(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "samsar-js",
3
- "version": "0.48.30",
3
+ "version": "0.48.31",
4
4
  "description": "TypeScript client for the Samsar Processor API routes.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",