@sogni-ai/sogni-client 4.0.0-alpha.3 → 4.0.0-alpha.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/README.md +279 -28
  3. package/dist/Account/index.d.ts +18 -16
  4. package/dist/Account/index.js +31 -20
  5. package/dist/Account/index.js.map +1 -1
  6. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.d.ts +66 -0
  7. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js +332 -0
  8. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js.map +1 -0
  9. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.d.ts +28 -0
  10. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js +203 -0
  11. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js.map +1 -0
  12. package/dist/ApiClient/WebSocketClient/events.d.ts +11 -0
  13. package/dist/ApiClient/WebSocketClient/index.d.ts +2 -2
  14. package/dist/ApiClient/WebSocketClient/index.js +13 -3
  15. package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
  16. package/dist/ApiClient/WebSocketClient/types.d.ts +13 -0
  17. package/dist/ApiClient/index.d.ts +4 -4
  18. package/dist/ApiClient/index.js +23 -4
  19. package/dist/ApiClient/index.js.map +1 -1
  20. package/dist/Projects/Job.d.ts +44 -4
  21. package/dist/Projects/Job.js +83 -16
  22. package/dist/Projects/Job.js.map +1 -1
  23. package/dist/Projects/Project.d.ts +18 -0
  24. package/dist/Projects/Project.js +34 -6
  25. package/dist/Projects/Project.js.map +1 -1
  26. package/dist/Projects/createJobRequestMessage.js +109 -15
  27. package/dist/Projects/createJobRequestMessage.js.map +1 -1
  28. package/dist/Projects/index.d.ts +110 -11
  29. package/dist/Projects/index.js +423 -42
  30. package/dist/Projects/index.js.map +1 -1
  31. package/dist/Projects/types/EstimationResponse.d.ts +2 -0
  32. package/dist/Projects/types/SamplerParams.d.ts +13 -0
  33. package/dist/Projects/types/SamplerParams.js +26 -0
  34. package/dist/Projects/types/SamplerParams.js.map +1 -0
  35. package/dist/Projects/types/SchedulerParams.d.ts +14 -0
  36. package/dist/Projects/types/SchedulerParams.js +24 -0
  37. package/dist/Projects/types/SchedulerParams.js.map +1 -0
  38. package/dist/Projects/types/events.d.ts +5 -1
  39. package/dist/Projects/types/index.d.ts +150 -39
  40. package/dist/Projects/types/index.js +13 -0
  41. package/dist/Projects/types/index.js.map +1 -1
  42. package/dist/Projects/utils.d.ts +19 -1
  43. package/dist/Projects/utils.js +68 -0
  44. package/dist/Projects/utils.js.map +1 -1
  45. package/dist/index.d.ts +12 -4
  46. package/dist/index.js +12 -4
  47. package/dist/index.js.map +1 -1
  48. package/dist/lib/AuthManager/TokenAuthManager.js +0 -2
  49. package/dist/lib/AuthManager/TokenAuthManager.js.map +1 -1
  50. package/dist/lib/DataEntity.js +4 -2
  51. package/dist/lib/DataEntity.js.map +1 -1
  52. package/dist/lib/validation.d.ts +7 -0
  53. package/dist/lib/validation.js +36 -0
  54. package/dist/lib/validation.js.map +1 -1
  55. package/package.json +4 -4
  56. package/src/Account/index.ts +30 -19
  57. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.ts +426 -0
  58. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/index.ts +237 -0
  59. package/src/ApiClient/WebSocketClient/events.ts +13 -0
  60. package/src/ApiClient/WebSocketClient/index.ts +15 -5
  61. package/src/ApiClient/WebSocketClient/types.ts +16 -0
  62. package/src/ApiClient/index.ts +30 -8
  63. package/src/Projects/Job.ts +97 -16
  64. package/src/Projects/Project.ts +42 -9
  65. package/src/Projects/createJobRequestMessage.ts +155 -36
  66. package/src/Projects/index.ts +447 -46
  67. package/src/Projects/types/EstimationResponse.ts +2 -0
  68. package/src/Projects/types/SamplerParams.ts +24 -0
  69. package/src/Projects/types/SchedulerParams.ts +22 -0
  70. package/src/Projects/types/events.ts +6 -0
  71. package/src/Projects/types/index.ts +181 -47
  72. package/src/Projects/utils.ts +66 -1
  73. package/src/index.ts +38 -11
  74. package/src/lib/AuthManager/TokenAuthManager.ts +0 -2
  75. package/src/lib/DataEntity.ts +4 -2
  76. package/src/lib/validation.ts +41 -0
