@sogni-ai/sogni-client 4.2.0-alpha.2 → 4.2.0-alpha.21

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 (109) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/CLAUDE.md +25 -3
  3. package/README.md +411 -136
  4. package/dist/Account/index.d.ts +4 -2
  5. package/dist/Account/index.js +27 -23
  6. package/dist/Account/index.js.map +1 -1
  7. package/dist/Account/types.d.ts +7 -0
  8. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.d.ts +3 -1
  9. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js +26 -2
  10. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js.map +1 -1
  11. package/dist/ApiClient/WebSocketClient/eventSubscriptions.d.ts +33 -0
  12. package/dist/ApiClient/WebSocketClient/eventSubscriptions.js +39 -0
  13. package/dist/ApiClient/WebSocketClient/eventSubscriptions.js.map +1 -0
  14. package/dist/ApiClient/WebSocketClient/events.d.ts +24 -7
  15. package/dist/ApiClient/WebSocketClient/index.d.ts +5 -1
  16. package/dist/ApiClient/WebSocketClient/index.js +24 -1
  17. package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
  18. package/dist/ApiClient/WebSocketClient/messages.d.ts +2 -0
  19. package/dist/ApiClient/WebSocketClient/types.d.ts +2 -0
  20. package/dist/ApiClient/index.d.ts +6 -1
  21. package/dist/ApiClient/index.js +7 -3
  22. package/dist/ApiClient/index.js.map +1 -1
  23. package/dist/Chat/ChatTools.d.ts +5 -49
  24. package/dist/Chat/ChatTools.js +311 -88
  25. package/dist/Chat/ChatTools.js.map +1 -1
  26. package/dist/Chat/index.d.ts +11 -2
  27. package/dist/Chat/index.js +78 -4
  28. package/dist/Chat/index.js.map +1 -1
  29. package/dist/Chat/modelRouting.d.ts +100 -0
  30. package/dist/Chat/modelRouting.js +441 -0
  31. package/dist/Chat/modelRouting.js.map +1 -0
  32. package/dist/Chat/sogniHostedTools.generated.json +529 -0
  33. package/dist/Chat/tools.d.ts +9 -55
  34. package/dist/Chat/tools.js +72 -228
  35. package/dist/Chat/tools.js.map +1 -1
  36. package/dist/Chat/types.d.ts +91 -2
  37. package/dist/CreativeWorkflows/index.d.ts +23 -0
  38. package/dist/CreativeWorkflows/index.js +274 -0
  39. package/dist/CreativeWorkflows/index.js.map +1 -0
  40. package/dist/CreativeWorkflows/types.d.ts +106 -0
  41. package/dist/CreativeWorkflows/types.js +3 -0
  42. package/dist/CreativeWorkflows/types.js.map +1 -0
  43. package/dist/Projects/Job.d.ts +6 -0
  44. package/dist/Projects/Job.js +60 -5
  45. package/dist/Projects/Job.js.map +1 -1
  46. package/dist/Projects/Project.js +15 -3
  47. package/dist/Projects/Project.js.map +1 -1
  48. package/dist/Projects/createJobRequestMessage.js +140 -6
  49. package/dist/Projects/createJobRequestMessage.js.map +1 -1
  50. package/dist/Projects/index.d.ts +10 -1
  51. package/dist/Projects/index.js +197 -58
  52. package/dist/Projects/index.js.map +1 -1
  53. package/dist/Projects/types/ModelOptions.d.ts +3 -3
  54. package/dist/Projects/types/ModelOptions.js +12 -5
  55. package/dist/Projects/types/ModelOptions.js.map +1 -1
  56. package/dist/Projects/types/ModelTiersRaw.d.ts +7 -7
  57. package/dist/Projects/types/RawProject.d.ts +2 -0
  58. package/dist/Projects/types/events.d.ts +5 -4
  59. package/dist/Projects/types/index.d.ts +77 -7
  60. package/dist/Projects/types/index.js.map +1 -1
  61. package/dist/Projects/utils/index.d.ts +8 -1
  62. package/dist/Projects/utils/index.js +22 -8
  63. package/dist/Projects/utils/index.js.map +1 -1
  64. package/dist/index.d.ts +28 -3
  65. package/dist/index.js +19 -1
  66. package/dist/index.js.map +1 -1
  67. package/dist/lib/RestClient.d.ts +4 -1
  68. package/dist/lib/RestClient.js +17 -9
  69. package/dist/lib/RestClient.js.map +1 -1
  70. package/dist/lib/mediaValidation.d.ts +16 -0
  71. package/dist/lib/mediaValidation.js +280 -0
  72. package/dist/lib/mediaValidation.js.map +1 -0
  73. package/dist/lib/validation.d.ts +6 -1
  74. package/dist/lib/validation.js +28 -2
  75. package/dist/lib/validation.js.map +1 -1
  76. package/llms-full.txt +372 -133
  77. package/llms.txt +197 -86
  78. package/package.json +13 -4
  79. package/src/Account/index.ts +22 -2
  80. package/src/Account/types.ts +7 -0
  81. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/index.ts +47 -3
  82. package/src/ApiClient/WebSocketClient/eventSubscriptions.ts +92 -0
  83. package/src/ApiClient/WebSocketClient/events.ts +25 -7
  84. package/src/ApiClient/WebSocketClient/index.ts +33 -1
  85. package/src/ApiClient/WebSocketClient/messages.ts +2 -0
  86. package/src/ApiClient/WebSocketClient/types.ts +2 -0
  87. package/src/ApiClient/index.ts +32 -2
  88. package/src/Chat/ChatTools.ts +395 -95
  89. package/src/Chat/index.ts +149 -5
  90. package/src/Chat/modelRouting.ts +602 -0
  91. package/src/Chat/sogniHostedTools.generated.json +529 -0
  92. package/src/Chat/tools.ts +98 -245
  93. package/src/Chat/types.ts +100 -2
  94. package/src/CreativeWorkflows/index.ts +290 -0
  95. package/src/CreativeWorkflows/types.ts +134 -0
  96. package/src/Projects/Job.ts +76 -5
  97. package/src/Projects/Project.ts +13 -3
  98. package/src/Projects/createJobRequestMessage.ts +152 -13
  99. package/src/Projects/index.ts +230 -52
  100. package/src/Projects/types/ModelOptions.ts +15 -8
  101. package/src/Projects/types/ModelTiersRaw.ts +7 -7
  102. package/src/Projects/types/RawProject.ts +2 -0
  103. package/src/Projects/types/events.ts +5 -4
  104. package/src/Projects/types/index.ts +86 -6
  105. package/src/Projects/utils/index.ts +24 -8
  106. package/src/index.ts +93 -0
  107. package/src/lib/RestClient.ts +15 -5
  108. package/src/lib/mediaValidation.ts +367 -0
  109. package/src/lib/validation.ts +38 -2
