@civitai/sdk 0.12.0 → 0.13.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/README.md +6 -6
- package/dist/core/transport.d.ts +4 -1
- package/dist/core/transports/host-replies.generated.d.ts +18 -0
- package/dist/core/transports/host-replies.generated.js +66 -0
- package/dist/core/transports/iframe-transport.d.ts +6 -0
- package/dist/core/transports/iframe-transport.js +44 -26
- package/dist/host/index.js +6 -4
- package/dist/session/index.d.ts +1 -1
- package/dist/session/index.js +5 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/workflows/index.d.ts +6 -4
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -492,15 +492,15 @@ Do **one of two things, and never mint a new key for that press**:
|
|
|
492
492
|
🔴 **For a `kind: 'training'` body and a step body carrying a `quoteId`, the
|
|
493
493
|
key is not the run's identity.** The host does not use the client key on those
|
|
494
494
|
two; the run is identified by the confirmed quote (a step) or by the training
|
|
495
|
-
run itself.
|
|
496
|
-
carries. So after an unknown outcome on one of these, check
|
|
495
|
+
run itself. So after an unknown outcome on one of these, check
|
|
497
496
|
`app.workflows.list()` **before** asking the viewer to confirm another quote.
|
|
498
497
|
|
|
499
498
|
What this client can promise stops there. Matching a repeated key to an
|
|
500
499
|
existing run is done by the host and the orchestrator, not here; it is not
|
|
501
|
-
guaranteed to match, and the host remembers a key only for a limited time.
|
|
502
|
-
`list()`
|
|
503
|
-
|
|
500
|
+
guaranteed to match, and the host remembers a key only for a limited time.
|
|
501
|
+
`list()` does not settle it either: a listed workflow carries no idempotency
|
|
502
|
+
key, so it cannot be tied to a press for certain, and a run missing from it is
|
|
503
|
+
not proof that nothing ran.
|
|
504
504
|
|
|
505
505
|
```ts
|
|
506
506
|
import { ApiError, SubmissionUnconfirmedError } from '@civitai/sdk';
|
|
@@ -565,7 +565,7 @@ server text — log it and show your own copy.
|
|
|
565
565
|
without one. The key is what lets the host recognise a submit that was sent
|
|
566
566
|
twice — a retry after a dropped connection, a double press — as one request
|
|
567
567
|
(for a `kind: 'training'` body or a step with a `quoteId`, see the note above:
|
|
568
|
-
there the
|
|
568
|
+
there the key is not the run's identity).
|
|
569
569
|
|
|
570
570
|
- Mint it **once per thing the viewer asked for**, keep it until that press has
|
|
571
571
|
a known outcome, and reuse it on every retry. A key minted inside the retry
|
package/dist/core/transport.d.ts
CHANGED
|
@@ -9,7 +9,10 @@ export interface BlockSnapshot {
|
|
|
9
9
|
context: BlockContext;
|
|
10
10
|
token: BlockToken;
|
|
11
11
|
settings: BlockSettings;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* `null` for anonymous viewers. For identity, read `app.site.get('blocks/me')`
|
|
14
|
+
* rather than this — not `site.get('me')`, which does not accept a block token.
|
|
15
|
+
*/
|
|
13
16
|
viewer: ViewerInfo | null;
|
|
14
17
|
theme: Theme;
|
|
15
18
|
blockInstanceId: string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface HostReply {
|
|
2
|
+
/** The message type the host answers with. */
|
|
3
|
+
readonly reply: string;
|
|
4
|
+
/** `legacy`: fields straight in the payload, failure as a string. */
|
|
5
|
+
readonly framing: 'envelope' | 'legacy';
|
|
6
|
+
/** The keys a success carries besides `requestId`; `null` where the host's literal could not be read. */
|
|
7
|
+
readonly keys: readonly string[] | null;
|
|
8
|
+
}
|
|
9
|
+
/** The civitai commit this ledger was read from. A request the host added after it is refused too. */
|
|
10
|
+
export declare const HOST_SNAPSHOT = "464b2023e8";
|
|
11
|
+
/**
|
|
12
|
+
* Every request the host answered at {@link HOST_SNAPSHOT}. A type absent here is refused.
|
|
13
|
+
* Reply names and framing are fixed at publish time: if the host renames a reply or moves a
|
|
14
|
+
* type to envelope framing, builds on this version stop receiving it until they upgrade.
|
|
15
|
+
*/
|
|
16
|
+
export declare const HOST_REPLIES: Readonly<Record<string, HostReply>>;
|
|
17
|
+
/** The host's fire-and-forget messages: it handles them and never replies. */
|
|
18
|
+
export declare const HOST_NOTIFICATIONS: ReadonlySet<string>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by scripts/gen-host-replies.mjs from snapshots/host-messages.json
|
|
2
|
+
// (civitai/civitai 464b2023e8, 2026-10-14). Do not edit.
|
|
3
|
+
/** The civitai commit this ledger was read from. A request the host added after it is refused too. */
|
|
4
|
+
export const HOST_SNAPSHOT = "464b2023e8";
|
|
5
|
+
/**
|
|
6
|
+
* Every request the host answered at {@link HOST_SNAPSHOT}. A type absent here is refused.
|
|
7
|
+
* Reply names and framing are fixed at publish time: if the host renames a reply or moves a
|
|
8
|
+
* type to envelope framing, builds on this version stop receiving it until they upgrade.
|
|
9
|
+
*/
|
|
10
|
+
export const HOST_REPLIES = {
|
|
11
|
+
"APP_STORAGE_DELETE": { "reply": "APP_STORAGE_DELETE_RESULT", "framing": "legacy", "keys": ["deleted", "ok"] },
|
|
12
|
+
"APP_STORAGE_GET": { "reply": "APP_STORAGE_GET_RESULT", "framing": "legacy", "keys": ["value"] },
|
|
13
|
+
"APP_STORAGE_LIST": { "reply": "APP_STORAGE_LIST_RESULT", "framing": "legacy", "keys": ["keys", "nextCursor"] },
|
|
14
|
+
"APP_STORAGE_QUOTA": { "reply": "APP_STORAGE_QUOTA_RESULT", "framing": "legacy", "keys": ["limitBytes", "limitRows", "rowCount", "usedBytes"] },
|
|
15
|
+
"APP_STORAGE_SET": { "reply": "APP_STORAGE_SET_RESULT", "framing": "legacy", "keys": ["ok", "sizeBytes"] },
|
|
16
|
+
"CANCEL_APP_WORKFLOW": { "reply": "CANCEL_APP_WORKFLOW_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
17
|
+
"CANCEL_WORKFLOW": { "reply": "WORKFLOW_CANCELED", "framing": "legacy", "keys": ["snapshot"] },
|
|
18
|
+
"CREATE_POST_FROM_APP": { "reply": "CREATE_POST_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
19
|
+
"ESTIMATE_WORKFLOW": { "reply": "ESTIMATE_RESULT", "framing": "legacy", "keys": ["snapshot"] },
|
|
20
|
+
"ESTIMATE_WORKFLOW_BATCH": { "reply": "ESTIMATE_BATCH_RESULT", "framing": "legacy", "keys": ["aggregate", "snapshots"] },
|
|
21
|
+
"GET_BUZZ_ACCOUNTS": { "reply": "BUZZ_ACCOUNTS_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
22
|
+
"GET_BUZZ_BALANCE": { "reply": "BUZZ_BALANCE_RESULT", "framing": "legacy", "keys": ["balance"] },
|
|
23
|
+
"GET_BUZZ_TRANSACTIONS": { "reply": "BUZZ_TRANSACTIONS_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
24
|
+
"GET_DAILY_COMPENSATION": { "reply": "DAILY_COMPENSATION_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
25
|
+
"GET_IMAGES_BY_IDS": { "reply": "IMAGES_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
26
|
+
"GET_VIEWER": { "reply": "VIEWER_RESULT", "framing": "legacy", "keys": ["viewer"] },
|
|
27
|
+
"GET_WILDCARD_PACK": { "reply": "WILDCARD_PACK_RESULT", "framing": "legacy", "keys": ["pack"] },
|
|
28
|
+
"OPEN_BUZZ_PURCHASE": { "reply": "BUZZ_PURCHASE_RESULT", "framing": "legacy", "keys": ["purchased"] },
|
|
29
|
+
"OPEN_CHECKPOINT_PICKER": { "reply": "CHECKPOINT_PICKER_RESULT", "framing": "legacy", "keys": ["selected"] },
|
|
30
|
+
"OPEN_IMAGE_PICKER": { "reply": "IMAGE_PICKER_RESULT", "framing": "legacy", "keys": ["selected", "selectedImages"] },
|
|
31
|
+
"OPEN_IMAGE_UPLOAD": { "reply": "IMAGE_UPLOAD_RESULT", "framing": "legacy", "keys": ["selected"] },
|
|
32
|
+
"OPEN_RESOURCE_PICKER": { "reply": "RESOURCE_PICKER_RESULT", "framing": "legacy", "keys": ["selected", "selectedResources"] },
|
|
33
|
+
"POLL_WORKFLOW": { "reply": "WORKFLOW_STATUS", "framing": "legacy", "keys": ["snapshot"] },
|
|
34
|
+
"PREPARE_TRAINING_DATASET": { "reply": "TRAINING_DATASET_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
35
|
+
"PUBLISH_GENERATION_OUTPUTS": { "reply": "PUBLISH_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
36
|
+
"QUERY_APP_WORKFLOWS": { "reply": "APP_WORKFLOWS_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
37
|
+
"REQUEST_TOKEN": { "reply": "TOKEN_REFRESH_RESPONSE", "framing": "legacy", "keys": ["token"] },
|
|
38
|
+
"RUN_CONFIRMED_STEP": { "reply": "CONFIRMED_STEP_RESULT", "framing": "legacy", "keys": ["snapshot"] },
|
|
39
|
+
"RUN_TRAINING": { "reply": "TRAINING_RESULT", "framing": "legacy", "keys": ["snapshot"] },
|
|
40
|
+
"SAVE_IMAGE": { "reply": "SAVE_IMAGE_RESULT", "framing": "legacy", "keys": ["ok"] },
|
|
41
|
+
"SET_COLLECTION_FOLLOW": { "reply": "COLLECTION_FOLLOW_RESULT", "framing": "legacy", "keys": ["result"] },
|
|
42
|
+
"SET_USER_CHECKPOINT": { "reply": "USER_CHECKPOINT_SET", "framing": "legacy", "keys": ["ok"] },
|
|
43
|
+
"SHARED_APPEND": { "reply": "SHARED_APPEND_RESULT", "framing": "legacy", "keys": ["key"] },
|
|
44
|
+
"SHARED_GET": { "reply": "SHARED_GET_RESULT", "framing": "legacy", "keys": ["item"] },
|
|
45
|
+
"SHARED_GET_COUNT": { "reply": "SHARED_GET_COUNT_RESULT", "framing": "legacy", "keys": ["count"] },
|
|
46
|
+
"SHARED_GET_COUNTS": { "reply": "SHARED_GET_COUNTS_RESULT", "framing": "legacy", "keys": ["counts"] },
|
|
47
|
+
"SHARED_LIST": { "reply": "SHARED_LIST_RESULT", "framing": "legacy", "keys": ["items", "nextCursor"] },
|
|
48
|
+
"SHARED_REPORT": { "reply": "SHARED_REPORT_RESULT", "framing": "legacy", "keys": ["ok"] },
|
|
49
|
+
"SHARED_UNVOTE": { "reply": "SHARED_UNVOTE_RESULT", "framing": "legacy", "keys": ["count"] },
|
|
50
|
+
"SHARED_UPDATE": { "reply": "SHARED_UPDATE_RESULT", "framing": "legacy", "keys": ["ok"] },
|
|
51
|
+
"SHARED_VOTE": { "reply": "SHARED_VOTE_RESULT", "framing": "legacy", "keys": ["count"] },
|
|
52
|
+
"SHARED_WITHDRAW": { "reply": "SHARED_WITHDRAW_RESULT", "framing": "legacy", "keys": ["deleted", "ok"] },
|
|
53
|
+
"SUBMIT_WORKFLOW": { "reply": "WORKFLOW_SUBMITTED", "framing": "legacy", "keys": ["snapshot"] },
|
|
54
|
+
};
|
|
55
|
+
/** The host's fire-and-forget messages: it handles them and never replies. */
|
|
56
|
+
export const HOST_NOTIFICATIONS = new Set([
|
|
57
|
+
"BLOCK_ERROR",
|
|
58
|
+
"BLOCK_HELLO",
|
|
59
|
+
"BLOCK_MESSAGE_REJECTED",
|
|
60
|
+
"BLOCK_READY",
|
|
61
|
+
"NAVIGATE",
|
|
62
|
+
"REQUEST_CONSENT",
|
|
63
|
+
"REQUEST_SIGN_IN",
|
|
64
|
+
"RESIZE_IFRAME",
|
|
65
|
+
"TRACK_EVENT",
|
|
66
|
+
]);
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type BlockSnapshot, type BlockTransport, type RequestOptions } from '../transport.js';
|
|
2
|
+
import { BridgeError } from '../errors.js';
|
|
3
|
+
import { type HostReply } from './host-replies.generated.js';
|
|
4
|
+
/** Why `request(type)` cannot settle, and what to call instead. */
|
|
5
|
+
export declare function unanswerable(type: string): BridgeError;
|
|
6
|
+
/** Turns a reply into the value it carries, or the failure it reports. */
|
|
7
|
+
export declare function unwrap(type: string, reply: unknown, expected: HostReply): unknown;
|
|
2
8
|
export interface IframeTransportOptions {
|
|
3
9
|
/** At least one entry. Other origins — including the local one — drop silently. */
|
|
4
10
|
allowedParentOrigins: string[];
|
|
@@ -2,48 +2,63 @@ import { isHostMessage, parseBlockInitFragment, stripBlockInitFragment, } from '
|
|
|
2
2
|
import { EMPTY_SNAPSHOT, snapshotFromInit, tokenFromWrapped, } from '../transport.js';
|
|
3
3
|
import { BridgeError, classifyHostError } from '../errors.js';
|
|
4
4
|
import { OriginMatcher } from '../origin-matcher.js';
|
|
5
|
+
import { HOST_NOTIFICATIONS, HOST_REPLIES, HOST_SNAPSHOT } from './host-replies.generated.js';
|
|
5
6
|
import { VERSION } from '../../version.generated.js';
|
|
6
7
|
/**
|
|
7
8
|
* The framing the host had before this package owned the protocol: fields
|
|
8
9
|
* straight in the payload, and failure as the server's own sentence. Converting
|
|
9
10
|
* it here is what keeps the rest of this file — and every domain — speaking one
|
|
10
|
-
* shape; when the host modernises a message,
|
|
11
|
-
* and this stops being reached.
|
|
11
|
+
* shape; when the host modernises a message, the snapshot reports it as
|
|
12
|
+
* `envelope` and this stops being reached for it.
|
|
12
13
|
*/
|
|
13
|
-
function fromLegacyReply(reply) {
|
|
14
|
+
function fromLegacyReply(reply, keys) {
|
|
14
15
|
const { requestId, error, ...fields } = reply;
|
|
15
16
|
// An empty string is how the host spells "no failure" on these replies.
|
|
16
17
|
if (typeof error === 'string' && error !== '') {
|
|
17
18
|
return { requestId, error: { code: classifyHostError(error), message: error } };
|
|
18
19
|
}
|
|
19
20
|
// Some of these replies nest their value under `result` and others put its
|
|
20
|
-
// fields straight in the payload
|
|
21
|
-
|
|
21
|
+
// fields straight in the payload. The snapshot says which; where the host's
|
|
22
|
+
// reply could not be read (`keys` null), the payload itself decides.
|
|
23
|
+
const nested = keys === null ? 'result' in fields : keys.length === 1 && keys[0] === 'result';
|
|
24
|
+
return { requestId, result: nested ? fields.result : fields };
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* reply, and when it empties `fromLegacyReply` goes with it.
|
|
27
|
+
* Where a caller should go instead of a bridge message, from BREAKING.md. Only
|
|
28
|
+
* read when the host does not answer the type, so it is what a request the
|
|
29
|
+
* host dropped (or never had) says instead of hanging.
|
|
28
30
|
*/
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
const REPLACED_BY = [
|
|
32
|
+
[/^GET_VIEWER$/, "app.site.get('blocks/me')"],
|
|
33
|
+
[/^(SUBMIT|ESTIMATE|POLL|CANCEL)_WORKFLOW$|^QUERY_APP_WORKFLOWS$|^CANCEL_APP_WORKFLOW$/, 'app.workflows'],
|
|
34
|
+
[/^GET_IMAGES_BY_IDS$/, 'GET /api/v1/blocks/images?ids=… (app.site)'],
|
|
35
|
+
[/^APP_STORAGE_/, 'POST /api/v1/blocks/app-storage/* (app.site)'],
|
|
36
|
+
[/^SHARED_/, 'app.sharedStorage'],
|
|
37
|
+
[/^GET_BUZZ_BALANCE$/, "app.site.get('blocks/buzz')"],
|
|
38
|
+
[/^SET_COLLECTION_FOLLOW$/, 'POST /api/v1/blocks/collections/{id}/follow (app.site)'],
|
|
39
|
+
[/^TRACK_EVENT$/, 'app.host.track(eventName, properties)'],
|
|
40
|
+
[/^PUBLISH_GENERATION_OUTPUTS$/, 'app.host.publishGenerationOutputs'],
|
|
41
|
+
];
|
|
42
|
+
/** Why `request(type)` cannot settle, and what to call instead. */
|
|
43
|
+
export function unanswerable(type) {
|
|
44
|
+
const instead = REPLACED_BY.find(([pattern]) => pattern.test(type))?.[1];
|
|
45
|
+
const message = HOST_NOTIFICATIONS.has(type)
|
|
46
|
+
? `${type} is fire-and-forget: the host never answers it, so request() would wait forever. ` +
|
|
47
|
+
`Send it with notify()${instead ? `, or use ${instead}` : ''}.`
|
|
48
|
+
: `${type} is not a request the host answered at civitai ${HOST_SNAPSHOT}, ` +
|
|
49
|
+
`the host snapshot @civitai/sdk ${VERSION} was built from, so request() would wait forever. ` +
|
|
50
|
+
(instead
|
|
51
|
+
? `Use ${instead} instead.`
|
|
52
|
+
: 'If the host has added it since, upgrade @civitai/sdk; otherwise see BREAKING.md for where bridge messages moved.');
|
|
53
|
+
return new BridgeError('invalid', type, message);
|
|
39
54
|
}
|
|
40
55
|
/** Turns a reply into the value it carries, or the failure it reports. */
|
|
41
|
-
function unwrap(type, reply,
|
|
56
|
+
export function unwrap(type, reply, expected) {
|
|
42
57
|
if (reply == null || typeof reply !== 'object') {
|
|
43
58
|
throw new BridgeError('malformed', type, `${type} replied with no payload`);
|
|
44
59
|
}
|
|
45
|
-
const envelope = framing === 'legacy'
|
|
46
|
-
? fromLegacyReply(reply)
|
|
60
|
+
const envelope = expected.framing === 'legacy'
|
|
61
|
+
? fromLegacyReply(reply, expected.keys)
|
|
47
62
|
: reply;
|
|
48
63
|
if (envelope.error !== undefined) {
|
|
49
64
|
throw new BridgeError(envelope.error.code, type, envelope.error.message || `${type} failed`);
|
|
@@ -187,11 +202,14 @@ export class IframeTransport {
|
|
|
187
202
|
this.#dispatch(message.type, message.payload);
|
|
188
203
|
}
|
|
189
204
|
async request(type, params, opts = {}) {
|
|
190
|
-
|
|
191
|
-
|
|
205
|
+
// Own keys only: `HOST_REPLIES['toString']` must not read as an answer.
|
|
206
|
+
const expected = Object.hasOwn(HOST_REPLIES, type) ? HOST_REPLIES[type] : undefined;
|
|
207
|
+
// Nothing would ever answer it, so say so now rather than wait forever.
|
|
208
|
+
if (!expected)
|
|
209
|
+
throw unanswerable(type);
|
|
210
|
+
return unwrap(type, await this.#exchange(type, expected.reply, params, opts), expected);
|
|
192
211
|
}
|
|
193
|
-
#exchange(type, params, opts) {
|
|
194
|
-
const responseType = replyTypeFor(type);
|
|
212
|
+
#exchange(type, responseType, params, opts) {
|
|
195
213
|
const { signal } = opts;
|
|
196
214
|
if (signal?.aborted)
|
|
197
215
|
return Promise.reject(signal.reason);
|
package/dist/host/index.js
CHANGED
|
@@ -60,10 +60,12 @@ export function createHost(transport) {
|
|
|
60
60
|
transport,
|
|
61
61
|
});
|
|
62
62
|
// The host spells "no failure" as `error: ''`, which the transport reads
|
|
63
|
-
// as a success
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
63
|
+
// as a success. A reply with no `result` at all is refused by the
|
|
64
|
+
// transport (the ledger says this reply nests under `result`), but one
|
|
65
|
+
// whose `result` lacks the ids gets this far, and returning it would
|
|
66
|
+
// resolve `undefined` from a promise that says `number[]`. A caller
|
|
67
|
+
// reading that as "nothing published" would be guessing: images may well
|
|
68
|
+
// have been.
|
|
67
69
|
if (!Array.isArray(imageIds) || !imageIds.every((id) => typeof id === 'number')) {
|
|
68
70
|
throw new BridgeError('malformed', 'PUBLISH_GENERATION_OUTPUTS', 'PUBLISH_GENERATION_OUTPUTS reply carried no image ids. Whether anything ' +
|
|
69
71
|
'was published is unknown; read the workflow back rather than assuming.');
|
package/dist/session/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Every scope an app can hold, as the site names them. */
|
|
2
|
-
export declare const SCOPES: readonly ['ai:write:budgeted', 'apps:storage:read', 'apps:storage:shared:read', 'apps:storage:shared:write', 'apps:storage:write', 'buzz:read:self', 'collections:read:private', 'collections:read:self', 'collections:write:self', 'models:read:self', 'posts:write:self', 'social:tip:self', 'user:read:self'];
|
|
2
|
+
export declare const SCOPES: readonly ['ai:write:budgeted', 'apps:storage', 'apps:storage:publish', 'apps:storage:read', 'apps:storage:shared:read', 'apps:storage:shared:write', 'apps:storage:write', 'apps:store:items:write', 'buzz:read:self', 'collections:read:private', 'collections:read:self', 'collections:write:self', 'goods:purchase:self', 'goods:read:self', 'models:read:self', 'posts:write:self', 'social:tip:self', 'user:read:self'];
|
|
3
3
|
export type Scope = (typeof SCOPES)[number];
|
|
4
4
|
export interface TokenOptions {
|
|
5
5
|
/** Skip the held token and get a new one, e.g. after the API refused it. */
|
package/dist/session/index.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/** Every scope an app can hold, as the site names them. */
|
|
2
2
|
export const SCOPES = [
|
|
3
3
|
'ai:write:budgeted',
|
|
4
|
+
'apps:storage',
|
|
5
|
+
'apps:storage:publish',
|
|
4
6
|
'apps:storage:read',
|
|
5
7
|
'apps:storage:shared:read',
|
|
6
8
|
'apps:storage:shared:write',
|
|
7
9
|
'apps:storage:write',
|
|
10
|
+
'apps:store:items:write',
|
|
8
11
|
'buzz:read:self',
|
|
9
12
|
'collections:read:private',
|
|
10
13
|
'collections:read:self',
|
|
11
14
|
'collections:write:self',
|
|
15
|
+
'goods:purchase:self',
|
|
16
|
+
'goods:read:self',
|
|
12
17
|
'models:read:self',
|
|
13
18
|
'posts:write:self',
|
|
14
19
|
'social:tip:self',
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** This package's version, reported to the host as `sdkVersion` in `BLOCK_READY`. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.13.0";
|
|
@@ -138,13 +138,15 @@ export interface WorkflowsClient {
|
|
|
138
138
|
* {@link WorkflowsClient.list}. Never mint a new key for the same viewer
|
|
139
139
|
* action: to the host a new key is a new generation. That matching is the
|
|
140
140
|
* host's and the orchestrator's, is not guaranteed, and is not something
|
|
141
|
-
* this client can verify
|
|
141
|
+
* this client can verify. Nor does `list` settle it: a listed workflow
|
|
142
|
+
* carries no idempotency key, and a run missing from it is not proof that
|
|
143
|
+
* nothing ran.
|
|
142
144
|
*
|
|
143
145
|
* 🔴 For a `kind: 'training'` body and a step body carrying a `quoteId` the
|
|
144
146
|
* key is NOT the run's identity: the host does not use it there, and
|
|
145
|
-
* identifies the run by the confirmed quote or the training run.
|
|
146
|
-
*
|
|
147
|
-
*
|
|
147
|
+
* identifies the run by the confirmed quote or the training run. After an
|
|
148
|
+
* unknown outcome on one of these, check `list` before asking the viewer to
|
|
149
|
+
* confirm another quote.
|
|
148
150
|
*
|
|
149
151
|
* This client does not retry a failed submit itself; it only re-sends once
|
|
150
152
|
* after refreshing an expired token, as every call does.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@civitai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "The Civitai SDK: an app holds a token and calls the Civitai API and the orchestrator; a block asks its host only to show host UI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -69,6 +69,8 @@
|
|
|
69
69
|
"gen:steps": "node scripts/gen-step-types.mjs",
|
|
70
70
|
"check:steps": "node scripts/gen-step-types.mjs --check",
|
|
71
71
|
"gen:workflow-types": "node scripts/gen-workflow-types.mjs",
|
|
72
|
+
"gen:host-replies": "node scripts/gen-host-replies.mjs",
|
|
73
|
+
"check:host-replies": "node scripts/gen-host-replies.mjs --check",
|
|
72
74
|
"snapshot:host": "node scripts/snapshot-host-messages.mjs",
|
|
73
75
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json && tsc -p tsconfig.examples.json",
|
|
74
76
|
"test": "vitest run",
|