@@ -14,6 +14,8 @@ export interface Job {
14
14
  costInRenderSec: string;
15
15
  costInUSD: string;
16
16
  costInToken: string;
17
+ costInSpark: string;
18
+ costInSogni: string;
17
19
  calculatedStepCount?: number;
18
20
  }
19
21
 
@@ -0,0 +1,24 @@
1
+ export const SupportedSamplers = {
2
+ dfs_sd3: 'Discrete Flow Scheduler (SD3)',
3
+ dpm_pp: 'DPM Solver Multistep (DPM-Solver++)',
4
+ dpm_pp_sde: 'DPM++ SDE',
5
+ dpm_pp_2m: 'DPM++ 2M',
6
+ //dpm_pp_2m_sde: 'DPM++ 2M SDE',
7
+ euler: 'Euler',
8
+ euler_a: 'Euler a',
9
+ //heun: 'Heun',
10
+ lcm: 'LCM (Latent Consistency Model)',
11
+ pndm_plms: 'PNDM (Pseudo-linear multi-step)'
12
+ //uni_pc: 'UniPC'
13
+ };
14
+
15
+ export function isSampler(sampler: string): sampler is Sampler {
16
+ return sampler in SupportedSamplers;
17
+ }
18
+
19
+ export function isRawSampler(sampler: string): boolean {
20
+ const samplers = Object.values(SupportedSamplers);
21
+ return samplers.includes(sampler);
22
+ }
23
+
24
+ export type Sampler = keyof typeof SupportedSamplers;
@@ -0,0 +1,22 @@
1
+ export const SupportedSchedulers = {
2
+ beta: 'Beta',
3
+ ddim: 'DDIM',
4
+ karras: 'Karras',
5
+ kl_optimal: 'KL Optimal',
6
+ leading: 'Leading',
7
+ linear: 'Linear',
8
+ normal: 'Normal',
9
+ sgm_uniform: 'SGM Uniform',
10
+ simple: 'Simple'
11
+ };
12
+
13
+ export function isScheduler(scheduler: string): scheduler is Scheduler {
14
+ return scheduler in SupportedSchedulers;
15
+ }
16
+
17
+ export function isRawScheduler(scheduler: string): boolean {
18
+ const schedulers = Object.values(SupportedSchedulers);
19
+ return schedulers.includes(scheduler);
20
+ }
21
+
22
+ export type Scheduler = keyof typeof SupportedSchedulers;
@@ -48,6 +48,11 @@ export interface JobProgress extends JobEventBase {
48
48
  stepCount: number;
49
49
  }
50
50
 
