@civitai/app-sdk 0.65.0 → 0.66.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 +61 -1
- package/dist/blocks/index.d.ts +3 -1
- package/dist/blocks/index.js +2 -0
- package/dist/blocks/types.d.ts +261 -2
- package/dist/blocks/types.js +16 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -140,7 +140,7 @@ interface BlockInitPayload {
|
|
|
140
140
|
| `isModelSlotContext(ctx)` / `isPageSlotContext(ctx)` | Runtime narrowing for the `slotId`-discriminated `BlockContext` union. Real checks on a value that crossed a `postMessage` boundary — they verify every field they assert, not just `slotId`. |
|
|
141
141
|
| `fetchNestedDocument(opts)` | Embed one of your OWN bundled documents as an iframe `srcdoc`, because a nested `<iframe src>` of your own content **cannot load** — see [Nested documents](#nested-documents) below. `NestedDocumentError` carries a `.code` of `'invalid-url' \| 'http-error' \| 'network-error'`. |
|
|
142
142
|
| `isSignedIn(viewer)` | **The sign-in gate.** `isSignedIn(useBlockContext().viewer)` — do not open-code it as `viewer !== null` or `viewer?.signedIn === true`. Which of those is correct has already changed once with the host contract, and this is the one place it is decided. It reads neither `viewer.id` nor `viewer.username` (both `@deprecated`), so nothing written through it changes when those are removed. Need the identity rather than the presence? `useViewer()` — scope-gated and audited per call. |
|
|
143
|
-
| types | `BlockManifestV1`, `ManifestSettings` (+ field types), `BlockContext`, `ModelSlotContext`, `BlockCheckpointInfo`, `ShowcaseImage`, `BlockToken`, `WrappedToken`, `BlockSettings`, `ViewerInfo`, `Theme`, `WorkflowBody`, `BlockTextToImageParams`, `WorkflowBodyCustomComfy` (+ its two arms `WorkflowBodyCustomComfyRecipe` / `WorkflowBodyCustomComfyInline`, and `InlineComfyNode`), `WorkflowBodyStep` / `WorkflowBodyPassThroughStep` (the two arms of `kind: 'step'`), `WorkflowBodyTraining` (+ `AiToolkitTrainingParams`, `BlockTrainingQuote`, `BlockTrainingDatasetItem`, `BlockTrainingDatasetResult` and the `BLOCK_TRAINING_*` bounds), `BlockWorkflowSnapshot`, `WorkflowStatus`, `BlockInitPayload`, `ParentToBlockMessage`, `BlockToParentMessage`. |
|
|
143
|
+
| types | `BlockManifestV1`, `ManifestSettings` (+ field types), `BlockContext`, `ModelSlotContext`, `BlockCheckpointInfo`, `ShowcaseImage`, `BlockToken`, `WrappedToken`, `BlockSettings`, `ViewerInfo`, `Theme`, `WorkflowBody`, `BlockTextToImageParams`, `WorkflowBodyCustomComfy` (+ its two arms `WorkflowBodyCustomComfyRecipe` / `WorkflowBodyCustomComfyInline`, and `InlineComfyNode`), `WorkflowBodyStep` / `WorkflowBodyPassThroughStep` (the two arms of `kind: 'step'`), `WorkflowBodyTraining` (+ `AiToolkitTrainingParams`, `BlockTrainingQuote`, `BlockTrainingDatasetItem`, `BlockTrainingDatasetResult` and the `BLOCK_TRAINING_*` bounds), `WorkflowBodyWorkflow` (+ `WorkflowBodyWorkflowStep`, `WorkflowStepRef`, `WithWorkflowStepRefs`, `BlockWorkflowStepSnapshot` and `BLOCK_WORKFLOW_MAX_STEPS`), `BlockWorkflowSnapshot`, `WorkflowStatus`, `BlockInitPayload`, `ParentToBlockMessage`, `BlockToParentMessage`. |
|
|
144
144
|
|
|
145
145
|
`WorkflowBody`'s `customComfy` member is a discriminated union on `mode`, mirroring
|
|
146
146
|
the host's `blockCustomComfyMemberSchema`. Narrow on the VALUE (`body.mode === 'inline'`),
|
|
@@ -221,6 +221,66 @@ and review sessions. The dataset is prepared over `PREPARE_TRAINING_DATASET`
|
|
|
221
221
|
(civitai/civitai#5438). Use it through `@civitai/blocks-react`'s `usePrepareTrainingDataset()`
|
|
222
222
|
and `useRunTraining()`.
|
|
223
223
|
|
|
224
|
+
`WorkflowBodyWorkflow` (`kind: 'workflow'`) submits **several orchestrator steps as one
|
|
225
|
+
workflow**, 1 to `BLOCK_WORKFLOW_MAX_STEPS` (8), through the same messages as every other kind.
|
|
226
|
+
A value anywhere in a step's `input` may be a `WorkflowStepRef`
|
|
227
|
+
(`{ $ref, path, default?, format? }`) naming `'$arguments'`, an **earlier** step's `name`, or an
|
|
228
|
+
earlier **unnamed** step by position (`'$0'`). A `name` starts with a lowercase
|
|
229
|
+
letter, uses only lowercase letters, digits, `_` and `-`, and is unique (the exact rule is on
|
|
230
|
+
`WorkflowBodyWorkflowStep.name`). `suppressOutput: true` marks an intermediate step whose
|
|
231
|
+
blobs are not surfaced. There is no `maxBuzz`: the ceiling is the app's per-generation budget × the
|
|
232
|
+
number of steps.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import type { WorkflowBody } from '@civitai/app-sdk/blocks';
|
|
236
|
+
|
|
237
|
+
const body: WorkflowBody = {
|
|
238
|
+
kind: 'workflow',
|
|
239
|
+
arguments: { prompt: 'a lighthouse at dusk' },
|
|
240
|
+
steps: [
|
|
241
|
+
{
|
|
242
|
+
name: 'draw',
|
|
243
|
+
$type: 'imageGen',
|
|
244
|
+
input: {
|
|
245
|
+
engine: 'google',
|
|
246
|
+
model: 'nano-banana-2',
|
|
247
|
+
prompt: { $ref: '$arguments', path: 'prompt' },
|
|
248
|
+
},
|
|
249
|
+
suppressOutput: true,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: 'cutout',
|
|
253
|
+
$type: 'imageBackgroundRemoval',
|
|
254
|
+
input: { image: { $ref: 'draw', path: 'output.images[0].url' } },
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
};
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- 🔴 **The estimate is not a maximum.** The orchestrator re-prices a step once the values it
|
|
261
|
+
references are known and charges the difference.
|
|
262
|
+
- **A workflow the host cannot price still proceeds**, reserved at the ceiling above — unless it
|
|
263
|
+
contains a training step (refused without a quote, as on the single-step arm) or a `repeat`
|
|
264
|
+
step at any depth (also refused without a quote, before any reservation, as
|
|
265
|
+
`workflow_repeat_unbounded`).
|
|
266
|
+
- **One author fee per workflow**, on the quoted base, itemised as `cost.authorFee` on the
|
|
267
|
+
estimate. If the workflow bills more, the fee charged is held to the fee shown; a workflow that
|
|
268
|
+
does not succeed has its whole fee reversed, even if earlier steps delivered output.
|
|
269
|
+
- **`repeat` over `arguments` only, at most 16 iterations** (`BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS`,
|
|
270
|
+
nested repeats multiplied): `for.$ref` must be `'$arguments'` and `path` must name an array
|
|
271
|
+
there. A `merge` step's `fields` entries each need a string `$ref` (an earlier step or
|
|
272
|
+
`$arguments`) and a `reduce`. Repeat children appear in `snapshot.steps` as `<name>.<n>`. The
|
|
273
|
+
velocity limit counts one unit per step, and a `repeat` one per iteration.
|
|
274
|
+
- `snapshot.steps` reports each step's `status`, `imageUrls`, `output` and `error`. A `failed`
|
|
275
|
+
workflow can still carry `cost.total > 0` and usable `imageUrls`: steps that succeeded before
|
|
276
|
+
the failing one stay charged.
|
|
277
|
+
- A refused body carries `snapshot.errorCode`: `workflow_step_denied` (a platform-internal
|
|
278
|
+
`$type`), `workflow_ref_invalid` (a reference to the step itself, a later step, or nothing, or a
|
|
279
|
+
step name that breaks the naming rules, or a malformed `repeat`/`merge`),
|
|
280
|
+
`workflow_repeat_unbounded` (a `repeat` not over an array in `arguments`, or over 16 iterations)
|
|
281
|
+
or `workflow_too_many_steps`. The single-step pass-through arm refuses `repeat` outright.
|
|
282
|
+
- Requires a host that knows the kind; an older host refuses the body.
|
|
283
|
+
|
|
224
284
|
### `defineBlock` validator rules
|
|
225
285
|
|
|
226
286
|
**There is no rule list here, and that is the point.** `defineBlock` does not
|
package/dist/blocks/index.d.ts
CHANGED
|
@@ -109,7 +109,9 @@ export { isModelSlotContext, isPageSlotContext } from './types.js';
|
|
|
109
109
|
* in `types.ts` for which of the two it uses and why.
|
|
110
110
|
*/
|
|
111
111
|
export { isSignedIn } from './types.js';
|
|
112
|
-
export type { BlockContext, KnownSlotId, ModelSlotId, PageSlotContext, PageSlotId, UnknownSlotContext, BlockAnalyticsDeclaration, BlockAnalyticsEventDeclaration, BlockAnalyticsPropertyDeclaration, BlockManifest, BlockManifestGood, BlockManifestV1, BlockSettings, BlockToken, ContentRating, ManifestBooleanField, ManifestIframe, ManifestNumberField, ManifestPage, ManifestPreview, ManifestSettingField, ManifestSettings, ManifestStringField, ManifestTarget, ModelSlotContext, SettingScope, SettingWidget, Theme, ViewerInfo, BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockSourceImage, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockPendingImageInfo, BlockImageScanResult, BlockUploadPurpose, BlockNavigateScope, BlockTextToImageParams, BlockWorkflowSnapshot, BlockEstimateBatchAggregate, BlockModelSubstitution, ModelSubstitutionReason, KnownBlockWorkflowErrorCode, BlockStepToolCall, BlockTrainedEpoch, BlockPublishedModel, BuzzAccountType, ShowcaseImage, WorkflowBody, WorkflowBodyTextToImage, WorkflowBodyCustomComfy, WorkflowBodyCustomComfyRecipe, WorkflowBodyCustomComfyInline, InlineComfyNode, WorkflowBodyStep, WorkflowBodyPassThroughStep, WorkflowStatus, BlockBuzzTransaction, BlockBuzzAccount, BlockDailyCompensationResource, BlockViewer, BlockWildcardPack, BlockWildcardPackErrorCode, AppWorkflow, AppWorkflowImage, BlockGatedImage, BlockCollectionFollowErrorCode, BlockCollectionFollowResult, BlockPostSource, BlockCreatePostRequest, BlockCreatePostResult, BlockCreatePostHostError, WorkflowBodyTraining, AiToolkitTrainingParams, AiToolkitTrainingParamsBase, AiToolkitPlainEcosystem, AiToolkitLrScheduler, AiToolkitOptimizerType, BlockTrainingQuote, BlockTrainingDatasetItem, BlockTrainingDatasetResult, BlockTrainingRejectionReason, BlockPrepareTrainingDatasetHostError, BlockRunTrainingHostError, } from './types.js';
|
|
112
|
+
export type { BlockContext, KnownSlotId, ModelSlotId, PageSlotContext, PageSlotId, UnknownSlotContext, BlockAnalyticsDeclaration, BlockAnalyticsEventDeclaration, BlockAnalyticsPropertyDeclaration, BlockManifest, BlockManifestGood, BlockManifestV1, BlockSettings, BlockToken, ContentRating, ManifestBooleanField, ManifestIframe, ManifestNumberField, ManifestPage, ManifestPreview, ManifestSettingField, ManifestSettings, ManifestStringField, ManifestTarget, ModelSlotContext, SettingScope, SettingWidget, Theme, ViewerInfo, BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockSourceImage, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockPendingImageInfo, BlockImageScanResult, BlockUploadPurpose, BlockNavigateScope, BlockTextToImageParams, BlockWorkflowSnapshot, BlockEstimateBatchAggregate, BlockModelSubstitution, ModelSubstitutionReason, KnownBlockWorkflowErrorCode, BlockStepToolCall, BlockTrainedEpoch, BlockPublishedModel, BuzzAccountType, ShowcaseImage, WorkflowBody, WorkflowBodyTextToImage, WorkflowBodyCustomComfy, WorkflowBodyCustomComfyRecipe, WorkflowBodyCustomComfyInline, InlineComfyNode, WorkflowBodyStep, WorkflowBodyPassThroughStep, WorkflowBodyWorkflow, WorkflowBodyWorkflowStep, WorkflowStepRef, WithWorkflowStepRefs, BlockWorkflowStepSnapshot, WorkflowStatus, BlockBuzzTransaction, BlockBuzzAccount, BlockDailyCompensationResource, BlockViewer, BlockWildcardPack, BlockWildcardPackErrorCode, AppWorkflow, AppWorkflowImage, BlockGatedImage, BlockCollectionFollowErrorCode, BlockCollectionFollowResult, BlockPostSource, BlockCreatePostRequest, BlockCreatePostResult, BlockCreatePostHostError, WorkflowBodyTraining, AiToolkitTrainingParams, AiToolkitTrainingParamsBase, AiToolkitPlainEcosystem, AiToolkitLrScheduler, AiToolkitOptimizerType, BlockTrainingQuote, BlockTrainingDatasetItem, BlockTrainingDatasetResult, BlockTrainingRejectionReason, BlockPrepareTrainingDatasetHostError, BlockRunTrainingHostError, } from './types.js';
|
|
113
|
+
/** Host bound for the App Blocks `kind: 'workflow'` body — see `WorkflowBodyWorkflow`. */
|
|
114
|
+
export { BLOCK_WORKFLOW_MAX_STEPS, BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS } from './types.js';
|
|
113
115
|
/**
|
|
114
116
|
* Host bounds for the App Blocks `kind: 'training'` flow, mirrored from
|
|
115
117
|
* civitai/civitai's zod — see `WorkflowBodyTraining`.
|
package/dist/blocks/index.js
CHANGED
|
@@ -108,6 +108,8 @@ export { isModelSlotContext, isPageSlotContext } from './types.js';
|
|
|
108
108
|
* in `types.ts` for which of the two it uses and why.
|
|
109
109
|
*/
|
|
110
110
|
export { isSignedIn } from './types.js';
|
|
111
|
+
/** Host bound for the App Blocks `kind: 'workflow'` body — see `WorkflowBodyWorkflow`. */
|
|
112
|
+
export { BLOCK_WORKFLOW_MAX_STEPS, BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS } from './types.js';
|
|
111
113
|
/**
|
|
112
114
|
* Host bounds for the App Blocks `kind: 'training'` flow, mirrored from
|
|
113
115
|
* civitai/civitai's zod — see `WorkflowBodyTraining`.
|
package/dist/blocks/types.d.ts
CHANGED
|
@@ -1168,6 +1168,9 @@ export type WorkflowBodyStep = {
|
|
|
1168
1168
|
* checkpoint itself.
|
|
1169
1169
|
* - `$type` is bounded to **1…64 characters** and `input` to **262144 bytes**
|
|
1170
1170
|
* (256 KB) serialized. Both REJECT; neither truncates.
|
|
1171
|
+
* - **`repeat` is refused on this arm**, outright: a `repeat` may only
|
|
1172
|
+
* iterate an array in a body's own `arguments`, and this arm has none. Use
|
|
1173
|
+
* a `kind: 'workflow'` body ({@link WorkflowBodyWorkflow}) to repeat a step.
|
|
1171
1174
|
* - `maxBuzz` is the app's spend knob, and the host's quote can raise the
|
|
1172
1175
|
* reservation above it — see its own note below.
|
|
1173
1176
|
*
|
|
@@ -1249,6 +1252,196 @@ export type WorkflowBodyPassThroughStep = {
|
|
|
1249
1252
|
*/
|
|
1250
1253
|
maxBuzz: number;
|
|
1251
1254
|
};
|
|
1255
|
+
/**
|
|
1256
|
+
* The most steps one `kind: 'workflow'` body may carry. The host refuses a
|
|
1257
|
+
* longer list with `errorCode: 'workflow_too_many_steps'`; an empty list is
|
|
1258
|
+
* refused too.
|
|
1259
|
+
*/
|
|
1260
|
+
export declare const BLOCK_WORKFLOW_MAX_STEPS = 8;
|
|
1261
|
+
/**
|
|
1262
|
+
* The most times one top-level `repeat` step of a `kind: 'workflow'` body may
|
|
1263
|
+
* run its template, NESTED REPEATS MULTIPLIED (a 4-item repeat inside a 4-item
|
|
1264
|
+
* repeat is 16). The host refuses more with
|
|
1265
|
+
* `errorCode: 'workflow_repeat_unbounded'`.
|
|
1266
|
+
*/
|
|
1267
|
+
export declare const BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS = 16;
|
|
1268
|
+
/**
|
|
1269
|
+
* A REFERENCE inside a `kind: 'workflow'` step's `input` — the orchestrator's
|
|
1270
|
+
* own mechanism for feeding one step's result into a later step. Put it
|
|
1271
|
+
* anywhere a value would go, at any depth.
|
|
1272
|
+
*
|
|
1273
|
+
* `$ref` names where the value comes from:
|
|
1274
|
+
* - `'$arguments'` — the body's own {@link WorkflowBodyWorkflow.arguments};
|
|
1275
|
+
* - the `name` of an EARLIER step in the same body;
|
|
1276
|
+
* - `'$<index>'` — an EARLIER step you did NOT name, by its zero-based
|
|
1277
|
+
* position (`'$0'` is the first step). A step that has a `name` is
|
|
1278
|
+
* referenced by that name only.
|
|
1279
|
+
*
|
|
1280
|
+
* An object counts as a reference only when it has BOTH `$ref` and `path` and
|
|
1281
|
+
* no key other than `default` / `format`; anything else is ordinary input.
|
|
1282
|
+
*
|
|
1283
|
+
* `path` selects the value inside that source, e.g. `'output.images[0].url'`
|
|
1284
|
+
* for a step, or `'prompt'` for `$arguments`. The orchestrator resolves it; the
|
|
1285
|
+
* path is not checked by this package or by the host.
|
|
1286
|
+
*
|
|
1287
|
+
* 🔴 A reference may only point BACKWARDS. A step that names itself, a later
|
|
1288
|
+
* step, or a step that does not exist is refused by the host with
|
|
1289
|
+
* `errorCode: 'workflow_ref_invalid'` before anything is priced or reserved.
|
|
1290
|
+
* A body may hold at most 64 references, in inputs nested at most 32 levels.
|
|
1291
|
+
*
|
|
1292
|
+
* `default` is the value used when the path resolves to nothing; `format` is a
|
|
1293
|
+
* template applied to the resolved value. Both are passed to the orchestrator
|
|
1294
|
+
* unmodified.
|
|
1295
|
+
*/
|
|
1296
|
+
export type WorkflowStepRef = {
|
|
1297
|
+
$ref: '$arguments' | `$${number}` | (string & {});
|
|
1298
|
+
path: string;
|
|
1299
|
+
default?: unknown;
|
|
1300
|
+
format?: string;
|
|
1301
|
+
};
|
|
1302
|
+
/**
|
|
1303
|
+
* `T` with a {@link WorkflowStepRef} allowed in place of any value, at any
|
|
1304
|
+
* depth. Use it to keep a step input typed while still wiring references in:
|
|
1305
|
+
*
|
|
1306
|
+
* ```ts
|
|
1307
|
+
* type CutoutInput = { image: string; format?: 'png' | 'webp' };
|
|
1308
|
+
* const input: WithWorkflowStepRefs<CutoutInput> = {
|
|
1309
|
+
* image: { $ref: 'draw', path: 'output.images[0].url' },
|
|
1310
|
+
* format: 'png',
|
|
1311
|
+
* };
|
|
1312
|
+
* ```
|
|
1313
|
+
*/
|
|
1314
|
+
export type WithWorkflowStepRefs<T> = WorkflowStepRef | (T extends ReadonlyArray<infer U> ? Array<WithWorkflowStepRefs<U>> : T extends object ? {
|
|
1315
|
+
[K in keyof T]: WithWorkflowStepRefs<T[K]>;
|
|
1316
|
+
} : T);
|
|
1317
|
+
/** One step of a {@link WorkflowBodyWorkflow}. */
|
|
1318
|
+
export type WorkflowBodyWorkflowStep = {
|
|
1319
|
+
/**
|
|
1320
|
+
* What later steps call this one in a {@link WorkflowStepRef}, and the `name`
|
|
1321
|
+
* it reports under on {@link BlockWorkflowSnapshot.steps}. Optional: an
|
|
1322
|
+
* unnamed step is named by its position (`'$0'`, `'$1'`, …).
|
|
1323
|
+
*
|
|
1324
|
+
* A lowercase letter followed by up to 31 of `a-z`, `0-9`, `_` or `-`
|
|
1325
|
+
* (`/^[a-z][a-z0-9_-]{0,31}$/`), unique within the body, and not
|
|
1326
|
+
* `'block-step'`, which is reserved. A name that breaks a rule is refused
|
|
1327
|
+
* with `errorCode: 'workflow_ref_invalid'`.
|
|
1328
|
+
*/
|
|
1329
|
+
name?: string;
|
|
1330
|
+
/**
|
|
1331
|
+
* The ORCHESTRATOR step type to run, verbatim — e.g. `'imageGen'`. Not
|
|
1332
|
+
* resolved against any allowlist: it is refused only when it names a
|
|
1333
|
+
* platform-internal type (scanners, moderation classifiers, hashing, web
|
|
1334
|
+
* scrape/search, and the retired `textToImage` step type), with
|
|
1335
|
+
* `errorCode: 'workflow_step_denied'`. 1…64 characters.
|
|
1336
|
+
*
|
|
1337
|
+
* Two step types are read by shape, because they name their sources outside
|
|
1338
|
+
* a {@link WorkflowStepRef}:
|
|
1339
|
+
* - **`repeat` — over `arguments` only, at most
|
|
1340
|
+
* {@link BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS} iterations.** Its input must
|
|
1341
|
+
* be exactly `{ for: { $ref, path, as }, template: { $type, name?, input? } }`
|
|
1342
|
+
* with `for.$ref === '$arguments'` and `path` naming an ARRAY in the body's
|
|
1343
|
+
* `arguments`; its length is the iteration count, nested repeats
|
|
1344
|
+
* multiplied. A repeat over another step's output, a missing or non-array
|
|
1345
|
+
* path, or too many iterations is refused with
|
|
1346
|
+
* `errorCode: 'workflow_repeat_unbounded'`; a wrong shape, or repeats nested
|
|
1347
|
+
* more than 4 deep, with `workflow_ref_invalid`. Inside the template the
|
|
1348
|
+
* `as` name is a source a reference may name; it may not equal a step name.
|
|
1349
|
+
* The template's `$type` is held to the denylist too.
|
|
1350
|
+
* - **`merge`** — every entry of `input.fields` needs a string `$ref` and a
|
|
1351
|
+
* `reduce`, and each `$ref` must name `$arguments` or an EARLIER step,
|
|
1352
|
+
* never a repeat variable. Each counts toward the 64-reference cap.
|
|
1353
|
+
* Otherwise `workflow_ref_invalid`.
|
|
1354
|
+
*/
|
|
1355
|
+
$type: string;
|
|
1356
|
+
/**
|
|
1357
|
+
* The step's own input object. Any value in it, at any depth, may be a
|
|
1358
|
+
* {@link WorkflowStepRef}. The orchestrator's per-`$type` schema is the only
|
|
1359
|
+
* authority for what a given `$type` accepts. Every step's `input` plus the
|
|
1360
|
+
* body's `arguments` may total at most 262144 bytes (256 KB) serialized.
|
|
1361
|
+
*/
|
|
1362
|
+
input: Record<string, unknown>;
|
|
1363
|
+
/**
|
|
1364
|
+
* `true` marks an INTERMEDIATE step: its blobs are not surfaced, neither on
|
|
1365
|
+
* its own {@link BlockWorkflowStepSnapshot.imageUrls} nor in the top-level
|
|
1366
|
+
* {@link BlockWorkflowSnapshot.imageUrls}. The step still runs and is still
|
|
1367
|
+
* charged.
|
|
1368
|
+
*/
|
|
1369
|
+
suppressOutput?: boolean;
|
|
1370
|
+
};
|
|
1371
|
+
/**
|
|
1372
|
+
* The `workflow` member of {@link WorkflowBody} — SEVERAL orchestrator steps
|
|
1373
|
+
* submitted as ONE workflow, where a later step can consume an earlier step's
|
|
1374
|
+
* result through a {@link WorkflowStepRef}. It travels through the same
|
|
1375
|
+
* messages and hooks as every other kind (`estimate`, `submit`, `watch`,
|
|
1376
|
+
* `cancel`, a batch-estimate cell, `useWorkflowBatch`).
|
|
1377
|
+
*
|
|
1378
|
+
* Between 1 and {@link BLOCK_WORKFLOW_MAX_STEPS} steps. There is no `maxBuzz`:
|
|
1379
|
+
* the spend ceiling is the app's per-generation budget × the number of steps,
|
|
1380
|
+
* enforced by the host. The host's schema is strict: an unknown key on the
|
|
1381
|
+
* body or on a step is rejected, not dropped.
|
|
1382
|
+
*
|
|
1383
|
+
* 🔴 THREE THINGS ABOUT THE PRICE, all of them different from a single-step
|
|
1384
|
+
* body:
|
|
1385
|
+
* 1. **The estimate is NOT a maximum.** When a step's input references an
|
|
1386
|
+
* earlier step, the orchestrator re-prices that step once the referenced
|
|
1387
|
+
* values are known and charges the difference. Show the estimate as an
|
|
1388
|
+
* estimate; never as "you will pay at most".
|
|
1389
|
+
* 2. **A workflow the host cannot price still proceeds.** It is reserved at
|
|
1390
|
+
* the ceiling above instead of at a quote — unless it contains a training
|
|
1391
|
+
* step, which is refused without a quote exactly as on the single-step arm
|
|
1392
|
+
* (a `training-quote-*` `errorCode`), or a `repeat` step at any depth,
|
|
1393
|
+
* which is refused without a quote too, before any reservation, with
|
|
1394
|
+
* `errorCode: 'workflow_repeat_unbounded'` — retrying later may succeed.
|
|
1395
|
+
* 3. **One author fee per workflow**, not one per step, computed on the
|
|
1396
|
+
* QUOTED base. The estimate's `cost.authorFee` is that single fee, already
|
|
1397
|
+
* inside `cost.total`. If the workflow bills more than the quote, the fee
|
|
1398
|
+
* charged is held to the fee shown. A workflow that does not succeed has
|
|
1399
|
+
* its WHOLE fee reversed, even when earlier steps delivered output.
|
|
1400
|
+
*
|
|
1401
|
+
* The app's velocity limit counts one unit per step, and a `repeat` step one
|
|
1402
|
+
* per iteration (nested repeats multiplied) instead of one.
|
|
1403
|
+
*
|
|
1404
|
+
* 🔴 A FAILED WORKFLOW CAN STILL HAVE COST AND IMAGES. Steps that succeeded
|
|
1405
|
+
* before the failing one stay charged, so a `failed` snapshot can carry
|
|
1406
|
+
* `cost.total > 0` and usable `imageUrls`. See {@link BlockWorkflowSnapshot.steps}.
|
|
1407
|
+
*
|
|
1408
|
+
* 🔴 REQUIRES A HOST THAT KNOWS THIS KIND. An older host refuses the body.
|
|
1409
|
+
*
|
|
1410
|
+
* @example An image step whose output a second step consumes.
|
|
1411
|
+
* ```ts
|
|
1412
|
+
* const body: WorkflowBody = {
|
|
1413
|
+
* kind: 'workflow',
|
|
1414
|
+
* arguments: { prompt: 'a lighthouse at dusk' },
|
|
1415
|
+
* steps: [
|
|
1416
|
+
* {
|
|
1417
|
+
* name: 'draw',
|
|
1418
|
+
* $type: 'imageGen',
|
|
1419
|
+
* input: {
|
|
1420
|
+
* engine: 'google',
|
|
1421
|
+
* model: 'nano-banana-2',
|
|
1422
|
+
* prompt: { $ref: '$arguments', path: 'prompt' },
|
|
1423
|
+
* },
|
|
1424
|
+
* suppressOutput: true,
|
|
1425
|
+
* },
|
|
1426
|
+
* {
|
|
1427
|
+
* name: 'cutout',
|
|
1428
|
+
* $type: 'imageBackgroundRemoval',
|
|
1429
|
+
* input: { image: { $ref: 'draw', path: 'output.images[0].url' } },
|
|
1430
|
+
* },
|
|
1431
|
+
* ],
|
|
1432
|
+
* };
|
|
1433
|
+
* ```
|
|
1434
|
+
*/
|
|
1435
|
+
export type WorkflowBodyWorkflow = {
|
|
1436
|
+
kind: 'workflow';
|
|
1437
|
+
/** The steps, in order. 1…{@link BLOCK_WORKFLOW_MAX_STEPS}. */
|
|
1438
|
+
steps: WorkflowBodyWorkflowStep[];
|
|
1439
|
+
/**
|
|
1440
|
+
* Values the steps can read through `{ $ref: '$arguments', path }` — one
|
|
1441
|
+
* place to put a prompt or a seed that several steps share.
|
|
1442
|
+
*/
|
|
1443
|
+
arguments?: Record<string, unknown>;
|
|
1444
|
+
};
|
|
1252
1445
|
/** Ceiling on what ONE confirmed `kind: 'training'` run may cost, in Buzz. Host constant `BLOCK_TRAINING_MAX_BUZZ_PER_RUN`. */
|
|
1253
1446
|
export declare const BLOCK_TRAINING_MAX_BUZZ_PER_RUN = 5000;
|
|
1254
1447
|
/** Max images in one prepared training dataset. Host constant `BLOCK_TRAINING_DATASET_MAX_ITEMS`. */
|
|
@@ -1431,6 +1624,10 @@ export interface WorkflowBodyTraining {
|
|
|
1431
1624
|
* on a server-prepared dataset of the viewer's own images. ESTIMATE ONLY
|
|
1432
1625
|
* through `useBuzzWorkflow`; it runs through `useRunTraining()`, whose
|
|
1433
1626
|
* host-chrome consent dialog is the only way to confirm its quote.
|
|
1627
|
+
* - {@link WorkflowBodyWorkflow} (`kind: 'workflow'`) — up to
|
|
1628
|
+
* {@link BLOCK_WORKFLOW_MAX_STEPS} orchestrator steps submitted as one
|
|
1629
|
+
* workflow, a later step consuming an earlier one's result through a
|
|
1630
|
+
* {@link WorkflowStepRef}. Its estimate is not a maximum — read its doc.
|
|
1434
1631
|
*
|
|
1435
1632
|
* `kind: 'step'` is therefore itself a union, discriminated on the PRESENCE of
|
|
1436
1633
|
* `step` — the same nesting {@link WorkflowBodyCustomComfy} has on `mode`.
|
|
@@ -1447,7 +1644,7 @@ export interface WorkflowBodyTraining {
|
|
|
1447
1644
|
* over `kind`. Host code that must handle every member gets a compile error
|
|
1448
1645
|
* pointing at the new one, which is the intended behaviour.
|
|
1449
1646
|
*/
|
|
1450
|
-
export type WorkflowBody = WorkflowBodyTextToImage | WorkflowBodyCustomComfy | WorkflowBodyStep | WorkflowBodyPassThroughStep | WorkflowBodyTraining;
|
|
1647
|
+
export type WorkflowBody = WorkflowBodyTextToImage | WorkflowBodyCustomComfy | WorkflowBodyStep | WorkflowBodyPassThroughStep | WorkflowBodyTraining | WorkflowBodyWorkflow;
|
|
1451
1648
|
/**
|
|
1452
1649
|
* The host-mediated view of an orchestrator workflow that an iframe block
|
|
1453
1650
|
* receives over `postMessage`.
|
|
@@ -1487,6 +1684,9 @@ export interface BlockWorkflowSnapshot {
|
|
|
1487
1684
|
* orchestrator price quote, which refuses before any fee is looked up; and
|
|
1488
1685
|
* the kinds that price no fee (`customComfy`, pass-through `step`,
|
|
1489
1686
|
* `training`). **Do not read absent as `0`** — show `total` on its own.
|
|
1687
|
+
*
|
|
1688
|
+
* A `kind: 'workflow'` estimate itemises it too, and it is ONE fee for the
|
|
1689
|
+
* whole workflow however many steps it has.
|
|
1490
1690
|
*/
|
|
1491
1691
|
authorFee?: number;
|
|
1492
1692
|
};
|
|
@@ -1507,6 +1707,8 @@ export interface BlockWorkflowSnapshot {
|
|
|
1507
1707
|
* (which rejects with `WorkflowSubmitError`, before anything is reserved or
|
|
1508
1708
|
* charged), and to that body's cell in a batch estimate. Read it from the
|
|
1509
1709
|
* error's `.snapshot.errorCode`. The `kind: 'training'` arm does NOT set it.
|
|
1710
|
+
* A refused `kind: 'workflow'` body ({@link WorkflowBodyWorkflow}) sets it in
|
|
1711
|
+
* the same shape, on the same three replies.
|
|
1510
1712
|
*
|
|
1511
1713
|
* The values the host sends today ({@link KnownBlockWorkflowErrorCode}):
|
|
1512
1714
|
* - `'training-quote-rejected'` — the orchestrator refused the request
|
|
@@ -1515,6 +1717,21 @@ export interface BlockWorkflowSnapshot {
|
|
|
1515
1717
|
* - `'training-quote-unavailable'` — no usable answer (an outage, a timeout,
|
|
1516
1718
|
* a rate limit, insufficient funds, …). Retrying later may succeed.
|
|
1517
1719
|
* - `'training-quote-unpriced'` — the orchestrator answered without a price.
|
|
1720
|
+
* - `'workflow_step_denied'` — a step of a `kind: 'workflow'` body names a
|
|
1721
|
+
* platform-internal `$type`. Remove or replace that step.
|
|
1722
|
+
* - `'workflow_ref_invalid'` — a {@link WorkflowStepRef} in a step's `input`
|
|
1723
|
+
* points at the step itself, a later step, or nothing; or a step `name`
|
|
1724
|
+
* breaks the naming rules (see {@link WorkflowBodyWorkflowStep.name}).
|
|
1725
|
+
* `error` names the step by its position.
|
|
1726
|
+
* - `'workflow_too_many_steps'` — more than
|
|
1727
|
+
* {@link BLOCK_WORKFLOW_MAX_STEPS} steps.
|
|
1728
|
+
* - `'workflow_repeat_unbounded'` — a `repeat` step iterates something other
|
|
1729
|
+
* than an array in the body's `arguments`, or more than
|
|
1730
|
+
* {@link BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS} times, nested repeats
|
|
1731
|
+
* multiplied; or the workflow has a `repeat` and the host could get no
|
|
1732
|
+
* price quote for it (`error` then reads `… a workflow with a repeat needs
|
|
1733
|
+
* a price quote and none could be obtained; try again`, and a retry may
|
|
1734
|
+
* succeed).
|
|
1518
1735
|
*
|
|
1519
1736
|
* 🔴 AN UNKNOWN VALUE IS POSSIBLE: the host may add codes, and the SDK's
|
|
1520
1737
|
* inbound validator accepts any string here. Handle an unrecognised code as a
|
|
@@ -1722,6 +1939,48 @@ export interface BlockWorkflowSnapshot {
|
|
|
1722
1939
|
* that predate civitai/civitai#5434.
|
|
1723
1940
|
*/
|
|
1724
1941
|
trainingQuote?: BlockTrainingQuote;
|
|
1942
|
+
/**
|
|
1943
|
+
* The steps of a `kind: 'workflow'` run ({@link WorkflowBodyWorkflow}), in
|
|
1944
|
+
* the orchestrator's order, each with its own status and results. The steps a
|
|
1945
|
+
* `repeat` step generates follow it, named `<repeat name>.<n>`, so the list
|
|
1946
|
+
* can be longer than the body's.
|
|
1947
|
+
*
|
|
1948
|
+
* The top-level fields keep their meaning: `status` is the workflow's,
|
|
1949
|
+
* `imageUrls` is the union of every step that did NOT set `suppressOutput`,
|
|
1950
|
+
* and `cost` is the whole workflow's.
|
|
1951
|
+
*
|
|
1952
|
+
* 🔴 A `failed` WORKFLOW IS NOT AN EMPTY ONE. Steps that succeeded before the
|
|
1953
|
+
* failing step stay charged and keep their results, so a snapshot with
|
|
1954
|
+
* `status: 'failed'` can carry `cost.total > 0` and usable `imageUrls`. Read
|
|
1955
|
+
* `steps` to see which step failed (`status: 'failed'`, with its `error`)
|
|
1956
|
+
* and which finished.
|
|
1957
|
+
*
|
|
1958
|
+
* Read it from the poll and cancel replies of a `kind: 'workflow'` run; do
|
|
1959
|
+
* not rely on it being on the submit reply. ABSENT for every other kind, on
|
|
1960
|
+
* an estimate (which creates no workflow) and on a host that predates it.
|
|
1961
|
+
*/
|
|
1962
|
+
steps?: BlockWorkflowStepSnapshot[];
|
|
1963
|
+
}
|
|
1964
|
+
/** One entry of {@link BlockWorkflowSnapshot.steps}. */
|
|
1965
|
+
export interface BlockWorkflowStepSnapshot {
|
|
1966
|
+
/** The step's `name` from the body, or the name the host gave an unnamed step. */
|
|
1967
|
+
name: string;
|
|
1968
|
+
/** The orchestrator step type that ran. */
|
|
1969
|
+
$type: string;
|
|
1970
|
+
status: 'pending' | 'processing' | 'succeeded' | 'failed' | 'expired' | 'canceled';
|
|
1971
|
+
/**
|
|
1972
|
+
* This step's own image urls. Omitted when it has none, and always omitted
|
|
1973
|
+
* for a step submitted with `suppressOutput: true`.
|
|
1974
|
+
*/
|
|
1975
|
+
imageUrls?: string[];
|
|
1976
|
+
/**
|
|
1977
|
+
* The step's raw orchestrator output, minus its blobs — the same treatment
|
|
1978
|
+
* and the same caveats as {@link BlockWorkflowSnapshot.stepOutputs}: its shape
|
|
1979
|
+
* is whatever the orchestrator returns for that `$type`, and it is UNSCANNED.
|
|
1980
|
+
*/
|
|
1981
|
+
output?: unknown;
|
|
1982
|
+
/** Why this step failed. Diagnostic text; do not render it verbatim. */
|
|
1983
|
+
error?: string;
|
|
1725
1984
|
}
|
|
1726
1985
|
/**
|
|
1727
1986
|
* The run total a BATCH estimate reports beside its per-cell snapshots
|
|
@@ -1781,7 +2040,7 @@ export type ModelSubstitutionReason = 'wrong-workflow' | 'unrecognized' | 'gated
|
|
|
1781
2040
|
* and the SDK's inbound validator accepts any string. Handle an unrecognised
|
|
1782
2041
|
* code as a generic failure.
|
|
1783
2042
|
*/
|
|
1784
|
-
export type KnownBlockWorkflowErrorCode = 'training-quote-rejected' | 'training-quote-unavailable' | 'training-quote-unpriced';
|
|
2043
|
+
export type KnownBlockWorkflowErrorCode = 'training-quote-rejected' | 'training-quote-unavailable' | 'training-quote-unpriced' | 'workflow_step_denied' | 'workflow_ref_invalid' | 'workflow_too_many_steps' | 'workflow_repeat_unbounded';
|
|
1785
2044
|
/** One entry of {@link BlockWorkflowSnapshot.modelSubstitutions}. */
|
|
1786
2045
|
export interface BlockModelSubstitution {
|
|
1787
2046
|
/** The checkpoint version id the block asked for. */
|
package/dist/blocks/types.js
CHANGED
|
@@ -115,6 +115,22 @@ export function isSignedIn(viewer) {
|
|
|
115
115
|
return viewer !== null && viewer !== undefined;
|
|
116
116
|
}
|
|
117
117
|
// ============================================================
|
|
118
|
+
// App Blocks MULTI-STEP kind (`kind: 'workflow'`)
|
|
119
|
+
// ============================================================
|
|
120
|
+
/**
|
|
121
|
+
* The most steps one `kind: 'workflow'` body may carry. The host refuses a
|
|
122
|
+
* longer list with `errorCode: 'workflow_too_many_steps'`; an empty list is
|
|
123
|
+
* refused too.
|
|
124
|
+
*/
|
|
125
|
+
export const BLOCK_WORKFLOW_MAX_STEPS = 8;
|
|
126
|
+
/**
|
|
127
|
+
* The most times one top-level `repeat` step of a `kind: 'workflow'` body may
|
|
128
|
+
* run its template, NESTED REPEATS MULTIPLIED (a 4-item repeat inside a 4-item
|
|
129
|
+
* repeat is 16). The host refuses more with
|
|
130
|
+
* `errorCode: 'workflow_repeat_unbounded'`.
|
|
131
|
+
*/
|
|
132
|
+
export const BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS = 16;
|
|
133
|
+
// ============================================================
|
|
118
134
|
// App Blocks TRAINING kind (`kind: 'training'`)
|
|
119
135
|
// ============================================================
|
|
120
136
|
//
|
package/dist/index.d.ts
CHANGED
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
*
|
|
26
26
|
* - **`./blocks`** — importing it RUNS `./safe-storage` for its side effect
|
|
27
27
|
* (repairing `localStorage`/`sessionStorage` at an opaque origin). Folding
|
|
28
|
-
*
|
|
28
|
+
* 167 symbols and that side effect into the root would make every OAuth app
|
|
29
29
|
* that writes `import { exchangeCode } from '@civitai/app-sdk'` pay for the
|
|
30
30
|
* Civitai-Apps contract it does not use. Blocks and OAuth apps are disjoint
|
|
31
31
|
* audiences; see this package's README.
|
|
32
|
-
* 🔴 That
|
|
32
|
+
* 🔴 That 167 is ASSERTED, not merely quoted — by
|
|
33
33
|
* `packages/civitai-app-sdk/test/export-surface.test.ts`, which pins
|
|
34
34
|
* `surface.get('./blocks').size`. It said 119 here against a real 125 until
|
|
35
35
|
* 2026-10-04, because the existing checks pin the root as an exact union and
|
package/dist/index.js
CHANGED
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
*
|
|
26
26
|
* - **`./blocks`** — importing it RUNS `./safe-storage` for its side effect
|
|
27
27
|
* (repairing `localStorage`/`sessionStorage` at an opaque origin). Folding
|
|
28
|
-
*
|
|
28
|
+
* 167 symbols and that side effect into the root would make every OAuth app
|
|
29
29
|
* that writes `import { exchangeCode } from '@civitai/app-sdk'` pay for the
|
|
30
30
|
* Civitai-Apps contract it does not use. Blocks and OAuth apps are disjoint
|
|
31
31
|
* audiences; see this package's README.
|
|
32
|
-
* 🔴 That
|
|
32
|
+
* 🔴 That 167 is ASSERTED, not merely quoted — by
|
|
33
33
|
* `packages/civitai-app-sdk/test/export-surface.test.ts`, which pins
|
|
34
34
|
* `surface.get('./blocks').size`. It said 119 here against a real 125 until
|
|
35
35
|
* 2026-10-04, because the existing checks pin the root as an exact union and
|
package/package.json
CHANGED