@civitai/app-sdk 0.58.0 → 0.59.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 CHANGED
@@ -266,7 +266,7 @@ no entry fails the suite.
266
266
  > assigned server-side, so it cannot be enforced locally.
267
267
 
268
268
  **Where it runs.** Every scaffold that ships a `block.manifest.json`
269
- (`starters/civitai-block-starter` and all six `starters/examples/*`) registers
269
+ (`starters/civitai-block-starter` and every `starters/examples/*` app) registers
270
270
  `blockManifestPlugin` from `@civitai/app-sdk/vite` in its `vite.config.ts`. It
271
271
  fires from Vite's `configResolved`, the one hook called on both the dev-server
272
272
  and the build path — so `pnpm dev`, `pnpm dev:harness` and `pnpm build` all fail
@@ -213,7 +213,8 @@ export interface BlockInitPayload {
213
213
  * fail-closed defaults for you. `@civitai/blocks-react`'s
214
214
  * `useDomainMaturity()` is the React wrapper over the same thing — it is one
215
215
  * way to get this right, not the only one, since this module is
216
- * runtime-agnostic and two of the starters ship without React.
216
+ * runtime-agnostic and several starters — the Civitai App starter among
217
+ * them — ship without React.
217
218
  */
218
219
  effectiveBrowsingLevel?: number;
219
220
  }
@@ -26,6 +26,7 @@ export declare const BLOCK_SCOPES: {
26
26
  readonly POSTS_WRITE_SELF: "posts:write:self";
27
27
  readonly GOODS_READ_SELF: "goods:read:self";
28
28
  readonly GOODS_PURCHASE_SELF: "goods:purchase:self";
29
+ readonly APPS_STORE_ITEMS_WRITE: "apps:store:items:write";
29
30
  };
30
31
  export type BlockScopeKey = keyof typeof BLOCK_SCOPES;
31
32
  export type BlockScope = (typeof BLOCK_SCOPES)[BlockScopeKey];
@@ -44,8 +45,8 @@ export type BlockScope = (typeof BLOCK_SCOPES)[BlockScopeKey];
44
45
  *
45
46
  * The 4th segment was added to mirror the server's 4-segment
46
47
  * `apps:storage:shared:read` / `apps:storage:shared:write` scopes (the SHARED
47
- * cross-user datastore). The SDK now tracks the server's 4-segment scopes
48
- * directly, so this is no longer a coordinated-major-bump situation — the
48
+ * cross-user datastore); `apps:store:items:write` is the same shape. The SDK
49
+ * now tracks the server's 4-segment scopes directly, so this is no longer a coordinated-major-bump situation — the
49
50
  * pattern just widened to accept the shapes the canonical enum already lists.
50
51
  */
51
52
  export declare const BLOCK_SCOPE_PATTERN: RegExp;
@@ -24,7 +24,7 @@ export const BLOCK_SCOPES = {
24
24
  // apps:storage:shared:* — the SHARED (app-global / cross-user) datastore. Same
25
25
  // no-OAuth-bit posture as apps:storage:*; the server gates them by presence in
26
26
  // the block's approved scope set (plus a min-trust gate + fail-closed flag).
27
- // These are the SDK's only 4-segment scopes — see BLOCK_SCOPE_PATTERN below.
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
30
  // collections:* — the App Blocks Collections surface. These have no OAuth bit
@@ -62,6 +62,22 @@ export const BLOCK_SCOPES = {
62
62
  // always needs an explicit grant. Do not collapse the two.
63
63
  GOODS_READ_SELF: 'goods:read:self',
64
64
  GOODS_PURCHASE_SELF: 'goods:purchase:self',
65
+ // apps:store:items:write — publish the VIEWER'S OWN app items into the App
66
+ // Store as sub-listing cards under the calling app (civitai/civitai#5511,
67
+ // `/api/v1/blocks/sub-listings/{upsert,withdraw,mine}`). No OAuth bit.
68
+ //
69
+ // SENSITIVE: it writes store cards every visitor sees, under the viewer's
70
+ // name, so a declaring manifest MUST carry a `scopeJustifications` entry or
71
+ // the server rejects it at submit (not mirrored by `defineBlock` — see
72
+ // KNOWN_GAPS in `../manifest/defineBlock.ts`).
73
+ //
74
+ // CONSENT-EXEMPT on the server, like `apps:storage:shared:write`: the real
75
+ // gates run per call (the parent's enable switch, the shared-write trust
76
+ // check, item authorship, text safety, rate limits, moderator approval), and
77
+ // a consent-gated scope would be dropped from tokens before any could run.
78
+ // Requires a signed-in (non-anonymous) subject. 4-segment, like the shared
79
+ // storage scopes — see BLOCK_SCOPE_PATTERN below.
80
+ APPS_STORE_ITEMS_WRITE: 'apps:store:items:write',
65
81
  };
66
82
  /**
67
83
  * Format helper for the block-scope shape — 3 OR 4 colon-separated lowercase
@@ -78,8 +94,8 @@ export const BLOCK_SCOPES = {
78
94
  *
79
95
  * The 4th segment was added to mirror the server's 4-segment
80
96
  * `apps:storage:shared:read` / `apps:storage:shared:write` scopes (the SHARED
81
- * cross-user datastore). The SDK now tracks the server's 4-segment scopes
82
- * directly, so this is no longer a coordinated-major-bump situation — the
97
+ * cross-user datastore); `apps:store:items:write` is the same shape. The SDK
98
+ * now tracks the server's 4-segment scopes directly, so this is no longer a coordinated-major-bump situation — the
83
99
  * pattern just widened to accept the shapes the canonical enum already lists.
84
100
  */
85
101
  export const BLOCK_SCOPE_PATTERN = /^[a-z]+:[a-z]+:[a-z]+(?::[a-z]+)?$/;
@@ -1933,11 +1933,13 @@ export interface BlockManifestV1 {
1933
1933
  */
1934
1934
  $schema?: 'https://civitai.com/schemas/app-block/v1.json' | (string & {});
1935
1935
  /**
1936
- * NOT a canonical manifest property, and NOT validated. Your app id lives in
1937
- * `civitai.app.json` (`{"appId": "..."}`), which is what the `civitai` CLI
1938
- * reads. The canonical does not forbid extra top-level keys, so the server
1939
- * ignores this one; the scaffolds still carry `"app_REPLACE_ME"` and it is
1940
- * inert.
1936
+ * NOT a canonical manifest property, and NOT validated. Nothing reads it: the
1937
+ * canonical does not forbid extra top-level keys, so the server ignores this
1938
+ * one, and the Go `civitai` CLI identifies an app by the manifest's
1939
+ * `blockId` (its `app submit` keys the submission on it). There is no
1940
+ * separate app-id file either — an earlier version of this comment pointed at
1941
+ * a `civitai.app.json`, which no current tool reads. Scaffolds that still
1942
+ * carry `"app_REPLACE_ME"` here are carrying an inert key.
1941
1943
  */
1942
1944
  appId?: string;
1943
1945
  blockId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civitai/app-sdk",
3
- "version": "0.58.0",
3
+ "version": "0.59.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",
@@ -101,13 +101,14 @@
101
101
  "collections:read:private",
102
102
  "posts:write:self",
103
103
  "goods:read:self",
104
- "goods:purchase:self"
104
+ "goods:purchase:self",
105
+ "apps:store:items:write"
105
106
  ]
106
107
  }
107
108
  },
108
109
  "scopeJustifications": {
109
110
  "type": "object",
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.",
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.",
111
112
  "additionalProperties": {
112
113
  "type": "string",
113
114
  "minLength": 1,