@civitai/app-sdk 0.51.2 → 0.53.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 +5 -5
- package/dist/blocks/index.d.ts +1 -1
- package/dist/blocks/scopes.d.ts +2 -0
- package/dist/blocks/scopes.js +14 -0
- package/dist/blocks/types.d.ts +51 -0
- package/dist/manifest/index.d.ts +1 -1
- package/dist/orchestrator/index.d.ts +2 -0
- package/dist/orchestrator/index.js +2 -0
- package/dist/orchestrator/steps.d.ts +5 -5
- package/dist/orchestrator/steps.js +4 -4
- package/package.json +1 -1
- package/schemas/app-block/v1.json +49 -2
package/README.md
CHANGED
|
@@ -446,7 +446,7 @@ The starters in `civitai/civitai-app-starters` wire this into framework-specific
|
|
|
446
446
|
|
|
447
447
|
## Choosing a workflow step type
|
|
448
448
|
|
|
449
|
-
The orchestrator is a workflow API: each request submits a list of typed steps. `WORKFLOW_STEP_TYPES` is the in-code catalog of every step `$type` it accepts, with a one-line description for each — `textToImage`, `imageGen`, `videoGen`, `comfy`, `customComfy`, `textToSpeech`, `aceStepAudio`, `transcription`, `imageUpscaler` among them (
|
|
449
|
+
The orchestrator is a workflow API: each request submits a list of typed steps. `WORKFLOW_STEP_TYPES` is the in-code catalog of every step `$type` it accepts, with a one-line description for each — `textToImage`, `imageGen`, `videoGen`, `comfy`, `customComfy`, `textToSpeech`, `aceStepAudio`, `transcription`, `imageUpscaler` among them (51 in total).
|
|
450
450
|
|
|
451
451
|
The catalog is pinned to the orchestrator's published OpenAPI spec two ways — an offline unit test against a transcribed copy of the spec's `WorkflowStepTemplate` discriminator mapping, and a CI job (`pnpm check:catalogs`) that re-fetches the live spec and diffs it. If a `$type` is listed here, the orchestrator accepts it.
|
|
452
452
|
|
|
@@ -521,15 +521,15 @@ What it exports:
|
|
|
521
521
|
|
|
522
522
|
| Export | What |
|
|
523
523
|
|---|---|
|
|
524
|
-
| `WorkflowStepTemplates` | `$type` → template type, for 47 of the catalog's
|
|
524
|
+
| `WorkflowStepTemplates` | `$type` → template type, for 47 of the catalog's 51 step types. Keyed by the WIRE name, which the generated type names don't always match (`model3DPreview` → `Model3dPreviewStepTemplate`). |
|
|
525
525
|
| `WorkflowStepTemplateFor<'videoGen'>` | One step's template. |
|
|
526
526
|
| `WorkflowStepInputFor<'videoGen'>` | One step's `input` shape, without needing the generated `*Input` name. |
|
|
527
527
|
| `AnyWorkflowStepTemplate` | Discriminated union of all 47 mapped templates — `Extract<…, { $type: 'comfy' }>` and exhaustive `switch` work. `@civitai/client`'s base `WorkflowStepTemplate` has `$type` as a bare `string`, so it narrows nothing. |
|
|
528
528
|
| `TypedWorkflowTemplate` | The submit envelope with `steps` narrowed to that union. Pass it straight to `submitWorkflow` / `estimateWorkflow`. |
|
|
529
529
|
|
|
530
|
-
> 🔴 **The map is not total over the catalog, and that is the expected state.** `WORKFLOW_STEP_TYPES` documents
|
|
530
|
+
> 🔴 **The map is not total over the catalog, and that is the expected state.** `WORKFLOW_STEP_TYPES` documents 51 `$type`s; this map covers 47. The 4 with no generated template in the pinned `@civitai/client` are `imageScanning`, `preprocessVideo`, `soniloAudioGen`, `yuE2`, and `WorkflowStepTemplateFor<…>` is a compile error for each of them.
|
|
531
531
|
>
|
|
532
|
-
> The two surfaces move independently on purpose: the catalog tracks the **live** orchestrator spec (a daily job syncs it), while these types track whatever `@civitai/client` was last published from. So the catalog runs ahead and the client catches up. The gap is never silent — `test/orchestrator/step-templates.test-d.ts` carries it as a `never` ledger plus one `@ts-expect-error` per gap `$type`, and `test/orchestrator/step-count-prose.test.ts` derives all four numbers (
|
|
532
|
+
> The two surfaces move independently on purpose: the catalog tracks the **live** orchestrator spec (a daily job syncs it), while these types track whatever `@civitai/client` was last published from. So the catalog runs ahead and the client catches up. The gap is never silent — `test/orchestrator/step-templates.test-d.ts` carries it as a `never` ledger plus one `@ts-expect-error` per gap `$type`, and `test/orchestrator/step-count-prose.test.ts` derives all four numbers (51, 47, 4, and the names) from `WORKFLOW_STEP_TYPES` and the map's own AST, then fails if this paragraph or its twin in `src/orchestrator/steps.ts` disagrees by one character.
|
|
533
533
|
|
|
534
534
|
The generated `*StepTemplate` and `*Input` types are **not** re-exported individually. Using this subpath already requires `@civitai/client` installed, so if you want one by name, import it straight from there — `import type { TextToImageStepTemplate } from '@civitai/client'`.
|
|
535
535
|
|
|
@@ -566,7 +566,7 @@ A `$type` having a type here says nothing about whether you may submit it.
|
|
|
566
566
|
|
|
567
567
|
Several of the 47 exist to serve Civitai's own pipelines rather than third-party apps — `modelPickleScan`, `xGuardModeration`, `training`, `comfyNodepackSnapshot`, `qwenImageBench`, the `model*`/`media*` hashing and classification steps. They're in the consumer spec, so they're typed here. They are not an invitation.
|
|
568
568
|
|
|
569
|
-
Note that `WORKFLOW_STEP_TYPES` does **not** mark most of them: of its
|
|
569
|
+
Note that `WORKFLOW_STEP_TYPES` does **not** mark most of them: of its 51 entries exactly two — `comfyNodepackSnapshot` and `qwenImageBench` — sit under its "Platform internals" heading, and the rest are ordinary documented entries (`webScrape` even carries usage notes). The reason the platform steps are typed anyway is not that the catalog flags them as internal; it's that the catalog *documents* them, so skipping them would make `WorkflowStepTemplateFor<'training'>` a compile error for a step type the SDK documents — which is exactly what is live today for the 3 `$type`s the pinned client cannot type, and is why that gap is spelled out above rather than left to be discovered.
|
|
570
570
|
|
|
571
571
|
## Public vs. confidential clients
|
|
572
572
|
|
package/dist/blocks/index.d.ts
CHANGED
|
@@ -77,5 +77,5 @@ export { isModelSlotContext, isPageSlotContext } from './types.js';
|
|
|
77
77
|
* in `types.ts` for which of the two it uses and why.
|
|
78
78
|
*/
|
|
79
79
|
export { isSignedIn } from './types.js';
|
|
80
|
-
export type { BlockContext, KnownSlotId, ModelSlotId, PageSlotContext, PageSlotId, UnknownSlotContext, BlockManifest, BlockManifestV1, BlockSettings, BlockToken, ContentRating, ManifestBooleanField, ManifestIframe, ManifestNumberField, ManifestPage, ManifestPreview, ManifestSettingField, ManifestSettings, ManifestStringField, ManifestTarget, ModelSlotContext, SettingScope, SettingWidget, Theme, ViewerInfo, BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockSourceImage, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockPendingImageInfo, BlockImageScanResult, BlockUploadPurpose, BlockTextToImageParams, BlockWorkflowSnapshot, BuzzAccountType, ShowcaseImage, WorkflowBody, WorkflowBodyTextToImage, WorkflowBodyCustomComfy, WorkflowBodyCustomComfyRecipe, WorkflowBodyCustomComfyInline, InlineComfyNode, WorkflowBodyStep, WorkflowBodyPassThroughStep, WorkflowStatus, BlockBuzzTransaction, BlockBuzzAccount, BlockDailyCompensationResource, BlockViewer, BlockWildcardPack, BlockWildcardPackErrorCode, AppWorkflow, AppWorkflowImage, BlockGatedImage, BlockCollectionFollowErrorCode, BlockCollectionFollowResult, BlockPostSource, BlockCreatePostRequest, BlockCreatePostResult, BlockCreatePostHostError, } from './types.js';
|
|
80
|
+
export type { BlockContext, KnownSlotId, ModelSlotId, PageSlotContext, PageSlotId, UnknownSlotContext, BlockManifest, BlockManifestGood, BlockManifestV1, BlockSettings, BlockToken, ContentRating, ManifestBooleanField, ManifestIframe, ManifestNumberField, ManifestPage, ManifestPreview, ManifestSettingField, ManifestSettings, ManifestStringField, ManifestTarget, ModelSlotContext, SettingScope, SettingWidget, Theme, ViewerInfo, BlockCheckpointInfo, BlockResourceInfo, BlockResourcePickerType, BlockSourceImage, BlockUploadedImageInfo, BlockGenerationSourceImageInfo, BlockPendingImageInfo, BlockImageScanResult, BlockUploadPurpose, BlockTextToImageParams, BlockWorkflowSnapshot, BuzzAccountType, ShowcaseImage, WorkflowBody, WorkflowBodyTextToImage, WorkflowBodyCustomComfy, WorkflowBodyCustomComfyRecipe, WorkflowBodyCustomComfyInline, InlineComfyNode, WorkflowBodyStep, WorkflowBodyPassThroughStep, WorkflowStatus, BlockBuzzTransaction, BlockBuzzAccount, BlockDailyCompensationResource, BlockViewer, BlockWildcardPack, BlockWildcardPackErrorCode, AppWorkflow, AppWorkflowImage, BlockGatedImage, BlockCollectionFollowErrorCode, BlockCollectionFollowResult, BlockPostSource, BlockCreatePostRequest, BlockCreatePostResult, BlockCreatePostHostError, } from './types.js';
|
|
81
81
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/blocks/scopes.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare const BLOCK_SCOPES: {
|
|
|
24
24
|
readonly COLLECTIONS_WRITE_SELF: "collections:write:self";
|
|
25
25
|
readonly COLLECTIONS_READ_PRIVATE: "collections:read:private";
|
|
26
26
|
readonly POSTS_WRITE_SELF: "posts:write:self";
|
|
27
|
+
readonly GOODS_READ_SELF: "goods:read:self";
|
|
28
|
+
readonly GOODS_PURCHASE_SELF: "goods:purchase:self";
|
|
27
29
|
};
|
|
28
30
|
export type BlockScopeKey = keyof typeof BLOCK_SCOPES;
|
|
29
31
|
export type BlockScope = (typeof BLOCK_SCOPES)[BlockScopeKey];
|
package/dist/blocks/scopes.js
CHANGED
|
@@ -48,6 +48,20 @@ export const BLOCK_SCOPES = {
|
|
|
48
48
|
// per-post confirm rendering the SERVER'S resolution of the request, and the
|
|
49
49
|
// server re-runs every guard.
|
|
50
50
|
POSTS_WRITE_SELF: 'posts:write:self',
|
|
51
|
+
// goods:* — the DIGITAL GOODS rail (civitai/civitai#5171): the platform sells
|
|
52
|
+
// a manifest-declared entitlement to the viewer for Buzz, on the app's behalf.
|
|
53
|
+
// These were live on the SERVER and in the canonical schema while absent here,
|
|
54
|
+
// so `defineBlock` rejected both and no app scaffolded from this repo could
|
|
55
|
+
// DECLARE them — the hooks that call them were unreachable. Found by the
|
|
56
|
+
// round-0 reachability question on app-starters#489.
|
|
57
|
+
//
|
|
58
|
+
// `goods:read:self` is CONSENT-EXEMPT by design: the read is scoped
|
|
59
|
+
// server-side to the calling app's own appBlockId, so it can only ever return
|
|
60
|
+
// what that app itself sold and there is no third-party data to consent to.
|
|
61
|
+
// `goods:purchase:self` is CONSENT-GATED — money out of the viewer's balance
|
|
62
|
+
// always needs an explicit grant. Do not collapse the two.
|
|
63
|
+
GOODS_READ_SELF: 'goods:read:self',
|
|
64
|
+
GOODS_PURCHASE_SELF: 'goods:purchase:self',
|
|
51
65
|
};
|
|
52
66
|
/**
|
|
53
67
|
* Format helper for the block-scope shape — 3 OR 4 colon-separated lowercase
|
package/dist/blocks/types.d.ts
CHANGED
|
@@ -1402,6 +1402,40 @@ export interface ManifestPreview {
|
|
|
1402
1402
|
description: string;
|
|
1403
1403
|
screenshots?: string[];
|
|
1404
1404
|
}
|
|
1405
|
+
/**
|
|
1406
|
+
* One entry of a manifest's `goods[]`. Mirrors the canonical schema exactly;
|
|
1407
|
+
* `id`, `title` and `priceBuzz` are required there and so are they here.
|
|
1408
|
+
*
|
|
1409
|
+
* 🔴 DECLARED BEFORE `BlockManifestV1`'S DOCBLOCK ON PURPOSE. Inserting an
|
|
1410
|
+
* interface BETWEEN a docblock and the declaration it documents does not just
|
|
1411
|
+
* look untidy — `tsc` emits both comments onto THIS interface in
|
|
1412
|
+
* `dist/blocks/types.d.ts` and leaves `BlockManifestV1` undocumented, so the
|
|
1413
|
+
* published types told a reader that "only `blockId`, `version`, `name`,
|
|
1414
|
+
* `contentRating` and `scopes` are required" about a type with three fields and
|
|
1415
|
+
* different requirements. Keep any new sibling above this comment or below
|
|
1416
|
+
* `BlockManifestV1`.
|
|
1417
|
+
*/
|
|
1418
|
+
export interface BlockManifestGood {
|
|
1419
|
+
/** Lowercase alphanumeric with `-`/`_`, at most 64 chars. Colon-free, because it is composed into a redis key and a ledger external id. */
|
|
1420
|
+
id: string;
|
|
1421
|
+
/** At most 80 chars. */
|
|
1422
|
+
title: string;
|
|
1423
|
+
/** At most 500 chars. */
|
|
1424
|
+
description?: string;
|
|
1425
|
+
/**
|
|
1426
|
+
* Whole Buzz, minimum 2 — at a price of 1 the owner's floored 70% share is
|
|
1427
|
+
* ZERO, so the app would sell an item and earn nothing from it, permanently.
|
|
1428
|
+
*/
|
|
1429
|
+
priceBuzz: number;
|
|
1430
|
+
/**
|
|
1431
|
+
* What the entitlement grants. `app_unlock` marks a one-time unlock of the app
|
|
1432
|
+
* itself; it is RECORDED identically today and the platform does not yet act
|
|
1433
|
+
* on it, so declaring it buys nothing unless you intend that later behaviour.
|
|
1434
|
+
*/
|
|
1435
|
+
kind?: 'good' | 'app_unlock';
|
|
1436
|
+
/** Opaque app payload, carried verbatim onto the entitlement. Never interpreted by the platform. */
|
|
1437
|
+
payload?: Record<string, unknown>;
|
|
1438
|
+
}
|
|
1405
1439
|
/**
|
|
1406
1440
|
* v1 manifest shape. Mirrors `schemas/app-block/v1.json` — keep them in sync.
|
|
1407
1441
|
*
|
|
@@ -1452,6 +1486,23 @@ export interface BlockManifestV1 {
|
|
|
1452
1486
|
* with the canonical schema's `scopeJustifications` (civitai #3195).
|
|
1453
1487
|
*/
|
|
1454
1488
|
scopeJustifications?: Record<string, string>;
|
|
1489
|
+
/**
|
|
1490
|
+
* Optional DIGITAL GOODS catalog — entitlements the platform sells to a viewer
|
|
1491
|
+
* for Buzz on this app's behalf. Manifest-governed and REVIEW-GATED: the
|
|
1492
|
+
* catalog a moderator approves is the catalog that can be sold, and changing a
|
|
1493
|
+
* price means shipping a new version and being re-reviewed.
|
|
1494
|
+
*
|
|
1495
|
+
* Declaring goods is not by itself permission to sell — the manifest must also
|
|
1496
|
+
* carry `goods:purchase:self` in `scopes`.
|
|
1497
|
+
*
|
|
1498
|
+
* 🔴 THE TYPE WAS ABSENT WHILE THE SCHEMA PROPERTY EXISTED, so `defineBlock`'s
|
|
1499
|
+
* documented inline-literal form rejected a `goods` declaration with TS2353
|
|
1500
|
+
* even though Ajv accepted the same manifest from a JSON file. Nothing could
|
|
1501
|
+
* catch that: there is a vendored-schema↔`BLOCK_SCOPES` cross-check but no
|
|
1502
|
+
* schema-properties↔interface-keys check, and the repo's manifest tests cast.
|
|
1503
|
+
* Kept in lockstep with the canonical schema's `goods`.
|
|
1504
|
+
*/
|
|
1505
|
+
goods?: BlockManifestGood[];
|
|
1455
1506
|
/** Optional; the canonical declares no required sub-field. */
|
|
1456
1507
|
iframe?: ManifestIframe;
|
|
1457
1508
|
/** Full-page surface descriptor (W10). */
|
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 { BlockManifest, BlockManifestV1 } from '../blocks/types.js';
|
|
18
|
+
export type { BlockManifest, BlockManifestGood, BlockManifestV1 } from '../blocks/types.js';
|
|
19
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -130,6 +130,8 @@ export declare const WORKFLOW_STEP_TYPES: {
|
|
|
130
130
|
* `maxDuration` is an upper bound; generation can stop earlier.
|
|
131
131
|
*/
|
|
132
132
|
readonly yuE2: "Generate a song from style and lyrics with YuE2";
|
|
133
|
+
/** Music or a standalone sound effect from a text prompt. */
|
|
134
|
+
readonly soniloAudioGen: "Music or a sound effect from a text prompt (Sonilo)";
|
|
133
135
|
/** Speech-to-text transcription. */
|
|
134
136
|
readonly transcription: "Speech-to-text transcription";
|
|
135
137
|
/** Generate captions from audio. */
|
|
@@ -134,6 +134,8 @@ export const WORKFLOW_STEP_TYPES = {
|
|
|
134
134
|
* `maxDuration` is an upper bound; generation can stop earlier.
|
|
135
135
|
*/
|
|
136
136
|
yuE2: 'Generate a song from style and lyrics with YuE2',
|
|
137
|
+
/** Music or a standalone sound effect from a text prompt. */
|
|
138
|
+
soniloAudioGen: 'Music or a sound effect from a text prompt (Sonilo)',
|
|
137
139
|
/** Speech-to-text transcription. */
|
|
138
140
|
transcription: 'Speech-to-text transcription',
|
|
139
141
|
/** Generate captions from audio. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* own generated client (`@civitai/client`).
|
|
4
4
|
*
|
|
5
5
|
* The sibling `@civitai/app-sdk/orchestrator` module gives you the *catalog*
|
|
6
|
-
* (`WORKFLOW_STEP_TYPES` —
|
|
6
|
+
* (`WORKFLOW_STEP_TYPES` — 51 `$type` names and what each one does) and the
|
|
7
7
|
* fetch helpers (`submitWorkflow`, `estimateWorkflow`, …), but its body
|
|
8
8
|
* builders take `input: unknown`. This module is the missing half: the actual
|
|
9
9
|
* per-step input shapes, tracked against the orchestrator's OpenAPI spec by
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
* consumer spec, so they are typed here. They are not an invitation.
|
|
71
71
|
*
|
|
72
72
|
* ⚠️ `WORKFLOW_STEP_TYPES` does NOT mark most of them. Counted at this commit:
|
|
73
|
-
* of its
|
|
73
|
+
* of its 51 entries, exactly TWO sit under its "Platform internals" heading —
|
|
74
74
|
* `comfyNodepackSnapshot` and `qwenImageBench`. `training`, `webScrape`,
|
|
75
75
|
* `xGuardModeration`, `modelPickleScan` and the `model*` / `media*` steps are
|
|
76
76
|
* ordinary documented entries under ordinary headings, and `webScrape` carries
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
* (#315) without anything going red. The measured state, derived rather than
|
|
90
90
|
* typed:
|
|
91
91
|
*
|
|
92
|
-
* `WORKFLOW_STEP_TYPES` documents
|
|
92
|
+
* `WORKFLOW_STEP_TYPES` documents 51 `$type`s; this map covers 47. The 4 with
|
|
93
93
|
* no generated template in the pinned `@civitai/client` are `imageScanning`,
|
|
94
|
-
* `preprocessVideo`, `yuE2`, and `WorkflowStepTemplateFor<…>` is a compile
|
|
94
|
+
* `preprocessVideo`, `soniloAudioGen`, `yuE2`, and `WorkflowStepTemplateFor<…>` is a compile
|
|
95
95
|
* error for each of them.
|
|
96
96
|
*
|
|
97
97
|
* That gap is EXPECTED and is not a defect in either surface. The catalog
|
|
@@ -300,7 +300,7 @@ interface StepTemplateMap {
|
|
|
300
300
|
xGuardModeration: XGuardModerationStepTemplate;
|
|
301
301
|
}
|
|
302
302
|
/**
|
|
303
|
-
* `$type` → its step-template type, for 47 of the catalog's
|
|
303
|
+
* `$type` → its step-template type, for 47 of the catalog's 51 step types.
|
|
304
304
|
*
|
|
305
305
|
* Keyed by the WIRE name rather than the generated type name, because the wire
|
|
306
306
|
* name is what you actually have in hand and the generator does not always
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* own generated client (`@civitai/client`).
|
|
4
4
|
*
|
|
5
5
|
* The sibling `@civitai/app-sdk/orchestrator` module gives you the *catalog*
|
|
6
|
-
* (`WORKFLOW_STEP_TYPES` —
|
|
6
|
+
* (`WORKFLOW_STEP_TYPES` — 51 `$type` names and what each one does) and the
|
|
7
7
|
* fetch helpers (`submitWorkflow`, `estimateWorkflow`, …), but its body
|
|
8
8
|
* builders take `input: unknown`. This module is the missing half: the actual
|
|
9
9
|
* per-step input shapes, tracked against the orchestrator's OpenAPI spec by
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
* consumer spec, so they are typed here. They are not an invitation.
|
|
71
71
|
*
|
|
72
72
|
* ⚠️ `WORKFLOW_STEP_TYPES` does NOT mark most of them. Counted at this commit:
|
|
73
|
-
* of its
|
|
73
|
+
* of its 51 entries, exactly TWO sit under its "Platform internals" heading —
|
|
74
74
|
* `comfyNodepackSnapshot` and `qwenImageBench`. `training`, `webScrape`,
|
|
75
75
|
* `xGuardModeration`, `modelPickleScan` and the `model*` / `media*` steps are
|
|
76
76
|
* ordinary documented entries under ordinary headings, and `webScrape` carries
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
* (#315) without anything going red. The measured state, derived rather than
|
|
90
90
|
* typed:
|
|
91
91
|
*
|
|
92
|
-
* `WORKFLOW_STEP_TYPES` documents
|
|
92
|
+
* `WORKFLOW_STEP_TYPES` documents 51 `$type`s; this map covers 47. The 4 with
|
|
93
93
|
* no generated template in the pinned `@civitai/client` are `imageScanning`,
|
|
94
|
-
* `preprocessVideo`, `yuE2`, and `WorkflowStepTemplateFor<…>` is a compile
|
|
94
|
+
* `preprocessVideo`, `soniloAudioGen`, `yuE2`, and `WorkflowStepTemplateFor<…>` is a compile
|
|
95
95
|
* error for each of them.
|
|
96
96
|
*
|
|
97
97
|
* That gap is EXPECTED and is not a defect in either surface. The catalog
|
package/package.json
CHANGED
|
@@ -99,13 +99,15 @@
|
|
|
99
99
|
"collections:read:self",
|
|
100
100
|
"collections:write:self",
|
|
101
101
|
"collections:read:private",
|
|
102
|
-
"posts:write:self"
|
|
102
|
+
"posts:write:self",
|
|
103
|
+
"goods:read:self",
|
|
104
|
+
"goods:purchase:self"
|
|
103
105
|
]
|
|
104
106
|
}
|
|
105
107
|
},
|
|
106
108
|
"scopeJustifications": {
|
|
107
109
|
"type": "object",
|
|
108
|
-
"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`, `buzz:read:self`, `collections:read:private`, `apps:storage:shared:write`, `posts:write:self`) 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.",
|
|
110
|
+
"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`) 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.",
|
|
109
111
|
"additionalProperties": {
|
|
110
112
|
"type": "string",
|
|
111
113
|
"minLength": 1,
|
|
@@ -221,6 +223,51 @@
|
|
|
221
223
|
}
|
|
222
224
|
}
|
|
223
225
|
},
|
|
226
|
+
"goods": {
|
|
227
|
+
"type": "array",
|
|
228
|
+
"description": "Optional DIGITAL GOODS catalog — entitlements the platform sells to a viewer on your app's behalf, for Buzz. Manifest-governed and REVIEW-GATED: the catalog a moderator approves is the catalog that can be sold, and changing a price means shipping a new version and being re-reviewed. The platform owns the ledger (who bought what, when, at what price, and its refund state); the good's MEANING is your app's business — read the viewer's entitlements from GET /api/v1/blocks/entitlements and keep the semantics in your own app storage. Declaring goods does not by itself let you sell: the app must also declare the `goods:purchase:self` scope (and `goods:read:self` to read entitlements back), and the viewer must consent. Sales split platform 30% / app owner 70%, paid immediately. Kept in lockstep with the bounds in src/shared/constants/block-goods.constants.ts (a drift-guard test enforces equality); the imperative validator in that same module is authoritative.",
|
|
229
|
+
"maxItems": 32,
|
|
230
|
+
"items": {
|
|
231
|
+
"type": "object",
|
|
232
|
+
"additionalProperties": false,
|
|
233
|
+
"required": ["id", "title", "priceBuzz"],
|
|
234
|
+
"properties": {
|
|
235
|
+
"id": {
|
|
236
|
+
"type": "string",
|
|
237
|
+
"description": "Stable identifier for this good, unique within the manifest. This is what a purchase and an entitlement are keyed by, so changing it in a later version orphans every entitlement already granted under the old id. Lowercase letters, digits, - and _, starting with a letter or digit.",
|
|
238
|
+
"minLength": 1,
|
|
239
|
+
"maxLength": 64,
|
|
240
|
+
"pattern": "^[a-z0-9][a-z0-9_-]*$"
|
|
241
|
+
},
|
|
242
|
+
"title": {
|
|
243
|
+
"type": "string",
|
|
244
|
+
"description": "Human-readable name shown to the viewer at purchase. Non-empty; the server measures the TRIMMED length, so this maxLength is never more permissive than the server.",
|
|
245
|
+
"minLength": 1,
|
|
246
|
+
"maxLength": 80
|
|
247
|
+
},
|
|
248
|
+
"description": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"description": "Optional one-paragraph explanation of what the viewer gets.",
|
|
251
|
+
"maxLength": 500
|
|
252
|
+
},
|
|
253
|
+
"priceBuzz": {
|
|
254
|
+
"type": "integer",
|
|
255
|
+
"description": "Price in whole Buzz. Buzz has no sub-unit, so this must be a whole number, and the minimum is 2 rather than 1 because the app owner's 70% share is floored — a 1 Buzz item would earn its owner nothing, permanently. Capped so a single purchase can never drain an account; a viewer also has a daily ceiling across every app they have installed, so a purchase can be refused with a clean 4xx even at a legal price. Both bounds are kept in lockstep with BLOCK_GOOD_MIN_PRICE_BUZZ / BLOCK_GOOD_MAX_PRICE_BUZZ in src/shared/constants/block-goods.constants.ts by a drift-guard test.",
|
|
256
|
+
"minimum": 2,
|
|
257
|
+
"maximum": 50000
|
|
258
|
+
},
|
|
259
|
+
"kind": {
|
|
260
|
+
"type": "string",
|
|
261
|
+
"description": "What the entitlement grants, from the platform's point of view. \"good\" (the default) is an ordinary in-app purchase the platform records and does not interpret. \"app_unlock\" marks a one-time unlock of the app itself; it is RECORDED IDENTICALLY today and the platform does NOT yet act on it — the paid-app access gate is a later change that reads this value. Declaring it now buys nothing, so leave it unset unless you intend that later behaviour.",
|
|
262
|
+
"enum": ["good", "app_unlock"]
|
|
263
|
+
},
|
|
264
|
+
"payload": {
|
|
265
|
+
"type": "object",
|
|
266
|
+
"description": "Optional OPAQUE payload copied verbatim onto the entitlement at purchase and handed back to your app unchanged. The platform never reads or interprets it. It is manifest-sourced rather than client-supplied precisely so that what an entitlement carries is something a moderator saw. Must serialize to at most 2048 bytes."
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
224
271
|
"targets": {
|
|
225
272
|
"type": "array",
|
|
226
273
|
"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.",
|