@civitai/sdk 0.18.0 → 0.19.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.
@@ -1,5 +1,5 @@
1
1
  import type { BlockContext, BlockSettings, Theme, ViewerInfo } from '../core/handshake.js';
2
- import type { BlockTransport } from '../core/transport.js';
2
+ import { type BlockTransport } from '../core/transport.js';
3
3
  import { type Host } from '../host/index.js';
4
4
  import { type OrchestrationClient } from '../orchestration/index.js';
5
5
  import { type GrantOptions, type Scope, type TokenOptions, type TokenSessionOptions } from '../session/index.js';
package/dist/app/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { BridgeError, CivitaiError } from '../core/errors.js';
2
2
  import { getTransport } from '../core/get-transport.js';
3
+ import { isLocalPreviewStorage } from '../core/transport.js';
3
4
  import { createHost, createHostSession } from '../host/index.js';
4
5
  import { ApiError, createHttp } from '../http/index.js';
5
6
  import { createOrchestrationClient, DEFAULT_ORCHESTRATION_URL, } from '../orchestration/index.js';
@@ -26,13 +27,16 @@ export async function initialize(options = {}) {
26
27
  // from `token.scopes`. A published app whose manifest forgot `apps:storage`
27
28
  // holds a token that looks the same as a preview's, and must keep getting the
28
29
  // real route's `insufficient_scope` rather than a silent local store.
29
- const local = snapshot().storageMode === 'local-preview'
30
+ const localPreview = isLocalPreviewStorage(snapshot());
31
+ // The same latched answer configures the session below, so `requestGrants`
32
+ // and the store agree on whether the document store is local.
33
+ const local = localPreview
30
34
  ? // The manifest arrives only from `blockManifestPlugin()`'s dev-server
31
35
  // global: there is deliberately no option to pass one.
32
36
  await createLocalPreviewStorage(readInjectedManifest(), snapshot().viewer)
33
37
  : undefined;
34
38
  return {
35
- ...createAppClient(createHostSession(transport), options, holdsBlockTokenNow, holdsOAuthTokenNow, local),
39
+ ...createAppClient(createHostSession(transport, { localPreviewStorage: localPreview }), options, holdsBlockTokenNow, holdsOAuthTokenNow, local),
36
40
  host: createHost(transport),
37
41
  get viewer() {
38
42
  return snapshot().viewer;
@@ -63,6 +63,15 @@ export interface BlockTransport {
63
63
  on(type: string, handler: (payload: unknown) => void): () => void;
64
64
  }
65
65
  export declare const EMPTY_SNAPSHOT: BlockSnapshot;
66
+ /**
67
+ * Did the host mark this frame a dev-tunnel preview whose document store is
68
+ * served locally? THE predicate for that question. `initialize()` reads it once
69
+ * and the one latched answer selects the local document store AND tells the
70
+ * host session which scopes no grant can add (`requestGrants`), so the two
71
+ * cannot disagree. Never inferred from `token.scopes`: a published app whose
72
+ * token lacks `apps:storage` looks the same as a preview's.
73
+ */
74
+ export declare function isLocalPreviewStorage(snapshot: Pick<BlockSnapshot, 'storageMode'>): boolean;
66
75
  /** Convert a wire `BlockInitPayload` (ISO string expiresAt) into a `BlockSnapshot`. */
67
76
  export declare function snapshotFromInit(payload: BlockInitPayload, hostOrigin: string): BlockSnapshot;
68
77
  /** Wire `WrappedToken` (ISO expiry) → runtime `BlockToken` (Date expiry). */
@@ -10,6 +10,17 @@ export const EMPTY_SNAPSHOT = {
10
10
  blockInstanceId: '',
11
11
  hostOrigin: null,
12
12
  };
13
+ /**
14
+ * Did the host mark this frame a dev-tunnel preview whose document store is
15
+ * served locally? THE predicate for that question. `initialize()` reads it once
16
+ * and the one latched answer selects the local document store AND tells the
17
+ * host session which scopes no grant can add (`requestGrants`), so the two
18
+ * cannot disagree. Never inferred from `token.scopes`: a published app whose
19
+ * token lacks `apps:storage` looks the same as a preview's.
20
+ */
21
+ export function isLocalPreviewStorage(snapshot) {
22
+ return snapshot.storageMode === LOCAL_PREVIEW_STORAGE;
23
+ }
13
24
  /** Convert a wire `BlockInitPayload` (ISO string expiresAt) into a `BlockSnapshot`. */
14
25
  export function snapshotFromInit(payload, hostOrigin) {
15
26
  return {
@@ -7,7 +7,7 @@ export interface HostReply {
7
7
  readonly keys: readonly string[] | null;
8
8
  }
9
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 = "cd79a91fe4";
10
+ export declare const HOST_SNAPSHOT = "05f1d1fa8f";
11
11
  /**
12
12
  * Every request the host answered at {@link HOST_SNAPSHOT}. A type absent here is refused.
13
13
  * Reply names and framing are fixed at publish time: if the host renames a reply or moves a
@@ -1,7 +1,7 @@
1
1
  // Generated by scripts/gen-host-replies.mjs from snapshots/host-messages.json
2
- // (civitai/civitai cd79a91fe4, 2026-10-17). Do not edit.
2
+ // (civitai/civitai 05f1d1fa8f, 2026-10-20). Do not edit.
3
3
  /** The civitai commit this ledger was read from. A request the host added after it is refused too. */
4
- export const HOST_SNAPSHOT = "cd79a91fe4";
4
+ export const HOST_SNAPSHOT = "05f1d1fa8f";
5
5
  /**
6
6
  * Every request the host answered at {@link HOST_SNAPSHOT}. A type absent here is refused.
7
7
  * Reply names and framing are fixed at publish time: if the host renames a reply or moves a
@@ -33,7 +33,7 @@ export const HOST_REPLIES = {
33
33
  "OPEN_MEDIA_UPLOAD": { "reply": "MEDIA_UPLOAD_RESULT", "framing": "legacy", "keys": ["selected"] },
34
34
  "OPEN_RESOURCE_PICKER": { "reply": "RESOURCE_PICKER_RESULT", "framing": "legacy", "keys": ["selected", "selectedResources"] },
35
35
  "POLL_WORKFLOW": { "reply": "WORKFLOW_STATUS", "framing": "legacy", "keys": ["snapshot"] },
36
- "PREPARE_TRAINING_DATASET": { "reply": "TRAINING_DATASET_RESULT", "framing": "legacy", "keys": ["result"] },
36
+ "PREPARE_TRAINING_DATASET": { "reply": "TRAINING_DATASET_RESULT", "framing": "legacy", "keys": [] },
37
37
  "PUBLISH_GENERATION_OUTPUTS": { "reply": "PUBLISH_RESULT", "framing": "legacy", "keys": ["result"] },
38
38
  "QUERY_APP_WORKFLOWS": { "reply": "APP_WORKFLOWS_RESULT", "framing": "legacy", "keys": ["result"] },
39
39
  "REQUEST_TOKEN": { "reply": "TOKEN_REFRESH_RESPONSE", "framing": "legacy", "keys": ["token"] },
@@ -1,4 +1,5 @@
1
1
  import type { ViewerInfo } from '../core/handshake.js';
2
+ import type { Scope } from '../session/index.js';
2
3
  import { type DocumentStorage } from './index.js';
3
4
  /**
4
5
  * The document store for a DEV-TUNNEL PREVIEW: the host marked the frame
@@ -22,6 +23,15 @@ import { type DocumentStorage } from './index.js';
22
23
  * `tests/guards/local-preview-manifest-global.test.mjs`.
23
24
  */
24
25
  export declare const LOCAL_PREVIEW_MANIFEST_GLOBAL = "__CIVITAI_LOCAL_PREVIEW_MANIFEST__";
26
+ /**
27
+ * The scopes the local document store serves: the two the server's document
28
+ * store checks (`fake.ts` enforces the same pair). A preview token never
29
+ * carries them and no grant can add them, so `requestGrants` treats them as
30
+ * held in a local preview instead of asking the host. Shared storage
31
+ * (`apps:storage:shared:*`) and the deprecated key/value scopes are NOT here:
32
+ * they keep the real routes in a preview.
33
+ */
34
+ export declare const LOCAL_PREVIEW_STORAGE_SCOPES: ReadonlySet<Scope>;
25
35
  /** What a local preview reads from the manifest: the scopes it declares and its `storage` block. */
26
36
  export interface LocalPreviewManifest {
27
37
  scopes?: readonly string[];
@@ -21,6 +21,18 @@ import { createDocumentStorage, StorageError } from './index.js';
21
21
  * `tests/guards/local-preview-manifest-global.test.mjs`.
22
22
  */
23
23
  export const LOCAL_PREVIEW_MANIFEST_GLOBAL = '__CIVITAI_LOCAL_PREVIEW_MANIFEST__';
24
+ /**
25
+ * The scopes the local document store serves: the two the server's document
26
+ * store checks (`fake.ts` enforces the same pair). A preview token never
27
+ * carries them and no grant can add them, so `requestGrants` treats them as
28
+ * held in a local preview instead of asking the host. Shared storage
29
+ * (`apps:storage:shared:*`) and the deprecated key/value scopes are NOT here:
30
+ * they keep the real routes in a preview.
31
+ */
32
+ export const LOCAL_PREVIEW_STORAGE_SCOPES = new Set([
33
+ 'apps:storage',
34
+ 'apps:storage:publish',
35
+ ]);
24
36
  /** The manifest the dev server injected, if any. */
25
37
  export function readInjectedManifest() {
26
38
  const value = globalThis[LOCAL_PREVIEW_MANIFEST_GLOBAL];
@@ -124,5 +124,13 @@ export interface Host {
124
124
  }, opts?: HostCallOptions): Promise<number[]>;
125
125
  }
126
126
  export declare function createHost(transport: BlockTransport): Host;
127
+ export interface HostSessionOptions {
128
+ /**
129
+ * The document store is served by the in-tab local store (a dev-tunnel
130
+ * preview): the value `initialize()` latched from `isLocalPreviewStorage`.
131
+ * `requestGrants` then treats `LOCAL_PREVIEW_STORAGE_SCOPES` as held.
132
+ */
133
+ localPreviewStorage?: boolean;
134
+ }
127
135
  /** The token the host minted for this block, kept current as the host rotates it. */
128
- export declare function createHostSession(transport: BlockTransport): Session;
136
+ export declare function createHostSession(transport: BlockTransport, { localPreviewStorage }?: HostSessionOptions): Session;
@@ -1,6 +1,7 @@
1
1
  import { BridgeError } from '../core/errors.js';
2
2
  import { createCaller, createListener, createNotifier } from '../core/messaging.js';
3
3
  import { tokenFromWrapped } from '../core/transport.js';
4
+ import { LOCAL_PREVIEW_STORAGE_SCOPES } from '../doc-store/local-preview.js';
4
5
  const call = createCaller();
5
6
  const notify = createNotifier();
6
7
  const on = createListener();
@@ -254,7 +255,7 @@ function asScanResult(value) {
254
255
  return { status: 'error', ...(typeof v?.message === 'string' ? { message: v.message } : {}) };
255
256
  }
256
257
  /** The token the host minted for this block, kept current as the host rotates it. */
257
- export function createHostSession(transport) {
258
+ export function createHostSession(transport, { localPreviewStorage = false } = {}) {
258
259
  return {
259
260
  async getToken({ fresh, signal } = {}) {
260
261
  if (!fresh)
@@ -263,7 +264,14 @@ export function createHostSession(transport) {
263
264
  const { token } = await call('REQUEST_TOKEN', { blockInstanceId }, { transport, signal });
264
265
  return tokenFromWrapped(token).raw;
265
266
  },
266
- requestGrants: (scopes, opts = {}) => requestGrants(transport, scopes, opts),
267
+ requestGrants: (scopes, opts = {}) => requestGrants(transport,
268
+ // A preview token never carries a document-store scope and no grant can
269
+ // add one, so asking the host for it could only be refused — and the
270
+ // refusal would take the rest of the request down with it. The local
271
+ // store serves them; ask only for the rest. Nothing on the token changes.
272
+ localPreviewStorage
273
+ ? scopes.filter((scope) => !LOCAL_PREVIEW_STORAGE_SCOPES.has(scope))
274
+ : scopes, opts),
267
275
  };
268
276
  }
269
277
  /**
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ export { StorageError } from './doc-store/index.js';
17
17
  export type { DocumentAuthor, DocumentCallOptions, DocumentListQuery, DocumentPage, DocumentStorage, DocumentWhereValue, StorageCollection, StorageCollectionInfo, StorageDocument, StorageErrorCode, StorageIndexType, StorageInfo, StorageLimits, StorageUsage, WriteOptions, } from './doc-store/index.js';
18
18
  export { SubmissionUnconfirmedError } from './workflows/index.js';
19
19
  export type { WorkflowCallOptions, WorkflowGetOptions, WorkflowListQuery, WorkflowListResult, WorkflowSubmitOptions, WorkflowWatchOptions, WorkflowsClient, } from './workflows/index.js';
20
- export type { AiToolkitLrScheduler, AiToolkitOptimizerType, AiToolkitPlainEcosystem, AiToolkitTrainingParams, AiToolkitTrainingParamsBase, AppWorkflow, AppWorkflowImage, BlockModel3dOutput, BlockModelSubstitution, BlockPublishedModel, BlockSourceImage, BlockStepQuote, BlockStepToolCall, BlockTextToImageParams, BlockTrainedEpoch, BlockTrainingQuote, BlockWorkflowSnapshot, BlockWorkflowStepSnapshot, BuzzAccountType, InlineComfyNode, KnownBlockWorkflowErrorCode, ModelSubstitutionReason, WithWorkflowStepRefs, WorkflowBody, WorkflowBodyCustomComfy, WorkflowBodyCustomComfyInline, WorkflowBodyCustomComfyRecipe, WorkflowBodyPassThroughStep, WorkflowBodyStep, WorkflowBodyTextToImage, WorkflowBodyTraining, WorkflowBodyWorkflow, WorkflowBodyWorkflowStep, WorkflowStepRef, } from './workflows/types.generated.js';
20
+ export type { AiToolkitLrScheduler, AiToolkitOptimizerType, AiToolkitPlainEcosystem, AiToolkitTrainingParams, AiToolkitTrainingParamsBase, AppWorkflow, AppWorkflowImage, BlockModel3dOutput, BlockModelSubstitution, BlockPublishedModel, BlockSourceImage, BlockStepQuote, BlockStepToolCall, BlockTextToImageParams, BlockTrainedEpoch, BlockTrainingDatasetItem, BlockTrainingQuote, BlockWorkflowSnapshot, BlockWorkflowStepSnapshot, BuzzAccountType, InlineComfyNode, KnownBlockWorkflowErrorCode, ModelSubstitutionReason, WithWorkflowStepRefs, WorkflowBody, WorkflowBodyCustomComfy, WorkflowBodyCustomComfyInline, WorkflowBodyCustomComfyRecipe, WorkflowBodyPassThroughStep, WorkflowBodyStep, WorkflowBodyTextToImage, WorkflowBodyTraining, WorkflowBodyWorkflow, WorkflowBodyWorkflowStep, WorkflowStepRef, } from './workflows/types.generated.js';
21
21
  export { isTerminal, isTerminalStatus } from './orchestration/index.js';
22
22
  export type { OrchestrationClient, Step, StepTemplate, WaitOptions, Workflow, WorkflowPage, WorkflowQuery, WorkflowStatus, WorkflowTemplate, } from './orchestration/index.js';
23
23
  export { createHost } from './host/index.js';
@@ -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.18.0";
2
+ export declare const VERSION = "0.19.1";
@@ -1,3 +1,3 @@
1
1
  /* AUTOGENERATED from package.json by scripts/gen-version.mjs. DO NOT EDIT. */
2
2
  /** This package's version, reported to the host as `sdkVersion` in `BLOCK_READY`. */
3
- export const VERSION = "0.18.0";
3
+ export const VERSION = "0.19.1";
@@ -938,16 +938,16 @@ export type AiToolkitTrainingParams = AiToolkitTrainingParamsBase & ({
938
938
  modelVariant: 'base' | 'sft';
939
939
  });
940
940
  /**
941
- * Train a LoRA with the ai-toolkit engine on a dataset Civitai prepared from the
942
- * VIEWER'S OWN images — the App Blocks `kind: 'training'` workflow body.
941
+ * Train a LoRA with the ai-toolkit engine on images the VIEWER uploaded through
942
+ * the host — the App Blocks `kind: 'training'` workflow body.
943
943
  *
944
944
  * ## Availability — read before building on it
945
945
  *
946
946
  * - 🔴 Behind the host flag **`app-blocks-training-kind`**, which ships OFF and is
947
947
  * evaluated per viewer. Where it is off, every training call is refused
948
948
  * (`training from apps is not enabled`).
949
- * - **Page apps only** (`/apps/run/<slug>`). The model slot answers both training
950
- * messages with an error, and the server refuses a non-page token.
949
+ * - **Page apps only** (`/apps/run/<slug>`). The model slot answers
950
+ * `RUN_TRAINING` with an error, and the server refuses a non-page token.
951
951
  * - The manifest must declare **`ai:write:budgeted`** and the viewer must have
952
952
  * granted it; the viewer must be signed in.
953
953
  * - **Not from a development or review session**: dev tokens (`dev:live`, dev
@@ -956,17 +956,22 @@ export type AiToolkitTrainingParams = AiToolkitTrainingParamsBase & ({
956
956
  *
957
957
  * ## The flow
958
958
  *
959
- * 1. **Dataset** — `usePrepareTrainingDataset()` (`PREPARE_TRAINING_DATASET`)
960
- * with `[{ imageId, caption }]`. Only the viewer's OWN scanned, unflagged
961
- * images within the page's maturity ceiling are admitted; the rest come back
962
- * in `rejected`. You get an opaque {@link WorkflowBodyTraining.datasetId}.
959
+ * 1. **Upload** — `useImageUpload({ purpose: 'trainingData' }).open()`
960
+ * (`OPEN_IMAGE_UPLOAD { purpose: 'trainingData' }`). The viewer picks up to
961
+ * {@link BLOCK_TRAINING_DATASET_MAX_ITEMS} images in a host modal; you get
962
+ * `[{ url, air }]` ({@link BlockTrainingDataImage}), or `null` on cancel.
963
+ * Pair each `air` with your caption to build {@link WorkflowBodyTraining.items}.
963
964
  * 2. **Quote** — `useBuzzWorkflow().estimate(body)` with this body, `quoteId`
964
965
  * ABSENT. The reply's {@link BlockWorkflowSnapshot.trainingQuote} is the
965
966
  * orchestrator's own price for exactly this run, stored server-side.
966
967
  * 3. **Run** — `useRunTraining().runTraining({ ...body, quoteId })`
967
968
  * (`RUN_TRAINING`). Civitai shows the viewer a consent dialog in ITS chrome —
968
969
  * price, base model, length, dataset size, all read back from the server,
969
- * never from your body — and submits only on their click.
970
+ * never from your body, with the host's own copies of the uploads as
971
+ * thumbnails — and submits only on their click. A quote naming an image this
972
+ * host did not upload for the block is refused with no dialog
973
+ * (`training data not uploaded here`) — upload in the same page session as the
974
+ * run; a reload forgets the uploads.
970
975
  * 4. **Follow** — `useBuzzWorkflow().watch(snapshot.workflowId)`.
971
976
  *
972
977
  * 🔴 `useBuzzWorkflow().submit()` REFUSES THIS BODY before sending it. The server
@@ -982,8 +987,12 @@ export type AiToolkitTrainingParams = AiToolkitTrainingParamsBase & ({
982
987
  */
983
988
  export interface WorkflowBodyTraining {
984
989
  kind: 'training';
985
- /** The handle `usePrepareTrainingDataset()` returned — `tds_` + 32 hex characters. */
986
- datasetId: string;
990
+ /**
991
+ * The dataset: 1…{@link BLOCK_TRAINING_DATASET_MAX_ITEMS} images this host
992
+ * uploaded for the viewer, each with its caption — see
993
+ * {@link BlockTrainingDatasetItem}. One blob may appear once.
994
+ */
995
+ items: BlockTrainingDatasetItem[];
987
996
  /** The only engine accepted. */
988
997
  engine: 'ai-toolkit';
989
998
  /**
@@ -992,12 +1001,17 @@ export interface WorkflowBodyTraining {
992
1001
  */
993
1002
  model: string;
994
1003
  params: AiToolkitTrainingParams;
995
- /** At most {@link BLOCK_TRAINING_TRIGGER_WORD_MAX_CHARS} characters. Moderated like a prompt. */
1004
+ /**
1005
+ * At most {@link BLOCK_TRAINING_TRIGGER_WORD_MAX_CHARS} characters. The host runs
1006
+ * it through the same trigger-word check Civitai's trainer and Training Studio
1007
+ * use, at the estimate and again at the submit, before anything is reserved; a
1008
+ * refused trigger word fails the estimate.
1009
+ */
996
1010
  triggerWord: string;
997
1011
  /**
998
1012
  * At most {@link BLOCK_TRAINING_SAMPLE_PROMPTS_MAX} prompts of at most
999
- * {@link BLOCK_TRAINING_SAMPLE_PROMPT_MAX_CHARS} characters each. Moderated like
1000
- * prompts.
1013
+ * {@link BLOCK_TRAINING_SAMPLE_PROMPT_MAX_CHARS} characters each. Checked for
1014
+ * those bounds only, as in the Training Studio.
1001
1015
  */
1002
1016
  samplePrompts: string[];
1003
1017
  /**
@@ -1027,7 +1041,7 @@ export interface WorkflowBodyTraining {
1027
1041
  * unmodified. Bounded by a platform-internal denylist and by `maxBuzz`, not
1028
1042
  * by a registry.
1029
1043
  * - {@link WorkflowBodyTraining} (`kind: 'training'`) — an ai-toolkit LoRA run
1030
- * on a server-prepared dataset of the viewer's own images. ESTIMATE ONLY
1044
+ * on images the viewer uploaded through the host. ESTIMATE ONLY
1031
1045
  * through `useBuzzWorkflow`; it runs through `useRunTraining()`, whose
1032
1046
  * host-chrome consent dialog is the only way to confirm its quote.
1033
1047
  * - {@link WorkflowBodyWorkflow} (`kind: 'workflow'`) — up to
@@ -1395,8 +1409,8 @@ export interface BlockWorkflowSnapshot {
1395
1409
  *
1396
1410
  * `cost.total` on the same snapshot equals `trainingQuote.total`.
1397
1411
  * `expiresAt` is an ISO-8601 timestamp: after it the run is refused and you
1398
- * estimate again. `imageCount` is the server-derived size of the prepared
1399
- * dataset, never a number the block sent.
1412
+ * estimate again. `imageCount` is the size of the dataset the server quoted
1413
+ * (`items.length`).
1400
1414
  *
1401
1415
  * Present ONLY on the reply to a `kind: 'training'` estimate. Absent on hosts
1402
1416
  * that predate civitai/civitai#5434.
@@ -1529,7 +1543,7 @@ export interface BlockTrainingQuote {
1529
1543
  quoteId: string;
1530
1544
  /** The quoted price, in Buzz. */
1531
1545
  total: number;
1532
- /** How many images the prepared dataset holds. */
1546
+ /** How many images the quoted dataset holds. */
1533
1547
  imageCount: number;
1534
1548
  /** ISO-8601. The quote cannot be run after this. */
1535
1549
  expiresAt: string;
@@ -1710,3 +1724,20 @@ export interface AppWorkflow {
1710
1724
  */
1711
1725
  model3dOutputs?: BlockModel3dOutput[];
1712
1726
  }
1727
+ /**
1728
+ * One image of a training dataset ({@link WorkflowBodyTraining.items}) — a blob
1729
+ * this host uploaded for the viewer, and the caption to train it with. The
1730
+ * Training Studio's own `{ air, caption }` shape.
1731
+ *
1732
+ * Host bounds (`blockTrainingDatasetItemsSchema`, civitai/civitai#6461): `air`
1733
+ * is the blob's key ({@link BlockTrainingDataImage.air}) or its Civitai-hosted
1734
+ * blob url — the server keeps only the key; `caption` at most
1735
+ * {@link BLOCK_TRAINING_CAPTION_MAX_CHARS} characters; no other keys;
1736
+ * 1…{@link BLOCK_TRAINING_DATASET_MAX_ITEMS} items per body, and one blob at
1737
+ * most once (keys compare case-insensitively). A body outside them is refused at
1738
+ * the estimate.
1739
+ */
1740
+ export interface BlockTrainingDatasetItem {
1741
+ air: string;
1742
+ caption: string;
1743
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civitai/sdk",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
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",