@civitai/app-sdk 0.75.0 → 0.77.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 +21 -6
- package/dist/blocks/index.d.ts +1 -1
- package/dist/blocks/messages.d.ts +18 -16
- package/dist/blocks/messages.js +0 -1
- package/dist/blocks/types.d.ts +93 -91
- package/dist/blocks/types.js +9 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/vite/index.d.ts +29 -0
- package/dist/vite/index.js +81 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ pnpm add @civitai/app-sdk
|
|
|
32
32
|
| `orchestrator/steps` — `WorkflowStepTemplates`, `WorkflowStepTemplateFor`, `WorkflowStepInputFor`, `AnyWorkflowStepTemplate`, `TypedWorkflowTemplate` | **Type-only** subpath (0 runtime bytes) keying the orchestrator's generated workflow-step shapes from `@civitai/client` by wire `$type`, so apps compose real step bodies against types that track the spec instead of hand-maintained copies. Requires the optional peer `@civitai/client@beta`. Type surface only — it grants no submit permission; see "Typed step shapes" below. |
|
|
33
33
|
| `blocks/*` — `BlockManifestError`, `BLOCK_SCOPES`, `BLOCK_SCOPE_PATTERN`, `isMessage`, types (`BlockManifestV1`, `BlockContext`, `BlockToken`, `BlockSettings`, `ViewerInfo`, `ThemeInfo`, `BlockWorkflowSnapshot`, `BlockInitPayload`, `ParentToBlockMessage`, `BlockToParentMessage`, …) | Framework-agnostic contract for [Civitai Apps](https://github.com/civitai/civitai-app-starters/blob/main/docs/build-your-first-app-block.md). Ships a byte-identical copy of the server-published canonical JSON Schema (draft 2020-12, https://civitai.com/schemas/app-block/v1.json) at the `./schemas/app-block/v1.json` subpath for offline validation; a CI drift-check keeps it in sync. Runtime-agnostic and **zero runtime dependencies** — no React, no DOM types, nothing in your install graph. Hooks and the iframe transport live in a separate package. |
|
|
34
34
|
| `manifest/*` — `defineBlock`, `SCHEMA_DIVERGENCES`, `KNOWN_GAPS` (**Node only**) | Build-time manifest validation. `defineBlock(config)` compiles the vendored canonical schema with [Ajv](https://ajv.js.org) and validates a `BlockManifestV1` against it, so authoring mistakes surface in `pnpm dev` instead of at `civitai app validate`/submit. It is **derived from the schema, not a hand-written mirror of it** — that mirror is what produced [#330](https://github.com/civitai/civitai-app-starters/issues/330). Needs `node:fs` and the optional peer `ajv`, which is why it is not on the browser-facing `./blocks` surface. |
|
|
35
|
-
| `vite/*` — `blockManifestPlugin` (**Node only**) | A Vite plugin wrapping `defineBlock`, firing from `configResolved` — the one hook Vite calls on both the dev-server and the build path. Every block scaffold registers it, so `pnpm dev`, `pnpm dev:harness` and `pnpm build` all fail on a bad manifest with the offending field path. Optional peers: `ajv` (runtime) and `vite` (types only). |
|
|
35
|
+
| `vite/*` — `blockManifestPlugin` (**Node only**) | A Vite plugin wrapping `defineBlock`, firing from `configResolved` — the one hook Vite calls on both the dev-server and the build path. Every block scaffold registers it, so `pnpm dev`, `pnpm dev:harness` and `pnpm build` all fail on a bad manifest with the offending field path. On the dev server only, it also exposes the manifest's `scopes` + `storage` to `@civitai/sdk` for a dev-tunnel local preview. Optional peers: `ajv` (runtime) and `vite` (types only). |
|
|
36
36
|
|
|
37
37
|
## Entry points, and what the root barrel is
|
|
38
38
|
|
|
@@ -151,7 +151,7 @@ interface BlockInitPayload {
|
|
|
151
151
|
| `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`. |
|
|
152
152
|
| `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'`. |
|
|
153
153
|
| `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. |
|
|
154
|
-
| 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`, `
|
|
154
|
+
| 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`, `BlockTrainingDataImage`, `BlockTrainingDataUploadResult`, `BlockRunTrainingHostError` and the `BLOCK_TRAINING_*` bounds), `WorkflowBodyWorkflow` (+ `WorkflowBodyWorkflowStep`, `WorkflowStepRef`, `WithWorkflowStepRefs`, `BlockWorkflowStepSnapshot` and `BLOCK_WORKFLOW_MAX_STEPS`), `BlockStepQuote` / `BlockRunConfirmedStepHostError` (+ `BLOCK_CONFIRMED_STEP_MAX_BUZZ_PER_JOB`, `BLOCK_STEP_QUOTE_ID_REGEX`), `BlockModel3dOutput`, `BlockWorkflowSnapshot`, `WorkflowStatus`, `BlockInitPayload`, `ParentToBlockMessage`, `BlockToParentMessage`. |
|
|
155
155
|
|
|
156
156
|
`WorkflowBody`'s `customComfy` member is a discriminated union on `mode`, mirroring
|
|
157
157
|
the host's `blockCustomComfyMemberSchema`. Narrow on the VALUE (`body.mode === 'inline'`),
|
|
@@ -267,15 +267,21 @@ const rigged = pickModel(snapshot, 'fbx', 'riggedFbxModel');
|
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
`WorkflowBodyTraining` (`kind: 'training'`) is the **quoted** way to train: an ai-toolkit LoRA
|
|
270
|
-
run on
|
|
271
|
-
`blockTrainingBodySchema` (civitai/civitai#5434).
|
|
270
|
+
run on images the viewer uploaded through the host, mirroring the host's
|
|
271
|
+
`blockTrainingBodySchema` (civitai/civitai#5434, #6461). Its dataset is `items: [{ air, caption }]`
|
|
272
|
+
(`BlockTrainingDatasetItem`; at most `BLOCK_TRAINING_DATASET_MAX_ITEMS` items and
|
|
273
|
+
`BLOCK_TRAINING_CAPTION_MAX_CHARS` caption characters, one blob at most once). There is no `maxBuzz` and no timeout — the
|
|
272
274
|
`estimate` reply carries `snapshot.trainingQuote` (`quoteId`, `total`, `imageCount`,
|
|
273
275
|
`expiresAt`), and the run starts only through the `RUN_TRAINING` bridge, after the viewer
|
|
274
276
|
confirms that price in Civitai's own dialog. A confirmed run may exceed the token's per-call
|
|
275
277
|
budget, up to `BLOCK_TRAINING_MAX_BUZZ_PER_RUN` (5,000). Page apps only, `ai:write:budgeted`,
|
|
276
278
|
behind the host flag `app-blocks-training-kind` (off by default), and refused from development
|
|
277
|
-
and review sessions. The
|
|
278
|
-
|
|
279
|
+
and review sessions. The images are uploaded over `OPEN_IMAGE_UPLOAD { purpose: 'trainingData' }`,
|
|
280
|
+
which replies `IMAGE_UPLOAD_RESULT { selected: { images: [{ url, air }] } }`
|
|
281
|
+
(`BlockTrainingDataUploadResult`); the host refuses a run whose quote names a blob it did not
|
|
282
|
+
upload for the block, with the `BlockRunTrainingHostError` `training data not uploaded here`.
|
|
283
|
+
`PREPARE_TRAINING_DATASET` (the server-prepared dataset of civitai/civitai#5438) is removed from
|
|
284
|
+
the protocol. Use it through `@civitai/blocks-react`'s `useImageUpload({ purpose: 'trainingData' })`
|
|
279
285
|
and `useRunTraining()`.
|
|
280
286
|
|
|
281
287
|
`WorkflowBodyWorkflow` (`kind: 'workflow'`) submits **several orchestrator steps as one
|
|
@@ -407,6 +413,15 @@ import { blockManifestPlugin } from '@civitai/app-sdk/vite';
|
|
|
407
413
|
const plugins = [blockManifestPlugin()];
|
|
408
414
|
```
|
|
409
415
|
|
|
416
|
+
**On the dev server only**, the plugin also puts the manifest's `scopes` and
|
|
417
|
+
`storage` on the page (a `<script>` at the end of `index.html`'s `<head>`; `vite build` never
|
|
418
|
+
emits it). `@civitai/sdk` reads it in a dev-tunnel preview, where the host marks the
|
|
419
|
+
frame `storageMode: 'local-preview'` and `app.storage.collection(name)` is served by
|
|
420
|
+
an in-memory store that enforces these declarations — see "In a dev-tunnel preview"
|
|
421
|
+
in `@civitai/sdk`'s README. Nothing else of the manifest is exposed. Without the
|
|
422
|
+
plugin, a preview's document store refuses every call `local_preview_no_manifest`:
|
|
423
|
+
this plugin is the only way the manifest reaches `@civitai/sdk`.
|
|
424
|
+
|
|
410
425
|
### Web storage in a block (`@civitai/app-sdk/safe-storage`)
|
|
411
426
|
|
|
412
427
|
Block iframes are sandboxed **without `allow-same-origin`**, so the document has
|
package/dist/blocks/index.d.ts
CHANGED
|
@@ -116,7 +116,7 @@ export { isModelSlotContext, isPageSlotContext } from './types.js';
|
|
|
116
116
|
* in `types.ts` for which of the two it uses and why.
|
|
117
117
|
*/
|
|
118
118
|
export { isSignedIn } from './types.js';
|
|
119
|
-
export type { BlockContext, KnownSlotId, ModelSlotId, PageSlotContext, PageSlotId, UnknownSlotContext, BlockAnalyticsDeclaration, BlockAnalyticsEventDeclaration, BlockAnalyticsPropertyDeclaration, BlockManifest, BlockManifestGood, BlockManifestV1, BlockSettings, BlockStorageCollectionDeclaration, BlockStorageDeclaration, BlockStorageIndexes, BlockStorageIndexType, BlockStoragePrivateCollectionDeclaration, BlockStorageSharedCollectionDeclaration, BlockToken, ContentRating, ManifestBooleanField, ManifestIframe, ManifestNumberField, ManifestPage, ManifestPreview, ManifestSettingField, ManifestSettings, ManifestStringField, ManifestTarget, ModelSlotContext, SettingScope, SettingWidget, Theme, ViewerInfo, BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockSourceImage, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockImagePickerSource, BlockPickedImageInfo, BlockMediaKind, BlockMediaUploadInfo, 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,
|
|
119
|
+
export type { BlockContext, KnownSlotId, ModelSlotId, PageSlotContext, PageSlotId, UnknownSlotContext, BlockAnalyticsDeclaration, BlockAnalyticsEventDeclaration, BlockAnalyticsPropertyDeclaration, BlockManifest, BlockManifestGood, BlockManifestV1, BlockSettings, BlockStorageCollectionDeclaration, BlockStorageDeclaration, BlockStorageIndexes, BlockStorageIndexType, BlockStoragePrivateCollectionDeclaration, BlockStorageSharedCollectionDeclaration, BlockToken, ContentRating, ManifestBooleanField, ManifestIframe, ManifestNumberField, ManifestPage, ManifestPreview, ManifestSettingField, ManifestSettings, ManifestStringField, ManifestTarget, ModelSlotContext, SettingScope, SettingWidget, Theme, ViewerInfo, BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockSourceImage, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockImagePickerSource, BlockPickedImageInfo, BlockMediaKind, BlockMediaUploadInfo, 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, BlockTrainingDataImage, BlockTrainingDataUploadResult, BlockRunTrainingHostError, BlockStepQuote, BlockModel3dOutput, BlockRunConfirmedStepHostError, } from './types.js';
|
|
120
120
|
/** Host bound for the App Blocks `kind: 'workflow'` body — see `WorkflowBodyWorkflow`. */
|
|
121
121
|
export { BLOCK_WORKFLOW_MAX_STEPS, BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS } from './types.js';
|
|
122
122
|
/**
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Wire format: `window.postMessage({ type, payload }, targetOrigin)`.
|
|
9
9
|
*/
|
|
10
10
|
import type { ColorDomain } from './browsingLevel.js';
|
|
11
|
-
import type { BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockImagePickerSource, BlockPickedImageInfo, BlockMediaKind, BlockMediaUploadInfo, BlockPendingImageInfo, BlockImageScanResult, BlockUploadPurpose, BlockNavigateScope, BlockContext, BlockSettings, Theme, ViewerInfo, WorkflowBody, BlockWorkflowSnapshot, BlockEstimateBatchAggregate, BlockBuzzTransaction, BlockBuzzAccount, BlockDailyCompensationResource, BlockViewer, BlockWildcardPack, BlockWildcardPackErrorCode, AppWorkflow, BlockGatedImage, BlockCollectionFollowErrorCode, BlockCollectionFollowResult, BlockPostSource, BlockCreatePostResult,
|
|
11
|
+
import type { BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockImagePickerSource, BlockPickedImageInfo, BlockMediaKind, BlockMediaUploadInfo, BlockPendingImageInfo, BlockImageScanResult, BlockUploadPurpose, BlockNavigateScope, BlockContext, BlockSettings, Theme, ViewerInfo, WorkflowBody, BlockWorkflowSnapshot, BlockEstimateBatchAggregate, BlockBuzzTransaction, BlockBuzzAccount, BlockDailyCompensationResource, BlockViewer, BlockWildcardPack, BlockWildcardPackErrorCode, AppWorkflow, BlockGatedImage, BlockCollectionFollowErrorCode, BlockCollectionFollowResult, BlockPostSource, BlockCreatePostResult, BlockTrainingDataUploadResult, WorkflowBodyTraining, WorkflowBodyPassThroughStep } from './types.js';
|
|
12
12
|
import type { BlockAppReaction, BlockEntityReactionErrorCode, BlockEntityReactionResult, BlockEntityReactionsResult, BlockReactionEntityType } from './reactions.js';
|
|
13
13
|
/**
|
|
14
14
|
* Filter params for `GET_BUZZ_TRANSACTIONS`. All optional; the host validates
|
|
@@ -218,6 +218,21 @@ export interface BlockInitPayload {
|
|
|
218
218
|
* them — ship without React.
|
|
219
219
|
*/
|
|
220
220
|
effectiveBrowsingLevel?: number;
|
|
221
|
+
/**
|
|
222
|
+
* `'local-preview'` when the host mounted this frame as a DEV-TUNNEL preview,
|
|
223
|
+
* which has no server-side storage namespace. The host sets it from the
|
|
224
|
+
* surface it mounted — never from the token's scopes, and never from anything
|
|
225
|
+
* the block sent. Absent on every other surface.
|
|
226
|
+
*
|
|
227
|
+
* `@civitai/sdk`'s `initialize()` reads it once and serves
|
|
228
|
+
* `app.storage.collection(name)` from an in-memory store in the tab
|
|
229
|
+
* (`app.storage.mode === 'local-preview'`). Nothing in this package or in
|
|
230
|
+
* `@civitai/blocks-react` acts on it: their storage hooks keep the real routes.
|
|
231
|
+
*
|
|
232
|
+
* ADDITIVE + OPTIONAL. A host that predates it omits the field; a value other
|
|
233
|
+
* than the exact string must be treated as absent.
|
|
234
|
+
*/
|
|
235
|
+
storageMode?: 'local-preview';
|
|
221
236
|
}
|
|
222
237
|
/**
|
|
223
238
|
* The freeform value carried by one SHARED-storage entry. Unlike the per-user
|
|
@@ -495,13 +510,6 @@ export type ParentToBlockMessage = {
|
|
|
495
510
|
result?: BlockCreatePostResult;
|
|
496
511
|
error?: string;
|
|
497
512
|
};
|
|
498
|
-
} | {
|
|
499
|
-
type: 'TRAINING_DATASET_RESULT';
|
|
500
|
-
payload: {
|
|
501
|
-
requestId: string;
|
|
502
|
-
result?: BlockTrainingDatasetResult;
|
|
503
|
-
error?: string;
|
|
504
|
-
};
|
|
505
513
|
} | {
|
|
506
514
|
type: 'TRAINING_RESULT';
|
|
507
515
|
payload: {
|
|
@@ -573,7 +581,7 @@ export type ParentToBlockMessage = {
|
|
|
573
581
|
type: 'IMAGE_UPLOAD_RESULT';
|
|
574
582
|
payload: {
|
|
575
583
|
requestId: string;
|
|
576
|
-
selected?: BlockUploadedImageInfo | BlockGenerationSourceImageInfo | BlockPendingImageInfo;
|
|
584
|
+
selected?: BlockUploadedImageInfo | BlockGenerationSourceImageInfo | BlockPendingImageInfo | BlockTrainingDataUploadResult;
|
|
577
585
|
/** A `bytes` upload's refusal or failure: a host string or a forwarded server message. */
|
|
578
586
|
error?: string;
|
|
579
587
|
};
|
|
@@ -873,12 +881,6 @@ export type BlockToParentMessage = {
|
|
|
873
881
|
/** Optional model-version gallery attach. Gated hard server-side. */
|
|
874
882
|
modelVersionId?: number;
|
|
875
883
|
};
|
|
876
|
-
} | {
|
|
877
|
-
type: 'PREPARE_TRAINING_DATASET';
|
|
878
|
-
payload: {
|
|
879
|
-
requestId: string;
|
|
880
|
-
items: BlockTrainingDatasetItem[];
|
|
881
|
-
};
|
|
882
884
|
} | {
|
|
883
885
|
type: 'RUN_TRAINING';
|
|
884
886
|
payload: {
|
|
@@ -1214,7 +1216,7 @@ export type BlockToParentMessageType = BlockToParentMessage['type'];
|
|
|
1214
1216
|
* it is a measurement, not an invariant, and civitai's own compile-time gate
|
|
1215
1217
|
* (published SDK union ⊆ `keyof INVENTORY`) is what holds one direction of it.
|
|
1216
1218
|
*/
|
|
1217
|
-
export declare const BLOCK_TO_PARENT_MESSAGE_TYPES: readonly ["BLOCK_HELLO", "BLOCK_READY", "BLOCK_ERROR", "BLOCK_MESSAGE_REJECTED", "REQUEST_TOKEN", "RESIZE_IFRAME", "SUBMIT_WORKFLOW", "ESTIMATE_WORKFLOW", "ESTIMATE_WORKFLOW_BATCH", "POLL_WORKFLOW", "CANCEL_WORKFLOW", "OPEN_BUZZ_PURCHASE", "GET_BUZZ_BALANCE", "GET_VIEWER", "GET_BUZZ_TRANSACTIONS", "GET_BUZZ_ACCOUNTS", "GET_DAILY_COMPENSATION", "GET_WILDCARD_PACK", "QUERY_APP_WORKFLOWS", "PUBLISH_GENERATION_OUTPUTS", "CREATE_POST_FROM_APP", "
|
|
1219
|
+
export declare const BLOCK_TO_PARENT_MESSAGE_TYPES: readonly ["BLOCK_HELLO", "BLOCK_READY", "BLOCK_ERROR", "BLOCK_MESSAGE_REJECTED", "REQUEST_TOKEN", "RESIZE_IFRAME", "SUBMIT_WORKFLOW", "ESTIMATE_WORKFLOW", "ESTIMATE_WORKFLOW_BATCH", "POLL_WORKFLOW", "CANCEL_WORKFLOW", "OPEN_BUZZ_PURCHASE", "GET_BUZZ_BALANCE", "GET_VIEWER", "GET_BUZZ_TRANSACTIONS", "GET_BUZZ_ACCOUNTS", "GET_DAILY_COMPENSATION", "GET_WILDCARD_PACK", "QUERY_APP_WORKFLOWS", "PUBLISH_GENERATION_OUTPUTS", "CREATE_POST_FROM_APP", "RUN_TRAINING", "RUN_CONFIRMED_STEP", "GET_IMAGES_BY_IDS", "CANCEL_APP_WORKFLOW", "OPEN_CHECKPOINT_PICKER", "OPEN_RESOURCE_PICKER", "OPEN_IMAGE_UPLOAD", "OPEN_IMAGE_PICKER", "OPEN_MEDIA_UPLOAD", "SET_USER_CHECKPOINT", "NAVIGATE", "REQUEST_SIGN_IN", "REQUEST_CONSENT", "TRACK_EVENT", "APP_STORAGE_GET", "APP_STORAGE_SET", "APP_STORAGE_DELETE", "APP_STORAGE_LIST", "APP_STORAGE_QUOTA", "SHARED_LIST", "SHARED_GET_COUNT", "SHARED_GET_COUNTS", "SHARED_APPEND", "SHARED_VOTE", "SHARED_UNVOTE", "SHARED_WITHDRAW", "SHARED_UPDATE", "SHARED_GET", "SHARED_REPORT", "SAVE_IMAGE", "SET_COLLECTION_FOLLOW", "SET_ENTITY_REACTION", "GET_ENTITY_REACTIONS"];
|
|
1218
1220
|
/**
|
|
1219
1221
|
* The bucket a message type falls into when the protocol does not declare it.
|
|
1220
1222
|
*
|
package/dist/blocks/messages.js
CHANGED
package/dist/blocks/types.d.ts
CHANGED
|
@@ -256,8 +256,17 @@ export type BlockImageScanResult = {
|
|
|
256
256
|
* UNSCANNED — the orchestrator scans it at generation time — so the host
|
|
257
257
|
* returns ONLY the source shape ({@link BlockGenerationSourceImageInfo}); no
|
|
258
258
|
* `imageId`/`nsfwLevel`/`contentRating` crosses back into the block.
|
|
259
|
-
|
|
260
|
-
|
|
259
|
+
* - `'trainingData'`: PRIVATE training images for a `kind: 'training'` run
|
|
260
|
+
* (civitai/civitai#6461). The viewer picks up to
|
|
261
|
+
* {@link BLOCK_TRAINING_DATASET_MAX_ITEMS} PNG, JPEG or WebP files in a host
|
|
262
|
+
* modal; each is uploaded as a consumer blob, as Civitai's own training form
|
|
263
|
+
* does. ONE reply carries every image that uploaded
|
|
264
|
+
* ({@link BlockTrainingDataUploadResult}), and the host remembers each key it
|
|
265
|
+
* uploaded for this block — `RUN_TRAINING` refuses a quote naming any other.
|
|
266
|
+
* Page apps only. A host that predates the purpose normalises it to
|
|
267
|
+
* `'display'` and answers with ONE moderated image instead.
|
|
268
|
+
*/
|
|
269
|
+
export type BlockUploadPurpose = 'display' | 'generationSource' | 'trainingData';
|
|
261
270
|
/**
|
|
262
271
|
* Which SPACE a `NAVIGATE` path is resolved in. Mirrors the host's
|
|
263
272
|
* `NavigateScope` in civitai/civitai's `pageBlockHostLogic.ts`. Keep in lockstep.
|
|
@@ -296,6 +305,32 @@ export type BlockNavigateScope = 'app' | 'site';
|
|
|
296
305
|
* lockstep.
|
|
297
306
|
*/
|
|
298
307
|
export type BlockGenerationSourceImageInfo = BlockSourceImage;
|
|
308
|
+
/**
|
|
309
|
+
* One image an `OPEN_IMAGE_UPLOAD { purpose: 'trainingData' }` uploaded — an
|
|
310
|
+
* element of {@link BlockTrainingDataUploadResult.images}. Mirrors the host's
|
|
311
|
+
* `TrainingDataUpload` in civitai/civitai's
|
|
312
|
+
* `src/components/AppBlocks/trainingDataUpload.ts` (civitai/civitai#6461).
|
|
313
|
+
*
|
|
314
|
+
* The image is PRIVATE training data: it is not published, scanned or given an
|
|
315
|
+
* `Image` row, so there is no `imageId`.
|
|
316
|
+
*/
|
|
317
|
+
export interface BlockTrainingDataImage {
|
|
318
|
+
/** The uploaded blob's url. Show it as the thumbnail; it is also accepted as an item's `air`. */
|
|
319
|
+
url: string;
|
|
320
|
+
/**
|
|
321
|
+
* The consumer-blob key — pass it as {@link BlockTrainingDatasetItem.air}.
|
|
322
|
+
* Opaque. The host compares keys case-insensitively.
|
|
323
|
+
*/
|
|
324
|
+
air: string;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* `IMAGE_UPLOAD_RESULT.selected` for `purpose: 'trainingData'`: every image that
|
|
328
|
+
* uploaded, in one reply. The viewer may finish with fewer than they picked when
|
|
329
|
+
* some failed to upload; a cancel is a reply with NO `selected`.
|
|
330
|
+
*/
|
|
331
|
+
export interface BlockTrainingDataUploadResult {
|
|
332
|
+
images: BlockTrainingDataImage[];
|
|
333
|
+
}
|
|
299
334
|
/**
|
|
300
335
|
* Which of the viewer's own image libraries `OPEN_IMAGE_PICKER` (via
|
|
301
336
|
* `useImagePicker`) offers:
|
|
@@ -1618,10 +1653,13 @@ export type WorkflowBodyWorkflow = {
|
|
|
1618
1653
|
};
|
|
1619
1654
|
/** Ceiling on what ONE confirmed `kind: 'training'` run may cost, in Buzz. Host constant `BLOCK_TRAINING_MAX_BUZZ_PER_RUN`. */
|
|
1620
1655
|
export declare const BLOCK_TRAINING_MAX_BUZZ_PER_RUN = 5000;
|
|
1621
|
-
/**
|
|
1656
|
+
/**
|
|
1657
|
+
* Max images in one training dataset ({@link WorkflowBodyTraining.items}), and in
|
|
1658
|
+
* one `trainingData` upload. Host constant `BLOCK_TRAINING_DATASET_MAX_ITEMS`.
|
|
1659
|
+
*/
|
|
1622
1660
|
export declare const BLOCK_TRAINING_DATASET_MAX_ITEMS = 50;
|
|
1623
1661
|
/** Max characters of one dataset caption. Host constant `BLOCK_TRAINING_CAPTION_MAX_CHARS`. */
|
|
1624
|
-
export declare const BLOCK_TRAINING_CAPTION_MAX_CHARS =
|
|
1662
|
+
export declare const BLOCK_TRAINING_CAPTION_MAX_CHARS = 8192;
|
|
1625
1663
|
/** Max sample prompts on a training body. Host constant `BLOCK_TRAINING_SAMPLE_PROMPTS_MAX`. */
|
|
1626
1664
|
export declare const BLOCK_TRAINING_SAMPLE_PROMPTS_MAX = 6;
|
|
1627
1665
|
/** Max characters of one sample prompt. Host constant `BLOCK_TRAINING_SAMPLE_PROMPT_MAX_CHARS`. */
|
|
@@ -1706,16 +1744,16 @@ export type AiToolkitTrainingParams = AiToolkitTrainingParamsBase & ({
|
|
|
1706
1744
|
modelVariant: 'base' | 'sft';
|
|
1707
1745
|
});
|
|
1708
1746
|
/**
|
|
1709
|
-
* Train a LoRA with the ai-toolkit engine on
|
|
1710
|
-
*
|
|
1747
|
+
* Train a LoRA with the ai-toolkit engine on images the VIEWER uploaded through
|
|
1748
|
+
* the host — the App Blocks `kind: 'training'` workflow body.
|
|
1711
1749
|
*
|
|
1712
1750
|
* ## Availability — read before building on it
|
|
1713
1751
|
*
|
|
1714
1752
|
* - 🔴 Behind the host flag **`app-blocks-training-kind`**, which ships OFF and is
|
|
1715
1753
|
* evaluated per viewer. Where it is off, every training call is refused
|
|
1716
1754
|
* (`training from apps is not enabled`).
|
|
1717
|
-
* - **Page apps only** (`/apps/run/<slug>`). The model slot answers
|
|
1718
|
-
*
|
|
1755
|
+
* - **Page apps only** (`/apps/run/<slug>`). The model slot answers
|
|
1756
|
+
* `RUN_TRAINING` with an error, and the server refuses a non-page token.
|
|
1719
1757
|
* - The manifest must declare **`ai:write:budgeted`** and the viewer must have
|
|
1720
1758
|
* granted it; the viewer must be signed in.
|
|
1721
1759
|
* - **Not from a development or review session**: dev tokens (`dev:live`, dev
|
|
@@ -1724,17 +1762,22 @@ export type AiToolkitTrainingParams = AiToolkitTrainingParamsBase & ({
|
|
|
1724
1762
|
*
|
|
1725
1763
|
* ## The flow
|
|
1726
1764
|
*
|
|
1727
|
-
* 1. **
|
|
1728
|
-
*
|
|
1729
|
-
*
|
|
1730
|
-
*
|
|
1765
|
+
* 1. **Upload** — `useImageUpload({ purpose: 'trainingData' }).open()`
|
|
1766
|
+
* (`OPEN_IMAGE_UPLOAD { purpose: 'trainingData' }`). The viewer picks up to
|
|
1767
|
+
* {@link BLOCK_TRAINING_DATASET_MAX_ITEMS} images in a host modal; you get
|
|
1768
|
+
* `[{ url, air }]` ({@link BlockTrainingDataImage}), or `null` on cancel.
|
|
1769
|
+
* Pair each `air` with your caption to build {@link WorkflowBodyTraining.items}.
|
|
1731
1770
|
* 2. **Quote** — `useBuzzWorkflow().estimate(body)` with this body, `quoteId`
|
|
1732
1771
|
* ABSENT. The reply's {@link BlockWorkflowSnapshot.trainingQuote} is the
|
|
1733
1772
|
* orchestrator's own price for exactly this run, stored server-side.
|
|
1734
1773
|
* 3. **Run** — `useRunTraining().runTraining({ ...body, quoteId })`
|
|
1735
1774
|
* (`RUN_TRAINING`). Civitai shows the viewer a consent dialog in ITS chrome —
|
|
1736
1775
|
* price, base model, length, dataset size, all read back from the server,
|
|
1737
|
-
* never from your body
|
|
1776
|
+
* never from your body, with the host's own copies of the uploads as
|
|
1777
|
+
* thumbnails — and submits only on their click. A quote naming an image this
|
|
1778
|
+
* host did not upload for the block is refused with no dialog
|
|
1779
|
+
* (`training data not uploaded here`) — upload in the same page session as the
|
|
1780
|
+
* run; a reload forgets the uploads.
|
|
1738
1781
|
* 4. **Follow** — `useBuzzWorkflow().watch(snapshot.workflowId)`.
|
|
1739
1782
|
*
|
|
1740
1783
|
* 🔴 `useBuzzWorkflow().submit()` REFUSES THIS BODY before sending it. The server
|
|
@@ -1750,8 +1793,12 @@ export type AiToolkitTrainingParams = AiToolkitTrainingParamsBase & ({
|
|
|
1750
1793
|
*/
|
|
1751
1794
|
export interface WorkflowBodyTraining {
|
|
1752
1795
|
kind: 'training';
|
|
1753
|
-
/**
|
|
1754
|
-
|
|
1796
|
+
/**
|
|
1797
|
+
* The dataset: 1…{@link BLOCK_TRAINING_DATASET_MAX_ITEMS} images this host
|
|
1798
|
+
* uploaded for the viewer, each with its caption — see
|
|
1799
|
+
* {@link BlockTrainingDatasetItem}. One blob may appear once.
|
|
1800
|
+
*/
|
|
1801
|
+
items: BlockTrainingDatasetItem[];
|
|
1755
1802
|
/** The only engine accepted. */
|
|
1756
1803
|
engine: 'ai-toolkit';
|
|
1757
1804
|
/**
|
|
@@ -1760,12 +1807,17 @@ export interface WorkflowBodyTraining {
|
|
|
1760
1807
|
*/
|
|
1761
1808
|
model: string;
|
|
1762
1809
|
params: AiToolkitTrainingParams;
|
|
1763
|
-
/**
|
|
1810
|
+
/**
|
|
1811
|
+
* At most {@link BLOCK_TRAINING_TRIGGER_WORD_MAX_CHARS} characters. The host runs
|
|
1812
|
+
* it through the same trigger-word check Civitai's trainer and Training Studio
|
|
1813
|
+
* use, at the estimate and again at the submit, before anything is reserved; a
|
|
1814
|
+
* refused trigger word fails the estimate.
|
|
1815
|
+
*/
|
|
1764
1816
|
triggerWord: string;
|
|
1765
1817
|
/**
|
|
1766
1818
|
* At most {@link BLOCK_TRAINING_SAMPLE_PROMPTS_MAX} prompts of at most
|
|
1767
|
-
* {@link BLOCK_TRAINING_SAMPLE_PROMPT_MAX_CHARS} characters each.
|
|
1768
|
-
*
|
|
1819
|
+
* {@link BLOCK_TRAINING_SAMPLE_PROMPT_MAX_CHARS} characters each. Checked for
|
|
1820
|
+
* those bounds only, as in the Training Studio.
|
|
1769
1821
|
*/
|
|
1770
1822
|
samplePrompts: string[];
|
|
1771
1823
|
/**
|
|
@@ -1795,7 +1847,7 @@ export interface WorkflowBodyTraining {
|
|
|
1795
1847
|
* unmodified. Bounded by a platform-internal denylist and by `maxBuzz`, not
|
|
1796
1848
|
* by a registry.
|
|
1797
1849
|
* - {@link WorkflowBodyTraining} (`kind: 'training'`) — an ai-toolkit LoRA run
|
|
1798
|
-
* on
|
|
1850
|
+
* on images the viewer uploaded through the host. ESTIMATE ONLY
|
|
1799
1851
|
* through `useBuzzWorkflow`; it runs through `useRunTraining()`, whose
|
|
1800
1852
|
* host-chrome consent dialog is the only way to confirm its quote.
|
|
1801
1853
|
* - {@link WorkflowBodyWorkflow} (`kind: 'workflow'`) — up to
|
|
@@ -2163,8 +2215,8 @@ export interface BlockWorkflowSnapshot {
|
|
|
2163
2215
|
*
|
|
2164
2216
|
* `cost.total` on the same snapshot equals `trainingQuote.total`.
|
|
2165
2217
|
* `expiresAt` is an ISO-8601 timestamp: after it the run is refused and you
|
|
2166
|
-
* estimate again. `imageCount` is the
|
|
2167
|
-
*
|
|
2218
|
+
* estimate again. `imageCount` is the size of the dataset the server quoted
|
|
2219
|
+
* (`items.length`).
|
|
2168
2220
|
*
|
|
2169
2221
|
* Present ONLY on the reply to a `kind: 'training'` estimate. Absent on hosts
|
|
2170
2222
|
* that predate civitai/civitai#5434.
|
|
@@ -2318,7 +2370,7 @@ export interface BlockTrainingQuote {
|
|
|
2318
2370
|
quoteId: string;
|
|
2319
2371
|
/** The quoted price, in Buzz. */
|
|
2320
2372
|
total: number;
|
|
2321
|
-
/** How many images the
|
|
2373
|
+
/** How many images the quoted dataset holds. */
|
|
2322
2374
|
imageCount: number;
|
|
2323
2375
|
/** ISO-8601. The quote cannot be run after this. */
|
|
2324
2376
|
expiresAt: string;
|
|
@@ -3451,85 +3503,30 @@ export interface BlockCreatePostResult {
|
|
|
3451
3503
|
*/
|
|
3452
3504
|
export type BlockCreatePostHostError = 'review-mode' | 'block is not ready' | 'sign in to post' | 'no images to post' | 'no block token' | 'declined';
|
|
3453
3505
|
/**
|
|
3454
|
-
* One image of a training dataset
|
|
3455
|
-
* the caption to train it with.
|
|
3506
|
+
* One image of a training dataset ({@link WorkflowBodyTraining.items}) — a blob
|
|
3507
|
+
* this host uploaded for the viewer, and the caption to train it with. The
|
|
3508
|
+
* Training Studio's own `{ air, caption }` shape.
|
|
3456
3509
|
*
|
|
3457
|
-
* Host bounds (`blockTrainingDatasetItemsSchema
|
|
3458
|
-
*
|
|
3459
|
-
*
|
|
3460
|
-
*
|
|
3461
|
-
*
|
|
3510
|
+
* Host bounds (`blockTrainingDatasetItemsSchema`, civitai/civitai#6461): `air`
|
|
3511
|
+
* is the blob's key ({@link BlockTrainingDataImage.air}) or its Civitai-hosted
|
|
3512
|
+
* blob url — the server keeps only the key; `caption` at most
|
|
3513
|
+
* {@link BLOCK_TRAINING_CAPTION_MAX_CHARS} characters; no other keys;
|
|
3514
|
+
* 1…{@link BLOCK_TRAINING_DATASET_MAX_ITEMS} items per body, and one blob at
|
|
3515
|
+
* most once (keys compare case-insensitively). A body outside them is refused at
|
|
3516
|
+
* the estimate.
|
|
3462
3517
|
*/
|
|
3463
3518
|
export interface BlockTrainingDatasetItem {
|
|
3464
|
-
|
|
3519
|
+
air: string;
|
|
3465
3520
|
caption: string;
|
|
3466
3521
|
}
|
|
3467
|
-
/**
|
|
3468
|
-
* Why the server left an image out of a prepared dataset. Mirrors
|
|
3469
|
-
* civitai/civitai's `BlockTrainingRejectionReason`.
|
|
3470
|
-
*
|
|
3471
|
-
* - `unavailable` — not found, OR not the viewer's own image. One reason for
|
|
3472
|
-
* both, on purpose: the server will not tell an app whether someone else's
|
|
3473
|
-
* image id exists.
|
|
3474
|
-
* - `unsupported-media` — a video or audio row.
|
|
3475
|
-
* - `not-eligible` — refused by moderation state or the page's maturity ceiling.
|
|
3476
|
-
* - `pending-scan` — not scanned yet; retry once the scan finishes.
|
|
3477
|
-
* - `import-failed` — the orchestrator did not accept the image.
|
|
3478
|
-
* - `import-unavailable` — the import timed out or the orchestrator was
|
|
3479
|
-
* unavailable; retryable.
|
|
3480
|
-
*
|
|
3481
|
-
* The SDK's inbound validator checks `reason` only as a STRING, so a reason the
|
|
3482
|
-
* host adds later still arrives — give an exhaustive `switch` a default branch.
|
|
3483
|
-
*/
|
|
3484
|
-
export type BlockTrainingRejectionReason = 'unavailable' | 'unsupported-media' | 'not-eligible' | 'pending-scan' | 'import-failed' | 'import-unavailable';
|
|
3485
|
-
/**
|
|
3486
|
-
* The success payload of `TRAINING_DATASET_RESULT` — what
|
|
3487
|
-
* `usePrepareTrainingDataset().prepareDataset()` resolves with.
|
|
3488
|
-
*/
|
|
3489
|
-
export interface BlockTrainingDatasetResult {
|
|
3490
|
-
/**
|
|
3491
|
-
* Opaque handle for {@link WorkflowBodyTraining.datasetId} (`tds_` + 32 hex
|
|
3492
|
-
* characters), bound to this viewer, app and install.
|
|
3493
|
-
*/
|
|
3494
|
-
datasetId: string;
|
|
3495
|
-
/**
|
|
3496
|
-
* How many images were ADMITTED — always at least 1: when nothing is admitted
|
|
3497
|
-
* the server refuses the request instead of returning an empty dataset. The
|
|
3498
|
-
* server derives it; a run trains on exactly these.
|
|
3499
|
-
*/
|
|
3500
|
-
count: number;
|
|
3501
|
-
/** The images left out, each with its reason. Empty when every image was admitted. */
|
|
3502
|
-
rejected: Array<{
|
|
3503
|
-
imageId: number;
|
|
3504
|
-
reason: BlockTrainingRejectionReason;
|
|
3505
|
-
}>;
|
|
3506
|
-
}
|
|
3507
|
-
/**
|
|
3508
|
-
* The HOST'S OWN refusal codes on a `TRAINING_DATASET_RESULT`'s `error`. Mirrors
|
|
3509
|
-
* civitai/civitai's `PREPARE_TRAINING_DATASET_HOST_ERRORS`
|
|
3510
|
-
* (`src/components/AppBlocks/prepareTrainingDatasetGate.ts`, civitai/civitai#5438).
|
|
3511
|
-
*
|
|
3512
|
-
* 🔴 THE SET A BLOCK MAY RELY ON, NOT THE SET IT MAY RECEIVE: `error` also carries
|
|
3513
|
-
* any server message verbatim (`training from apps is not enabled`, a rate limit,
|
|
3514
|
-
* a moderation refusal of a caption). Compare by EQUALITY against these members
|
|
3515
|
-
* and treat anything else as an opaque server message.
|
|
3516
|
-
*
|
|
3517
|
-
* - `review-mode` — a mod-review sandbox with "run for real" off.
|
|
3518
|
-
* - `block is not ready` — the host handshake has not completed.
|
|
3519
|
-
* - `sign in to train` — anonymous viewer; there are no images of theirs to read.
|
|
3520
|
-
* - `invalid training dataset` — `items` failed the host's item schema (shape,
|
|
3521
|
-
* count or caption length). Nothing was sent to the server.
|
|
3522
|
-
* - `no block token` — the host holds no block token yet.
|
|
3523
|
-
*/
|
|
3524
|
-
export type BlockPrepareTrainingDatasetHostError = 'review-mode' | 'block is not ready' | 'sign in to train' | 'invalid training dataset' | 'no block token';
|
|
3525
3522
|
/**
|
|
3526
3523
|
* The HOST'S OWN refusal codes on a `TRAINING_RESULT`'s `error`. Mirrors
|
|
3527
3524
|
* civitai/civitai's `RUN_TRAINING_HOST_ERRORS`
|
|
3528
3525
|
* (`src/components/AppBlocks/runTrainingGate.ts`).
|
|
3529
3526
|
*
|
|
3530
3527
|
* 🔴 THE SET A BLOCK MAY RELY ON, NOT THE SET IT MAY RECEIVE: server messages
|
|
3531
|
-
* (an expired or already-used quote, a body that differs from the quoted one
|
|
3532
|
-
*
|
|
3528
|
+
* (an expired or already-used quote, a body that differs from the quoted one)
|
|
3529
|
+
* arrive verbatim in the same field.
|
|
3533
3530
|
*
|
|
3534
3531
|
* - `review-mode` — a mod-review sandbox with "run for real" off.
|
|
3535
3532
|
* - `block is not ready` — the host handshake has not completed.
|
|
@@ -3537,6 +3534,11 @@ export type BlockPrepareTrainingDatasetHostError = 'review-mode' | 'block is not
|
|
|
3537
3534
|
* - `invalid training request` — the body is not a `kind: 'training'` body
|
|
3538
3535
|
* naming a `quoteId`.
|
|
3539
3536
|
* - `no block token` — the host holds no block token yet.
|
|
3537
|
+
* - `training data not uploaded here` — the quote names an image this host did
|
|
3538
|
+
* not upload for this block (civitai/civitai#6461): the host remembers only the
|
|
3539
|
+
* blobs its own `OPEN_IMAGE_UPLOAD { purpose: 'trainingData' }` uploaded, and
|
|
3540
|
+
* forgets them on a reload. Refused BEFORE any dialog: NO RUN, nothing
|
|
3541
|
+
* charged. Upload the images again, estimate again, run that quote.
|
|
3540
3542
|
* - `declined` — the viewer dismissed the consent dialog. 🔴 GUARANTEED to mean
|
|
3541
3543
|
* NO RUN WAS SUBMITTED.
|
|
3542
3544
|
* - `submission-unconfirmed` — the submit was SENT but its outcome is unknown
|
|
@@ -3546,7 +3548,7 @@ export type BlockPrepareTrainingDatasetHostError = 'review-mode' | 'block is not
|
|
|
3546
3548
|
* offering a retry — a retry of the same body after the server did start the
|
|
3547
3549
|
* run is a SECOND, separately charged run.
|
|
3548
3550
|
*/
|
|
3549
|
-
export type BlockRunTrainingHostError = 'review-mode' | 'block is not ready' | 'sign in to train' | 'invalid training request' | 'no block token' | 'declined' | 'submission-unconfirmed';
|
|
3551
|
+
export type BlockRunTrainingHostError = 'review-mode' | 'block is not ready' | 'sign in to train' | 'invalid training request' | 'no block token' | 'training data not uploaded here' | 'declined' | 'submission-unconfirmed';
|
|
3550
3552
|
/**
|
|
3551
3553
|
* The HOST'S OWN refusal codes on a `CONFIRMED_STEP_RESULT`'s `error`. Mirrors
|
|
3552
3554
|
* civitai/civitai's `RUN_CONFIRMED_STEP_HOST_ERRORS`
|
package/dist/blocks/types.js
CHANGED
|
@@ -151,8 +151,10 @@ export const BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS = 16;
|
|
|
151
151
|
// ============================================================
|
|
152
152
|
//
|
|
153
153
|
// 🔴 MIRRORED FROM THE HOST, NOT DESIGNED HERE. Every type in this section copies
|
|
154
|
-
// civitai/civitai's zod
|
|
155
|
-
// `blockTrainingBodySchema` in `src/server/schema/blocks/workflow.schema.ts`,
|
|
154
|
+
// civitai/civitai's zod as of civitai/civitai#6461 (head `05f1d1fa8f`):
|
|
155
|
+
// `blockTrainingBodySchema` in `src/server/schema/blocks/workflow.schema.ts`,
|
|
156
|
+
// `blockTrainingDatasetItemsSchema` in
|
|
157
|
+
// `src/server/schema/blocks/training-dataset.schema.ts` for `items`, and
|
|
156
158
|
// `aiToolkitTrainingParamsSchema` in `src/server/schema/orchestrator/training.schema.ts`
|
|
157
159
|
// for `params`. The host's zod is the definition; this is the copy. A field the
|
|
158
160
|
// host adds is invisible here until this file is updated, and the host rejects a
|
|
@@ -160,10 +162,13 @@ export const BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS = 16;
|
|
|
160
162
|
// as a silently different run.
|
|
161
163
|
/** Ceiling on what ONE confirmed `kind: 'training'` run may cost, in Buzz. Host constant `BLOCK_TRAINING_MAX_BUZZ_PER_RUN`. */
|
|
162
164
|
export const BLOCK_TRAINING_MAX_BUZZ_PER_RUN = 5000;
|
|
163
|
-
/**
|
|
165
|
+
/**
|
|
166
|
+
* Max images in one training dataset ({@link WorkflowBodyTraining.items}), and in
|
|
167
|
+
* one `trainingData` upload. Host constant `BLOCK_TRAINING_DATASET_MAX_ITEMS`.
|
|
168
|
+
*/
|
|
164
169
|
export const BLOCK_TRAINING_DATASET_MAX_ITEMS = 50;
|
|
165
170
|
/** Max characters of one dataset caption. Host constant `BLOCK_TRAINING_CAPTION_MAX_CHARS`. */
|
|
166
|
-
export const BLOCK_TRAINING_CAPTION_MAX_CHARS =
|
|
171
|
+
export const BLOCK_TRAINING_CAPTION_MAX_CHARS = 8192;
|
|
167
172
|
/** Max sample prompts on a training body. Host constant `BLOCK_TRAINING_SAMPLE_PROMPTS_MAX`. */
|
|
168
173
|
export const BLOCK_TRAINING_SAMPLE_PROMPTS_MAX = 6;
|
|
169
174
|
/** Max characters of one sample prompt. Host constant `BLOCK_TRAINING_SAMPLE_PROMPT_MAX_CHARS`. */
|
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
|
+
* 197 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 197 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
|
+
* 197 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 197 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/vite/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
+
import type { BlockManifest } from '../blocks/types.js';
|
|
2
3
|
export interface BlockManifestPluginOptions {
|
|
3
4
|
/**
|
|
4
5
|
* Path to the manifest. Relative paths resolve against `root`, which defaults
|
|
@@ -9,6 +10,34 @@ export interface BlockManifestPluginOptions {
|
|
|
9
10
|
/** Overrides the Vite project root used to resolve a relative `manifestPath`. */
|
|
10
11
|
root?: string;
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* The global the dev server's HTML sets for `@civitai/sdk` to read. Spelled again
|
|
15
|
+
* in `packages/civitai-sdk/src/doc-store/local-preview.ts` (the two packages share
|
|
16
|
+
* no code); `tests/guards/local-preview-manifest-global.test.mjs` pins the two equal.
|
|
17
|
+
*
|
|
18
|
+
* WHY A GLOBAL, set by a `<script>` the plugin adds to `index.html`, rather than
|
|
19
|
+
* the alternatives:
|
|
20
|
+
* - a VIRTUAL MODULE needs `@civitai/sdk` to import it, which fails to resolve in
|
|
21
|
+
* every bundle not built by this plugin — production included;
|
|
22
|
+
* - a `define` substitution has to reach `@civitai/sdk` inside `node_modules`,
|
|
23
|
+
* where it depends on how the dependency optimizer pre-bundles it, and it would
|
|
24
|
+
* rewrite production builds too;
|
|
25
|
+
* - an `initialize()` option needs every app to import its manifest and pass it,
|
|
26
|
+
* and would be public API.
|
|
27
|
+
* The `<script>` is added on the DEV SERVER only (`vite build` never emits it),
|
|
28
|
+
* needs no change in an app that registers this plugin, and the SDK reads it only
|
|
29
|
+
* when the host marks the frame a local preview. It is the ONLY way the manifest
|
|
30
|
+
* reaches the SDK, so an app that does NOT register the plugin gets the SDK's
|
|
31
|
+
* `local_preview_no_manifest` error. Every scaffold in this repo that ships a
|
|
32
|
+
* manifest registers it; not every scaffold elsewhere does (the CLI's
|
|
33
|
+
* `page-money` template, for one, does not), and those apps must add it.
|
|
34
|
+
*/
|
|
35
|
+
export declare const LOCAL_PREVIEW_MANIFEST_GLOBAL = "__CIVITAI_LOCAL_PREVIEW_MANIFEST__";
|
|
36
|
+
/**
|
|
37
|
+
* The classic `<script>` body: only `scopes` and `storage`, as JSON with `<`
|
|
38
|
+
* escaped so no value can close the element.
|
|
39
|
+
*/
|
|
40
|
+
export declare function localPreviewManifestScript(manifest: Pick<BlockManifest, 'scopes' | 'storage'>): string;
|
|
12
41
|
export declare function blockManifestPlugin(options?: BlockManifestPluginOptions): Plugin;
|
|
13
42
|
export { BlockManifestError } from '../blocks/manifestError.js';
|
|
14
43
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/vite/index.js
CHANGED
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
* pre-check against the same canonical). It exists so a manifest mistake
|
|
19
19
|
* surfaces in the dev loop rather than at submit time.
|
|
20
20
|
*
|
|
21
|
+
* DEV SERVER ONLY, it also hands the manifest's `scopes` and `storage` to
|
|
22
|
+
* `@civitai/sdk`, for a dev-tunnel preview. A preview has no server-side storage,
|
|
23
|
+
* so when the host marks the frame `storageMode: 'local-preview'` the SDK serves
|
|
24
|
+
* `app.storage.collection(name)` from an in-memory store that enforces THESE
|
|
25
|
+
* declarations — the ones of the code being previewed, which the server has
|
|
26
|
+
* never seen. See {@link LOCAL_PREVIEW_MANIFEST_GLOBAL} for why it is a global.
|
|
27
|
+
*
|
|
21
28
|
* PEERS: `ajv` (used at runtime by `@civitai/app-sdk/manifest`) and `vite`
|
|
22
29
|
* (types only). Both are optional peers of `@civitai/app-sdk`; a scaffold using
|
|
23
30
|
* this plugin needs both in its devDependencies.
|
|
@@ -25,7 +32,60 @@
|
|
|
25
32
|
import { readFileSync } from 'node:fs';
|
|
26
33
|
import { resolve } from 'node:path';
|
|
27
34
|
import { BlockManifestError, defineBlock } from '../manifest/index.js';
|
|
35
|
+
/**
|
|
36
|
+
* The global the dev server's HTML sets for `@civitai/sdk` to read. Spelled again
|
|
37
|
+
* in `packages/civitai-sdk/src/doc-store/local-preview.ts` (the two packages share
|
|
38
|
+
* no code); `tests/guards/local-preview-manifest-global.test.mjs` pins the two equal.
|
|
39
|
+
*
|
|
40
|
+
* WHY A GLOBAL, set by a `<script>` the plugin adds to `index.html`, rather than
|
|
41
|
+
* the alternatives:
|
|
42
|
+
* - a VIRTUAL MODULE needs `@civitai/sdk` to import it, which fails to resolve in
|
|
43
|
+
* every bundle not built by this plugin — production included;
|
|
44
|
+
* - a `define` substitution has to reach `@civitai/sdk` inside `node_modules`,
|
|
45
|
+
* where it depends on how the dependency optimizer pre-bundles it, and it would
|
|
46
|
+
* rewrite production builds too;
|
|
47
|
+
* - an `initialize()` option needs every app to import its manifest and pass it,
|
|
48
|
+
* and would be public API.
|
|
49
|
+
* The `<script>` is added on the DEV SERVER only (`vite build` never emits it),
|
|
50
|
+
* needs no change in an app that registers this plugin, and the SDK reads it only
|
|
51
|
+
* when the host marks the frame a local preview. It is the ONLY way the manifest
|
|
52
|
+
* reaches the SDK, so an app that does NOT register the plugin gets the SDK's
|
|
53
|
+
* `local_preview_no_manifest` error. Every scaffold in this repo that ships a
|
|
54
|
+
* manifest registers it; not every scaffold elsewhere does (the CLI's
|
|
55
|
+
* `page-money` template, for one, does not), and those apps must add it.
|
|
56
|
+
*/
|
|
57
|
+
export const LOCAL_PREVIEW_MANIFEST_GLOBAL = '__CIVITAI_LOCAL_PREVIEW_MANIFEST__';
|
|
58
|
+
/** Reads and validates the manifest, throwing the message Vite should print. */
|
|
59
|
+
function loadManifest(manifestPath) {
|
|
60
|
+
let manifest;
|
|
61
|
+
try {
|
|
62
|
+
manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
throw new Error(`block.manifest.json could not be read or parsed (${manifestPath}): ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
defineBlock({ manifest });
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
// Re-thrown with the field path up front: Vite prints the message, not
|
|
72
|
+
// the error's own properties, so `.field` would otherwise be invisible.
|
|
73
|
+
const field = err instanceof BlockManifestError && err.field ? ` [${err.field}]` : '';
|
|
74
|
+
throw new Error(`block.manifest.json is invalid${field}: ${err.message}`);
|
|
75
|
+
}
|
|
76
|
+
return manifest;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The classic `<script>` body: only `scopes` and `storage`, as JSON with `<`
|
|
80
|
+
* escaped so no value can close the element.
|
|
81
|
+
*/
|
|
82
|
+
export function localPreviewManifestScript(manifest) {
|
|
83
|
+
const exposed = JSON.stringify({ scopes: manifest.scopes, storage: manifest.storage }).replace(/</g, '\\u003c');
|
|
84
|
+
return `globalThis[${JSON.stringify(LOCAL_PREVIEW_MANIFEST_GLOBAL)}] = ${exposed};`;
|
|
85
|
+
}
|
|
28
86
|
export function blockManifestPlugin(options = {}) {
|
|
87
|
+
let manifestPath = '';
|
|
88
|
+
let serving = false;
|
|
29
89
|
return {
|
|
30
90
|
name: 'civitai-block-manifest',
|
|
31
91
|
// `enforce: 'pre'` so the manifest error is the FIRST thing reported rather
|
|
@@ -36,23 +96,27 @@ export function blockManifestPlugin(options = {}) {
|
|
|
36
96
|
// this module's own location — this file now lives inside the installed
|
|
37
97
|
// package, not next to the consumer's manifest.
|
|
38
98
|
const root = options.root ?? config?.root ?? process.cwd();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
99
|
+
manifestPath = resolve(root, options.manifestPath ?? './block.manifest.json');
|
|
100
|
+
serving = config?.command === 'serve';
|
|
101
|
+
loadManifest(manifestPath);
|
|
102
|
+
},
|
|
103
|
+
transformIndexHtml() {
|
|
104
|
+
// Dev server only: a build never carries the manifest into the page.
|
|
105
|
+
if (!serving)
|
|
106
|
+
return undefined;
|
|
107
|
+
// Re-read per page load, so an edited manifest takes effect on reload.
|
|
108
|
+
const manifest = loadManifest(manifestPath);
|
|
109
|
+
return [
|
|
110
|
+
{
|
|
111
|
+
tag: 'script',
|
|
112
|
+
// End of <head>, NOT `head-prepend`: prepended, a large `storage` block
|
|
113
|
+
// could push `<meta charset>` past the 1024-byte prescan. Nothing needs
|
|
114
|
+
// it earlier: the SDK reads the global inside `initialize()`, after
|
|
115
|
+
// BLOCK_INIT, and a classic script still runs before any module script.
|
|
116
|
+
injectTo: 'head',
|
|
117
|
+
children: localPreviewManifestScript(manifest),
|
|
118
|
+
},
|
|
119
|
+
];
|
|
56
120
|
},
|
|
57
121
|
};
|
|
58
122
|
}
|
package/package.json
CHANGED