@sogni-ai/sogni-client 5.56.2 → 5.57.0
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 +14 -0
- package/README.md +24 -0
- package/dist/Projects/index.d.ts +137 -0
- package/dist/Projects/index.js +170 -0
- package/dist/Projects/index.js.map +1 -1
- package/dist/Projects/utils/index.js +4 -1
- package/dist/Projects/utils/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist-esm/Projects/index.js +170 -0
- package/dist-esm/Projects/index.js.map +1 -1
- package/dist-esm/Projects/utils/index.js +4 -1
- package/dist-esm/Projects/utils/index.js.map +1 -1
- package/dist-esm/index.js +3 -0
- package/dist-esm/index.js.map +1 -1
- package/dist-esm/version.js +1 -1
- package/package.json +2 -1
- package/src/Projects/index.ts +296 -0
- package/src/Projects/utils/index.ts +6 -1
- package/src/index.ts +16 -1
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [5.57.0](https://github.com/Sogni-AI/sogni-client/compare/v5.56.3...v5.57.0) (2026-09-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **projects:** fetch a project's results by id and list recent completed projects ([89cd46d](https://github.com/Sogni-AI/sogni-client/commit/89cd46d4991fcddc83737d2abc3a0106d3734660))
|
|
7
|
+
|
|
8
|
+
## [5.56.3](https://github.com/Sogni-AI/sogni-client/compare/v5.56.2...v5.56.3) (2026-09-26)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **projects:** know the live Wan sound-to-video and Qwen3 TTS ids as media ([f621acb](https://github.com/Sogni-AI/sogni-client/commit/f621acb974de81659a958b594f0a5c52c4d957e4))
|
|
14
|
+
|
|
1
15
|
## [5.56.2](https://github.com/Sogni-AI/sogni-client/compare/v5.56.1...v5.56.2) (2026-09-26)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -525,6 +525,30 @@ when they finish.
|
|
|
525
525
|
Recovery is per app instance: the server hands projects back to the `appId` that created them, so
|
|
526
526
|
persist your `appId` (browsers: `localStorage`) and reuse it across reloads.
|
|
527
527
|
|
|
528
|
+
#### Results after you stopped waiting
|
|
529
|
+
|
|
530
|
+
The socket holds a project that finished while its client was disconnected for one hour. A client
|
|
531
|
+
that restarts, or a script or agent that exits before its projects finish, can still collect them:
|
|
532
|
+
|
|
533
|
+
- `sogni.projects.getResult(id)` returns a project's state and its renders at any time: while it is
|
|
534
|
+
queued (with the server's `waitingReason`, which says whether the account's own plan concurrency is
|
|
535
|
+
holding it or it is waiting for a worker) and after it finished, with signed download URLs for the
|
|
536
|
+
completed renders. Pass `{ kind: 'video' }` (or `image`, `audio`, `model`) when you know what it
|
|
537
|
+
produces and the model is not in this client's catalog.
|
|
538
|
+
- `sogni.projects.listRecent({ since })` lists this account's recently completed media projects,
|
|
539
|
+
newest first, from the durable history (up to 7 days back, 24 hours by default), including ones
|
|
540
|
+
that finished while no client was connected.
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
for (const project of await sogni.projects.listRecent({ since: Date.now() - 6 * 3600_000 })) {
|
|
544
|
+
const result = await sogni.projects.getResult(project.id);
|
|
545
|
+
for (const job of result.jobs) if (job.url) console.log(project.modelName, job.url);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const pending = await sogni.projects.getResult(projectId);
|
|
549
|
+
if (!pending.finished) console.log(pending.status, pending.waitingReason?.message);
|
|
550
|
+
```
|
|
551
|
+
|
|
528
552
|
### Project parameters
|
|
529
553
|
|
|
530
554
|
Here is a full list of project parameters that you can use:
|
package/dist/Projects/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { AvailableLorasParams, LoraCatalog, LoraCatalogEntry, LoraConstraints }
|
|
|
7
7
|
import PersonalLoras from './PersonalLoras.js';
|
|
8
8
|
import { ProjectApiEvents, type ProjectSyncReason, type ProjectSyncResult } from './types/events.js';
|
|
9
9
|
import { RawProject } from './types/RawProject.js';
|
|
10
|
+
import type { WaitingReason } from './types/WaitingReason.js';
|
|
10
11
|
import { SupernetType } from '../ApiClient/WebSocketClient/types.js';
|
|
11
12
|
import { type ResultMediaEvidence, type ResultMediaKind } from './utils/index.js';
|
|
12
13
|
import { TokenType } from '../types/token.js';
|
|
@@ -62,6 +63,86 @@ export type ProjectStatusSnapshot = Partial<Omit<RawProject, 'status' | 'workerJ
|
|
|
62
63
|
workerJobs: RawProject['workerJobs'];
|
|
63
64
|
completedWorkerJobs: RawProject['completedWorkerJobs'];
|
|
64
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* One render of a project returned by {@link ProjectsApi.getResult}.
|
|
68
|
+
*/
|
|
69
|
+
export interface ProjectResultJob {
|
|
70
|
+
/** The render's result id (the `imgID` of its events). */
|
|
71
|
+
id: string;
|
|
72
|
+
/**
|
|
73
|
+
* `completed`, `failed` or `canceled` once it has finished; otherwise the
|
|
74
|
+
* worker job's in-flight status (`queued`, `assigned`, `jobStarted`, ...).
|
|
75
|
+
*/
|
|
76
|
+
status: string;
|
|
77
|
+
/** Why a failed or cancelled render ended, e.g. `genfailure` or `artistCanceled`. */
|
|
78
|
+
reason?: string;
|
|
79
|
+
/** What the result is, when it is known. */
|
|
80
|
+
kind?: ResultMediaKind;
|
|
81
|
+
/** Signed download URL for a completed render's media. It expires; fetch a new one when it does. */
|
|
82
|
+
url?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Why a completed render has no `url`: `sensitiveContent` when the Sensitive
|
|
85
|
+
* Content Filter withheld it, `unknownMediaKind` when neither the model nor
|
|
86
|
+
* the result says what media it is, `downloadUrlFailed` when the API refused
|
|
87
|
+
* or failed to sign one (retry later).
|
|
88
|
+
*/
|
|
89
|
+
urlUnavailable?: 'sensitiveContent' | 'unknownMediaKind' | 'downloadUrlFailed';
|
|
90
|
+
/** Seed the render used, when recorded. */
|
|
91
|
+
seed?: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One of this account's projects as {@link ProjectsApi.getResult} sees it:
|
|
95
|
+
* its current state, why it is still waiting if it is, and every render with
|
|
96
|
+
* a download URL for the ones that completed.
|
|
97
|
+
*/
|
|
98
|
+
export interface ProjectResult {
|
|
99
|
+
id: string;
|
|
100
|
+
status: ProjectLookupStatus;
|
|
101
|
+
/** `true` for `completed`, `failed` and `canceled`. */
|
|
102
|
+
finished: boolean;
|
|
103
|
+
modelId?: string;
|
|
104
|
+
/**
|
|
105
|
+
* While it is still queued: the server's explanation, e.g. the account's own
|
|
106
|
+
* plan concurrency limit (`concurrency_limit`, `model_concurrency_limit`)
|
|
107
|
+
* rather than a shortage of workers (`no_workers`). Absent when the server
|
|
108
|
+
* did not report one.
|
|
109
|
+
*/
|
|
110
|
+
waitingReason?: WaitingReason | null;
|
|
111
|
+
jobs: ProjectResultJob[];
|
|
112
|
+
}
|
|
113
|
+
/** A render of a project returned by {@link ProjectsApi.listRecent}. */
|
|
114
|
+
export interface RecentProjectJob {
|
|
115
|
+
/** The render's result id; pass the project id to {@link ProjectsApi.getResult} for its URL. */
|
|
116
|
+
id: string;
|
|
117
|
+
status: string;
|
|
118
|
+
/** The Sensitive Content Filter withheld this render's media. */
|
|
119
|
+
sensitiveContentWithheld: boolean;
|
|
120
|
+
/** Milliseconds since the epoch. */
|
|
121
|
+
finishedAt?: number;
|
|
122
|
+
}
|
|
123
|
+
/** A project returned by {@link ProjectsApi.listRecent}. */
|
|
124
|
+
export interface RecentProject {
|
|
125
|
+
id: string;
|
|
126
|
+
modelId?: string;
|
|
127
|
+
modelName?: string;
|
|
128
|
+
/** The app that submitted it, when recorded (e.g. `sogni-creative-agent-skill`). */
|
|
129
|
+
appSource?: string;
|
|
130
|
+
/** When its latest render finished, in milliseconds since the epoch. */
|
|
131
|
+
finishedAt?: number;
|
|
132
|
+
jobs: RecentProjectJob[];
|
|
133
|
+
}
|
|
134
|
+
export interface ListRecentProjectsOptions {
|
|
135
|
+
/**
|
|
136
|
+
* Oldest finish time to include, as a `Date` or milliseconds since the epoch.
|
|
137
|
+
* Defaults to 24 hours ago. The history keeps 7 days, so anything older is
|
|
138
|
+
* read as 7 days ago.
|
|
139
|
+
*/
|
|
140
|
+
since?: Date | number;
|
|
141
|
+
/** Renders to read, 1-100 (default 50). Projects are grouped from these. */
|
|
142
|
+
limit?: number;
|
|
143
|
+
/** Only projects submitted by this app source. */
|
|
144
|
+
appSource?: string;
|
|
145
|
+
}
|
|
65
146
|
declare class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
66
147
|
private _personalLoras?;
|
|
67
148
|
/** Import, inspect, discover, and remove the signed-in account's personal LoRAs. */
|
|
@@ -418,6 +499,62 @@ declare class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
418
499
|
* @param projectId
|
|
419
500
|
*/
|
|
420
501
|
getStatus(projectId: string): Promise<ProjectStatusSnapshot>;
|
|
502
|
+
/**
|
|
503
|
+
* State and results of one of this account's projects by id, whenever it is
|
|
504
|
+
* asked: while it is queued or rendering, and after it finished, including
|
|
505
|
+
* one that finished while this client was offline, or after it stopped
|
|
506
|
+
* waiting, or long after the socket stopped holding it for a reconnect.
|
|
507
|
+
*
|
|
508
|
+
* Completed renders come back with signed download URLs, minted the same way
|
|
509
|
+
* a live result's are. A queued project carries the server's `waitingReason`,
|
|
510
|
+
* which says whether it is held by the account's own plan concurrency or is
|
|
511
|
+
* waiting for a worker. Needs an authenticated client; another account's or
|
|
512
|
+
* an unknown project rejects with a 404 `ApiError`.
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```ts
|
|
516
|
+
* const result = await sogni.projects.getResult(projectId);
|
|
517
|
+
* if (result.finished) {
|
|
518
|
+
* for (const job of result.jobs) if (job.url) console.log(job.url);
|
|
519
|
+
* } else {
|
|
520
|
+
* console.log(result.status, result.waitingReason?.message);
|
|
521
|
+
* }
|
|
522
|
+
* ```
|
|
523
|
+
* @param projectId
|
|
524
|
+
* @param options.kind - What the project produces, when the caller knows it
|
|
525
|
+
* (`image`, `video`, `audio`, `model`). Used only when neither the model
|
|
526
|
+
* catalog nor the stored result says, so a URL is never minted from the
|
|
527
|
+
* wrong endpoint.
|
|
528
|
+
*/
|
|
529
|
+
getResult(projectId: string, options?: {
|
|
530
|
+
kind?: ResultMediaKind;
|
|
531
|
+
}): Promise<ProjectResult>;
|
|
532
|
+
/**
|
|
533
|
+
* This account's recently completed projects that produced media, newest
|
|
534
|
+
* first, read from the durable history rather than the socket. It includes
|
|
535
|
+
* projects that finished while no client was connected, and ones the socket
|
|
536
|
+
* has stopped holding for a reconnect (it keeps a finished project for one
|
|
537
|
+
* hour). Pass a project's id to {@link getResult} for its download URLs.
|
|
538
|
+
*
|
|
539
|
+
* Reaches back at most 7 days. Needs a signed-in account.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```ts
|
|
543
|
+
* const recent = await sogni.projects.listRecent({ since: Date.now() - 6 * 3600_000 });
|
|
544
|
+
* for (const project of recent) {
|
|
545
|
+
* const result = await sogni.projects.getResult(project.id);
|
|
546
|
+
* }
|
|
547
|
+
* ```
|
|
548
|
+
*/
|
|
549
|
+
listRecent(options?: ListRecentProjectsOptions): Promise<RecentProject[]>;
|
|
550
|
+
private _accountAddress?;
|
|
551
|
+
/**
|
|
552
|
+
* How {@link listRecent} learns the signed-in account's address. Set by
|
|
553
|
+
* `SogniClient`, which owns the account.
|
|
554
|
+
* @internal
|
|
555
|
+
*/
|
|
556
|
+
_setAccountAddressResolver(resolve: () => Promise<string | undefined>): void;
|
|
557
|
+
private _resolveAccountAddress;
|
|
421
558
|
/**
|
|
422
559
|
* Ids of this account's projects that are currently live on the socket,
|
|
423
560
|
* including ones still queued with no worker assigned.
|
package/dist/Projects/index.js
CHANGED
|
@@ -313,6 +313,18 @@ const RESUBMIT_RECONNECT_TIMEOUT_MS = 60000;
|
|
|
313
313
|
const MISSING_PROJECT_ATTEMPTS = 4;
|
|
314
314
|
const MISSING_PROJECT_RETRY_MS = 2500;
|
|
315
315
|
const IN_FLIGHT_LOOKUP_STATUSES = new Set(['pending', 'queued', 'processing']);
|
|
316
|
+
const RECENT_PROJECTS_DEFAULT_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
317
|
+
// The history API refuses a media-only lookup reaching back more than 7 days;
|
|
318
|
+
// stay a minute inside it so a slow clock cannot turn a 7-day request into a 400.
|
|
319
|
+
const RECENT_PROJECTS_MAX_WINDOW_MS = 7 * 24 * 60 * 60 * 1000 - 60 * 1000;
|
|
320
|
+
/** A worker job's status in the names {@link ProjectResultJob} uses. */
|
|
321
|
+
function resultJobStatus(job) {
|
|
322
|
+
if (job.status === 'jobCompleted')
|
|
323
|
+
return 'completed';
|
|
324
|
+
if (job.status === 'jobError')
|
|
325
|
+
return job.reason === 'artistCanceled' ? 'canceled' : 'failed';
|
|
326
|
+
return job.status || 'unknown';
|
|
327
|
+
}
|
|
316
328
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
317
329
|
class ProjectsApi extends ApiGroup_js_1.default {
|
|
318
330
|
/** Import, inspect, discover, and remove the signed-in account's personal LoRAs. */
|
|
@@ -2132,6 +2144,164 @@ class ProjectsApi extends ApiGroup_js_1.default {
|
|
|
2132
2144
|
return data.project;
|
|
2133
2145
|
});
|
|
2134
2146
|
}
|
|
2147
|
+
/**
|
|
2148
|
+
* State and results of one of this account's projects by id, whenever it is
|
|
2149
|
+
* asked: while it is queued or rendering, and after it finished, including
|
|
2150
|
+
* one that finished while this client was offline, or after it stopped
|
|
2151
|
+
* waiting, or long after the socket stopped holding it for a reconnect.
|
|
2152
|
+
*
|
|
2153
|
+
* Completed renders come back with signed download URLs, minted the same way
|
|
2154
|
+
* a live result's are. A queued project carries the server's `waitingReason`,
|
|
2155
|
+
* which says whether it is held by the account's own plan concurrency or is
|
|
2156
|
+
* waiting for a worker. Needs an authenticated client; another account's or
|
|
2157
|
+
* an unknown project rejects with a 404 `ApiError`.
|
|
2158
|
+
*
|
|
2159
|
+
* @example
|
|
2160
|
+
* ```ts
|
|
2161
|
+
* const result = await sogni.projects.getResult(projectId);
|
|
2162
|
+
* if (result.finished) {
|
|
2163
|
+
* for (const job of result.jobs) if (job.url) console.log(job.url);
|
|
2164
|
+
* } else {
|
|
2165
|
+
* console.log(result.status, result.waitingReason?.message);
|
|
2166
|
+
* }
|
|
2167
|
+
* ```
|
|
2168
|
+
* @param projectId
|
|
2169
|
+
* @param options.kind - What the project produces, when the caller knows it
|
|
2170
|
+
* (`image`, `video`, `audio`, `model`). Used only when neither the model
|
|
2171
|
+
* catalog nor the stored result says, so a URL is never minted from the
|
|
2172
|
+
* wrong endpoint.
|
|
2173
|
+
*/
|
|
2174
|
+
getResult(projectId_1) {
|
|
2175
|
+
return __awaiter(this, arguments, void 0, function* (projectId, options = {}) {
|
|
2176
|
+
var _a, _b, _c, _d, _e;
|
|
2177
|
+
const assertSession = (0, requestSession_js_1.captureRequestSession)(this.client.auth);
|
|
2178
|
+
const snapshot = yield this.getStatus(projectId);
|
|
2179
|
+
assertSession();
|
|
2180
|
+
const modelId = (_a = snapshot.model) === null || _a === void 0 ? void 0 : _a.id;
|
|
2181
|
+
// The stored record's model carries its media type even though ProjectModel does not declare it.
|
|
2182
|
+
const recordType = (_b = snapshot.model) === null || _b === void 0 ? void 0 : _b.type;
|
|
2183
|
+
const projectType = typeof recordType === 'string' ? recordType : undefined;
|
|
2184
|
+
const jobs = [];
|
|
2185
|
+
const seen = new Set();
|
|
2186
|
+
for (const job of [...(snapshot.completedWorkerJobs || []), ...(snapshot.workerJobs || [])]) {
|
|
2187
|
+
const id = job.imgID || job.id;
|
|
2188
|
+
if (!id || seen.has(id))
|
|
2189
|
+
continue;
|
|
2190
|
+
seen.add(id);
|
|
2191
|
+
const status = resultJobStatus(job);
|
|
2192
|
+
const entry = { id, status };
|
|
2193
|
+
if (status !== 'completed' && job.reason)
|
|
2194
|
+
entry.reason = job.reason;
|
|
2195
|
+
if (typeof job.seedUsed === 'number' && job.seedUsed >= 0)
|
|
2196
|
+
entry.seed = job.seedUsed;
|
|
2197
|
+
if (status === 'completed') {
|
|
2198
|
+
// Same rule as a live result: withheld only when the filter fired and
|
|
2199
|
+
// no advisory label says the media was delivered anyway.
|
|
2200
|
+
if (job.triggeredNSFWFilter === true && job.nsfwDetected !== true) {
|
|
2201
|
+
entry.urlUnavailable = 'sensitiveContent';
|
|
2202
|
+
}
|
|
2203
|
+
else if (typeof job.resultUrl === 'string' && job.resultUrl) {
|
|
2204
|
+
entry.url = job.resultUrl;
|
|
2205
|
+
}
|
|
2206
|
+
else {
|
|
2207
|
+
const result = (0, index_js_2.resultMediaEvidence)(Object.assign(Object.assign({}, (job.result || {})), { outputFormat: (_c = job.outputFormat) !== null && _c !== void 0 ? _c : (_d = job.result) === null || _d === void 0 ? void 0 : _d.outputFormat }));
|
|
2208
|
+
const kind = (_e = this._resultMediaKind({ modelId, projectType, result })) !== null && _e !== void 0 ? _e : options.kind;
|
|
2209
|
+
if (!kind) {
|
|
2210
|
+
entry.urlUnavailable = 'unknownMediaKind';
|
|
2211
|
+
}
|
|
2212
|
+
else {
|
|
2213
|
+
entry.kind = kind;
|
|
2214
|
+
try {
|
|
2215
|
+
entry.url = yield this._mintResultUrl({
|
|
2216
|
+
projectId: snapshot.id,
|
|
2217
|
+
jobId: id,
|
|
2218
|
+
kind,
|
|
2219
|
+
audioContentType: result === null || result === void 0 ? void 0 : result.contentType
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
catch (error) {
|
|
2223
|
+
this.client.logger.error(`Failed to sign a download URL for ${snapshot.id}/${id}`);
|
|
2224
|
+
this.client.logger.error(error);
|
|
2225
|
+
entry.urlUnavailable = 'downloadUrlFailed';
|
|
2226
|
+
}
|
|
2227
|
+
assertSession();
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
jobs.push(entry);
|
|
2232
|
+
}
|
|
2233
|
+
return Object.assign(Object.assign(Object.assign({ id: snapshot.id, status: snapshot.status, finished: snapshot.finished }, (modelId ? { modelId } : {})), (snapshot.waitingReason !== undefined ? { waitingReason: snapshot.waitingReason } : {})), { jobs });
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
/**
|
|
2237
|
+
* This account's recently completed projects that produced media, newest
|
|
2238
|
+
* first, read from the durable history rather than the socket. It includes
|
|
2239
|
+
* projects that finished while no client was connected, and ones the socket
|
|
2240
|
+
* has stopped holding for a reconnect (it keeps a finished project for one
|
|
2241
|
+
* hour). Pass a project's id to {@link getResult} for its download URLs.
|
|
2242
|
+
*
|
|
2243
|
+
* Reaches back at most 7 days. Needs a signed-in account.
|
|
2244
|
+
*
|
|
2245
|
+
* @example
|
|
2246
|
+
* ```ts
|
|
2247
|
+
* const recent = await sogni.projects.listRecent({ since: Date.now() - 6 * 3600_000 });
|
|
2248
|
+
* for (const project of recent) {
|
|
2249
|
+
* const result = await sogni.projects.getResult(project.id);
|
|
2250
|
+
* }
|
|
2251
|
+
* ```
|
|
2252
|
+
*/
|
|
2253
|
+
listRecent() {
|
|
2254
|
+
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
2255
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2256
|
+
const assertSession = (0, requestSession_js_1.captureRequestSession)(this.client.auth);
|
|
2257
|
+
const address = yield this._resolveAccountAddress();
|
|
2258
|
+
assertSession();
|
|
2259
|
+
if (!address) {
|
|
2260
|
+
throw new Error('listRecent needs a signed-in account');
|
|
2261
|
+
}
|
|
2262
|
+
const now = Date.now();
|
|
2263
|
+
const requestedSince = options.since instanceof Date
|
|
2264
|
+
? options.since.getTime()
|
|
2265
|
+
: typeof options.since === 'number'
|
|
2266
|
+
? options.since
|
|
2267
|
+
: now - RECENT_PROJECTS_DEFAULT_WINDOW_MS;
|
|
2268
|
+
const since = Math.max(requestedSince, now - RECENT_PROJECTS_MAX_WINDOW_MS);
|
|
2269
|
+
const limit = Math.min(100, Math.max(1, Math.floor((_a = options.limit) !== null && _a !== void 0 ? _a : 50)));
|
|
2270
|
+
const { data } = yield this.client.rest.get('/v1/jobs/list', Object.assign({ role: 'artist', address, state: 'completed', mediaOnly: true, since,
|
|
2271
|
+
limit }, (options.appSource ? { appSource: options.appSource } : {})));
|
|
2272
|
+
assertSession();
|
|
2273
|
+
const projects = new Map();
|
|
2274
|
+
for (const job of (data === null || data === void 0 ? void 0 : data.jobs) || []) {
|
|
2275
|
+
const projectId = (_b = job.parentRequest) === null || _b === void 0 ? void 0 : _b.id;
|
|
2276
|
+
if (!projectId)
|
|
2277
|
+
continue;
|
|
2278
|
+
let project = projects.get(projectId);
|
|
2279
|
+
if (!project) {
|
|
2280
|
+
project = Object.assign(Object.assign(Object.assign(Object.assign({ id: projectId }, (((_d = (_c = job.parentRequest) === null || _c === void 0 ? void 0 : _c.model) === null || _d === void 0 ? void 0 : _d.id) ? { modelId: job.parentRequest.model.id } : {})), (((_f = (_e = job.parentRequest) === null || _e === void 0 ? void 0 : _e.model) === null || _f === void 0 ? void 0 : _f.name) ? { modelName: job.parentRequest.model.name } : {})), (((_g = job.parentRequest) === null || _g === void 0 ? void 0 : _g.appSource) ? { appSource: job.parentRequest.appSource } : {})), { jobs: [] });
|
|
2281
|
+
projects.set(projectId, project);
|
|
2282
|
+
}
|
|
2283
|
+
const finishedAt = typeof job.endTime === 'number' && job.endTime > 0 ? job.endTime : undefined;
|
|
2284
|
+
project.jobs.push(Object.assign({ id: job.imgID || job.id, status: resultJobStatus(job), sensitiveContentWithheld: job.triggeredNSFWFilter === true && job.nsfwDetected !== true }, (finishedAt ? { finishedAt } : {})));
|
|
2285
|
+
if (finishedAt && (!project.finishedAt || finishedAt > project.finishedAt)) {
|
|
2286
|
+
project.finishedAt = finishedAt;
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
return [...projects.values()].sort((a, b) => { var _a, _b; return ((_a = b.finishedAt) !== null && _a !== void 0 ? _a : 0) - ((_b = a.finishedAt) !== null && _b !== void 0 ? _b : 0); });
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
/**
|
|
2293
|
+
* How {@link listRecent} learns the signed-in account's address. Set by
|
|
2294
|
+
* `SogniClient`, which owns the account.
|
|
2295
|
+
* @internal
|
|
2296
|
+
*/
|
|
2297
|
+
_setAccountAddressResolver(resolve) {
|
|
2298
|
+
this._accountAddress = resolve;
|
|
2299
|
+
}
|
|
2300
|
+
_resolveAccountAddress() {
|
|
2301
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2302
|
+
return this._accountAddress ? this._accountAddress() : undefined;
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2135
2305
|
/**
|
|
2136
2306
|
* Ids of this account's projects that are currently live on the socket,
|
|
2137
2307
|
* including ones still queued with no worker assigned.
|