@@ -133,7 +133,15 @@ class AccountApi extends ApiGroup {
133
133
  * @internal
134
134
  */
135
135
  async create(
136
- { username, email, password, subscribe, turnstileToken, referralCode }: AccountCreateParams,
136
+ {
137
+ username,
138
+ email,
139
+ password,
140
+ subscribe,
141
+ turnstileToken,
142
+ referralCode,
143
+ appSource
144
+ }: AccountCreateParams,
137
145
  rememberMe = false
138
146
  ): Promise<AccountCreateData> {
139
147
  const wallet = this.getWallet(username, password);
@@ -146,9 +154,11 @@ class AccountApi extends ApiGroup {
146
154
  walletAddress: wallet.address,
147
155
  turnstileToken
148
156
  };
157
+ const resolvedAppSource = appSource?.trim() || this.client.appSource;
149
158
  const signature = await this.eip712.signTypedData(wallet, 'signup', { ...payload, nonce });
150
159
  const res = await this.client.rest.post<ApiResponse<AccountCreateData>>('/v1/account/create', {
151
160
  ...payload,
161
+ ...(resolvedAppSource ? { appSource: resolvedAppSource } : {}),
152
162
  referralCode,
153
163
  signature,
154
164
  rememberMe
@@ -175,17 +185,26 @@ class AccountApi extends ApiGroup {
175
185
  * @param password
176
186
  * @param rememberMe - Whether to establish a long-lived session. Default is false. Only
177
187
  * applicable for cookie-based authentication.
188
+ * @param appSource - Optional client app/source label for login attribution. Defaults to the
189
+ * SogniClient connection appSource when configured.
178
190
  */
179
- async login(username: string, password: string, rememberMe = false): Promise<LoginData> {
191
+ async login(
192
+ username: string,
193
+ password: string,
194
+ rememberMe = false,
195
+ appSource?: string
196
+ ): Promise<LoginData> {
180
197
  const wallet = this.getWallet(username, password);
181
198
  const nonce = await this.getNonce(wallet.address);
182
199
  const signature = await this.eip712.signTypedData(wallet, 'authentication', {
183
200
  walletAddress: wallet.address,
184
201
  nonce
185
202
  });
203
+ const resolvedAppSource = appSource?.trim() || this.client.appSource;
186
204
  const res = await this.client.rest.post<ApiResponse<LoginData>>('/v1/account/login', {
187
205
  walletAddress: wallet.address,
188
206
  signature,
207
+ ...(resolvedAppSource ? { appSource: resolvedAppSource } : {}),
189
208
  rememberMe
190
209
  });
191
210
  const auth = this.client.auth;
@@ -414,6 +433,7 @@ class AccountApi extends ApiGroup {
414
433
  tokenType: raw.tokenType,
415
434
  claimed: !!raw.claimed,
416
435
  canClaim: !!raw.canClaim,
436
+ cantClaimReason: raw.cantClaimReason ?? null,
417
437
  lastClaim: new Date(raw.lastClaimTimestamp * 1000),
418
438
  provider: query.provider || 'base',
419
439
  nextClaim:
@@ -11,6 +11,11 @@ export interface AccountCreateParams {
11
11
  subscribe: boolean;
12
12
  turnstileToken: string;
13
13
  referralCode?: string;
14
+ /**
15
+ * Optional client app/source label for signup attribution. Defaults to the
16
+ * SogniClient connection appSource when configured.
17
+ */
18
+ appSource?: string;
14
19
  }
15
20
 
16
21
  export interface AccountCreateData {
@@ -126,6 +131,7 @@ export interface RewardRaw {
126
131
  tokenType: TokenType;
127
132
  claimed: number;
128
133
  canClaim: number;
134
+ cantClaimReason?: 'already_claimed' | 'over_free_cap' | null;
129
135
  lastClaimTimestamp: number;
130
136
  claimResetFrequencySec: number;
131
137
  }
@@ -143,6 +149,7 @@ export interface Reward {
143
149
  tokenType: TokenType;
144
150
  claimed: boolean;
145
151
  canClaim: boolean;
152
+ cantClaimReason?: 'already_claimed' | 'over_free_cap' | null;
146
153
  lastClaim: Date;
147
154
  nextClaim: Date | null;
148
155
  provider?: string;
@@ -6,6 +6,7 @@ import RestClient from '../../../lib/RestClient';
6
6
  import { SocketEventMap } from '../events';
7
7
  import { MessageType, SocketMessageMap } from '../messages';
8
8
  import ChannelCoordinator from './ChannelCoordinator';
9
+ import type { SocketEventSubscriptionInput, SocketEventSubscriptions } from '../eventSubscriptions';
9
10
 
10
11
  interface SocketSend<T extends MessageType = MessageType> {
11
12
  type: 'socket-send';
@@ -25,7 +26,17 @@ interface SwitchNetwork {
25
26
  payload: SupernetType;
26
27
  }
27
28
 
28
- type Message = SocketConnect | SocketDisconnect | SocketSend | SwitchNetwork;
29
+ interface SetSocketEventSubscriptions {
30
+ type: 'setSocketEventSubscriptions';
31
+ payload: SocketEventSubscriptionInput;
32
+ }
33
+
34
+ type Message =
35
+ | SocketConnect
36
+ | SocketDisconnect
37
+ | SocketSend
38
+ | SwitchNetwork
39
+ | SetSocketEventSubscriptions;
29
40
 
30
41
  interface EventNotification<T extends keyof SocketEventMap = keyof SocketEventMap> {
31
42
  type: 'socket-event';
@@ -70,9 +81,19 @@ class BrowserWebSocketClient extends RestClient<SocketEventMap> implements IWebS
70
81
  auth: AuthManager,
71
82
  appId: string,
72
83
  supernetType: SupernetType,
73
- logger: Logger
84
+ logger: Logger,
85
+ appSource?: string,
86
+ socketEventSubscriptions?: SocketEventSubscriptions
74
87
  ) {
75
- const socketClient = new WrappedClient(baseUrl, auth, appId, supernetType, logger);
88
+ const socketClient = new WrappedClient(
89
+ baseUrl,
90
+ auth,
91
+ appId,
92
+ supernetType,
93
+ logger,
94
+ appSource,
95
+ socketEventSubscriptions
96
+ );
76
97
  super(socketClient.baseUrl, auth, logger);
77
98
  this.socketClient = socketClient;
78
99
  this.appId = appId;
@@ -88,6 +109,14 @@ class BrowserWebSocketClient extends RestClient<SocketEventMap> implements IWebS
88
109
  });
89
110
  this.auth.on('updated', this.handleAuthUpdated.bind(this));
90
111
  this.socketClient.intercept(this.handleSocketEvent.bind(this));
112
+ // Keep this tab's WrappedClient subscription state in sync with the server's authoritative
113
+ // snapshot, even when this tab is currently a secondary. If we get promoted to primary, the
114
+ // next `connect()` will serialize the up-to-date state into the URL query string.
115
+ this.on('socketEventSubscriptionsUpdated', (payload) => {
116
+ if (payload && payload.socketEventSubscriptions) {
117
+ this.socketClient.socketEventSubscriptions = { ...payload.socketEventSubscriptions };
118
+ }
119
+ });
91
120
  }
92
121
 
93
122
  get isConnected() {
@@ -133,6 +162,17 @@ class BrowserWebSocketClient extends RestClient<SocketEventMap> implements IWebS
133
162
  return supernetType;
134
163
  }
135
164
 
165
+ async setSocketEventSubscriptions(update: SocketEventSubscriptionInput): Promise<void> {
166
+ await this.coordinator.isReady();
167
+ if (this.coordinator.isPrimary) {
168
+ return this.socketClient.setSocketEventSubscriptions(update);
169
+ }
170
+ return this.coordinator.sendMessage({
171
+ type: 'setSocketEventSubscriptions',
172
+ payload: update
173
+ });
174
+ }
175
+
136
176
  async send<T extends MessageType>(messageType: T, data: SocketMessageMap[T]): Promise<void> {
137
177
  await this.coordinator.isReady();
138
178
  if (this.coordinator.isPrimary) {
@@ -172,6 +212,10 @@ class BrowserWebSocketClient extends RestClient<SocketEventMap> implements IWebS
172
212
  await this.switchNetwork(message.payload);
173
213
  return;
174
214
  }
215
+ case 'setSocketEventSubscriptions': {
216
+ await this.socketClient.setSocketEventSubscriptions(message.payload);
217
+ return;
218
+ }
175
219
  default: {
176
220
  this._logger.error('Received unknown message type:', message);
177
221
  }
@@ -0,0 +1,92 @@
1
+ import type { SocketEventName } from './events';
2
+
3
+ export type SocketEventSubscriptionGroup = 'modelAvailability';
4
+
5
+ export type SocketEventSubscriptionName =
6
+ | SocketEventName
7
+ | SocketEventSubscriptionGroup
8
+ | (string & {});
9
+
10
+ export type SocketEventSubscriptions = Partial<
11
+ Record<SocketEventName | SocketEventSubscriptionGroup, boolean>
12
+ > &
13
+ Record<string, boolean | undefined>;
14
+
15
+ export interface SocketEventSubscriptionUpdate {
16
+ /**
17
+ * Replace or merge explicit event subscription flags.
18
+ */
19
+ subscriptions?: SocketEventSubscriptions;
20
+ /**
21
+ * Subscribe to one or more socket events or event groups.
22
+ */
23
+ subscribe?: SocketEventSubscriptionName | SocketEventSubscriptionName[];
24
+ /**
25
+ * Unsubscribe from one or more socket events or event groups.
26
+ */
27
+ unsubscribe?: SocketEventSubscriptionName | SocketEventSubscriptionName[];
28
+ /**
29
+ * Clear existing server-side subscription overrides before applying this update.
30
+ */
31
+ reset?: boolean;
32
+ /**
33
+ * Single-event update shorthand.
34
+ */
35
+ event?: SocketEventSubscriptionName;
36
+ /**
37
+ * Boolean value for the single-event update shorthand.
38
+ */
39
+ enabled?: boolean;
40
+ }
41
+
42
+ export type SocketEventSubscriptionInput = SocketEventSubscriptions | SocketEventSubscriptionUpdate;
43
+
44
+ const UPDATE_KEYS = new Set([
45
+ 'subscriptions',
46
+ 'subscribe',
47
+ 'unsubscribe',
48
+ 'reset',
49
+ 'event',
50
+ 'enabled'
51
+ ]);
52
+
53
+ function hasUpdateShape(input: Record<string, unknown>): boolean {
54
+ return Object.keys(input).some((key) => UPDATE_KEYS.has(key));
55
+ }
56
+
57
+ function normalizeSubscriptions(
58
+ subscriptions?: SocketEventSubscriptions
59
+ ): SocketEventSubscriptions | undefined {
60
+ if (!subscriptions || typeof subscriptions !== 'object') {
61
+ return undefined;
62
+ }
63
+
64
+ const normalized: SocketEventSubscriptions = {};
65
+ for (const [eventName, enabled] of Object.entries(subscriptions)) {
66
+ if (typeof enabled === 'boolean') {
67
+ normalized[eventName] = enabled;
68
+ }
69
+ }
70
+ return Object.keys(normalized).length ? normalized : undefined;
71
+ }
72
+
73
+ export function normalizeSocketEventSubscriptionUpdate(
74
+ input: SocketEventSubscriptionInput
75
+ ): SocketEventSubscriptionUpdate {
76
+ const raw = input && typeof input === 'object' ? input : {};
77
+ const update = hasUpdateShape(raw as Record<string, unknown>)
78
+ ? (raw as SocketEventSubscriptionUpdate)
79
+ : { subscriptions: raw as SocketEventSubscriptions };
80
+
81
+ return {
82
+ ...update,
83
+ subscriptions: normalizeSubscriptions(update.subscriptions)
84
+ };
85
+ }
86
+
87
+ export function serializeSocketEventSubscriptions(
88
+ subscriptions?: SocketEventSubscriptions
89
+ ): string | undefined {
90
+ const normalized = normalizeSubscriptions(subscriptions);
91
+ return normalized ? JSON.stringify(normalized) : undefined;
92
+ }
@@ -44,9 +44,10 @@ export type JobErrorData = {
44
44
  export type JobProgressData = {
45
45
  jobID: string;
46
46
  imgID: string;
47
- hasImage: boolean;
48
- step: number;
49
- stepCount: number;
47
+ hasImage?: boolean;
48
+ step?: number;
49
+ stepCount?: number;
50
+ progress?: number;
50
51
  };
51
52
 
52
53
  export type JobETAData = {
@@ -58,11 +59,20 @@ export type JobETAData = {
58
59
  export type JobResultData = {
59
60
  jobID: string;
60
61
  imgID: string;
61
- performedStepCount: number;
62
- lastSeed: string;
63
- userCanceled: boolean;
64
- triggeredNSFWFilter: boolean;
62
+ performedStepCount?: number;
63
+ lastSeed?: string;
64
+ userCanceled?: boolean;
65
+ triggeredNSFWFilter?: boolean;
65
66
  resultUrl?: string;
67
+ resultKey?: string;
68
+ /**
69
+ * @deprecated Use `resultUrl`. Kept for older video worker/socket payload compatibility.
70
+ */
71
+ videoUrl?: string;
72
+ /**
73
+ * @deprecated Use `resultUrl`. Kept for older video worker/socket payload compatibility.
74
+ */
75
+ videoFile?: string;
66
76
  };
67
77
 
68
78
  export type JobStateData =
@@ -148,6 +158,10 @@ export type LLMJobErrorData = {
148
158
  workerName?: string;
149
159
  };
150
160
 
161
+ export type SocketEventSubscriptionsUpdatedData = {
162
+ socketEventSubscriptions: Record<string, boolean | undefined>;
163
+ };
164
+
151
165
  export type SocketEventMap = {
152
166
  /**
153
167
  * @event WebSocketClient#authenticated - Received after successful connection to the WebSocket server
@@ -204,6 +218,10 @@ export type SocketEventMap = {
204
218
  * @event WebSocketClient#swarmLLMModels - Available LLM models with worker counts
205
219
  */
206
220
  swarmLLMModels: Record<string, number | LLMModelInfo>;
221
+ /**
222
+ * @event WebSocketClient#socketEventSubscriptionsUpdated - Current socket event subscriptions changed
223
+ */
224
+ socketEventSubscriptionsUpdated: SocketEventSubscriptionsUpdatedData;
207
225
  /**
208
226
  * @event WebSocketClient#connected - WebSocket connection opened
209
227
  */
@@ -8,6 +8,11 @@ import isNodejs from '../../lib/isNodejs';
8
8
  import { LIB_VERSION } from '../../version';
9
9
  import { Logger } from '../../lib/DefaultLogger';
10
10
  import { AuthManager } from '../../lib/AuthManager';
11
+ import {
12
+ normalizeSocketEventSubscriptionUpdate,
13
+ serializeSocketEventSubscriptions
14
+ } from './eventSubscriptions';
15
+ import type { SocketEventSubscriptionInput, SocketEventSubscriptions } from './eventSubscriptions';
11
16
 
12
17
  const PROTOCOL_VERSION = '3.0.0';
13
18
 
@@ -15,7 +20,9 @@ const PING_INTERVAL = 15000;
15
20
 
16
21
  class WebSocketClient extends RestClient<SocketEventMap> implements IWebSocketClient {
17
22
  appId: string;
23
+ appSource?: string;
18
24
  baseUrl: string;
25
+ socketEventSubscriptions?: SocketEventSubscriptions;
19
26
  private socket: WebSocket | null = null;
20
27
  private _supernetType: SupernetType;
21
28
  private _pingInterval: NodeJS.Timeout | null = null;
@@ -25,7 +32,9 @@ class WebSocketClient extends RestClient<SocketEventMap> implements IWebSocketCl
25
32
  auth: AuthManager,
26
33
  appId: string,
27
34
  supernetType: SupernetType,
28
- logger: Logger
35
+ logger: Logger,
36
+ appSource?: string,
37
+ socketEventSubscriptions?: SocketEventSubscriptions
29
38
  ) {
30
39
  const _baseUrl = new URL(baseUrl);
31
40
  switch (_baseUrl.protocol) {
@@ -42,8 +51,17 @@ class WebSocketClient extends RestClient<SocketEventMap> implements IWebSocketCl
42
51
  }
43
52
  super(_baseUrl.toString(), auth, logger);
44
53
  this.appId = appId;
54
+ this.appSource = appSource?.trim() || undefined;
55
+ this.socketEventSubscriptions = socketEventSubscriptions;
45
56
  this.baseUrl = _baseUrl.toString();
46
57
  this._supernetType = supernetType;
58
+ // Mirror the server's authoritative subscriptions snapshot so reconnects keep any
59
+ // runtime updates applied via `setSocketEventSubscriptions` after the initial connect.
60
+ this.on('socketEventSubscriptionsUpdated', (payload) => {
61
+ if (payload && payload.socketEventSubscriptions) {
62
+ this.socketEventSubscriptions = { ...payload.socketEventSubscriptions };
63
+ }
64
+ });
47
65
  }
48
66
 
49
67
  get supernetType(): SupernetType {
@@ -63,6 +81,15 @@ class WebSocketClient extends RestClient<SocketEventMap> implements IWebSocketCl
63
81
  const isNotSecure = url.protocol === 'http:' || url.protocol === 'ws:';
64
82
  url.protocol = isNotSecure ? 'ws:' : 'wss:';
65
83
  url.searchParams.set('appId', this.appId);
84
+ if (this.appSource) {
85
+ url.searchParams.set('appSource', this.appSource);
86
+ }
87
+ const socketEventSubscriptions = serializeSocketEventSubscriptions(
88
+ this.socketEventSubscriptions
89
+ );
90
+ if (socketEventSubscriptions) {
91
+ url.searchParams.set('socketEventSubscriptions', socketEventSubscriptions);
92
+ }
66
93
  url.searchParams.set('clientName', userAgent);
67
94
  url.searchParams.set('clientType', 'artist');
68
95
  //At this point 'relaxed' does not work as expected, so we use 'fast' or empty
@@ -115,6 +142,11 @@ class WebSocketClient extends RestClient<SocketEventMap> implements IWebSocketCl
115
142
  });
116
143
  }
117
144
 
145
+ async setSocketEventSubscriptions(update: SocketEventSubscriptionInput): Promise<void> {
146
+ const normalizedUpdate = normalizeSocketEventSubscriptionUpdate(update);
147
+ await this.send('setSocketEventSubscriptions', normalizedUpdate);
148
+ }
149
+
118
150
  /**
119
151
  * Ensure the WebSocket connection is open, waiting if necessary and throwing an error if it fails
120
152
  * @private
@@ -1,6 +1,7 @@
1
1
  import { JobRequestRaw } from '../../Projects/createJobRequestMessage';
2
2
  import { SupernetType } from './types';
3
3
  import { ChatRequestMessage } from '../../Chat/types';
4
+ import type { SocketEventSubscriptionUpdate } from './eventSubscriptions';
4
5
 
5
6
  export interface JobErrorMessage {
6
7
  jobID: string;
@@ -14,6 +15,7 @@ export interface SocketMessageMap {
14
15
  jobError: JobErrorMessage;
15
16
  changeNetwork: SupernetType;
16
17
  llmJobRequest: ChatRequestMessage;
18
+ setSocketEventSubscriptions: SocketEventSubscriptionUpdate;
17
19
  }
18
20
 
19
21
  export type MessageType = keyof SocketMessageMap;
@@ -1,6 +1,7 @@
1
1
  import { MessageType, SocketMessageMap } from './messages';
2
2
  import RestClient from '../../lib/RestClient';
3
3
  import { SocketEventMap } from './events';
4
+ import type { SocketEventSubscriptionInput } from './eventSubscriptions';
4
5
 
5
6
  export type SupernetType = 'relaxed' | 'fast';
6
7
 
@@ -13,5 +14,6 @@ export interface IWebSocketClient extends RestClient<SocketEventMap> {
13
14
  connect(): Promise<void>;
14
15
  disconnect(): void;
15
16
  send<T extends MessageType>(messageType: T, data: SocketMessageMap[T]): Promise<void>;
17
+ setSocketEventSubscriptions(update: SocketEventSubscriptionInput): Promise<void>;
16
18
  switchNetwork(supernetType: SupernetType): Promise<SupernetType>;
17
19
  }
@@ -6,6 +6,10 @@ import { ServerConnectData, ServerDisconnectData } from './WebSocketClient/event
6
6
  import { ErrorCode, isNotRecoverable } from './WebSocketClient/ErrorCode';
7
7
  import { JSONValue } from '../types/json';
8
8
  import { IWebSocketClient, SupernetType } from './WebSocketClient/types';
9
+ import type {
10
+ SocketEventSubscriptionInput,
11
+ SocketEventSubscriptions
12
+ } from './WebSocketClient/eventSubscriptions';
9
13
  import { Logger } from '../lib/DefaultLogger';
10
14
  import ApiKeyAuthManager from '../lib/AuthManager/ApiKeyAuthManager';
11
15
  import CookieAuthManager from '../lib/AuthManager/CookieAuthManager';
@@ -41,6 +45,8 @@ export interface ApiClientOptions {
41
45
  baseUrl: string;
42
46
  socketUrl: string;
43
47
  appId: string;
48
+ appSource?: string;
49
+ socketEventSubscriptions?: SocketEventSubscriptions;
44
50
  networkType: SupernetType;
45
51
  logger: Logger;
46
52
  authType: 'token' | 'cookies' | 'apiKey';
@@ -50,6 +56,7 @@ export interface ApiClientOptions {
50
56
 
51
57
  class ApiClient extends TypedEventEmitter<ApiClientEvents> {
52
58
  readonly appId: string;
59
+ readonly appSource?: string;
53
60
  readonly logger: Logger;
54
61
  private _rest: RestClient;
55
62
  private _socket: IWebSocketClient;
@@ -61,6 +68,8 @@ class ApiClient extends TypedEventEmitter<ApiClientEvents> {
61
68
  baseUrl,
62
69
  socketUrl,
63
70
  appId,
71
+ appSource,
72
+ socketEventSubscriptions,
64
73
  networkType,
65
74
  authType,
66
75
  logger,
@@ -69,6 +78,7 @@ class ApiClient extends TypedEventEmitter<ApiClientEvents> {
69
78
  }: ApiClientOptions) {
70
79
  super();
71
80
  this.appId = appId;
81
+ this.appSource = appSource?.trim() || undefined;
72
82
  this.logger = logger;
73
83
  if (authType === 'apiKey') {
74
84
  this._auth = new ApiKeyAuthManager(logger);
@@ -81,9 +91,25 @@ class ApiClient extends TypedEventEmitter<ApiClientEvents> {
81
91
  const supportMultiInstance = !isNodejs && this._auth instanceof CookieAuthManager;
82
92
  if (supportMultiInstance && multiInstance) {
83
93
  // Use coordinated WebSocket client to share single connection between tabs
84
- this._socket = new BrowserWebSocketClient(socketUrl, this._auth, appId, networkType, logger);
94
+ this._socket = new BrowserWebSocketClient(
95
+ socketUrl,
96
+ this._auth,
97
+ appId,
98
+ networkType,
99
+ logger,
100
+ this.appSource,
101
+ socketEventSubscriptions
102
+ );
85
103
  } else {
86
- this._socket = new WebSocketClient(socketUrl, this._auth, appId, networkType, logger);
104
+ this._socket = new WebSocketClient(
105
+ socketUrl,
106
+ this._auth,
107
+ appId,
108
+ networkType,
109
+ logger,
110
+ this.appSource,
111
+ socketEventSubscriptions
112
+ );
87
113
  }
88
114
  this._disableSocket = disableSocket;
89
115
  this._auth.on('updated', this.handleAuthUpdated.bind(this));
@@ -111,6 +137,10 @@ class ApiClient extends TypedEventEmitter<ApiClientEvents> {
111
137
  return !this._disableSocket;
112
138
  }
113
139
 
140
+ setSocketEventSubscriptions(update: SocketEventSubscriptionInput): Promise<void> {
141
+ return this.socket.setSocketEventSubscriptions(update);
142
+ }
143
+
114
144
  handleSocketConnect({ network }: ServerConnectData) {
115
145
  this._reconnectAttempts = WS_RECONNECT_ATTEMPTS;
116
146
  this.emit('connected', { network });