@civitai/app-sdk 0.72.0 → 0.73.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.
@@ -29,6 +29,7 @@ export declare const BLOCK_SCOPES: {
29
29
  readonly GOODS_READ_SELF: "goods:read:self";
30
30
  readonly GOODS_PURCHASE_SELF: "goods:purchase:self";
31
31
  readonly APPS_STORE_ITEMS_WRITE: "apps:store:items:write";
32
+ readonly SOCIAL_REACT_SELF: "social:react:self";
32
33
  };
33
34
  export type BlockScopeKey = keyof typeof BLOCK_SCOPES;
34
35
  export type BlockScope = (typeof BLOCK_SCOPES)[BlockScopeKey];
@@ -90,6 +90,13 @@ export const BLOCK_SCOPES = {
90
90
  // Requires a signed-in (non-anonymous) subject. 4-segment, like the shared
91
91
  // storage scopes — see BLOCK_SCOPE_PATTERN below.
92
92
  APPS_STORE_ITEMS_WRITE: 'apps:store:items:write',
93
+ // social:react:self — set the VIEWER'S reaction on an image a block endpoint
94
+ // served the app (civitai/civitai#6144). SENSITIVE (a public, reward-paying
95
+ // reaction under the viewer's name, so a declaring manifest MUST carry a
96
+ // `scopeJustifications` entry) and CONSENT-GATED. Listed here because the
97
+ // canonical schema's `scopes` enum carries it; the server ships the feature
98
+ // behind a dark flag, and this package has no reaction helper yet.
99
+ SOCIAL_REACT_SELF: 'social:react:self',
93
100
  };
94
101
  /**
95
102
  * Format helper for the block-scope shape — 2, 3 OR 4 colon-separated
@@ -2573,7 +2573,8 @@ export interface BlockStorageIndexes {
2573
2573
  /**
2574
2574
  * A PRIVATE collection — a separate key space per viewer, read and written
2575
2575
  * only by that viewer. Carries none of the shared-only fields (`write`,
2576
- * `counters`, `marks`, `showAuthor`, `dailyWritesPerAuthor`); the canonical
2576
+ * `counters`, `marks`, `showAuthor`, `dailyWritesPerAuthor`,
2577
+ * `ownedModelVersions`); the canonical
2577
2578
  * forbids them here. See {@link BlockStorageSharedCollectionDeclaration} for
2578
2579
  * the fields both kinds share.
2579
2580
  */
@@ -2656,6 +2657,32 @@ export interface BlockStorageSharedCollectionDeclaration {
2656
2657
  * collection viewers write (`write` `'own'` or `'anyone'` only).
2657
2658
  */
2658
2659
  dailyWritesPerAuthor?: number;
2660
+ /**
2661
+ * `write` `'own'` collections only — the canonical refuses it under
2662
+ * `'anyone'`, `'owner'` and `'none'`, and on private collections. Fields of a
2663
+ * document's `data` that, when present, must hold the id of a Civitai model
2664
+ * version owned by the viewer writing the document — for example
2665
+ * `['/workflow/modelVersionId']` for a collection where viewers publish their
2666
+ * own workflows.
2667
+ *
2668
+ * 1 to 4 distinct pointers, each 1 to 4 segments of `/` then a letter or `_`
2669
+ * followed by up to 63 letters, digits or `_` (pattern
2670
+ * `^(/[A-Za-z_][A-Za-z0-9_]{0,63}){1,4}$`). A pointer names one field of
2671
+ * nested objects: it never indexes into an array, and a step through an
2672
+ * array or any other non-object finds nothing.
2673
+ *
2674
+ * On every create and update the server resolves each pointer in the new
2675
+ * `data`. An absent field is allowed. A present one must be a positive
2676
+ * integer naming a model version whose model the writer owns; anything else
2677
+ * — someone else's version, a missing or deleted one, a value that is not a
2678
+ * positive integer — is refused 403 `resource_not_owned`, with
2679
+ * `details.pointer` naming the field, before moderation and before any
2680
+ * write budget is spent. If the ownership lookup itself fails, the write is
2681
+ * refused 503 `service_unavailable` (retryable). Ownership is checked only
2682
+ * when a document is written: documents already stored keep the id if the
2683
+ * model later changes hands or is deleted.
2684
+ */
2685
+ ownedModelVersions?: string[];
2659
2686
  }
