@sogni-ai/sogni-client 5.71.1 → 5.72.1
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 +16 -0
- package/README.md +28 -1
- package/dist/Account/index.d.ts +27 -2
- package/dist/Account/index.js +27 -2
- package/dist/Account/index.js.map +1 -1
- package/dist/Account/types.d.ts +10 -0
- package/dist/Chat/_hostedToolsManifest.generated.js +8 -0
- package/dist/Chat/_hostedToolsManifest.generated.js.map +1 -1
- package/dist/Projects/ReusableUploads.d.ts +1 -0
- package/dist/Projects/ReusableUploads.js +47 -18
- package/dist/Projects/ReusableUploads.js.map +1 -1
- package/dist/Projects/types/index.d.ts +4 -1
- package/dist/Projects/types/index.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/types/ErrorData.d.ts +13 -0
- package/dist/types/ErrorData.js +14 -1
- package/dist/types/ErrorData.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist-esm/Account/index.js +27 -2
- package/dist-esm/Account/index.js.map +1 -1
- package/dist-esm/Chat/_hostedToolsManifest.generated.js +8 -0
- package/dist-esm/Chat/_hostedToolsManifest.generated.js.map +1 -1
- package/dist-esm/Projects/ReusableUploads.js +47 -18
- package/dist-esm/Projects/ReusableUploads.js.map +1 -1
- package/dist-esm/Projects/types/index.js.map +1 -1
- package/dist-esm/index.js +2 -2
- package/dist-esm/index.js.map +1 -1
- package/dist-esm/types/ErrorData.js +13 -0
- package/dist-esm/types/ErrorData.js.map +1 -1
- package/dist-esm/version.js +1 -1
- package/llms-full.txt +32 -4
- package/llms.txt +2 -1
- package/package.json +8 -4
- package/src/Account/index.ts +30 -2
- package/src/Account/types.ts +11 -0
- package/src/Chat/_hostedToolsManifest.generated.ts +8 -0
- package/src/Projects/ReusableUploads.ts +47 -19
- package/src/Projects/types/index.ts +4 -1
- package/src/index.ts +10 -1
- package/src/types/ErrorData.ts +14 -0
- package/src/version.ts +1 -1
package/src/Account/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
ClaimOptions,
|
|
6
6
|
FullBalances,
|
|
7
7
|
LoginData,
|
|
8
|
+
LoginOptions,
|
|
8
9
|
MeData,
|
|
9
10
|
Nonce,
|
|
10
11
|
Reward,
|
|
@@ -459,18 +460,44 @@ class AccountApi extends ApiGroup {
|
|
|
459
460
|
* console.log('Logged in');
|
|
460
461
|
* ```
|
|
461
462
|
*
|
|
463
|
+
* @example Offer to restore a deleted account at sign-in
|
|
464
|
+
* ```typescript
|
|
465
|
+
* import { ApiError, ACCOUNT_RESTORABLE_ERROR_CODE } from '@sogni-ai/sogni-client';
|
|
466
|
+
*
|
|
467
|
+
* try {
|
|
468
|
+
* await sogni.account.login(username, password, rememberMe, appSource);
|
|
469
|
+
* } catch (error) {
|
|
470
|
+
* if (!(error instanceof ApiError) || error.payload.errorCode !== ACCOUNT_RESTORABLE_ERROR_CODE) {
|
|
471
|
+
* throw error;
|
|
472
|
+
* }
|
|
473
|
+
* const deletedAt = new Date(Number(error.details?.deletedAt) * 1000);
|
|
474
|
+
* // Ask the person whether to restore the account deleted on `deletedAt`. If they agree,
|
|
475
|
+
* // repeat the original arguments and add the option:
|
|
476
|
+
* await sogni.account.login(username, password, rememberMe, appSource, {
|
|
477
|
+
* restoreDeletedAccount: true
|
|
478
|
+
* });
|
|
479
|
+
* }
|
|
480
|
+
* ```
|
|
481
|
+
*
|
|
462
482
|
* @param username
|
|
463
483
|
* @param password
|
|
464
484
|
* @param rememberMe - Whether to establish a long-lived session. Default is false. Only
|
|
465
485
|
* applicable for cookie-based authentication.
|
|
466
486
|
* @param appSource - Optional client app/source label for login attribution. Defaults to the
|
|
467
487
|
* SogniClient connection appSource when configured.
|
|
488
|
+
* @param options - Optional sign-in settings. Set `restoreDeletedAccount: true` to restore a
|
|
489
|
+
* deleted account and sign in, after the person confirms; repeat the original `rememberMe` and
|
|
490
|
+
* `appSource` on that call so the session lasts as long as first requested. A deleted account
|
|
491
|
+
* that can be restored makes `login()` throw an `ApiError` with
|
|
492
|
+
* `payload.errorCode === ACCOUNT_RESTORABLE_ERROR_CODE` (196) and `details.deletedAt` (Unix
|
|
493
|
+
* seconds).
|
|
468
494
|
*/
|
|
469
495
|
async login(
|
|
470
496
|
username: string,
|
|
471
497
|
password: string,
|
|
472
498
|
rememberMe = false,
|
|
473
|
-
appSource?: string
|
|
499
|
+
appSource?: string,
|
|
500
|
+
options?: LoginOptions
|
|
474
501
|
): Promise<LoginData> {
|
|
475
502
|
const wallet = this.getWallet(username, password);
|
|
476
503
|
const nonce = await this.getNonce(wallet.address);
|
|
@@ -483,7 +510,8 @@ class AccountApi extends ApiGroup {
|
|
|
483
510
|
walletAddress: wallet.address,
|
|
484
511
|
signature,
|
|
485
512
|
...(resolvedAppSource ? { appSource: resolvedAppSource } : {}),
|
|
486
|
-
rememberMe
|
|
513
|
+
rememberMe,
|
|
514
|
+
...(options?.restoreDeletedAccount ? { restoreDeletedAccount: true } : {})
|
|
487
515
|
});
|
|
488
516
|
const auth = this.client.auth;
|
|
489
517
|
if (auth instanceof TokenAuthManager) {
|
package/src/Account/types.ts
CHANGED
|
@@ -37,6 +37,17 @@ export interface LoginData {
|
|
|
37
37
|
username: string;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/** Optional settings for `sogni.account.login()`. */
|
|
41
|
+
export interface LoginOptions {
|
|
42
|
+
/**
|
|
43
|
+
* Restore the account, then sign in, when the account was deleted. Set it
|
|
44
|
+
* after the person confirms they want the account back, usually in answer to
|
|
45
|
+
* an `ACCOUNT_RESTORABLE_ERROR_CODE` error from an earlier `login()` call.
|
|
46
|
+
* It changes nothing for an account that has not been deleted.
|
|
47
|
+
*/
|
|
48
|
+
restoreDeletedAccount?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
export interface MeData {
|
|
41
52
|
currentEmail: string;
|
|
42
53
|
discord2FA: boolean;
|
|
@@ -326,6 +326,14 @@ export const SOGNI_HOSTED_TOOLS_MANIFEST: unknown = {
|
|
|
326
326
|
"returnLastFrame": {
|
|
327
327
|
"type": "boolean",
|
|
328
328
|
"description": "Seedance 2.5 only. Set true to export a separate image of the final frame alongside the video. The result includes lastFrameUrl, which can be used as the first-frame image for a subsequent clip. Defaults to false; this does not extend the video automatically."
|
|
329
|
+
},
|
|
330
|
+
"referenceVideoCompression": {
|
|
331
|
+
"type": "string",
|
|
332
|
+
"enum": [
|
|
333
|
+
"none",
|
|
334
|
+
"vpack"
|
|
335
|
+
],
|
|
336
|
+
"description": "Legacy compatibility preference for MiniMax H3 reference video. Current services select compression automatically; this field no longer selects compression. Leave it unset for new requests."
|
|
329
337
|
}
|
|
330
338
|
},
|
|
331
339
|
"required": [
|
|
@@ -40,7 +40,8 @@ class AutomaticSaveBlockedError extends Error {}
|
|
|
40
40
|
|
|
41
41
|
/** Private subscriber uploads that can be reused across projects. */
|
|
42
42
|
export default class ReusableUploads {
|
|
43
|
-
private pending = new Map<string, Promise<SavedUpload
|
|
43
|
+
private pending = new Map<string, { upload: Promise<SavedUpload>; users: number }>();
|
|
44
|
+
private bindings = new Map<string, Promise<void>>();
|
|
44
45
|
// Bound hashing/upload memory even when a project has many reference files.
|
|
45
46
|
private lanes: Promise<unknown>[] = [Promise.resolve(), Promise.resolve()];
|
|
46
47
|
private nextLane = 0;
|
|
@@ -60,6 +61,7 @@ export default class ReusableUploads {
|
|
|
60
61
|
if (session !== this.lastSession) {
|
|
61
62
|
this.lastSession = session;
|
|
62
63
|
this.pending.clear();
|
|
64
|
+
this.bindings.clear();
|
|
63
65
|
this.availability = undefined;
|
|
64
66
|
this.automaticSaveBlockedUntil = 0;
|
|
65
67
|
}
|
|
@@ -112,11 +114,24 @@ export default class ReusableUploads {
|
|
|
112
114
|
|
|
113
115
|
async bind(id: string, binding: SavedUploadBinding): Promise<void> {
|
|
114
116
|
const session = this.session;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
// The server holds a per-file lock while copying. Queue only this file;
|
|
118
|
+
// unrelated files still use the two upload lanes concurrently.
|
|
119
|
+
const previous = this.bindings.get(id) ?? Promise.resolve();
|
|
120
|
+
const operation = previous
|
|
121
|
+
.catch(() => undefined)
|
|
122
|
+
.then(async () => {
|
|
123
|
+
await this.retryBusy(() => {
|
|
124
|
+
this.assertSession(session);
|
|
125
|
+
return this.rest.post(`/v1/assets/${encodeURIComponent(id)}/bind`, { ...binding });
|
|
126
|
+
});
|
|
127
|
+
this.assertSession(session);
|
|
128
|
+
});
|
|
129
|
+
this.bindings.set(id, operation);
|
|
130
|
+
try {
|
|
131
|
+
await operation;
|
|
132
|
+
} finally {
|
|
133
|
+
if (this.bindings.get(id) === operation) this.bindings.delete(id);
|
|
134
|
+
}
|
|
120
135
|
}
|
|
121
136
|
|
|
122
137
|
private async retryBusy<T>(operation: () => Promise<T>): Promise<T> {
|
|
@@ -139,7 +154,8 @@ export default class ReusableUploads {
|
|
|
139
154
|
file: Blob | Buffer,
|
|
140
155
|
contentType: string,
|
|
141
156
|
name: string,
|
|
142
|
-
automatic: boolean
|
|
157
|
+
automatic: boolean,
|
|
158
|
+
binding?: SavedUploadBinding
|
|
143
159
|
): Promise<SavedUpload> {
|
|
144
160
|
const session = this.session;
|
|
145
161
|
const size = file instanceof Blob ? file.size : file.byteLength;
|
|
@@ -152,7 +168,7 @@ export default class ReusableUploads {
|
|
|
152
168
|
})
|
|
153
169
|
);
|
|
154
170
|
const lane = this.nextLane++ % this.lanes.length;
|
|
155
|
-
const
|
|
171
|
+
const prepared = this.lanes[lane].then(async () => {
|
|
156
172
|
this.assertSession(session);
|
|
157
173
|
// Concurrent project helpers can all pass the capability check before
|
|
158
174
|
// the first quota response arrives. Recheck once this lane reaches the
|
|
@@ -166,18 +182,30 @@ export default class ReusableUploads {
|
|
|
166
182
|
value.toString(16).padStart(2, '0')
|
|
167
183
|
).join('');
|
|
168
184
|
const key = `${sha256}:${contentType}`;
|
|
169
|
-
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
185
|
+
let pending = this.pending.get(key);
|
|
186
|
+
if (!pending) {
|
|
187
|
+
pending = {
|
|
188
|
+
upload: this.performUpload(file, bytes.byteLength, sha256, contentType, name, session),
|
|
189
|
+
users: 0
|
|
190
|
+
};
|
|
191
|
+
this.pending.set(key, pending);
|
|
192
|
+
}
|
|
193
|
+
pending.users += 1;
|
|
194
|
+
return { pending, key };
|
|
195
|
+
});
|
|
196
|
+
// The lane bounds hashing and transfer, not the per-file server copy.
|
|
197
|
+
this.lanes[lane] = prepared.then(({ pending }) => pending.upload).catch(() => undefined);
|
|
198
|
+
return prepared.then(async ({ pending, key }) => {
|
|
173
199
|
try {
|
|
174
|
-
|
|
200
|
+
const saved = await pending.upload;
|
|
201
|
+
this.assertSession(session);
|
|
202
|
+
if (binding) await this.bind(saved.id, binding);
|
|
203
|
+
return saved;
|
|
175
204
|
} finally {
|
|
176
|
-
|
|
205
|
+
pending.users -= 1;
|
|
206
|
+
if (pending.users === 0 && this.pending.get(key) === pending) this.pending.delete(key);
|
|
177
207
|
}
|
|
178
208
|
});
|
|
179
|
-
this.lanes[lane] = run.catch(() => undefined);
|
|
180
|
-
return run;
|
|
181
209
|
}
|
|
182
210
|
|
|
183
211
|
private async performUpload(
|
|
@@ -247,16 +275,16 @@ export default class ReusableUploads {
|
|
|
247
275
|
this.assertSession(session);
|
|
248
276
|
if (!enabled) return false;
|
|
249
277
|
try {
|
|
250
|
-
|
|
278
|
+
await this.uploadInternal(
|
|
251
279
|
file,
|
|
252
280
|
contentType,
|
|
253
281
|
file instanceof Blob && 'name' in file && typeof file.name === 'string'
|
|
254
282
|
? file.name
|
|
255
283
|
: 'Saved upload',
|
|
256
|
-
true
|
|
284
|
+
true,
|
|
285
|
+
binding
|
|
257
286
|
);
|
|
258
287
|
this.assertSession(session);
|
|
259
|
-
await this.bind(saved.id, binding);
|
|
260
288
|
return true;
|
|
261
289
|
} catch (error) {
|
|
262
290
|
this.assertSession(session);
|
|
@@ -717,7 +717,10 @@ export interface VideoProjectParams extends BaseProjectParams {
|
|
|
717
717
|
* pricing and job admission. Omit this field when duration is unavailable.
|
|
718
718
|
*/
|
|
719
719
|
referenceVideoDurations?: number[];
|
|
720
|
-
/**
|
|
720
|
+
/**
|
|
721
|
+
* Legacy MiniMax H3 reference-video preference, retained for compatibility.
|
|
722
|
+
* @deprecated Current services select compression automatically. Leave unset for new requests.
|
|
723
|
+
*/
|
|
721
724
|
referenceVideoCompression?: 'none' | 'vpack';
|
|
722
725
|
/**
|
|
723
726
|
* Inpaint mask IMAGE for distilled LTX 2.5 or LTX 2.3 v2v inpaint workflows.
|
package/src/index.ts
CHANGED
|
@@ -120,7 +120,13 @@ import {
|
|
|
120
120
|
isProjectLostError,
|
|
121
121
|
projectParamsFromRecoveredProject
|
|
122
122
|
} from './Projects/recovery.js';
|
|
123
|
-
import type {
|
|
123
|
+
import type {
|
|
124
|
+
Balances,
|
|
125
|
+
LoginOptions,
|
|
126
|
+
Reward,
|
|
127
|
+
RewardCantClaimReason,
|
|
128
|
+
TxHistoryEntry
|
|
129
|
+
} from './Account/types.js';
|
|
124
130
|
import type {
|
|
125
131
|
CreateSubscriptionCheckoutOptions,
|
|
126
132
|
SubscriptionCheckoutResult,
|
|
@@ -255,6 +261,7 @@ import {
|
|
|
255
261
|
} from './Replay/types.js';
|
|
256
262
|
// Base Types
|
|
257
263
|
import ErrorData, {
|
|
264
|
+
ACCOUNT_RESTORABLE_ERROR_CODE,
|
|
258
265
|
MODEL_CONSENT_REQUIRED_ERROR_CODE,
|
|
259
266
|
MODEL_NOT_YET_AVAILABLE_ERROR_CODE,
|
|
260
267
|
SUBSCRIPTION_ERROR_CODES
|
|
@@ -418,6 +425,7 @@ export type {
|
|
|
418
425
|
// Primitives promoted from deep paths so consumers can import from the
|
|
419
426
|
// package root rather than reaching into `./dist/*`.
|
|
420
427
|
Balances,
|
|
428
|
+
LoginOptions,
|
|
421
429
|
Reward,
|
|
422
430
|
RewardCantClaimReason,
|
|
423
431
|
TxHistoryEntry,
|
|
@@ -532,6 +540,7 @@ export {
|
|
|
532
540
|
PROJECT_LOST_ORIGINAL_CODE,
|
|
533
541
|
SogniTools,
|
|
534
542
|
SUBSCRIPTION_ERROR_CODES,
|
|
543
|
+
ACCOUNT_RESTORABLE_ERROR_CODE,
|
|
535
544
|
MODEL_CONSENT_REQUIRED_ERROR_CODE,
|
|
536
545
|
MODEL_NOT_YET_AVAILABLE_ERROR_CODE,
|
|
537
546
|
isModelConsentRequiredError,
|
package/src/types/ErrorData.ts
CHANGED
|
@@ -98,6 +98,20 @@ export const MODEL_CONSENT_REQUIRED_ERROR_CODE = 4103;
|
|
|
98
98
|
*/
|
|
99
99
|
export const MODEL_NOT_YET_AVAILABLE_ERROR_CODE = 4104;
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* REST error code `sogni.account.login()` throws when the account was deleted
|
|
103
|
+
* and signing in can restore it. It arrives as an `ApiError` with HTTP status
|
|
104
|
+
* 400 and `error.payload.errorCode` set to this code. `error.details.deletedAt`
|
|
105
|
+
* is when the account was deleted, in Unix seconds.
|
|
106
|
+
*
|
|
107
|
+
* Ask the person whether to restore the account. If they agree, call `login()`
|
|
108
|
+
* again with the same arguments, including `rememberMe` and `appSource`, plus
|
|
109
|
+
* `{ restoreDeletedAccount: true }`: the account is restored and the call signs
|
|
110
|
+
* in as usual. The error's `message` is readable as is for apps that do not
|
|
111
|
+
* handle this code.
|
|
112
|
+
*/
|
|
113
|
+
export const ACCOUNT_RESTORABLE_ERROR_CODE = 196;
|
|
114
|
+
|
|
101
115
|
/**
|
|
102
116
|
* Socket error codes returned when a job explicitly submitted with
|
|
103
117
|
* `billingMode: 'subscription'` cannot be covered by the subscription, plus
|
package/src/version.ts
CHANGED