@sogni-ai/sogni-client 5.63.2 → 5.63.4

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [5.63.4](https://github.com/Sogni-AI/sogni-client/compare/v5.63.3...v5.63.4) (2026-10-16)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **projects:** start admission grace after request preparation ([2d9d99a](https://github.com/Sogni-AI/sogni-client/commit/2d9d99accdce4c897331b6a5ceefe05e3ec46c52))
7
+
8
+ ## [5.63.3](https://github.com/Sogni-AI/sogni-client/compare/v5.63.2...v5.63.3) (2026-10-14)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **projects:** declare FLAC, Ogg and WebM reference files by their bytes ([4b03ac8](https://github.com/Sogni-AI/sogni-client/commit/4b03ac80ca792746fdfc69a60833cff9cf054702))
14
+
1
15
  ## [5.63.2](https://github.com/Sogni-AI/sogni-client/compare/v5.63.1...v5.63.2) (2026-10-12)
2
16
 
3
17
 
package/README.md CHANGED
@@ -1524,8 +1524,11 @@ const workflow = await sogni.workflows.start({
1524
1524
  }
1525
1525
  },
1526
1526
  {
1527
+ // animate_photo starts the clip from the keyframe. generate_video's
1528
+ // referenceImageIndices are loose references, which only Seedance,
1529
+ // HappyHorse, Wan 3 and MiniMax H3 reference-to-video accept.
1527
1530
  id: 'clip',
1528
- toolName: 'generate_video',
1531
+ toolName: 'animate_photo',
1529
1532
  arguments: {
1530
1533
  prompt: 'slow dolly-in, warm stage lights, subtle hand motion',
1531
1534
  videoModel: 'ltx23',
@@ -1535,7 +1538,7 @@ const workflow = await sogni.workflows.start({
1535
1538
  {
1536
1539
  sourceStepId: 'keyframe',
1537
1540
  sourceArtifactIndex: 0,
1538
- targetArgument: 'referenceImageIndices',
1541
+ targetArgument: 'sourceImageIndex',
1539
1542
  mediaType: 'image',
1540
1543
  transform: 'image_index',
1541
1544
  required: true
@@ -170,6 +170,8 @@ declare class ProjectsApi extends ApiGroup<ProjectApiEvents> {
170
170
  /** Projects waiting for a reconnect to be resubmitted on. */
171
171
  private _awaitingResubmit;
172
172
  private _resubmitWaiters;
173
+ /** Initial sends finish after model lookups and uploads, independently of creation time. */
174
+ private _submittedAt;
173
175
  /** When each resubmitted project was last sent, for the recently-created grace. */
174
176
  private _resubmittedAt;
175
177
  /** Bumped on every transport loss; tells a frame sent before a drop from one sent after. */
@@ -58,6 +58,7 @@ const getUUID_js_1 = __importDefault(require("../lib/getUUID.js"));
58
58
  const Cache_js_1 = __importDefault(require("../lib/Cache.js"));
59
59
  const Job_js_1 = require("./Job.js");
60
60
  const index_js_2 = require("./utils/index.js");
61
+ const fileContentType_js_1 = require("./utils/fileContentType.js");
61
62
  const validation_js_1 = require("../lib/validation.js");
62
63
  const ModelTiersRaw_js_1 = require("./types/ModelTiersRaw.js");
63
64
  const ModelOptions_js_1 = require("./types/ModelOptions.js");
@@ -186,46 +187,6 @@ function deriveLoraCapableModelIds(loras) {
186
187
  }
187
188
  return Array.from(modelIds).sort();
188
189
  }
189
- /**
190
- * Detect content type from a file object.
191
- * For File objects in browser, uses the type property.
192
- * Returns undefined if content type cannot be detected.
193
- */
194
- function getFileContentType(file) {
195
- if (file instanceof Blob && 'type' in file && file.type) {
196
- return file.type;
197
- }
198
- if (typeof Buffer !== 'undefined' && Buffer.isBuffer(file)) {
199
- if (file.length >= 12) {
200
- if (file[0] === 0xff && file[1] === 0xd8 && file[2] === 0xff)
201
- return 'image/jpeg';
202
- if (file[0] === 0x89 && file[1] === 0x50 && file[2] === 0x4e && file[3] === 0x47) {
203
- return 'image/png';
204
- }
205
- if (file.toString('ascii', 0, 4) === 'RIFF' && file.toString('ascii', 8, 12) === 'WEBP') {
206
- return 'image/webp';
207
- }
208
- if (file.toString('ascii', 0, 3) === 'GIF')
209
- return 'image/gif';
210
- if (file.toString('ascii', 4, 8) === 'ftyp') {
211
- const brand = file.toString('ascii', 8, 12).toLowerCase();
212
- if (brand.includes('m4a') || brand.includes('m4b'))
213
- return 'audio/mp4';
214
- if (brand.includes('qt'))
215
- return 'video/quicktime';
216
- return 'video/mp4';
217
- }
218
- if (file.toString('ascii', 0, 4) === 'RIFF' && file.toString('ascii', 8, 12) === 'WAVE') {
219
- return 'audio/wav';
220
- }
221
- }
222
- if (file.length >= 3 && file.toString('ascii', 0, 3) === 'ID3')
223
- return 'audio/mpeg';
224
- if (file.length >= 2 && file[0] === 0xff && (file[1] & 0xe0) === 0xe0)
225
- return 'audio/mpeg';
226
- }
227
- return undefined;
228
- }
229
190
  /**
230
191
  * Convert file to a format compatible with fetch body.
231
192
  * Converts Node.js Buffer to Blob for cross-platform compatibility.
@@ -483,6 +444,8 @@ class ProjectsApi extends ApiGroup_js_1.default {
483
444
  /** Projects waiting for a reconnect to be resubmitted on. */
484
445
  this._awaitingResubmit = new Set();
485
446
  this._resubmitWaiters = new Set();
447
+ /** Initial sends finish after model lookups and uploads, independently of creation time. */
448
+ this._submittedAt = new Map();
486
449
  /** When each resubmitted project was last sent, for the recently-created grace. */
487
450
  this._resubmittedAt = new Map();
488
451
  /** Bumped on every transport loss; tells a frame sent before a drop from one sent after. */
@@ -565,6 +528,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
565
528
  for (const stopWaiting of this._resubmitWaiters)
566
529
  stopWaiting();
567
530
  this._awaitingResubmit.clear();
531
+ this._submittedAt.clear();
568
532
  this._resubmittedAt.clear();
569
533
  this._sentOnGeneration.clear();
570
534
  this._recoveredCompletedIds.clear();
@@ -999,6 +963,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
999
963
  }
1000
964
  if (project.finished) {
1001
965
  this._unadmittedRequests.delete(project.id);
966
+ this._submittedAt.delete(project.id);
1002
967
  this._resubmittedAt.delete(project.id);
1003
968
  this._sentOnGeneration.delete(project.id);
1004
969
  // Sync project data with the server and remove it from the list after some time
@@ -1286,8 +1251,8 @@ class ProjectsApi extends ApiGroup_js_1.default {
1286
1251
  }, Math.max(0, delayMs) + 250);
1287
1252
  }
1288
1253
  _lastSubmittedAt(project) {
1289
- var _a;
1290
- return Math.max(project.startedAt.getTime(), (_a = this._resubmittedAt.get(project.id)) !== null && _a !== void 0 ? _a : 0);
1254
+ var _a, _b;
1255
+ return Math.max((_a = this._submittedAt.get(project.id)) !== null && _a !== void 0 ? _a : project.startedAt.getTime(), (_b = this._resubmittedAt.get(project.id)) !== null && _b !== void 0 ? _b : 0);
1291
1256
  }
1292
1257
  handleServerConnected() {
1293
1258
  this.transportDisconnected = false;
@@ -2007,6 +1972,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2007
1972
  _trackSubmitted(project) {
2008
1973
  const tracked = this.projects.find((candidate) => candidate.id === project.id);
2009
1974
  if (!tracked) {
1975
+ this._submittedAt.set(project.id, Date.now());
2010
1976
  this.projects.push(project);
2011
1977
  return project;
2012
1978
  }
@@ -2066,7 +2032,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2066
2032
  if (!keyFrame)
2067
2033
  return;
2068
2034
  if (data.referenceAudio && data.referenceAudio !== true) {
2069
- keyFrame.referenceAudioContentType = getFileContentType(data.referenceAudio);
2035
+ keyFrame.referenceAudioContentType = (0, fileContentType_js_1.getFileContentType)(data.referenceAudio, 'audio');
2070
2036
  }
2071
2037
  }
2072
2038
  _processVideoAssets(project, data) {
@@ -2123,37 +2089,37 @@ class ProjectsApi extends ApiGroup_js_1.default {
2123
2089
  if (!keyFrame)
2124
2090
  return;
2125
2091
  if (data.referenceImage && data.referenceImage !== true) {
2126
- keyFrame.referenceImageContentType = getFileContentType(data.referenceImage);
2092
+ keyFrame.referenceImageContentType = (0, fileContentType_js_1.getFileContentType)(data.referenceImage);
2127
2093
  }
2128
2094
  if (data.referenceImageEnd && data.referenceImageEnd !== true) {
2129
- keyFrame.referenceImageEndContentType = getFileContentType(data.referenceImageEnd);
2095
+ keyFrame.referenceImageEndContentType = (0, fileContentType_js_1.getFileContentType)(data.referenceImageEnd);
2130
2096
  }
2131
2097
  const isMinimaxH3R2v = (0, index_js_2.isMinimaxH3ReferenceModel)(data.modelId);
2132
2098
  if (!isMinimaxH3R2v && data.referenceAudio && data.referenceAudio !== true) {
2133
- keyFrame.referenceAudioContentType = getFileContentType(data.referenceAudio);
2099
+ keyFrame.referenceAudioContentType = (0, fileContentType_js_1.getFileContentType)(data.referenceAudio, 'audio');
2134
2100
  }
2135
2101
  if (data.referenceAudioIdentity && data.referenceAudioIdentity !== true) {
2136
- const contentType = getFileContentType(data.referenceAudioIdentity);
2102
+ const contentType = (0, fileContentType_js_1.getFileContentType)(data.referenceAudioIdentity, 'audio');
2137
2103
  keyFrame.referenceAudioIdentityContentType = contentType;
2138
2104
  (_b = keyFrame.referenceAudioContentType) !== null && _b !== void 0 ? _b : (keyFrame.referenceAudioContentType = contentType);
2139
2105
  }
2140
2106
  if (!isMinimaxH3R2v && data.referenceVideo && data.referenceVideo !== true) {
2141
- keyFrame.referenceVideoContentType = getFileContentType(data.referenceVideo);
2107
+ keyFrame.referenceVideoContentType = (0, fileContentType_js_1.getFileContentType)(data.referenceVideo, 'video');
2142
2108
  }
2143
2109
  if (isMinimaxH3R2v) {
2144
2110
  for (const { slot, media } of (0, index_js_2.getMinimaxH3ReferenceAudioSlots)(data)) {
2145
2111
  if (typeof media !== 'boolean') {
2146
- keyFrame[`referenceAudio${slot}ContentType`] = getFileContentType(media);
2112
+ keyFrame[`referenceAudio${slot}ContentType`] = (0, fileContentType_js_1.getFileContentType)(media, 'audio');
2147
2113
  }
2148
2114
  }
2149
2115
  for (const { slot, media } of (0, index_js_2.getMinimaxH3ReferenceVideoSlots)(data)) {
2150
2116
  if (typeof media !== 'boolean') {
2151
- keyFrame[`referenceVideo${slot}ContentType`] = getFileContentType(media);
2117
+ keyFrame[`referenceVideo${slot}ContentType`] = (0, fileContentType_js_1.getFileContentType)(media, 'video');
2152
2118
  }
2153
2119
  }
2154
2120
  }
2155
2121
  if (data.referenceMask && data.referenceMask !== true && (0, index_js_2.usesReferenceMask)(data)) {
2156
- keyFrame.referenceMaskContentType = getFileContentType(data.referenceMask);
2122
+ keyFrame.referenceMaskContentType = (0, fileContentType_js_1.getFileContentType)(data.referenceMask);
2157
2123
  }
2158
2124
  }
2159
2125
  /**
@@ -2491,7 +2457,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2491
2457
  const imageId = (0, getUUID_js_1.default)();
2492
2458
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2493
2459
  assertSession();
2494
- const contentType = getFileContentType(file);
2460
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2495
2461
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'startingImage' }))
2496
2462
  return imageId;
2497
2463
  assertSession();
@@ -2527,7 +2493,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2527
2493
  const imageId = (0, getUUID_js_1.default)();
2528
2494
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2529
2495
  assertSession();
2530
- const contentType = getFileContentType(file);
2496
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2531
2497
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'cnImage' }))
2532
2498
  return imageId;
2533
2499
  assertSession();
@@ -2564,7 +2530,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2564
2530
  const imageIndex = (index + 1);
2565
2531
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2566
2532
  assertSession();
2567
- const contentType = getFileContentType(file);
2533
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2568
2534
  if (yield this.assets.tryBindFile(file, contentType, {
2569
2535
  projectId,
2570
2536
  type: `contextImage${imageIndex}`
@@ -2610,7 +2576,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2610
2576
  const type = `keyframeImage${slot}`;
2611
2577
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2612
2578
  assertSession();
2613
- const contentType = getFileContentType(file);
2579
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2614
2580
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type }))
2615
2581
  return imageId;
2616
2582
  assertSession();
@@ -2648,7 +2614,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2648
2614
  const imageId = (0, getUUID_js_1.default)();
2649
2615
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2650
2616
  assertSession();
2651
- const contentType = getFileContentType(file);
2617
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2652
2618
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'referenceImage' }))
2653
2619
  return imageId;
2654
2620
  assertSession();
@@ -2688,7 +2654,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2688
2654
  const imageId = (0, getUUID_js_1.default)();
2689
2655
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2690
2656
  assertSession();
2691
- const contentType = getFileContentType(file);
2657
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2692
2658
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'referenceMask' }))
2693
2659
  return imageId;
2694
2660
  assertSession();
@@ -2728,7 +2694,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2728
2694
  const imageId = (0, getUUID_js_1.default)();
2729
2695
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2730
2696
  assertSession();
2731
- const contentType = getFileContentType(file);
2697
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file);
2732
2698
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'referenceImageEnd' }))
2733
2699
  return imageId;
2734
2700
  assertSession();
@@ -2769,7 +2735,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2769
2735
  var _a;
2770
2736
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2771
2737
  assertSession();
2772
- const contentType = getFileContentType(file);
2738
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file, 'audio');
2773
2739
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'referenceAudio', id }))
2774
2740
  return;
2775
2741
  assertSession();
@@ -2809,7 +2775,7 @@ class ProjectsApi extends ApiGroup_js_1.default {
2809
2775
  var _a;
2810
2776
  const assertSession = (_a = this._preparingSessions.get(projectId)) !== null && _a !== void 0 ? _a : (0, requestSession_js_1.captureRequestSession)(this.client.auth);
2811
2777
  assertSession();
2812
- const contentType = getFileContentType(file);
2778
+ const contentType = (0, fileContentType_js_1.getFileContentType)(file, 'video');
2813
2779
  if (yield this.assets.tryBindFile(file, contentType, { projectId, type: 'referenceVideo', id }))
2814
2780
  return;
2815
2781
  assertSession();