@civitai/app-sdk 0.70.0 → 0.71.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 +3 -1
- package/dist/blocks/index.d.ts +1 -1
- package/dist/blocks/scopes.d.ts +7 -2
- package/dist/blocks/scopes.js +18 -3
- package/dist/blocks/types.d.ts +169 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/manifest/defineBlock.d.ts +1 -0
- package/dist/manifest/defineBlock.js +7 -0
- package/dist/manifest/index.d.ts +1 -1
- package/package.json +1 -1
- package/schemas/app-block/v1.json +153 -3
package/README.md
CHANGED
|
@@ -191,7 +191,9 @@ own key:
|
|
|
191
191
|
`$type` cap, a 256 KB `input` cap, and the spend reservation. **Unlike the inline arm, `maxBuzz`
|
|
192
192
|
is not always the timeout here**: on both `estimate` and `submit` the host asks the orchestrator
|
|
193
193
|
for a `whatif` quote of the step. **Quoted** → it reserves `max(maxBuzz, quote)`, gated against
|
|
194
|
-
the token's per-call budget (`token.buzzBudget
|
|
194
|
+
the token's per-call budget (`token.buzzBudget`: a platform default when the manifest declares
|
|
195
|
+
none, clamped to a platform cap — current values in the
|
|
196
|
+
[limits table](https://developer.civitai.com/apps/guide/text-to-image.md#limits-table) — so the
|
|
195
197
|
reservation can exceed the 1–250 `maxBuzz` range), and stamps **no** step timeout.
|
|
196
198
|
**Unquoted** → `maxBuzz` is both the reservation and the step timeout in seconds; the timeout
|
|
197
199
|
bounds wall-clock time, and spend only for a step billed by compute time — a step priced per
|
package/dist/blocks/index.d.ts
CHANGED
|
@@ -109,7 +109,7 @@ 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, BlockImagePickerSource, BlockPickedImageInfo, 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, BlockStepQuote, BlockModel3dOutput, BlockRunConfirmedStepHostError, } from './types.js';
|
|
112
|
+
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, 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, BlockStepQuote, BlockModel3dOutput, BlockRunConfirmedStepHostError, } from './types.js';
|
|
113
113
|
/** Host bound for the App Blocks `kind: 'workflow'` body — see `WorkflowBodyWorkflow`. */
|
|
114
114
|
export { BLOCK_WORKFLOW_MAX_STEPS, BLOCK_WORKFLOW_REPEAT_MAX_ITERATIONS } from './types.js';
|
|
115
115
|
/**
|
package/dist/blocks/scopes.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export declare const BLOCK_SCOPES: {
|
|
|
20
20
|
readonly APPS_STORAGE_WRITE: "apps:storage:write";
|
|
21
21
|
readonly APPS_STORAGE_SHARED_READ: "apps:storage:shared:read";
|
|
22
22
|
readonly APPS_STORAGE_SHARED_WRITE: "apps:storage:shared:write";
|
|
23
|
+
readonly APPS_STORAGE: "apps:storage";
|
|
24
|
+
readonly APPS_STORAGE_PUBLISH: "apps:storage:publish";
|
|
23
25
|
readonly COLLECTIONS_READ_SELF: "collections:read:self";
|
|
24
26
|
readonly COLLECTIONS_WRITE_SELF: "collections:write:self";
|
|
25
27
|
readonly COLLECTIONS_READ_PRIVATE: "collections:read:private";
|
|
@@ -31,8 +33,9 @@ export declare const BLOCK_SCOPES: {
|
|
|
31
33
|
export type BlockScopeKey = keyof typeof BLOCK_SCOPES;
|
|
32
34
|
export type BlockScope = (typeof BLOCK_SCOPES)[BlockScopeKey];
|
|
33
35
|
/**
|
|
34
|
-
* Format helper for the block-scope shape — 3 OR 4 colon-separated
|
|
35
|
-
* segments (`domain:
|
|
36
|
+
* Format helper for the block-scope shape — 2, 3 OR 4 colon-separated
|
|
37
|
+
* lowercase segments (`domain:area`, `domain:verb:target` or
|
|
38
|
+
* `domain:area:verb:target`).
|
|
36
39
|
*
|
|
37
40
|
* NOTE: this regex is **not** the authoritative validity contract. The
|
|
38
41
|
* canonical manifest schema (https://civitai.com/schemas/app-block/v1.json)
|
|
@@ -48,6 +51,8 @@ export type BlockScope = (typeof BLOCK_SCOPES)[BlockScopeKey];
|
|
|
48
51
|
* cross-user datastore); `apps:store:items:write` is the same shape. The SDK
|
|
49
52
|
* now tracks the server's 4-segment scopes directly, so this is no longer a coordinated-major-bump situation — the
|
|
50
53
|
* pattern just widened to accept the shapes the canonical enum already lists.
|
|
54
|
+
* It widened again, at the other end, for the 2-segment `apps:storage`
|
|
55
|
+
* (the document store's base scope).
|
|
51
56
|
*/
|
|
52
57
|
export declare const BLOCK_SCOPE_PATTERN: RegExp;
|
|
53
58
|
/**
|
package/dist/blocks/scopes.js
CHANGED
|
@@ -27,6 +27,18 @@ export const BLOCK_SCOPES = {
|
|
|
27
27
|
// 4-segment (as is `apps:store:items:write`) — see BLOCK_SCOPE_PATTERN below.
|
|
28
28
|
APPS_STORAGE_SHARED_READ: 'apps:storage:shared:read',
|
|
29
29
|
APPS_STORAGE_SHARED_WRITE: 'apps:storage:shared:write',
|
|
30
|
+
// apps:storage / apps:storage:publish — the DOCUMENT STORE, declared per
|
|
31
|
+
// collection in the manifest's `storage` block, that succeeds the four
|
|
32
|
+
// scopes above (which stay live until apps migrate). Same no-OAuth-bit
|
|
33
|
+
// posture. `apps:storage` covers reads, the viewer's private collections,
|
|
34
|
+
// marks and counters, and is CONSENT-EXEMPT; any manifest declaring a
|
|
35
|
+
// collection must request it. `apps:storage:publish` writes documents in a
|
|
36
|
+
// SHARED collection under the viewer's identity — SENSITIVE (needs a
|
|
37
|
+
// `scopeJustifications` entry) and CONSENT-GATED. `apps:storage` is the one
|
|
38
|
+
// 2-segment scope — see BLOCK_SCOPE_PATTERN below. Server source:
|
|
39
|
+
// civitai/civitai `src/shared/constants/block-scope.constants.ts`.
|
|
40
|
+
APPS_STORAGE: 'apps:storage',
|
|
41
|
+
APPS_STORAGE_PUBLISH: 'apps:storage:publish',
|
|
30
42
|
// collections:* — the App Blocks Collections surface. These have no OAuth bit
|
|
31
43
|
// (they never touch the user's civitai resources via the OAuth surface); the
|
|
32
44
|
// server gates them per-op server-side (collection visibility/ownership +
|
|
@@ -80,8 +92,9 @@ export const BLOCK_SCOPES = {
|
|
|
80
92
|
APPS_STORE_ITEMS_WRITE: 'apps:store:items:write',
|
|
81
93
|
};
|
|
82
94
|
/**
|
|
83
|
-
* Format helper for the block-scope shape — 3 OR 4 colon-separated
|
|
84
|
-
* segments (`domain:
|
|
95
|
+
* Format helper for the block-scope shape — 2, 3 OR 4 colon-separated
|
|
96
|
+
* lowercase segments (`domain:area`, `domain:verb:target` or
|
|
97
|
+
* `domain:area:verb:target`).
|
|
85
98
|
*
|
|
86
99
|
* NOTE: this regex is **not** the authoritative validity contract. The
|
|
87
100
|
* canonical manifest schema (https://civitai.com/schemas/app-block/v1.json)
|
|
@@ -97,8 +110,10 @@ export const BLOCK_SCOPES = {
|
|
|
97
110
|
* cross-user datastore); `apps:store:items:write` is the same shape. The SDK
|
|
98
111
|
* now tracks the server's 4-segment scopes directly, so this is no longer a coordinated-major-bump situation — the
|
|
99
112
|
* pattern just widened to accept the shapes the canonical enum already lists.
|
|
113
|
+
* It widened again, at the other end, for the 2-segment `apps:storage`
|
|
114
|
+
* (the document store's base scope).
|
|
100
115
|
*/
|
|
101
|
-
export const BLOCK_SCOPE_PATTERN = /^[a-z]+:[a-z]
|
|
116
|
+
export const BLOCK_SCOPE_PATTERN = /^[a-z]+:[a-z]+(?::[a-z]+){0,2}$/;
|
|
102
117
|
/**
|
|
103
118
|
* Marketplace category taxonomy for the optional manifest `category` field —
|
|
104
119
|
* the app's `/apps` store listing bucket. Mirrors `MARKETPLACE_CATEGORIES` in
|
package/dist/blocks/types.d.ts
CHANGED
|
@@ -619,14 +619,17 @@ export interface ViewerInfo {
|
|
|
619
619
|
*/
|
|
620
620
|
signedIn?: true;
|
|
621
621
|
/**
|
|
622
|
-
* @deprecated Init-time identity disclosure.
|
|
623
|
-
*
|
|
624
|
-
*
|
|
622
|
+
* @deprecated Init-time identity disclosure. For the viewer id use
|
|
623
|
+
* `useViewer()` (`GET_VIEWER`) in React, or `app.site.get('blocks/me')` from
|
|
624
|
+
* `@civitai/sdk` anywhere else — both are scope-gated and audited per call.
|
|
625
|
+
* Still sent; scheduled for removal once block adoption of `useViewer()` is
|
|
626
|
+
* measured.
|
|
625
627
|
*/
|
|
626
628
|
id: number;
|
|
627
629
|
/**
|
|
628
|
-
* @deprecated Init-time identity disclosure.
|
|
629
|
-
*
|
|
630
|
+
* @deprecated Init-time identity disclosure. For the username use
|
|
631
|
+
* `useViewer()` (`GET_VIEWER`) in React, or `app.site.get('blocks/me')` from
|
|
632
|
+
* `@civitai/sdk` anywhere else. Still sent; scheduled for removal alongside `id`.
|
|
630
633
|
*/
|
|
631
634
|
username: string | null;
|
|
632
635
|
/** @deprecated Not sent by the platform to third-party iframes (civitai #2521). */
|
|
@@ -1302,9 +1305,12 @@ export type WorkflowBodyPassThroughStep = {
|
|
|
1302
1305
|
* - **Quoted** — the host reserves `max(maxBuzz, quote)` and stamps NO step
|
|
1303
1306
|
* timeout. That reservation can exceed 250: it is gated against the token's
|
|
1304
1307
|
* per-call budget (`token.buzzBudget` — the app's per-generation budget,
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
+
* i.e. `page.buzzBudgetPerGen` for a page app: a platform default when
|
|
1309
|
+
* nothing declares one, and clamped to a platform cap on every mint), and
|
|
1310
|
+
* a submit whose reservation exceeds that budget comes back `failed` with
|
|
1311
|
+
* an `insufficient buzz budget` error before any Buzz is reserved. The
|
|
1312
|
+
* current default and cap are in the pinned limits table,
|
|
1313
|
+
* https://developer.civitai.com/apps/guide/text-to-image.md#limits-table.
|
|
1308
1314
|
* - **Unquoted** (the orchestrator returned no price, or the quote could not
|
|
1309
1315
|
* be had) — the host reserves `maxBuzz` and stamps it as the step timeout,
|
|
1310
1316
|
* in seconds. `maxBuzz: 10` then buys a job that is KILLED after 10
|
|
@@ -2531,6 +2537,141 @@ export interface BlockAnalyticsDeclaration {
|
|
|
2531
2537
|
*/
|
|
2532
2538
|
events?: Record<string, BlockAnalyticsEventDeclaration>;
|
|
2533
2539
|
}
|
|
2540
|
+
/**
|
|
2541
|
+
* The type of one storage index — see {@link BlockStorageIndexes}. A `string`
|
|
2542
|
+
* index holds values of at most 128 bytes. Mirrors the canonical schema's
|
|
2543
|
+
* `storage.collections.*.indexes.*` enum.
|
|
2544
|
+
*/
|
|
2545
|
+
export type BlockStorageIndexType = 'string' | 'number' | 'boolean' | 'time';
|
|
2546
|
+
/**
|
|
2547
|
+
* A collection's `indexes`: fields of a document's `data` the app can filter and
|
|
2548
|
+
* sort by, as a map of field PATH → {@link BlockStorageIndexType}. At most 4.
|
|
2549
|
+
* A path is 1 to 3 segments joined by `.` (`status`, `datasetId`,
|
|
2550
|
+
* `meta.round`), each a letter followed by up to 31 letters, digits or `_`; a
|
|
2551
|
+
* field whose own name contains `.` cannot be indexed. Changing an index's
|
|
2552
|
+
* type is not supported: remove it and add one under a new name.
|
|
2553
|
+
*
|
|
2554
|
+
* `key`, `createdAt` and `updatedAt` are built-in sort keys and cannot be index
|
|
2555
|
+
* names — the canonical declares each as `false`, and they are typed `never`
|
|
2556
|
+
* here so declaring one is a compile error. (That is also why the index
|
|
2557
|
+
* signature admits `undefined`: TypeScript requires an optional property to be
|
|
2558
|
+
* assignable to the signature.) Mirrors the canonical schema's
|
|
2559
|
+
* `storage.collections.*.indexes`.
|
|
2560
|
+
*/
|
|
2561
|
+
export interface BlockStorageIndexes {
|
|
2562
|
+
[path: string]: BlockStorageIndexType | undefined;
|
|
2563
|
+
key?: never;
|
|
2564
|
+
createdAt?: never;
|
|
2565
|
+
updatedAt?: never;
|
|
2566
|
+
}
|
|
2567
|
+
/**
|
|
2568
|
+
* A PRIVATE collection — a separate key space per viewer, read and written
|
|
2569
|
+
* only by that viewer. Carries none of the shared-only fields (`write`,
|
|
2570
|
+
* `counters`, `marks`, `showAuthor`, `dailyWritesPerAuthor`); the canonical
|
|
2571
|
+
* forbids them here. See {@link BlockStorageSharedCollectionDeclaration} for
|
|
2572
|
+
* the fields both kinds share.
|
|
2573
|
+
*/
|
|
2574
|
+
export interface BlockStoragePrivateCollectionDeclaration {
|
|
2575
|
+
/** See {@link BlockStorageSharedCollectionDeclaration.kind}. */
|
|
2576
|
+
kind?: 'docs' | 'log';
|
|
2577
|
+
/** Cannot be changed later: declare a new collection instead. */
|
|
2578
|
+
visibility: 'private';
|
|
2579
|
+
/** See {@link BlockStorageIndexes}. */
|
|
2580
|
+
indexes?: BlockStorageIndexes;
|
|
2581
|
+
/** RESERVED — see {@link BlockStorageSharedCollectionDeclaration.ttlSeconds}. */
|
|
2582
|
+
ttlSeconds?: number;
|
|
2583
|
+
/** RESERVED — see {@link BlockStorageSharedCollectionDeclaration.maxEntries}. */
|
|
2584
|
+
maxEntries?: number;
|
|
2585
|
+
}
|
|
2586
|
+
/**
|
|
2587
|
+
* A SHARED collection — one key space for the whole app, read by every viewer
|
|
2588
|
+
* of the app, signed-out viewers included. `write` is REQUIRED on it.
|
|
2589
|
+
*/
|
|
2590
|
+
export interface BlockStorageSharedCollectionDeclaration {
|
|
2591
|
+
/**
|
|
2592
|
+
* `'docs'` (the default): documents with app-chosen or server-assigned keys
|
|
2593
|
+
* that can be updated in place. `'log'`: append-only entries, trimmed to
|
|
2594
|
+
* `maxEntries` per key space. RESERVED: civitai.com refuses `'log'` until log
|
|
2595
|
+
* collections are enabled, so declare `'docs'` or omit it.
|
|
2596
|
+
*/
|
|
2597
|
+
kind?: 'docs' | 'log';
|
|
2598
|
+
/** Cannot be changed later: declare a new collection instead. */
|
|
2599
|
+
visibility: 'shared';
|
|
2600
|
+
/**
|
|
2601
|
+
* Who may create, update and delete documents.
|
|
2602
|
+
*
|
|
2603
|
+
* - `'own'` — eligible signed-in viewers create documents; only a document's
|
|
2604
|
+
* author updates or deletes it.
|
|
2605
|
+
* - `'none'` — nobody writes documents; viewers only increment the declared
|
|
2606
|
+
* `counters` and set the declared `marks`. Must declare at least one
|
|
2607
|
+
* counter or mark.
|
|
2608
|
+
* - `'anyone'` — RESERVED (refused at submit until enabled): eligible
|
|
2609
|
+
* signed-in viewers update or delete any document.
|
|
2610
|
+
* - `'owner'` — RESERVED (refused at submit until enabled): only the app
|
|
2611
|
+
* owner writes documents; viewers can still mark and count.
|
|
2612
|
+
*
|
|
2613
|
+
* `'own'` and `'anyone'` require the `apps:storage:publish` scope.
|
|
2614
|
+
*/
|
|
2615
|
+
write: 'own' | 'anyone' | 'owner' | 'none';
|
|
2616
|
+
/**
|
|
2617
|
+
* Names of the atomic counters each document carries (for example `plays`).
|
|
2618
|
+
* At most 8 distinct lowercase snake_case names (`^[a-z][a-z0-9_]{0,31}$`),
|
|
2619
|
+
* never `report`, and never a name also used by a mark.
|
|
2620
|
+
*/
|
|
2621
|
+
counters?: string[];
|
|
2622
|
+
/**
|
|
2623
|
+
* Names of the per-viewer marks a viewer can set on a document (for example
|
|
2624
|
+
* `vote`), at most one of each per viewer per document. A reader sees each
|
|
2625
|
+
* mark's count and whether THEY set it, never who else did. At most 8
|
|
2626
|
+
* distinct lowercase snake_case names. `report` is built in on every shared
|
|
2627
|
+
* collection and must NOT be declared.
|
|
2628
|
+
*/
|
|
2629
|
+
marks?: string[];
|
|
2630
|
+
/** See {@link BlockStorageIndexes}. */
|
|
2631
|
+
indexes?: BlockStorageIndexes;
|
|
2632
|
+
/**
|
|
2633
|
+
* When true, readers see each viewer-authored document's author USERNAME.
|
|
2634
|
+
* Default false. The numeric user id is never exposed either way.
|
|
2635
|
+
*/
|
|
2636
|
+
showAuthor?: boolean;
|
|
2637
|
+
/**
|
|
2638
|
+
* RESERVED — refused at submit until expiring documents are enabled. The
|
|
2639
|
+
* default document lifetime in seconds, 60 to 31536000 (provisional bounds).
|
|
2640
|
+
*/
|
|
2641
|
+
ttlSeconds?: number;
|
|
2642
|
+
/**
|
|
2643
|
+
* RESERVED — log collections are refused at submit. For `kind: 'log'` only:
|
|
2644
|
+
* the most entries kept per key space, 1 to 10000 (omitted means 10000).
|
|
2645
|
+
*/
|
|
2646
|
+
maxEntries?: number;
|
|
2647
|
+
/**
|
|
2648
|
+
* RESERVED — refused at submit until per-collection write budgets are
|
|
2649
|
+
* enabled. The per-viewer daily create/update budget, 1 to 1000, for a
|
|
2650
|
+
* collection viewers write (`write` `'own'` or `'anyone'` only).
|
|
2651
|
+
*/
|
|
2652
|
+
dailyWritesPerAuthor?: number;
|
|
2653
|
+
}
|
|
2654
|
+
/**
|
|
2655
|
+
* One collection declaration — see {@link BlockManifestV1.storage}.
|
|
2656
|
+
* Discriminated on `visibility`, mirroring the canonical's `if visibility is
|
|
2657
|
+
* "shared" then write is required, else no shared-only field` rule. Mirrors the
|
|
2658
|
+
* canonical schema's `storage.collections.*`.
|
|
2659
|
+
*/
|
|
2660
|
+
export type BlockStorageCollectionDeclaration = BlockStoragePrivateCollectionDeclaration | BlockStorageSharedCollectionDeclaration;
|
|
2661
|
+
/**
|
|
2662
|
+
* The manifest's `storage` object — see {@link BlockManifestV1.storage}.
|
|
2663
|
+
* Mirrors the canonical schema's `storage`; no other key is allowed.
|
|
2664
|
+
*/
|
|
2665
|
+
export interface BlockStorageDeclaration {
|
|
2666
|
+
/**
|
|
2667
|
+
* Collection name → declaration. At least 1 and at most 16 collections. A
|
|
2668
|
+
* collection name is lowercase snake_case: a letter, then up to 31 of `a-z`,
|
|
2669
|
+
* `0-9` or `_` (`^[a-z][a-z0-9_]{0,31}$`). Renaming a collection, or changing
|
|
2670
|
+
* its visibility, is a NEW collection: the old one's documents are not
|
|
2671
|
+
* carried over.
|
|
2672
|
+
*/
|
|
2673
|
+
collections: Record<string, BlockStorageCollectionDeclaration>;
|
|
2674
|
+
}
|
|
2534
2675
|
/**
|
|
2535
2676
|
* One entry of a manifest's `goods[]`. Mirrors the canonical schema exactly;
|
|
2536
2677
|
* `id`, `title` and `priceBuzz` are required there and so are they here.
|
|
@@ -2670,6 +2811,26 @@ export interface BlockManifestV1 {
|
|
|
2670
2811
|
* canonical schema's `analytics`.
|
|
2671
2812
|
*/
|
|
2672
2813
|
analytics?: BlockAnalyticsDeclaration;
|
|
2814
|
+
/**
|
|
2815
|
+
* Optional APP STORAGE declaration — every collection of JSON documents the
|
|
2816
|
+
* app keeps, and who may read and write each one. Manifest-governed and
|
|
2817
|
+
* REVIEW-GATED: a collection not declared here does not exist at runtime.
|
|
2818
|
+
*
|
|
2819
|
+
* Declaring any collection requires the `apps:storage` scope; a shared
|
|
2820
|
+
* collection viewers write (`write` `'own'` or `'anyone'`) also requires the
|
|
2821
|
+
* sensitive, consent-gated `apps:storage:publish` scope with a
|
|
2822
|
+
* `scopeJustifications` entry; and requesting either scope with nothing here
|
|
2823
|
+
* for it to reach is rejected. Those couplings, and the RESERVED features
|
|
2824
|
+
* (`kind: 'log'`, `ttlSeconds`, `dailyWritesPerAuthor`, `write` `'anyone'` /
|
|
2825
|
+
* `'owner'`), are enforced by the platform's manifest validator at submit,
|
|
2826
|
+
* not by `defineBlock` — see `KNOWN_GAPS['storage-server-only-rules']`.
|
|
2827
|
+
*
|
|
2828
|
+
* This TYPES the declaration only. Storage is not yet enabled on civitai.com
|
|
2829
|
+
* (its routes answer `503 storage_disabled`); the published schema and the Go
|
|
2830
|
+
* CLI already accept the field. Kept in lockstep with the canonical schema's
|
|
2831
|
+
* `storage`.
|
|
2832
|
+
*/
|
|
2833
|
+
storage?: BlockStorageDeclaration;
|
|
2673
2834
|
/** Optional; the canonical declares no required sub-field. */
|
|
2674
2835
|
iframe?: ManifestIframe;
|
|
2675
2836
|
/** Full-page surface descriptor (W10). */
|
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
|
+
* 180 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 180 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
|
+
* 180 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 180 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
|
|
@@ -96,6 +96,7 @@ export declare const KNOWN_GAPS: {
|
|
|
96
96
|
readonly 'review-granted-scope-subset': "Which of the requested `scopes` review actually grants has no schema expression at all.";
|
|
97
97
|
readonly 'slotId-registry': string;
|
|
98
98
|
readonly 'settings-meta-schema-not-vendored': string;
|
|
99
|
+
readonly 'storage-server-only-rules': string;
|
|
99
100
|
readonly 'format-uri-not-enforced': string;
|
|
100
101
|
};
|
|
101
102
|
/** The canonical schema object, parsed once. Exported for tests and tooling. */
|
|
@@ -143,6 +143,13 @@ export const KNOWN_GAPS = {
|
|
|
143
143
|
'settings-meta-schema-not-vendored': "civitai/civitai's `manifest-settings.meta.schema.ts` is not published at a URL and not " +
|
|
144
144
|
'vendored here, so `settings` is the one surface still checked by a hand-written mirror. ' +
|
|
145
145
|
'See SCHEMA_DIVERGENCES.settings.',
|
|
146
|
+
'storage-server-only-rules': 'The canonical `storage` description states rules it does not encode: declaring any ' +
|
|
147
|
+
'collection requires the `apps:storage` scope, a shared collection viewers write (`write` ' +
|
|
148
|
+
'"own" or "anyone") also requires `apps:storage:publish`, requesting either scope with no ' +
|
|
149
|
+
'collection for it to reach is rejected, a counter may not share a name with a mark, and the ' +
|
|
150
|
+
'RESERVED features (`kind` "log", `ttlSeconds`, `dailyWritesPerAuthor`, `write` "anyone" / ' +
|
|
151
|
+
'"owner") validate offline and are refused at submit. Ajv enforces the structural rules ' +
|
|
152
|
+
'exactly; these are server-side.',
|
|
146
153
|
'format-uri-not-enforced': '`assetBundleUrl` carries `format: "uri"` in addition to `pattern: "^https://"`. Ajv ignores ' +
|
|
147
154
|
'unknown formats unless `ajv-formats` is installed, which would be a second optional peer for ' +
|
|
148
155
|
'one field whose pattern is already enforced. The pattern IS enforced; the `uri` format is ' +
|
package/dist/manifest/index.d.ts
CHANGED
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
export { defineBlock, SCHEMA_DIVERGENCES, KNOWN_GAPS, loadCanonicalSchema } from './defineBlock.js';
|
|
16
16
|
export type { DefineBlockConfig } from './defineBlock.js';
|
|
17
17
|
export { BlockManifestError } from '../blocks/manifestError.js';
|
|
18
|
-
export type { BlockAnalyticsDeclaration, BlockAnalyticsEventDeclaration, BlockAnalyticsPropertyDeclaration, BlockManifest, BlockManifestGood, BlockManifestV1, } from '../blocks/types.js';
|
|
18
|
+
export type { BlockAnalyticsDeclaration, BlockAnalyticsEventDeclaration, BlockAnalyticsPropertyDeclaration, BlockManifest, BlockManifestGood, BlockManifestV1, BlockStorageCollectionDeclaration, BlockStorageDeclaration, BlockStorageIndexes, BlockStorageIndexType, BlockStoragePrivateCollectionDeclaration, BlockStorageSharedCollectionDeclaration, } from '../blocks/types.js';
|
|
19
19
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"auth": {
|
|
74
74
|
"type": "string",
|
|
75
|
-
"description": "Which credential the host hands the block: \"block-token\" (default when omitted) is the block-scoped JWT; \"oauth\" asks for an opaque OAuth access token for the block's own OauthClient, which ordinary /api/v1 routes accept as a viewer bearer. Minting it is gated on a server flag that is not generally enabled, and also requires a signed-in viewer and a declared \"user:read:self\" scope; when any of those is unmet the host hands back a block JWT instead of failing, so branch on the token kind the host reports rather than on this field. An OAuth token is refused by the postMessage bridge procedures, which verify a block JWT only, and a manifest declaring \"oauth\" alongside any \"apps:storage:*\" scope is rejected by manifest validation.",
|
|
75
|
+
"description": "Which credential the host hands the block: \"block-token\" (default when omitted) is the block-scoped JWT; \"oauth\" asks for an opaque OAuth access token for the block's own OauthClient, which ordinary /api/v1 routes accept as a viewer bearer. Minting it is gated on a server flag that is not generally enabled, and also requires a signed-in viewer and a declared \"user:read:self\" scope; when any of those is unmet the host hands back a block JWT instead of failing, so branch on the token kind the host reports rather than on this field. An OAuth token is refused by the postMessage bridge procedures, which verify a block JWT only, and a manifest declaring \"oauth\" alongside \"apps:storage\" or any \"apps:storage:*\" scope is rejected by manifest validation.",
|
|
76
76
|
"enum": ["block-token", "oauth"]
|
|
77
77
|
},
|
|
78
78
|
"trustTier": {
|
|
@@ -96,6 +96,8 @@
|
|
|
96
96
|
"apps:storage:write",
|
|
97
97
|
"apps:storage:shared:read",
|
|
98
98
|
"apps:storage:shared:write",
|
|
99
|
+
"apps:storage",
|
|
100
|
+
"apps:storage:publish",
|
|
99
101
|
"collections:read:self",
|
|
100
102
|
"collections:write:self",
|
|
101
103
|
"collections:read:private",
|
|
@@ -108,7 +110,7 @@
|
|
|
108
110
|
},
|
|
109
111
|
"scopeJustifications": {
|
|
110
112
|
"type": "object",
|
|
111
|
-
"description": "Per-scope justification: a map of scope-id → free-text rationale explaining WHY the app needs that permission, shown to the moderator during review. REQUIRED for SENSITIVE scopes — any declared scope that can spend or read the viewer's Buzz, read the viewer's private data, or write data other users see (e.g. `ai:write:budgeted`, `social:tip:self`, `goods:purchase:self`, `buzz:read:self`, `collections:read:private`, `apps:storage:shared:write`, `posts:write:self`, `apps:store:items:write`) MUST carry a non-empty justification here, or the manifest is rejected at submit time. OPTIONAL for non-sensitive scopes — omit those and the manifest stays valid. Every key MUST be a scope also present in `scopes` (justifications for scopes you don't request are rejected). Each value is a non-empty string of at most 500 characters. The requirement is enforced imperatively by the manifest validator (not expressed as JSON-Schema conditionals here). NOTE: the justification captures the developer's STATED rationale only; the platform does not verify the truth of the claims.",
|
|
113
|
+
"description": "Per-scope justification: a map of scope-id → free-text rationale explaining WHY the app needs that permission, shown to the moderator during review. REQUIRED for SENSITIVE scopes — any declared scope that can spend or read the viewer's Buzz, read the viewer's private data, or write data other users see (e.g. `ai:write:budgeted`, `social:tip:self`, `goods:purchase:self`, `buzz:read:self`, `collections:read:private`, `apps:storage:shared:write`, `apps:storage:publish`, `posts:write:self`, `apps:store:items:write`) MUST carry a non-empty justification here, or the manifest is rejected at submit time. OPTIONAL for non-sensitive scopes — omit those and the manifest stays valid. Every key MUST be a scope also present in `scopes` (justifications for scopes you don't request are rejected). Each value is a non-empty string of at most 500 characters. The requirement is enforced imperatively by the manifest validator (not expressed as JSON-Schema conditionals here). NOTE: the justification captures the developer's STATED rationale only; the platform does not verify the truth of the claims.",
|
|
112
114
|
"additionalProperties": {
|
|
113
115
|
"type": "string",
|
|
114
116
|
"minLength": 1,
|
|
@@ -219,7 +221,7 @@
|
|
|
219
221
|
},
|
|
220
222
|
"buzzBudgetPerGen": {
|
|
221
223
|
"type": "integer",
|
|
222
|
-
"description": "Optional per-generation Buzz SAFETY CEILING for `ai:write:budgeted` tokens — the most a SINGLE generation this app requests is allowed to cost. It is a ceiling against a malicious or compromised app draining the viewer's Buzz, NOT a cost forecast: size it WELL ABOVE your worst-case generation (a good rule of thumb is several times your expected cost — e.g. 1000 when a run costs ~100), never at your estimate. Setting it to an estimate is the common mistake. The server re-prices every submit and compares that real price against this budget BEFORE anything runs, so a generation that comes in over budget is REJECTED outright with `insufficient buzz budget` — no workflow is created and no Buzz is spent, but the user gets nothing, and it stays broken for EVERY user until you ship a new manifest version and it is re-approved. So any upward drift in real cost (more steps, a bigger resolution, a pricier model or recipe, a colder cache) turns a budget sized to today's estimate into a hard outage. Positive integer. Omit it and the token is minted with
|
|
224
|
+
"description": "Optional per-generation Buzz SAFETY CEILING for `ai:write:budgeted` tokens — the most a SINGLE generation this app requests is allowed to cost. It is a ceiling against a malicious or compromised app draining the viewer's Buzz, NOT a cost forecast: size it WELL ABOVE your worst-case generation (a good rule of thumb is several times your expected cost — e.g. 1000 when a run costs ~100), never at your estimate. Setting it to an estimate is the common mistake. The server re-prices every submit and compares that real price against this budget BEFORE anything runs, so a generation that comes in over budget is REJECTED outright with `insufficient buzz budget` — no workflow is created and no Buzz is spent, but the user gets nothing, and it stays broken for EVERY user until you ship a new manifest version and it is re-approved. So any upward drift in real cost (more steps, a bigger resolution, a pricier model or recipe, a colder cache) turns a budget sized to today's estimate into a hard outage. Positive integer. Omit it and the token is minted with the platform default budget. Server-clamped to the platform per-call cap, so a generous value is safe. The current default and cap are listed in the App Blocks developer docs (https://developer.civitai.com/apps). This bounds ONE generation only — cumulative spend is separately capped per viewer per day and per app, so a high per-gen ceiling does not widen total exposure.",
|
|
223
225
|
"exclusiveMinimum": 0
|
|
224
226
|
}
|
|
225
227
|
}
|
|
@@ -373,6 +375,154 @@
|
|
|
373
375
|
}
|
|
374
376
|
}
|
|
375
377
|
},
|
|
378
|
+
"storage": {
|
|
379
|
+
"type": "object",
|
|
380
|
+
"description": "Optional APP STORAGE declaration — every collection of JSON documents your app keeps, and who may read and write each one. Manifest-governed and REVIEW-GATED: a collection that is not declared here does not exist at runtime, and the moderator sees each collection's visibility, write policy, counters, marks and indexes. Declaring any collection also requires the `apps:storage` scope; declaring a shared collection that viewers write (`write` of \"own\" or \"anyone\") also requires the sensitive, consent-gated `apps:storage:publish` scope with a `scopeJustifications` entry; and requesting either scope with nothing here for it to reach is rejected. This schema describes the WHOLE declaration, including features the platform does not accept yet: today the server's manifest validation refuses `kind` \"log\", `ttlSeconds`, `dailyWritesPerAuthor`, `write` \"anyone\" and `write` \"owner\" with a message saying they are not available yet, so those validate offline and are rejected at submit. Kept in lockstep with src/shared/constants/block-storage.constants.ts (a drift-guard test enforces equality); the imperative validator in that module is authoritative.",
|
|
381
|
+
"additionalProperties": false,
|
|
382
|
+
"required": ["collections"],
|
|
383
|
+
"properties": {
|
|
384
|
+
"collections": {
|
|
385
|
+
"type": "object",
|
|
386
|
+
"description": "Map of collection name → declaration. At least 1 and at most 16 collections. A collection name is lowercase snake_case: a letter, then up to 31 of a-z, 0-9 or _. Renaming a collection, or changing its visibility, is a NEW collection: the old one's documents are not carried over.",
|
|
387
|
+
"minProperties": 1,
|
|
388
|
+
"maxProperties": 16,
|
|
389
|
+
"additionalProperties": false,
|
|
390
|
+
"patternProperties": {
|
|
391
|
+
"^[a-z][a-z0-9_]{0,31}$": {
|
|
392
|
+
"type": "object",
|
|
393
|
+
"additionalProperties": false,
|
|
394
|
+
"required": ["visibility"],
|
|
395
|
+
"properties": {
|
|
396
|
+
"kind": {
|
|
397
|
+
"type": "string",
|
|
398
|
+
"description": "\"docs\" (the default): documents with app-chosen or server-assigned keys that can be updated in place. \"log\": append-only entries with server-assigned keys, never updated, trimmed to `maxEntries` per key space. RESERVED: civitai.com refuses \"log\" until log collections are enabled, so declare \"docs\" (or omit `kind`).",
|
|
399
|
+
"enum": ["docs", "log"]
|
|
400
|
+
},
|
|
401
|
+
"visibility": {
|
|
402
|
+
"type": "string",
|
|
403
|
+
"description": "Who can read the collection. \"private\": a separate key space per viewer — only that viewer reads or writes their documents. \"shared\": one key space for the whole app — every viewer of the app reads it, including signed-out viewers. Cannot be changed later: declare a new collection instead.",
|
|
404
|
+
"enum": ["private", "shared"]
|
|
405
|
+
},
|
|
406
|
+
"write": {
|
|
407
|
+
"type": "string",
|
|
408
|
+
"description": "Shared collections only, and REQUIRED on them. Who may create, update and delete documents. \"own\": eligible signed-in viewers create documents, and only a document's author updates or deletes it. \"anyone\": eligible signed-in viewers may update or delete any document — RESERVED: civitai.com refuses \"anyone\" until it is enabled. \"none\": nobody creates, updates or deletes documents — viewers may only increment the declared `counters` and set the declared `marks`, and incrementing a counter on a document that does not exist creates an empty one authored by no viewer; a \"none\" collection must declare at least one counter or mark. \"owner\": only the app owner writes documents; viewers can still mark and count. Only \"own\" and \"anyone\" require the `apps:storage:publish` scope. RESERVED: civitai.com refuses \"owner\" until owner-written documents are enabled. Available today: \"own\" and \"none\".",
|
|
409
|
+
"enum": ["own", "anyone", "owner", "none"]
|
|
410
|
+
},
|
|
411
|
+
"counters": {
|
|
412
|
+
"type": "array",
|
|
413
|
+
"description": "Shared collections only. Names of the counters each document carries — atomic tallies the app increments (for example plays). At most 8 distinct names, each lowercase snake_case: a letter, then up to 31 of a-z, 0-9 or _. A counter may not share a name with a mark on the same collection, or with the built-in `report` mark.",
|
|
414
|
+
"maxItems": 8,
|
|
415
|
+
"uniqueItems": true,
|
|
416
|
+
"items": {
|
|
417
|
+
"type": "string",
|
|
418
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}$",
|
|
419
|
+
"not": { "enum": ["report"] }
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
"marks": {
|
|
423
|
+
"type": "array",
|
|
424
|
+
"description": "Shared collections only. Names of the per-user marks a viewer can set on a document (for example vote) — at most one of each per viewer per document. A reader sees each mark's count and whether THEY set it, never who else did. At most 8 distinct names, each lowercase snake_case: a letter, then up to 31 of a-z, 0-9 or _. `report` is built in on every shared collection and must NOT be declared. A mark may not share a name with a counter on the same collection.",
|
|
425
|
+
"maxItems": 8,
|
|
426
|
+
"uniqueItems": true,
|
|
427
|
+
"items": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"pattern": "^[a-z][a-z0-9_]{0,31}$",
|
|
430
|
+
"not": { "enum": ["report"] }
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
"indexes": {
|
|
434
|
+
"type": "object",
|
|
435
|
+
"description": "Fields of a document's `data` the app can filter and sort by, as a map of field PATH → type. A path is 1 to 3 segments joined by `.` (for example status, datasetId or meta.round), each a letter followed by up to 31 letters, digits or _; a field whose own name contains `.` cannot be indexed. At most 4 indexes. Types: \"string\" (values up to 128 bytes), \"number\", \"boolean\", \"time\". `key`, `createdAt` and `updatedAt` are built-in sort keys and cannot be index names. Changing an index's type is not supported: remove it and add one under a new name.",
|
|
436
|
+
"maxProperties": 4,
|
|
437
|
+
"additionalProperties": false,
|
|
438
|
+
"properties": {
|
|
439
|
+
"key": false,
|
|
440
|
+
"createdAt": false,
|
|
441
|
+
"updatedAt": false
|
|
442
|
+
},
|
|
443
|
+
"patternProperties": {
|
|
444
|
+
"^[A-Za-z][A-Za-z0-9_]{0,31}(\\.[A-Za-z][A-Za-z0-9_]{0,31}){0,2}$": {
|
|
445
|
+
"type": "string",
|
|
446
|
+
"enum": ["string", "number", "boolean", "time"]
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
"showAuthor": {
|
|
451
|
+
"type": "boolean",
|
|
452
|
+
"description": "Shared collections only. When true, readers see each viewer-authored document's author USERNAME. Default false: readers learn only whether they wrote a document themselves. The numeric user id is never exposed either way."
|
|
453
|
+
},
|
|
454
|
+
"ttlSeconds": {
|
|
455
|
+
"type": "integer",
|
|
456
|
+
"description": "RESERVED — civitai.com refuses this field until expiring documents are enabled, so do not declare it yet. Intended meaning: the default lifetime of a document in this collection, in seconds. The bounds (60 to 31536000, i.e. one minute to 365 days) are provisional and may change before the field is enabled.",
|
|
457
|
+
"minimum": 60,
|
|
458
|
+
"maximum": 31536000
|
|
459
|
+
},
|
|
460
|
+
"maxEntries": {
|
|
461
|
+
"type": "integer",
|
|
462
|
+
"description": "RESERVED — log collections are refused by civitai.com until enabled, so this field cannot be used yet. Intended meaning, for `kind` \"log\" only: the most entries kept per key space, the oldest trimmed beyond it, from 1 to 10000 (omitted means 10000). The default is provisional and may change before log collections are enabled.",
|
|
463
|
+
"minimum": 1,
|
|
464
|
+
"maximum": 10000
|
|
465
|
+
},
|
|
466
|
+
"dailyWritesPerAuthor": {
|
|
467
|
+
"type": "integer",
|
|
468
|
+
"description": "RESERVED — civitai.com refuses this field until per-collection write budgets are enabled, so do not declare it yet. Intended meaning: for a shared collection that viewers write (`write` \"own\" or \"anyone\"; refused with \"owner\" or \"none\"), the per-viewer daily budget for creating and updating documents in this collection in place of the platform default, from 1 to 1000, shown to the moderator at review. The bounds are provisional and may change before the field is enabled.",
|
|
469
|
+
"minimum": 1,
|
|
470
|
+
"maximum": 1000
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
"allOf": [
|
|
474
|
+
{
|
|
475
|
+
"$comment": "A shared collection must state its write policy; a private one carries none of the shared-only fields.",
|
|
476
|
+
"if": {
|
|
477
|
+
"required": ["visibility"],
|
|
478
|
+
"properties": { "visibility": { "const": "shared" } }
|
|
479
|
+
},
|
|
480
|
+
"then": { "required": ["write"] },
|
|
481
|
+
"else": {
|
|
482
|
+
"properties": {
|
|
483
|
+
"write": false,
|
|
484
|
+
"counters": false,
|
|
485
|
+
"marks": false,
|
|
486
|
+
"showAuthor": false,
|
|
487
|
+
"dailyWritesPerAuthor": false
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
"$comment": "maxEntries belongs to log collections only (kind defaults to docs).",
|
|
493
|
+
"if": {
|
|
494
|
+
"required": ["kind"],
|
|
495
|
+
"properties": { "kind": { "const": "log" } }
|
|
496
|
+
},
|
|
497
|
+
"else": { "properties": { "maxEntries": false } }
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"$comment": "No viewer authors documents in a write:\"owner\" or write:\"none\" collection, so it has no per-author budget.",
|
|
501
|
+
"if": {
|
|
502
|
+
"required": ["write"],
|
|
503
|
+
"properties": { "write": { "enum": ["owner", "none"] } }
|
|
504
|
+
},
|
|
505
|
+
"then": { "properties": { "dailyWritesPerAuthor": false } }
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
"$comment": "A write:\"none\" collection is written only through counters and marks, so it must declare at least one.",
|
|
509
|
+
"if": {
|
|
510
|
+
"required": ["write"],
|
|
511
|
+
"properties": { "write": { "const": "none" } }
|
|
512
|
+
},
|
|
513
|
+
"then": {
|
|
514
|
+
"anyOf": [
|
|
515
|
+
{ "required": ["counters"], "properties": { "counters": { "minItems": 1 } } },
|
|
516
|
+
{ "required": ["marks"], "properties": { "marks": { "minItems": 1 } } }
|
|
517
|
+
]
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
},
|
|
376
526
|
"targets": {
|
|
377
527
|
"type": "array",
|
|
378
528
|
"description": "Model-page slot targets. Each target's slotId must be a known registered model slot (not the page slot). Optional for page-only apps.",
|