51
+ export interface JobETA extends JobEventBase {
52
+ type: 'jobETA';
53
+ etaSeconds: number;
54
+ }
55
+
51
56
  export interface JobPreview extends JobEventBase {
52
57
  type: 'preview';
53
58
  url: string;
@@ -75,6 +80,7 @@ export type JobEvent =
75
80
  | JobInitiating
76
81
  | JobStarted
77
82
  | JobProgress
83
+ | JobETA
78
84
  | JobPreview
79
85
  | JobCompleted
80
86
  | JobError;
@@ -1,17 +1,27 @@
1
1
  import { SupernetType } from '../../ApiClient/WebSocketClient/types';
2
2
  import { ControlNetParams } from './ControlNetParams';
3
3
  import { TokenType } from '../../types/token';
4
+ import { Sampler, SupportedSamplers } from './SamplerParams';
5
+ import { Scheduler, SupportedSchedulers } from './SchedulerParams';
4
6
 
5
7
  export interface SupportedModel {
6
8
  id: string;
7
9
  name: string;
8
10
  SID: number;
11
+ /**
12
+ * Media type produced by this model: 'image' or 'video'
13
+ */
14
+ media: 'image' | 'video';
9
15
  }
10
16
 
11
17
  export interface AvailableModel {
12
18
  id: string;
13
19
  name: string;
14
20
  workerCount: number;
21
+ /**
22
+ * Media type produced by this model: 'image' or 'video'
23
+ */
24
+ media: 'image' | 'video';
15
25
  }
16
26
 
17
27
  export interface SizePreset {
@@ -23,25 +33,22 @@ export interface SizePreset {
23
33
  aspect: string;
24
34
  }
25
35
 
26
- export type Scheduler =
27
- | 'DPM Solver Multistep (DPM-Solver++)'
28
- | 'PNDM (Pseudo-linear multi-step)'
29
- | 'LCM (Latent Consistency Model)'
30
- | 'Discrete Flow Scheduler (SD3)'
31
- | 'Euler' // Used by Flux
32
- | 'Euler a'; // Used by Flux
33
-
34
- export type TimeStepSpacing = 'Leading' | 'Linear' | 'Karras' | 'Simple' | 'SGM Uniform';
36
+ export type { Sampler, Scheduler };
35
37
 
36
- export type OutputFormat = 'png' | 'jpg';
38
+ export { SupportedSamplers, SupportedSchedulers };
37
39
 
38
- export type InputImage = File | Buffer | Blob | boolean;
40
+ export type ImageOutputFormat = 'png' | 'jpg';
41
+ export type VideoOutputFormat = 'mp4';
39
42
 
40
- export interface ProjectParams {
43
+ export interface BaseProjectParams {
41
44
  /**
42
45
  * ID of the model to use, available models are available in the `availableModels` property of the `ProjectsApi` instance.
43
46
  */
44
47
  modelId: string;
48
+ /**
49
+ * Number of media files to generate. Depending on project type, this can be number of images or number of videos.
50
+ */
51
+ numberOfMedia: number;
45
52
  /**
46
53
  * Prompt for what to be created
47
54
  */
@@ -55,15 +62,15 @@ export interface ProjectParams {
55
62
  */
56
63
  stylePrompt: string;
57
64
  /**
58
- * Number of steps. For most Stable Diffusion models, optimal value is 20
65
+ * Number of steps. For most Stable Diffusion models, optimal value is 20.
59
66
  */
60
- steps: number;
67
+ steps?: number;
61
68
  /**
62
- * Guidance scale. For most Stable Diffusion models, optimal value is 7.5
69
+ * Guidance scale. For most Stable Diffusion models, optimal value is 7.5.
63
70
  */
64
- guidance: number;
71
+ guidance?: number;
65
72
  /**
66
- * Override current network type. Default value can be read from `client.account.currentAccount.network`
73
+ * Override current network type. Default value can be read from `sogni.account.currentAccount.network`
67
74
  */
68
75
  network?: SupernetType;
69
76
  /**
@@ -76,46 +83,102 @@ export interface ProjectParams {
76
83
  */
77
84
  seed?: number;
78
85
  /**
79
- * Number of images to generate
86
+ * Select which tokens to use for the project.
87
+ * If not specified, the Sogni token will be used.
80
88
  */
81
- numberOfImages: number;
89
+ tokenType?: TokenType;
90
+ }
91
+
92
+ export type InputMedia = File | Buffer | Blob | boolean;
93
+
94
+ /**
95
+ * Video-specific parameters for video workflows (t2v, i2v, s2v, animate).
96
+ * Only applicable when using video models like wan_v2.2-14b-fp8_t2v.
97
+ * Includes frame count, fps, shift, and reference assets (image, audio, video).
98
+ */
99
+ export interface VideoProjectParams extends BaseProjectParams {
100
+ type: 'video';
82
101
  /**
83
- * Generate images based on the starting image.
84
- * Supported types:
85
- * `File` - file object from input[type=file]
86
- * `Buffer` - Node.js buffer object with image data
87
- * `Blob` - blob object with image data
88
- * `true` - indicates that the image is already uploaded to the server
102
+ * Number of frames to generate
89
103
  */
90
- startingImage?: InputImage;
104
+ frames?: number;
91
105
  /**
92
- * How strong effect of starting image should be. From 0 to 1, default 0.5
106
+ * Frames per second for output video
93
107
  */
94
- startingImageStrength?: number;
108
+ fps?: number;
109
+ /**
110
+ * Shift parameter for video diffusion models
111
+ */
112
+ shift?: number;
113
+ /**
114
+ * Reference image for WAN video workflows.
115
+ * Maps to: startImage (i2v), characterImage (animate), referenceImage (s2v)
116
+ */
117
+ referenceImage?: InputMedia;
118
+ /**
119
+ * Optional end image for i2v interpolation workflows.
120
+ * When provided with referenceImage, the video will interpolate between the two images.
121
+ */
122
+ referenceImageEnd?: InputMedia;
123
+ /**
124
+ * Reference audio for s2v (sound-to-video) workflows.
125
+ */
126
+ referenceAudio?: InputMedia;
127
+ /**
128
+ * Reference video for animate workflows.
129
+ * Maps to: drivingVideo (animate-move), sourceVideo (animate-replace)
130
+ */
131
+ referenceVideo?: InputMedia;
132
+ /**
133
+ * Output video width. Only used if `sizePreset` is "custom"
134
+ */
135
+ width?: number;
136
+ /**
137
+ * Output video height. Only used if `sizePreset` is "custom"
138
+ */
139
+ height?: number;
140
+ /**
141
+ * Output video format. For now only 'mp4' is supported, defaults to 'mp4'.
142
+ */
143
+ outputFormat?: VideoOutputFormat;
144
+ }
145
+
146
+ export interface ImageProjectParams extends BaseProjectParams {
147
+ type: 'image';
148
+ /**
149
+ * Number of previews to generate. Note that previews affect project cost
150
+ */
151
+ numberOfPreviews?: number;
95
152
  /**
96
- * Context images for Flux Kontext model. Flux Kontext support up to 2 context images.
153
+ * Starting image for img2img workflows.
97
154
  * Supported types:
98
155
  * `File` - file object from input[type=file]
99
156
  * `Buffer` - Node.js buffer object with image data
100
157
  * `Blob` - blob object with image data
101
158
  * `true` - indicates that the image is already uploaded to the server
102
159
  */
103
- contextImages?: InputImage[];
160
+ startingImage?: InputMedia;
104
161
  /**
105
- * Number of previews to generate. Note that previews affect project cost\
162
+ * How strong effect of starting image should be. From 0 to 1, default 0.5
106
163
  */
107
- numberOfPreviews?: number;
164
+ startingImageStrength?: number;
165
+ /**
166
+ * Context images for multi-reference image generation.
167
+ * Flux.2 Dev and Qwen Image Edit Plus support up to 3 context images.
168
+ * Flux Kontext supports up to 2 context images.
169
+ */
170
+ contextImages?: InputMedia[];
108
171
  /**
109
172
  * Scheduler to use
110
173
  */
111
- scheduler?: Scheduler;
174
+ sampler?: Sampler;
112
175
  /**
113
176
  * Time step spacing method
114
177
  */
115
- timeStepSpacing?: TimeStepSpacing;
178
+ scheduler?: Scheduler;
116
179
  /**
117
180
  * Size preset ID to use. You can query available size presets
118
- * from `client.projects.sizePresets(network, modelId)`
181
+ * from `sogni.projects.sizePresets(network, modelId)`
119
182
  */
120
183
  sizePreset?: 'custom' | string;
121
184
  /**
@@ -131,25 +194,59 @@ export interface ProjectParams {
131
194
  */
132
195
  controlNet?: ControlNetParams;
133
196
  /**
134
- * Select which tokens to use for the project.
135
- * If not specified, the Sogni token will be used.
136
- */
137
- tokenType?: TokenType;
138
- /**
139
- * Output image format. Can be 'png' or 'jpg'.
140
- * If not specified, 'png' will be used.
197
+ * Output format. Can be 'png' or 'jpg'. Defaults to 'png'.
141
198
  */
142
- outputFormat?: OutputFormat;
199
+ outputFormat?: ImageOutputFormat;
200
+ }
201
+
202
+ export type ProjectParams = ImageProjectParams | VideoProjectParams;
203
+
204
+ export function isVideoParams(params: ProjectParams): params is VideoProjectParams {
205
+ return params.type === 'video';
206
+ }
207
+
208
+ export function isImageParams(params: ProjectParams): params is ImageProjectParams {
209
+ return params.type === 'image';
143
210
  }
144
211
 
212
+ /**
213
+ * Supported audio formats
214
+ */
215
+ export type AudioFormat = 'm4a' | 'mp3' | 'wav';
216
+
217
+ /**
218
+ * Supported video formats
219
+ */
220
+ export type VideoFormat = 'mp4' | 'mov';
221
+
222
+ /**
223
+ * Parameters for image asset URL requests (upload/download)
224
+ */
145
225
  export type ImageUrlParams = {
146
226
  imageId: string;
147
227
  jobId: string;
148
- type: 'preview' | 'complete' | 'startingImage' | 'cnImage' | 'contextImage1' | 'contextImage2';
149
- // This seems to be unused currently
228
+ type:
229
+ | 'preview'
230
+ | 'complete'
231
+ | 'startingImage'
232
+ | 'cnImage'
233
+ | 'contextImage1'
234
+ | 'contextImage2'
235
+ | 'contextImage3'
236
+ | 'referenceImage'
237
+ | 'referenceImageEnd';
150
238
  startContentType?: string;
151
239
  };
152
240
 
241
+ /**
242
+ * Parameters for media asset URL requests (video/audio upload/download)
243
+ */
244
+ export type MediaUrlParams = {
245
+ id?: string;
246
+ jobId: string;
247
+ type: 'complete' | 'preview' | 'referenceAudio' | 'referenceVideo';
248
+ };
249
+
153
250
  export interface EstimateRequest {
154
251
  /**
155
252
  * Network to use. Can be 'fast' or 'relaxed'
@@ -202,9 +299,9 @@ export interface EstimateRequest {
202
299
  */
203
300
  guidance?: number;
204
301
  /**
205
- * Scheduler
302
+ * Sampler
206
303
  */
207
- scheduler?: Scheduler;
304
+ sampler?: Sampler;
208
305
  /**
209
306
  * Number of context images to use (for Flux Kontext).
210
307
  * Note that this parameter is ignored if `scheduler` is not provided
@@ -212,4 +309,41 @@ export interface EstimateRequest {
212
309
  contextImages?: number;
213
310
  }
214
311
 
312
+ export interface VideoEstimateRequest {
313
+ tokenType: TokenType;
314
+ model: string;
315
+ width: number;
316
+ height: number;
317
+ frames: number;
318
+ fps: number;
319
+ steps: number;
320
+ }
321
+
322
+ /**
323
+ * Represents estimation of project cost in different currency formats
324
+ */
325
+ export interface CostEstimation {
326
+ /** Cost in selected token type */
327
+ token: string;
328
+ /** Cost in USD */
329
+ usd: string;
330
+ /** Cost in Spark Points */
331
+ spark: string;
332
+ /** Cost in Sogni tokens */
333
+ sogni: string;
334
+ }
335
+
215
336
  export type EnhancementStrength = 'light' | 'medium' | 'heavy';
337
+
338
+ /**
339
+ * Video workflow types for WAN models
340
+ */
341
+ export type VideoWorkflowType = 't2v' | 'i2v' | 's2v' | 'animate-move' | 'animate-replace' | null;
342
+
343
+ export type AssetRequirement = 'required' | 'optional' | 'forbidden';
344
+
345
+ export type VideoAssetKey =
346
+ | 'referenceImage'
347
+ | 'referenceImageEnd'
348
+ | 'referenceAudio'
349
+ | 'referenceVideo';
@@ -1,4 +1,4 @@
1
- import { EnhancementStrength } from './types';
1
+ import { AssetRequirement, EnhancementStrength, VideoAssetKey, VideoWorkflowType } from './types';
2
2
 
3
3
  export function getEnhacementStrength(strength: EnhancementStrength): number {
4
4
  switch (strength) {
@@ -10,3 +10,68 @@ export function getEnhacementStrength(strength: EnhancementStrength): number {
10
10
  return 0.35;
11
11
  }
12
12
  }
13
+
14
+ /**
15
+ * Check if a model ID is for a video workflow.
16
+ * This is consistent with the `media` property returned by the models list API.
17
+ * Video models produce MP4 output; image models produce PNG/JPG output.
18
+ */
19
+ export function isVideoModel(modelId: string): boolean {
20
+ return modelId.startsWith('wan_');
21
+ }
22
+
23
+ /**
24
+ * Get the video workflow type from a model ID.
25
+ * Returns null for non-video models.
26
+ */
27
+ export function getVideoWorkflowType(modelId: string): VideoWorkflowType {
28
+ if (!modelId || !modelId.startsWith('wan_')) return null;
29
+ if (modelId.includes('_i2v')) return 'i2v';
30
+ if (modelId.includes('_s2v')) return 's2v';
31
+ if (modelId.includes('_animate-move')) return 'animate-move';
32
+ if (modelId.includes('_animate-replace')) return 'animate-replace';
33
+ if (modelId.includes('_t2v')) return 't2v';
34
+ return null;
35
+ }
36
+
37
+ /**
38
+ * Asset requirements for each video workflow type.
39
+ * - required: Must be provided
40
+ * - optional: Can be provided
41
+ * - forbidden: Must NOT be provided
42
+ */
43
+ export const VIDEO_WORKFLOW_ASSETS: Record<
44
+ NonNullable<VideoWorkflowType>,
45
+ Record<VideoAssetKey, AssetRequirement>
46
+ > = {
47
+ t2v: {
48
+ referenceImage: 'forbidden',
49
+ referenceImageEnd: 'forbidden',
50
+ referenceAudio: 'forbidden',
51
+ referenceVideo: 'forbidden'
52
+ },
53
+ i2v: {
54
+ referenceImage: 'required',
55
+ referenceImageEnd: 'optional',
56
+ referenceAudio: 'forbidden',
57
+ referenceVideo: 'forbidden'
58
+ },
59
+ s2v: {
60
+ referenceImage: 'required',
61
+ referenceAudio: 'required',
62
+ referenceImageEnd: 'forbidden',
63
+ referenceVideo: 'forbidden'
64
+ },
65
+ 'animate-move': {
66
+ referenceImage: 'required',
67
+ referenceVideo: 'required',
68
+ referenceImageEnd: 'forbidden',
69
+ referenceAudio: 'forbidden'
70
+ },
71
+ 'animate-replace': {
72
+ referenceImage: 'required',
73
+ referenceVideo: 'required',
74
+ referenceImageEnd: 'forbidden',
75
+ referenceAudio: 'forbidden'
76
+ }
77
+ };
package/src/index.ts CHANGED
@@ -14,10 +14,18 @@ import Job, { JobStatus } from './Projects/Job';
14
14
  import Project, { ProjectStatus } from './Projects/Project';
15
15
  import {
16
16
  AvailableModel,
17
- OutputFormat,
17
+ ImageProjectParams,
18
+ ImageOutputFormat,
18
19
  ProjectParams,
20
+ Sampler,
19
21
  Scheduler,
20
- TimeStepSpacing
22
+ SupportedSamplers,
23
+ SupportedSchedulers,
24
+ VideoProjectParams,
25
+ AudioFormat,
26
+ VideoFormat,
27
+ VideoOutputFormat,
28
+ VideoWorkflowType
21
29
  } from './Projects/types';
22
30
  // Stats API
23
31
  import StatsApi from './Stats';
@@ -28,21 +36,27 @@ import { CookieAuthManager, TokenAuthData, TokenAuthManager } from './lib/AuthMa
28
36
  import { MeData } from './Account/types';
29
37
 
30
38
  export type {
39
+ AudioFormat,
31
40
  AvailableModel,
32
41
  ErrorData,
42
+ ImageProjectParams,
43
+ ImageOutputFormat,
33
44
  JobStatus,
34
45
  Logger,
35
46
  LogLevel,
36
- OutputFormat,
37
47
  ProjectParams,
38
48
  ProjectStatus,
39
- Scheduler,
49
+ Sampler,
40
50
  SupernetType,
41
- TimeStepSpacing,
42
- TokenType
51
+ Scheduler,
52
+ TokenType,
53
+ VideoFormat,
54
+ VideoOutputFormat,
55
+ VideoProjectParams,
56
+ VideoWorkflowType
43
57
  };
44
58
 
45
- export { ApiError, CurrentAccount, Job, Project };
59
+ export { ApiError, CurrentAccount, Job, Project, SupportedSamplers, SupportedSchedulers };
46
60
 
47
61
  export interface SogniClientConfig {
48
62
  /**
@@ -61,7 +75,7 @@ export interface SogniClientConfig {
61
75
  socketEndpoint?: string;
62
76
  /**
63
77
  * Disable WebSocket connection. Useful for testing or when WebSocket is not needed.
64
- * Note that many may not work without WebSocket connection.
78
+ * Note that many APIs may not work without WebSocket connection.
65
79
  * @experimental
66
80
  * @internal
67
81
  */
@@ -93,6 +107,14 @@ export interface SogniClientConfig {
93
107
  * @experimental
94
108
  */
95
109
  authType?: 'token' | 'cookies';
110
+ /**
111
+ * Browser only. If true, the client will use a single WebSocket connection shared across multiple
112
+ * tabs. This is useful for browser apps that need to process multiple projects at the same time.
113
+ * Only works in browser environment and with cookie authentication.
114
+ * @default false
115
+ * @experimental
116
+ */
117
+ multiInstance?: boolean;
96
118
  }
97
119
 
98
120
  export class SogniClient {
@@ -139,9 +161,13 @@ export class SogniClient {
139
161
  throw Error('This method should only be called when using cookie auth');
140
162
  }
141
163
  try {
142
- await this.apiClient.rest.get<ApiResponse<MeData>>('/v1/account/me');
164
+ const res = await this.apiClient.rest.get<ApiResponse<MeData>>('/v1/account/me');
143
165
  await auth.authenticate();
144
- await this.account.me();
166
+ this.currentAccount._update({
167
+ username: res.data.username,
168
+ email: res.data.currentEmail,
169
+ walletAddress: res.data.walletAddress
170
+ });
145
171
  return true;
146
172
  } catch (e) {
147
173
  this.apiClient.logger.info('Client is not authenticated');
@@ -167,7 +193,8 @@ export class SogniClient {
167
193
  networkType: network,
168
194
  logger,
169
195
  authType: config.authType || 'token',
170
- disableSocket: config.disableSocket
196
+ disableSocket: config.disableSocket,
197
+ multiInstance: config.multiInstance
171
198
  });
172
199
  const eip712 = new EIP712Helper({
173
200
  name: isTestnet ? 'Sogni-testnet' : 'Sogni AI',
@@ -46,7 +46,6 @@ class TokenAuthManager extends AuthManagerBase<TokenAuthData | null> {
46
46
  const { expiresAt } = decodeToken(token);
47
47
  if (expiresAt > new Date()) {
48
48
  this._updateTokens({ token, refreshToken });
49
- this.emit('updated', true);
50
49
  return;
51
50
  }
52
51
  }
@@ -55,7 +54,6 @@ class TokenAuthManager extends AuthManagerBase<TokenAuthData | null> {
55
54
  const { expiresAt: refreshExpiresAt } = decodeRefreshToken(refreshToken);
56
55
  this._refreshTokenExpiresAt = refreshExpiresAt;
57
56
  await this._renewTokenSafe();
58
- this.emit('updated', true);
59
57
  }
60
58
 
61
59
  clear() {
@@ -25,9 +25,11 @@ abstract class DataEntity<D, E extends EntityEvents = EntityEvents> extends Type
25
25
  _update(delta: Partial<D>) {
26
26
  //@ts-ignore
27
27
  const changedKeys = Object.keys(delta).filter((key) => this.data[key] !== delta[key]);
28
- this.data = { ...this.data, ...delta };
29
28
  this.lastUpdated = new Date();
30
- this.emit('updated', changedKeys);
29
+ if (changedKeys.length > 0) {
30
+ this.data = { ...this.data, ...delta };
31
+ this.emit('updated', changedKeys);
32
+ }
31
33
  }
32
34
 
33
35
  /**
@@ -1,7 +1,18 @@
1
+ import { isRawSampler, isSampler, SupportedSamplers } from '../Projects/types/SamplerParams';
2
+ import { isScheduler, SupportedSchedulers } from '../Projects/types/SchedulerParams';
3
+
1
4
  export function validateCustomImageSize(value: any): number {
2
5
  return validateNumber(value, { min: 256, max: 2048, propertyName: 'Width and height' });
3
6
  }
4
7
 
8
+ /**
9
+ * Validate video dimensions for Wan 2.2 models.
10
+ * Minimum dimension is 480px for both width and height.
11
+ */
12
+ export function validateVideoSize(value: any, propertyName: 'width' | 'height'): number {
13
+ return validateNumber(value, { min: 480, propertyName: `Video ${propertyName}` });
14
+ }
15
+
5
16
  interface NumberValidationOptions {
6
17
  min?: number;
7
18
  max?: number;
@@ -38,3 +49,33 @@ export function validateNumber(
38
49
  }
39
50
  return number;
40
51
  }
52
+
53
+ export function validateSampler(value?: string) {
54
+ if (!value) {
55
+ return null;
56
+ }
57
+ if (isRawSampler(value)) {
58
+ return value;
59
+ }
60
+ if (isSampler(value)) {
61
+ return SupportedSamplers[value];
62
+ }
63
+ throw new Error(
64
+ `Invalid sampler: ${value}. Supported options: ${Object.keys(SupportedSamplers).join(', ')}`
65
+ );
66
+ }
67
+
68
+ export function validateScheduler(value?: string) {
69
+ if (!value) {
70
+ return null;
71
+ }
72
+ if (isRawSampler(value)) {
73
+ return value;
74
+ }
75
+ if (isScheduler(value)) {
76
+ return SupportedSchedulers[value];
77
+ }
78
+ throw new Error(
79
+ `Invalid scheduler: ${value}. Supported options: ${Object.keys(SupportedSchedulers).join(', ')}`
80
+ );
81
+ }