2660
2687
  /**
2661
2688
  * One collection declaration — see {@link BlockManifestV1.storage}.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civitai/app-sdk",
3
- "version": "0.72.0",
3
+ "version": "0.73.0",
4
4
  "description": "OAuth + PKCE, encrypted-cookie sessions, scopes, and orchestrator helpers for building third-party Civitai apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -104,13 +104,14 @@
104
104
  "posts:write:self",
105
105
  "goods:read:self",
106
106
  "goods:purchase:self",
107
- "apps:store:items:write"
107
+ "apps:store:items:write",
108
+ "social:react:self"
108
109
  ]
109
110
  }
110
111
  },
111
112
  "scopeJustifications": {
112
113
  "type": "object",
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.",
114
+ "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`, `social:react: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.",
114
115
  "additionalProperties": {
115
116
  "type": "string",
116
117
  "minLength": 1,
@@ -468,6 +469,17 @@
468
469
  "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
470
  "minimum": 1,
470
471
  "maximum": 1000
472
+ },
473
+ "ownedModelVersions": {
474
+ "type": "array",
475
+ "description": "Shared collections with `write` \"own\" only. Fields of a document's `data` that, when present, must hold a Civitai model version id owned by the viewer writing the document — for example [\"/workflow/modelVersionId\"] for a collection where viewers publish their own workflows. Each entry is a pointer of 1 to 4 segments, each \"/\" then a letter or _ followed by up to 63 letters, digits or _; 1 to 4 distinct pointers. A pointer names one field of nested objects: it never indexes into an array, and a step through an array or any other non-object finds nothing. On every create and update the server resolves each pointer in the new `data`: a field that is absent is allowed; a field that is present must be a positive integer naming a model version whose model the writer owns, and is otherwise refused with 403 `resource_not_owned` — a version that is someone else's, missing or deleted, and a value that is not a positive integer, are all refused the same way. The check runs before moderation and before any write budget is spent. Ownership is checked when a document is written, not afterwards: if the model later changes hands or is deleted, documents already stored keep the id.",
476
+ "minItems": 1,
477
+ "maxItems": 4,
478
+ "uniqueItems": true,
479
+ "items": {
480
+ "type": "string",
481
+ "pattern": "^(/[A-Za-z_][A-Za-z0-9_]{0,63}){1,4}$"
482
+ }
471
483
  }
472
484
  },
473
485
  "allOf": [
@@ -484,7 +496,8 @@
484
496
  "counters": false,
485
497
  "marks": false,
486
498
  "showAuthor": false,
487
- "dailyWritesPerAuthor": false
499
+ "dailyWritesPerAuthor": false,
500
+ "ownedModelVersions": false
488
501
  }
489
502
  }
490
503
  },
@@ -504,6 +517,14 @@
504
517
  },
505
518
  "then": { "properties": { "dailyWritesPerAuthor": false } }
506
519
  },
520
+ {
521
+ "$comment": "ownedModelVersions checks the version against the viewer WRITING the document, so it is declared only where that viewer is always the author: shared collections with write:\"own\" (private collections are refused above).",
522
+ "if": {
523
+ "required": ["write"],
524
+ "properties": { "write": { "enum": ["anyone", "owner", "none"] } }
525
+ },
526
+ "then": { "properties": { "ownedModelVersions": false } }
527
+ },
507
528
  {
508
529
  "$comment": "A write:\"none\" collection is written only through counters and marks, so it must declare at least one.",
509
530
  "if": {