@civitai/app-sdk 0.46.0 → 0.48.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 +120 -33
- package/dist/blocks/appStorageLimits.d.ts +113 -0
- package/dist/blocks/appStorageLimits.d.ts.map +1 -0
- package/dist/blocks/appStorageLimits.js +113 -0
- package/dist/blocks/appStorageLimits.js.map +1 -0
- package/dist/blocks/index.d.ts +26 -7
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/blocks/index.js +25 -5
- package/dist/blocks/index.js.map +1 -1
- package/dist/blocks/manifestError.d.ts +20 -0
- package/dist/blocks/manifestError.d.ts.map +1 -0
- package/dist/blocks/manifestError.js +22 -0
- package/dist/blocks/manifestError.js.map +1 -0
- package/dist/blocks/messages.d.ts.map +1 -1
- package/dist/blocks/messages.js.map +1 -1
- package/dist/blocks/scopes.d.ts +7 -3
- package/dist/blocks/scopes.d.ts.map +1 -1
- package/dist/blocks/scopes.js +7 -3
- package/dist/blocks/scopes.js.map +1 -1
- package/dist/blocks/types.d.ts +197 -50
- package/dist/blocks/types.d.ts.map +1 -1
- package/dist/blocks/types.js +56 -0
- package/dist/blocks/types.js.map +1 -1
- package/dist/manifest/defineBlock.d.ts +145 -0
- package/dist/manifest/defineBlock.d.ts.map +1 -0
- package/dist/manifest/defineBlock.js +390 -0
- package/dist/manifest/defineBlock.js.map +1 -0
- package/dist/manifest/index.d.ts +19 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +17 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/oauth/token.d.ts +34 -3
- package/dist/oauth/token.d.ts.map +1 -1
- package/dist/oauth/token.js +116 -4
- package/dist/oauth/token.js.map +1 -1
- package/dist/vite/index.d.ts +14 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +61 -0
- package/dist/vite/index.js.map +1 -0
- package/package.json +42 -2
- package/dist/blocks/defineBlock.d.ts +0 -53
- package/dist/blocks/defineBlock.d.ts.map +0 -1
- package/dist/blocks/defineBlock.js +0 -338
- package/dist/blocks/defineBlock.js.map +0 -1
package/README.md
CHANGED
|
@@ -19,12 +19,19 @@ pnpm add @civitai/app-sdk
|
|
|
19
19
|
| `cookies/*` — `sealCookie`, `unsealCookie`, `buildSetCookieHeader`, `readCookie` | AES-256-GCM authenticated cookie crypto. Use to seal a session blob (refresh token, expiry, scope) into an `httpOnly` cookie with zero external session store. |
|
|
20
20
|
| `orchestrator/*` — `createOrchestratorClient`, `estimateWorkflow`, `submitWorkflow`, `getWorkflow`, `pollWorkflow`, `buildTextToImageBody`, `buildImageGenBody`, `buildWorkflowBody`, `WORKFLOW_STEP_TYPES`, `IMAGE_GEN_ENGINES`, `isTerminal`, `extractImageUrls`, `OrchestratorError`, `WorkflowSnapshot`, `GenerateInput`, `ImageGenInput`, `WorkflowStepType`, `ImageGenEngine`, `DEFAULT_MODEL_AIR` | Orchestrator workflow glue — types, body builders, raw HTTP, and long-poll helper. Client + server safe (fetch-only). `estimateWorkflow` calls `?whatif=true` to preview Buzz cost without spending. `pollWorkflow` long-polls to terminal status. `WORKFLOW_STEP_TYPES` is the catalog of every step `$type` the orchestrator accepts. |
|
|
21
21
|
| `orchestrator/steps` — `WorkflowStepTemplates`, `WorkflowStepTemplateFor`, `WorkflowStepInputFor`, `AnyWorkflowStepTemplate`, `TypedWorkflowTemplate` | **Type-only** subpath (0 runtime bytes) keying the orchestrator's generated workflow-step shapes from `@civitai/client` by wire `$type`, so apps compose real step bodies against types that track the spec instead of hand-maintained copies. Requires the optional peer `@civitai/client@beta`. Type surface only — it grants no submit permission; see "Typed step shapes" below. |
|
|
22
|
-
| `blocks/*` — `
|
|
22
|
+
| `blocks/*` — `BlockManifestError`, `BLOCK_SCOPES`, `BLOCK_SCOPE_PATTERN`, `isMessage`, types (`BlockManifestV1`, `BlockContext`, `BlockToken`, `BlockSettings`, `ViewerInfo`, `ThemeInfo`, `BlockWorkflowSnapshot`, `BlockInitPayload`, `ParentToBlockMessage`, `BlockToParentMessage`, …) | Framework-agnostic contract for [Civitai Apps](https://github.com/civitai/civitai-app-starters/blob/main/docs/build-your-first-app-block.md). Ships a byte-identical copy of the server-published canonical JSON Schema (draft 2020-12, https://civitai.com/schemas/app-block/v1.json) at the `./schemas/app-block/v1.json` subpath for offline validation; a CI drift-check keeps it in sync. Runtime-agnostic and **zero runtime dependencies** — no React, no DOM types, nothing in your install graph. Hooks and the iframe transport live in a separate package. |
|
|
23
|
+
| `manifest/*` — `defineBlock`, `SCHEMA_DIVERGENCES`, `KNOWN_GAPS` (**Node only**) | Build-time manifest validation. `defineBlock(config)` compiles the vendored canonical schema with [Ajv](https://ajv.js.org) and validates a `BlockManifestV1` against it, so authoring mistakes surface in `pnpm dev` instead of at `civitai app validate`/submit. It is **derived from the schema, not a hand-written mirror of it** — that mirror is what produced [#330](https://github.com/civitai/civitai-app-starters/issues/330). Needs `node:fs` and the optional peer `ajv`, which is why it is not on the browser-facing `./blocks` surface. |
|
|
24
|
+
| `vite/*` — `blockManifestPlugin` (**Node only**) | A Vite plugin wrapping `defineBlock`, firing from `configResolved` — the one hook Vite calls on both the dev-server and the build path. Every block scaffold registers it, so `pnpm dev`, `pnpm dev:harness` and `pnpm build` all fail on a bad manifest with the offending field path. Optional peers: `ajv` (runtime) and `vite` (types only). |
|
|
23
25
|
|
|
24
26
|
## Subpath imports
|
|
25
27
|
|
|
26
28
|
```ts
|
|
27
|
-
import {
|
|
29
|
+
import { BLOCK_SCOPES, isSignedIn } from '@civitai/app-sdk/blocks';
|
|
30
|
+
// Build-time manifest validation (NODE ONLY — needs the optional peer `ajv`).
|
|
31
|
+
// Most projects want the Vite plugin below rather than calling this directly:
|
|
32
|
+
import { defineBlock } from '@civitai/app-sdk/manifest';
|
|
33
|
+
// The same gate as a Vite plugin (NODE ONLY — optional peers `ajv` + `vite`):
|
|
34
|
+
import { blockManifestPlugin } from '@civitai/app-sdk/vite';
|
|
28
35
|
// Type-only: the orchestrator's generated per-step shapes. Needs the optional
|
|
29
36
|
// peer `@civitai/client@beta` — see "Typed step shapes" below:
|
|
30
37
|
import type { TypedWorkflowTemplate } from '@civitai/app-sdk/orchestrator/steps';
|
|
@@ -37,9 +44,11 @@ import manifestSchema from '@civitai/app-sdk/schemas/app-block/v1.json' with { t
|
|
|
37
44
|
## Civitai Apps contract (`@civitai/app-sdk/blocks`)
|
|
38
45
|
|
|
39
46
|
> Building a **Civitai App** (an iframe-embedded UI on a civitai.com page)? This
|
|
40
|
-
> subpath is the framework-agnostic contract — manifest types, scope strings
|
|
41
|
-
> the `postMessage` protocol
|
|
42
|
-
>
|
|
47
|
+
> subpath is the framework-agnostic contract — manifest types, scope strings and
|
|
48
|
+
> the `postMessage` protocol. (The `defineBlock` validator moved to the node-only
|
|
49
|
+
> [`@civitai/app-sdk/manifest`](#defineblock-validator-rules) subpath; `./blocks`
|
|
50
|
+
> keeps zero runtime dependencies.) The React hooks + transport that consume it
|
|
51
|
+
> live in
|
|
43
52
|
> [`@civitai/blocks-react`](https://www.npmjs.com/package/@civitai/blocks-react).
|
|
44
53
|
> Start from the runnable [examples](https://github.com/civitai/civitai-app-starters/tree/main/starters/examples).
|
|
45
54
|
>
|
|
@@ -89,7 +98,7 @@ interface BlockInitPayload {
|
|
|
89
98
|
token: WrappedToken; // { raw, scopes[], expiresAt (ISO), buzzBudget? }
|
|
90
99
|
context: BlockContext; // { slotId, … } — narrow to ModelSlotContext
|
|
91
100
|
settings: BlockSettings; // { publisherSettings, userSettings }
|
|
92
|
-
viewer: ViewerInfo | null; // null = anonymous
|
|
101
|
+
viewer: ViewerInfo | null; // null = anonymous — gate with isSignedIn(viewer)
|
|
93
102
|
theme: 'light' | 'dark';
|
|
94
103
|
renderMode: 'iframe' | 'inline';
|
|
95
104
|
}
|
|
@@ -103,9 +112,10 @@ interface BlockInitPayload {
|
|
|
103
112
|
|
|
104
113
|
| Export | What |
|
|
105
114
|
|---|---|
|
|
106
|
-
| `
|
|
107
|
-
| `BLOCK_SCOPES` / `BLOCK_SCOPE_PATTERN` | The 15 known block scope strings (the authoritative enum `defineBlock` validates against) + the `domain:verb:target` format-helper regex. A scope is valid only if it's a member of `BLOCK_SCOPES`, matching the [canonical schema](https://civitai.com/schemas/app-block/v1.json). |
|
|
115
|
+
| `BLOCK_SCOPES` / `BLOCK_SCOPE_PATTERN` | The 15 known block scope strings (the authoritative enum the canonical schema validates `scopes` against) + the `domain:verb:target` format-helper regex. A scope is valid only if it's a member of `BLOCK_SCOPES`, matching the [canonical schema](https://civitai.com/schemas/app-block/v1.json). |
|
|
108
116
|
| `isMessage(data, type)` | Discriminator-only message narrowing (see above). |
|
|
117
|
+
| `isModelSlotContext(ctx)` / `isPageSlotContext(ctx)` | Runtime narrowing for the `slotId`-discriminated `BlockContext` union. Real checks on a value that crossed a `postMessage` boundary — they verify every field they assert, not just `slotId`. |
|
|
118
|
+
| `isSignedIn(viewer)` | **The sign-in gate.** `isSignedIn(useBlockContext().viewer)` — do not open-code it as `viewer !== null` or `viewer?.signedIn === true`. Which of those is correct has already changed once with the host contract, and this is the one place it is decided. It reads neither `viewer.id` nor `viewer.username` (both `@deprecated`), so nothing written through it changes when those are removed. Need the identity rather than the presence? `useViewer()` — scope-gated and audited per call. |
|
|
109
119
|
| types | `BlockManifestV1`, `ManifestSettings` (+ field types), `BlockContext`, `ModelSlotContext`, `BlockCheckpointInfo`, `ShowcaseImage`, `BlockToken`, `WrappedToken`, `BlockSettings`, `ViewerInfo`, `Theme`, `WorkflowBody`, `BlockTextToImageParams`, `WorkflowBodyCustomComfy` (+ its two arms `WorkflowBodyCustomComfyRecipe` / `WorkflowBodyCustomComfyInline`, and `InlineComfyNode`), `WorkflowBodyStep` / `WorkflowBodyPassThroughStep` (the two arms of `kind: 'step'`), `BlockWorkflowSnapshot`, `WorkflowStatus`, `BlockInitPayload`, `ParentToBlockMessage`, `BlockToParentMessage`. |
|
|
110
120
|
|
|
111
121
|
`WorkflowBody`'s `customComfy` member is a discriminated union on `mode`, mirroring
|
|
@@ -152,31 +162,67 @@ const body: WorkflowBody = {
|
|
|
152
162
|
|
|
153
163
|
### `defineBlock` validator rules
|
|
154
164
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
165
|
+
**There is no rule list here, and that is the point.** `defineBlock` does not
|
|
166
|
+
maintain one: it compiles the vendored copy of the
|
|
167
|
+
[canonical schema](https://civitai.com/schemas/app-block/v1.json) with
|
|
168
|
+
[Ajv](https://ajv.js.org) and validates against **that**. Every `required`,
|
|
169
|
+
`enum`, `pattern`, bound, `additionalProperties` and `allOf` the canonical
|
|
170
|
+
expresses is enforced, and moves when the canonical moves. The schema is the
|
|
171
|
+
rule list; read it, or read the errors.
|
|
172
|
+
|
|
173
|
+
That is [#330](https://github.com/civitai/civitai-app-starters/issues/330)'s own
|
|
174
|
+
proposed fix. The previous implementation hand-mirrored the schema, and the
|
|
175
|
+
mirror diverged exactly as the issue predicted: it required 11 fields where the
|
|
176
|
+
canonical requires **five** (`blockId`, `version`, `name`, `contentRating`,
|
|
177
|
+
`scopes`), required `appId` — not a canonical property at all — and *required*
|
|
178
|
+
the SERVER-OWNED `iframe.src` that `civitai app submit` refuses, so it rejected
|
|
179
|
+
every `block.manifest.json` this repo ships.
|
|
180
|
+
|
|
181
|
+
On top of the schema, `defineBlock` applies exactly five extra rules, each
|
|
182
|
+
mirroring a server rejection the canonical states only in **prose**:
|
|
183
|
+
|
|
184
|
+
| Rule | The canonical prose it mirrors |
|
|
185
|
+
|---|---|
|
|
186
|
+
| a dev-set **`iframe.src`** is rejected | *"SERVER-OWNED. Do NOT set `iframe.src` — the platform assigns it."* The JSON-Schema `not` is deliberately absent; the top-level `allOf` `$comment` says the platform validator and the Go CLI reject it instead. |
|
|
187
|
+
| a dev-set **`trustTier`** is rejected | *"SERVER-OWNED … the platform assigns the trust tier during review."* Same shape. |
|
|
188
|
+
| **`iframe.sandbox`** rejects `allow-same-origin` and every `allow-top-navigation*` token | *"Never combine allow-same-origin with allow-scripts."* Top-navigation is refused because a block must route navigation through the `NAVIGATE` postMessage. |
|
|
189
|
+
| every **`scopeJustifications`** key must be a scope in `scopes` | *"The requirement is enforced imperatively by the manifest validator (not expressed as JSON-Schema conditionals here)."* |
|
|
190
|
+
| **`settings`** is validated against the W3 settings meta-schema | Not in the app-block schema at all — settings are validated server-side by `manifest-settings.meta.schema.ts`. |
|
|
191
|
+
|
|
192
|
+
Each is **strictly additive**: it can only reject a manifest Ajv accepted, never
|
|
193
|
+
relax a canonical rule. `test/manifest/divergences.test.ts` asserts exactly that
|
|
194
|
+
per entry — the fixture must be schema-VALID and `defineBlock`-REJECTED — and the
|
|
195
|
+
table and the fixture set must be the same set, so a sixth hand-written rule with
|
|
196
|
+
no entry fails the suite.
|
|
197
|
+
|
|
198
|
+
> **Passing is necessary, not sufficient**, and it is **not** a replacement for
|
|
199
|
+
> `civitai app validate` (the Go CLI's local pre-check against the same
|
|
200
|
+
> canonical). Run that before `civitai app submit`. `KNOWN_GAPS` in
|
|
201
|
+
> `src/manifest/defineBlock.ts` names each thing only the server can check —
|
|
202
|
+
> including one that cuts the *other* way: the canonical's sandbox description is
|
|
203
|
+
> an **allowlist** (*"Unverified tier allows only: allow-scripts, allow-forms"*)
|
|
204
|
+
> while the rule above is a denylist, so `allow-popups`, `allow-modals` and
|
|
205
|
+
> `allow-downloads` **pass here and may be refused at review**. The tier is
|
|
206
|
+
> assigned server-side, so it cannot be enforced locally.
|
|
207
|
+
|
|
208
|
+
**Where it runs.** Every scaffold that ships a `block.manifest.json`
|
|
209
|
+
(`starters/civitai-block-starter` and all six `starters/examples/*`) registers
|
|
210
|
+
`blockManifestPlugin` from `@civitai/app-sdk/vite` in its `vite.config.ts`. It
|
|
211
|
+
fires from Vite's `configResolved`, the one hook called on both the dev-server
|
|
212
|
+
and the build path — so `pnpm dev`, `pnpm dev:harness` and `pnpm build` all fail
|
|
213
|
+
loudly on a bad manifest, with the offending field path in the message. Add
|
|
214
|
+
`ajv` to your devDependencies (it is an optional peer):
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pnpm add -D ajv
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
// vite.config.ts — drop this into your existing `defineConfig({ plugins: [...] })`.
|
|
222
|
+
import { blockManifestPlugin } from '@civitai/app-sdk/vite';
|
|
223
|
+
|
|
224
|
+
const plugins = [blockManifestPlugin()];
|
|
225
|
+
```
|
|
180
226
|
|
|
181
227
|
### Web storage in a block (`@civitai/app-sdk/safe-storage`)
|
|
182
228
|
|
|
@@ -295,6 +341,7 @@ const tokens = await exchangeCode({
|
|
|
295
341
|
redirectUri: 'https://your-app.com/api/auth/callback/civitai',
|
|
296
342
|
code: codeFromQuery,
|
|
297
343
|
codeVerifier: verifierFromSealedCookie,
|
|
344
|
+
fallbackScope: scope, // used if the response's `scope` is absent or unreadable
|
|
298
345
|
});
|
|
299
346
|
|
|
300
347
|
// 3. Store tokens in an encrypted httpOnly cookie
|
|
@@ -316,6 +363,46 @@ console.log(`Hi ${me.username}`);
|
|
|
316
363
|
> explicit `baseUrl` to each call only when targeting a local / self-hosted
|
|
317
364
|
> instance (e.g. a dev auth hub vs a dev main app).
|
|
318
365
|
|
|
366
|
+
> **`fallbackScope`, and what happens to a `scope` we cannot read.** Civitai's
|
|
367
|
+
> token endpoint returns `scope` as a decimal bitmask in a JSON *string*
|
|
368
|
+
> (`"scope": "114689"` — see the
|
|
369
|
+
> [endpoint reference](https://developer.civitai.com/site/oauth/endpoints)),
|
|
370
|
+
> matching the decimal `scope` `buildAuthorizeUrl` puts on the authorize URL,
|
|
371
|
+
> and that is what `exchangeCode` / `refreshToken` read. Anything that is not a
|
|
372
|
+
> whole number in `[0, 2**31-1]` is **not** used: `Number()` of
|
|
373
|
+
> [RFC 6749 §5.1](https://datatracker.ietf.org/doc/html/rfc6749#section-5.1)'s
|
|
374
|
+
> space-delimited form is `NaN`, and `NaN & anything` is `0`, so `hasScope()`
|
|
375
|
+
> would answer `false` for every scope and tell a user who just consented that
|
|
376
|
+
> they granted nothing. A wrong *type* is rejected on the same grounds:
|
|
377
|
+
> `Number(['65537'])` is `65537` and `Number(true)` is `1` (i.e.
|
|
378
|
+
> `TokenScope.UserRead`), so an un-guarded coercion would invent a
|
|
379
|
+
> valid-looking grant rather than fail. Such a value is replaced by
|
|
380
|
+
> `fallbackScope` and a warning naming the value received — not an exception,
|
|
381
|
+
> which on the token path would turn a degraded-but-working session into a hard
|
|
382
|
+
> login failure.
|
|
383
|
+
>
|
|
384
|
+
> Pass `fallbackScope: REQUESTED_SCOPES` on exchange and
|
|
385
|
+
> `fallbackScope: tokens.scope` on refresh — without it, either case resolves to
|
|
386
|
+
> `0`, and a caller that persists the whole refreshed token blob would lock the
|
|
387
|
+
> user out of features their token still grants. `fallbackScope` must itself be
|
|
388
|
+
> a whole number in `[0, 2**31-1]`; `NaN` (what `Number(stored.scope)` gives you
|
|
389
|
+
> on a half-populated store — and `??` does not catch it), a negative, a
|
|
390
|
+
> fraction or an over-ceiling value is **discarded in favour of `0`** with its
|
|
391
|
+
> own warning, rather than being handed back as the scope.
|
|
392
|
+
>
|
|
393
|
+
> **The two fallback paths are not equally sound.** An **omitted** `scope` is
|
|
394
|
+
> not a fault at all: RFC 6749 §5.1/§6 make it optional *precisely when the
|
|
395
|
+
> grant matches the request*, so the requested scope is the granted scope and
|
|
396
|
+
> `fallbackScope` is exactly right — that path is silent. A **present but
|
|
397
|
+
> unreadable** `scope` carries no such guarantee: the server is describing the
|
|
398
|
+
> grant in terms this SDK cannot read, and it may be a *reduced* grant, so
|
|
399
|
+
> falling back to the requested scope can **over-state** what the user granted.
|
|
400
|
+
> All four starters render `scopesFromBitmask(tokens.scope)` to the user as
|
|
401
|
+
> "Granted scopes", so the over-statement is user-visible. It is a deliberate
|
|
402
|
+
> trade (`0` and a thrown error are both worse here), which is why this path
|
|
403
|
+
> always warns — if you gate anything security-relevant on `tokens.scope`,
|
|
404
|
+
> treat that warning as "re-authenticate", not as noise.
|
|
405
|
+
|
|
319
406
|
```ts
|
|
320
407
|
|
|
321
408
|
// 5. Estimate cost, then submit
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The App Storage ceilings the host enforces — **the only RUNTIME or
|
|
3
|
+
* DOCUMENTATION site in this repository that spells these numbers**.
|
|
4
|
+
*
|
|
5
|
+
* Every doc site, the mock host, the live dev host and the starter harnesses
|
|
6
|
+
* reference these constants. That is the point of the module: seven
|
|
7
|
+
* hand-copied literals is how the old figures came to agree with each other
|
|
8
|
+
* and disagree with the host by 25x on bytes and 1000x on rows, with nothing
|
|
9
|
+
* in any build, test or type-check able to notice.
|
|
10
|
+
*
|
|
11
|
+
* 🔴 **"Only site" is a claim about what is ENFORCED, and the enforcement is
|
|
12
|
+
* much narrower than the repo.** `tests/guards/app-storage-quota-literals.test.mjs`
|
|
13
|
+
* bans the OLD figures, and pins the derivation at each runtime site, over
|
|
14
|
+
* exactly this surface:
|
|
15
|
+
*
|
|
16
|
+
* - this file and `messages.ts`, here in `src/blocks/`;
|
|
17
|
+
* - `useAppStorage.ts`, `internal/mockHost.ts` and `internal/liveHost.ts` in
|
|
18
|
+
* `packages/civitai-blocks-react` — NAMED FILES, not the package: the
|
|
19
|
+
* banned numbers are the TRUE ceilings of neighbouring features there
|
|
20
|
+
* (the shared-storage app-wide quota, the iframe frame cap, Buzz figures),
|
|
21
|
+
* and a value ban over the package failed the build for saying so;
|
|
22
|
+
* - all of `starters/examples/kv-storage`;
|
|
23
|
+
* - and, in `packages/civitai-blocks-react/README.md`,
|
|
24
|
+
* `packages/civitai-app-sdk/README.md` and `starters/examples/README.md`,
|
|
25
|
+
* ONLY the App-Storage REGION — sections whose heading names App Storage,
|
|
26
|
+
* plus lines that name it themselves. `### useSharedStorage()` in the same
|
|
27
|
+
* file is not read.
|
|
28
|
+
*
|
|
29
|
+
* It does NOT scan, and the rule does not apply to: the guard itself (it spells
|
|
30
|
+
* every figure, as test data), `CHANGELOG.md` and `.changeset/*.md` (history,
|
|
31
|
+
* which must not be rewritten to satisfy a guard), `scripts/`, `tests/`,
|
|
32
|
+
* `claudedocs/`, the root README, other sections of the READMEs above, or any
|
|
33
|
+
* other file in any package. If you are re-deriving after a host move, do not
|
|
34
|
+
* assume those paths are empty — grep them.
|
|
35
|
+
*
|
|
36
|
+
* ## Provenance — measured, not assumed
|
|
37
|
+
*
|
|
38
|
+
* Read from `civitai/civitai` `main` on **2026-09-19** via `gh api` (not a
|
|
39
|
+
* local checkout, which can lag), file
|
|
40
|
+
* `src/server/routers/apps.router.ts`, blob `654f2d6`:
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* const PER_VALUE_BYTE_CAP = 64 * 1024; // :172
|
|
44
|
+
* const USER_QUOTA_BYTES = 2 * 1024 * 1024; // :204
|
|
45
|
+
* const USER_ROW_LIMIT = 1_000; // :205
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* and the `getQuota` procedure returns `limitBytes: USER_QUOTA_BYTES,
|
|
49
|
+
* limitRows: USER_ROW_LIMIT` — so these are exactly the numbers a block reads
|
|
50
|
+
* back from {@link https://github.com/civitai/civitai-app-starters | `useAppStorage().getQuota()`}.
|
|
51
|
+
*
|
|
52
|
+
* Re-derive with:
|
|
53
|
+
*
|
|
54
|
+
* ```sh
|
|
55
|
+
* gh api repos/civitai/civitai/contents/src/server/routers/apps.router.ts \
|
|
56
|
+
* --jq '.content' | base64 -d | grep -n 'USER_QUOTA_BYTES\|USER_ROW_LIMIT\|PER_VALUE_BYTE_CAP'
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* 🔴 **DO NOT re-derive the numbers from this comment** — re-read the host.
|
|
60
|
+
* The per-user clamp was sized against a measured distribution (the host's own
|
|
61
|
+
* comment records: 2026-09-09, largest observed per-user footprint 0.65 MiB
|
|
62
|
+
* across 49 rows, `2 MiB` chosen for ~3.1x headroom) and is expected to move
|
|
63
|
+
* again when that distribution does.
|
|
64
|
+
*
|
|
65
|
+
* ## Which scope each number describes
|
|
66
|
+
*
|
|
67
|
+
* 🔴 **THE NAMESPACE AND THE BUDGET HAVE DIFFERENT SCOPES, and the docs used
|
|
68
|
+
* to quote one while naming the other.**
|
|
69
|
+
*
|
|
70
|
+
* - **Namespace** — rows are keyed `(block_instance_id, user_id, key)`. A key
|
|
71
|
+
* written by one block instance is invisible to another. "Per (block
|
|
72
|
+
* instance, viewer)" is correct, and unchanged.
|
|
73
|
+
* - **Budget** — {@link APP_STORAGE_MAX_BYTES} and
|
|
74
|
+
* {@link APP_STORAGE_MAX_ROWS} are enforced per **(app, viewer)**: the host
|
|
75
|
+
* counter is keyed `(app_block_id, user_id)`, so every block instance of the
|
|
76
|
+
* same app draws on ONE budget for that viewer. An app with three instances
|
|
77
|
+
* on a viewer's page shares 1,000 rows between them, not 3,000.
|
|
78
|
+
*
|
|
79
|
+
* A far larger app-wide umbrella also exists above both. It is deliberately
|
|
80
|
+
* NOT exported and its value is deliberately not written here: nothing reports
|
|
81
|
+
* an app's usage against it, so no block can render a meaningful "x of y" for
|
|
82
|
+
* it, and a constant nobody can act on is an invitation to build a UI that
|
|
83
|
+
* lies. The per-viewer clamp below is what a block will actually hit — it is
|
|
84
|
+
* orders of magnitude tighter.
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* Largest single value one `set()` may send, in **wire** bytes
|
|
88
|
+
* (`JSON.stringify(value)` measured as UTF-8).
|
|
89
|
+
*
|
|
90
|
+
* 🔴 This bounds what one call SENDS, not what it STORES. The host checks it
|
|
91
|
+
* in the wire unit while the byte budget below is enforced in the stored unit,
|
|
92
|
+
* and they diverge: the host records that the largest value this cap admits
|
|
93
|
+
* (65,535 wire bytes) stores 2,911,582 bytes — 44x, and on its own past
|
|
94
|
+
* {@link APP_STORAGE_MAX_BYTES}. So passing this check is not evidence the
|
|
95
|
+
* write will land.
|
|
96
|
+
*/
|
|
97
|
+
export declare const APP_STORAGE_MAX_VALUE_BYTES: number;
|
|
98
|
+
/**
|
|
99
|
+
* Total stored bytes one viewer may hold across **all instances of one app**.
|
|
100
|
+
*
|
|
101
|
+
* This is the value `getQuota().limitBytes` reports.
|
|
102
|
+
*/
|
|
103
|
+
export declare const APP_STORAGE_MAX_BYTES: number;
|
|
104
|
+
/**
|
|
105
|
+
* Total rows one viewer may hold across **all instances of one app**.
|
|
106
|
+
*
|
|
107
|
+
* This is the value `getQuota().limitRows` reports. It is the ceiling most
|
|
108
|
+
* likely to surprise: a block caching one small row per item a viewer looks at
|
|
109
|
+
* reaches it after a thousand items while using ~0.3 MB — well under
|
|
110
|
+
* {@link APP_STORAGE_MAX_BYTES} — so a byte-only estimate will not predict it.
|
|
111
|
+
*/
|
|
112
|
+
export declare const APP_STORAGE_MAX_ROWS = 1000;
|
|
113
|
+
//# sourceMappingURL=appStorageLimits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appStorageLimits.d.ts","sourceRoot":"","sources":["../../src/blocks/appStorageLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,QAAY,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,OAAQ,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The App Storage ceilings the host enforces — **the only RUNTIME or
|
|
3
|
+
* DOCUMENTATION site in this repository that spells these numbers**.
|
|
4
|
+
*
|
|
5
|
+
* Every doc site, the mock host, the live dev host and the starter harnesses
|
|
6
|
+
* reference these constants. That is the point of the module: seven
|
|
7
|
+
* hand-copied literals is how the old figures came to agree with each other
|
|
8
|
+
* and disagree with the host by 25x on bytes and 1000x on rows, with nothing
|
|
9
|
+
* in any build, test or type-check able to notice.
|
|
10
|
+
*
|
|
11
|
+
* 🔴 **"Only site" is a claim about what is ENFORCED, and the enforcement is
|
|
12
|
+
* much narrower than the repo.** `tests/guards/app-storage-quota-literals.test.mjs`
|
|
13
|
+
* bans the OLD figures, and pins the derivation at each runtime site, over
|
|
14
|
+
* exactly this surface:
|
|
15
|
+
*
|
|
16
|
+
* - this file and `messages.ts`, here in `src/blocks/`;
|
|
17
|
+
* - `useAppStorage.ts`, `internal/mockHost.ts` and `internal/liveHost.ts` in
|
|
18
|
+
* `packages/civitai-blocks-react` — NAMED FILES, not the package: the
|
|
19
|
+
* banned numbers are the TRUE ceilings of neighbouring features there
|
|
20
|
+
* (the shared-storage app-wide quota, the iframe frame cap, Buzz figures),
|
|
21
|
+
* and a value ban over the package failed the build for saying so;
|
|
22
|
+
* - all of `starters/examples/kv-storage`;
|
|
23
|
+
* - and, in `packages/civitai-blocks-react/README.md`,
|
|
24
|
+
* `packages/civitai-app-sdk/README.md` and `starters/examples/README.md`,
|
|
25
|
+
* ONLY the App-Storage REGION — sections whose heading names App Storage,
|
|
26
|
+
* plus lines that name it themselves. `### useSharedStorage()` in the same
|
|
27
|
+
* file is not read.
|
|
28
|
+
*
|
|
29
|
+
* It does NOT scan, and the rule does not apply to: the guard itself (it spells
|
|
30
|
+
* every figure, as test data), `CHANGELOG.md` and `.changeset/*.md` (history,
|
|
31
|
+
* which must not be rewritten to satisfy a guard), `scripts/`, `tests/`,
|
|
32
|
+
* `claudedocs/`, the root README, other sections of the READMEs above, or any
|
|
33
|
+
* other file in any package. If you are re-deriving after a host move, do not
|
|
34
|
+
* assume those paths are empty — grep them.
|
|
35
|
+
*
|
|
36
|
+
* ## Provenance — measured, not assumed
|
|
37
|
+
*
|
|
38
|
+
* Read from `civitai/civitai` `main` on **2026-09-19** via `gh api` (not a
|
|
39
|
+
* local checkout, which can lag), file
|
|
40
|
+
* `src/server/routers/apps.router.ts`, blob `654f2d6`:
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* const PER_VALUE_BYTE_CAP = 64 * 1024; // :172
|
|
44
|
+
* const USER_QUOTA_BYTES = 2 * 1024 * 1024; // :204
|
|
45
|
+
* const USER_ROW_LIMIT = 1_000; // :205
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* and the `getQuota` procedure returns `limitBytes: USER_QUOTA_BYTES,
|
|
49
|
+
* limitRows: USER_ROW_LIMIT` — so these are exactly the numbers a block reads
|
|
50
|
+
* back from {@link https://github.com/civitai/civitai-app-starters | `useAppStorage().getQuota()`}.
|
|
51
|
+
*
|
|
52
|
+
* Re-derive with:
|
|
53
|
+
*
|
|
54
|
+
* ```sh
|
|
55
|
+
* gh api repos/civitai/civitai/contents/src/server/routers/apps.router.ts \
|
|
56
|
+
* --jq '.content' | base64 -d | grep -n 'USER_QUOTA_BYTES\|USER_ROW_LIMIT\|PER_VALUE_BYTE_CAP'
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* 🔴 **DO NOT re-derive the numbers from this comment** — re-read the host.
|
|
60
|
+
* The per-user clamp was sized against a measured distribution (the host's own
|
|
61
|
+
* comment records: 2026-09-09, largest observed per-user footprint 0.65 MiB
|
|
62
|
+
* across 49 rows, `2 MiB` chosen for ~3.1x headroom) and is expected to move
|
|
63
|
+
* again when that distribution does.
|
|
64
|
+
*
|
|
65
|
+
* ## Which scope each number describes
|
|
66
|
+
*
|
|
67
|
+
* 🔴 **THE NAMESPACE AND THE BUDGET HAVE DIFFERENT SCOPES, and the docs used
|
|
68
|
+
* to quote one while naming the other.**
|
|
69
|
+
*
|
|
70
|
+
* - **Namespace** — rows are keyed `(block_instance_id, user_id, key)`. A key
|
|
71
|
+
* written by one block instance is invisible to another. "Per (block
|
|
72
|
+
* instance, viewer)" is correct, and unchanged.
|
|
73
|
+
* - **Budget** — {@link APP_STORAGE_MAX_BYTES} and
|
|
74
|
+
* {@link APP_STORAGE_MAX_ROWS} are enforced per **(app, viewer)**: the host
|
|
75
|
+
* counter is keyed `(app_block_id, user_id)`, so every block instance of the
|
|
76
|
+
* same app draws on ONE budget for that viewer. An app with three instances
|
|
77
|
+
* on a viewer's page shares 1,000 rows between them, not 3,000.
|
|
78
|
+
*
|
|
79
|
+
* A far larger app-wide umbrella also exists above both. It is deliberately
|
|
80
|
+
* NOT exported and its value is deliberately not written here: nothing reports
|
|
81
|
+
* an app's usage against it, so no block can render a meaningful "x of y" for
|
|
82
|
+
* it, and a constant nobody can act on is an invitation to build a UI that
|
|
83
|
+
* lies. The per-viewer clamp below is what a block will actually hit — it is
|
|
84
|
+
* orders of magnitude tighter.
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* Largest single value one `set()` may send, in **wire** bytes
|
|
88
|
+
* (`JSON.stringify(value)` measured as UTF-8).
|
|
89
|
+
*
|
|
90
|
+
* 🔴 This bounds what one call SENDS, not what it STORES. The host checks it
|
|
91
|
+
* in the wire unit while the byte budget below is enforced in the stored unit,
|
|
92
|
+
* and they diverge: the host records that the largest value this cap admits
|
|
93
|
+
* (65,535 wire bytes) stores 2,911,582 bytes — 44x, and on its own past
|
|
94
|
+
* {@link APP_STORAGE_MAX_BYTES}. So passing this check is not evidence the
|
|
95
|
+
* write will land.
|
|
96
|
+
*/
|
|
97
|
+
export const APP_STORAGE_MAX_VALUE_BYTES = 64 * 1024;
|
|
98
|
+
/**
|
|
99
|
+
* Total stored bytes one viewer may hold across **all instances of one app**.
|
|
100
|
+
*
|
|
101
|
+
* This is the value `getQuota().limitBytes` reports.
|
|
102
|
+
*/
|
|
103
|
+
export const APP_STORAGE_MAX_BYTES = 2 * 1024 * 1024;
|
|
104
|
+
/**
|
|
105
|
+
* Total rows one viewer may hold across **all instances of one app**.
|
|
106
|
+
*
|
|
107
|
+
* This is the value `getQuota().limitRows` reports. It is the ceiling most
|
|
108
|
+
* likely to surprise: a block caching one small row per item a viewer looks at
|
|
109
|
+
* reaches it after a thousand items while using ~0.3 MB — well under
|
|
110
|
+
* {@link APP_STORAGE_MAX_BYTES} — so a byte-only estimate will not predict it.
|
|
111
|
+
*/
|
|
112
|
+
export const APP_STORAGE_MAX_ROWS = 1_000;
|
|
113
|
+
//# sourceMappingURL=appStorageLimits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appStorageLimits.js","sourceRoot":"","sources":["../../src/blocks/appStorageLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,CAAC;AAErD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC"}
|
package/dist/blocks/index.d.ts
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@civitai/app-sdk/blocks` — framework-agnostic contract for Civitai Apps.
|
|
3
3
|
*
|
|
4
|
-
* This subpath exports the manifest type, scope strings
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This subpath exports the manifest type, scope strings and postMessage
|
|
5
|
+
* protocol. Hooks and transport implementations live in a separate package (see
|
|
6
|
+
* `@civitai/blocks-react`) so this module stays usable from any runtime — Node,
|
|
7
|
+
* browsers, workers — with no React dependency and no runtime dependencies at
|
|
8
|
+
* all. Build-time manifest validation lives at `@civitai/app-sdk/manifest`
|
|
9
|
+
* (node-only); see the note on `BlockManifestError` below.
|
|
8
10
|
*/
|
|
9
11
|
import '../safe-storage/index.js';
|
|
10
12
|
export { installSafeStorage, createMemoryStorage } from '../safe-storage/index.js';
|
|
11
13
|
export type { SafeStorageInstallResult, SafeStorageName } from '../safe-storage/index.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* `defineBlock` MOVED to `@civitai/app-sdk/manifest` (a NODE-ONLY subpath) in
|
|
16
|
+
* the release that closed #330. It now validates by compiling the vendored
|
|
17
|
+
* canonical schema with Ajv instead of maintaining a hand-written mirror of it,
|
|
18
|
+
* which needs `node:fs` and a runtime dependency — neither of which belongs on
|
|
19
|
+
* this browser-facing, zero-dependency surface. Most callers want the Vite
|
|
20
|
+
* plugin at `@civitai/app-sdk/vite` rather than the function.
|
|
21
|
+
*
|
|
22
|
+
* `BlockManifestError` stays exported here, from its own module, so
|
|
23
|
+
* `instanceof` means the same thing on both subpaths.
|
|
24
|
+
*/
|
|
25
|
+
export { BlockManifestError } from './manifestError.js';
|
|
14
26
|
export { BLOCK_SCOPES, BLOCK_SCOPE_PATTERN, BLOCK_CATEGORIES, BLOCK_TAGLINE_MAX_LENGTH, } from './scopes.js';
|
|
15
27
|
export type { BlockScope, BlockScopeKey, BlockCategory } from './scopes.js';
|
|
16
28
|
export { BrowsingLevel, SFW_LEVELS, NSFW_LEVELS, isSfwCeiling, isLevelAllowed, effectiveBrowsingCeiling, } from './browsingLevel.js';
|
|
17
29
|
export type { BrowsingLevelKey, BrowsingLevelBit, ColorDomain } from './browsingLevel.js';
|
|
30
|
+
export { APP_STORAGE_MAX_VALUE_BYTES, APP_STORAGE_MAX_BYTES, APP_STORAGE_MAX_ROWS, } from './appStorageLimits.js';
|
|
18
31
|
export { BLOCK_INIT_FRAGMENT_MARKER_KEY, BLOCK_INIT_FRAGMENT_VERSION, BLOCK_INIT_FRAGMENT_KEYS, encodeBlockInitFragment, parseBlockInitFragment, stripBlockInitFragment, } from './initFragment.js';
|
|
19
32
|
export type { BlockInitFragment } from './initFragment.js';
|
|
20
33
|
export { isMessage, BLOCK_TO_PARENT_MESSAGE_TYPES, OTHER_MESSAGE_TYPE_LABEL, boundBlockToParentMessageType, } from './messages.js';
|
|
@@ -25,5 +38,11 @@ export type { BlockInitPayload, BlockToParentMessage, BlockToParentMessageType,
|
|
|
25
38
|
* static shape is a claim the guard is what actually checks.
|
|
26
39
|
*/
|
|
27
40
|
export { isModelSlotContext, isPageSlotContext } from './types.js';
|
|
28
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The sign-in gate, spelled once. Blocks, docs and starters call this instead
|
|
43
|
+
* of open-coding `viewer !== null` or `viewer?.signedIn === true`; see its doc
|
|
44
|
+
* in `types.ts` for which of the two it uses and why.
|
|
45
|
+
*/
|
|
46
|
+
export { isSignedIn } from './types.js';
|
|
47
|
+
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';
|
|
29
48
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blocks/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blocks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,OAAO,0BAA0B,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACnF,YAAY,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,aAAa,EACb,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE1F,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EACL,SAAS,EACT,6BAA6B,EAC7B,wBAAwB,EACxB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,2BAA2B,EAC3B,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnE;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,YAAY,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,aAAa,EACb,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,KAAK,EACL,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,EACtB,8BAA8B,EAC9B,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,eAAe,EACf,gBAAgB,EAChB,2BAA2B,EAC3B,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,8BAA8B,EAC9B,WAAW,EACX,iBAAiB,EACjB,0BAA0B,EAC1B,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,8BAA8B,EAC9B,2BAA2B,EAC3B,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
|
package/dist/blocks/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@civitai/app-sdk/blocks` — framework-agnostic contract for Civitai Apps.
|
|
3
3
|
*
|
|
4
|
-
* This subpath exports the manifest type, scope strings
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This subpath exports the manifest type, scope strings and postMessage
|
|
5
|
+
* protocol. Hooks and transport implementations live in a separate package (see
|
|
6
|
+
* `@civitai/blocks-react`) so this module stays usable from any runtime — Node,
|
|
7
|
+
* browsers, workers — with no React dependency and no runtime dependencies at
|
|
8
|
+
* all. Build-time manifest validation lives at `@civitai/app-sdk/manifest`
|
|
9
|
+
* (node-only); see the note on `BlockManifestError` below.
|
|
8
10
|
*/
|
|
9
11
|
// FIRST import, on purpose. Blocks are framed at an opaque origin (sandbox
|
|
10
12
|
// without `allow-same-origin`), where touching `localStorage`/`sessionStorage`
|
|
@@ -14,9 +16,21 @@
|
|
|
14
16
|
// or is absent (Node/SSR/workers); see `../safe-storage/index.ts`.
|
|
15
17
|
import '../safe-storage/index.js';
|
|
16
18
|
export { installSafeStorage, createMemoryStorage } from '../safe-storage/index.js';
|
|
17
|
-
|
|
19
|
+
/**
|
|
20
|
+
* `defineBlock` MOVED to `@civitai/app-sdk/manifest` (a NODE-ONLY subpath) in
|
|
21
|
+
* the release that closed #330. It now validates by compiling the vendored
|
|
22
|
+
* canonical schema with Ajv instead of maintaining a hand-written mirror of it,
|
|
23
|
+
* which needs `node:fs` and a runtime dependency — neither of which belongs on
|
|
24
|
+
* this browser-facing, zero-dependency surface. Most callers want the Vite
|
|
25
|
+
* plugin at `@civitai/app-sdk/vite` rather than the function.
|
|
26
|
+
*
|
|
27
|
+
* `BlockManifestError` stays exported here, from its own module, so
|
|
28
|
+
* `instanceof` means the same thing on both subpaths.
|
|
29
|
+
*/
|
|
30
|
+
export { BlockManifestError } from './manifestError.js';
|
|
18
31
|
export { BLOCK_SCOPES, BLOCK_SCOPE_PATTERN, BLOCK_CATEGORIES, BLOCK_TAGLINE_MAX_LENGTH, } from './scopes.js';
|
|
19
32
|
export { BrowsingLevel, SFW_LEVELS, NSFW_LEVELS, isSfwCeiling, isLevelAllowed, effectiveBrowsingCeiling, } from './browsingLevel.js';
|
|
33
|
+
export { APP_STORAGE_MAX_VALUE_BYTES, APP_STORAGE_MAX_BYTES, APP_STORAGE_MAX_ROWS, } from './appStorageLimits.js';
|
|
20
34
|
export { BLOCK_INIT_FRAGMENT_MARKER_KEY, BLOCK_INIT_FRAGMENT_VERSION, BLOCK_INIT_FRAGMENT_KEYS, encodeBlockInitFragment, parseBlockInitFragment, stripBlockInitFragment, } from './initFragment.js';
|
|
21
35
|
export { isMessage, BLOCK_TO_PARENT_MESSAGE_TYPES, OTHER_MESSAGE_TYPE_LABEL, boundBlockToParentMessageType, } from './messages.js';
|
|
22
36
|
/**
|
|
@@ -25,4 +39,10 @@ export { isMessage, BLOCK_TO_PARENT_MESSAGE_TYPES, OTHER_MESSAGE_TYPE_LABEL, bou
|
|
|
25
39
|
* static shape is a claim the guard is what actually checks.
|
|
26
40
|
*/
|
|
27
41
|
export { isModelSlotContext, isPageSlotContext } from './types.js';
|
|
42
|
+
/**
|
|
43
|
+
* The sign-in gate, spelled once. Blocks, docs and starters call this instead
|
|
44
|
+
* of open-coding `viewer !== null` or `viewer?.signedIn === true`; see its doc
|
|
45
|
+
* in `types.ts` for which of the two it uses and why.
|
|
46
|
+
*/
|
|
47
|
+
export { isSignedIn } from './types.js';
|
|
28
48
|
//# sourceMappingURL=index.js.map
|
package/dist/blocks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blocks/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blocks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2EAA2E;AAC3E,+EAA+E;AAC/E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,mEAAmE;AACnE,OAAO,0BAA0B,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGnF;;;;;;;;;;GAUG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,aAAa,EACb,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,SAAS,EACT,6BAA6B,EAC7B,wBAAwB,EACxB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAiBvB;;;;GAIG;AACH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnE;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The manifest-validation error type, in its own zero-dependency module.
|
|
3
|
+
*
|
|
4
|
+
* It lives here rather than beside `defineBlock` because `defineBlock` now
|
|
5
|
+
* lives at the node-only `@civitai/app-sdk/manifest` subpath (it reads the
|
|
6
|
+
* vendored canonical schema off disk and compiles it with Ajv). The error class
|
|
7
|
+
* has to stay importable from the browser-safe `./blocks` surface so that
|
|
8
|
+
* `instanceof BlockManifestError` means the same thing on both sides — one
|
|
9
|
+
* class, one module, no duplicate identity.
|
|
10
|
+
*/
|
|
11
|
+
/** Thrown by `defineBlock` for any manifest violation. */
|
|
12
|
+
export declare class BlockManifestError extends Error {
|
|
13
|
+
/** Dot-path to the offending field, e.g. `iframe.sandbox`. */
|
|
14
|
+
readonly field?: string | undefined;
|
|
15
|
+
readonly name = "BlockManifestError";
|
|
16
|
+
constructor(message: string,
|
|
17
|
+
/** Dot-path to the offending field, e.g. `iframe.sandbox`. */
|
|
18
|
+
field?: string | undefined);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=manifestError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifestError.d.ts","sourceRoot":"","sources":["../../src/blocks/manifestError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,0DAA0D;AAC1D,qBAAa,kBAAmB,SAAQ,KAAK;IAIzC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;IAJzB,SAAkB,IAAI,wBAAwB;gBAE5C,OAAO,EAAE,MAAM;IACf,8DAA8D;IACrD,KAAK,CAAC,EAAE,MAAM,YAAA;CAI1B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The manifest-validation error type, in its own zero-dependency module.
|
|
3
|
+
*
|
|
4
|
+
* It lives here rather than beside `defineBlock` because `defineBlock` now
|
|
5
|
+
* lives at the node-only `@civitai/app-sdk/manifest` subpath (it reads the
|
|
6
|
+
* vendored canonical schema off disk and compiles it with Ajv). The error class
|
|
7
|
+
* has to stay importable from the browser-safe `./blocks` surface so that
|
|
8
|
+
* `instanceof BlockManifestError` means the same thing on both sides — one
|
|
9
|
+
* class, one module, no duplicate identity.
|
|
10
|
+
*/
|
|
11
|
+
/** Thrown by `defineBlock` for any manifest violation. */
|
|
12
|
+
export class BlockManifestError extends Error {
|
|
13
|
+
field;
|
|
14
|
+
name = 'BlockManifestError';
|
|
15
|
+
constructor(message,
|
|
16
|
+
/** Dot-path to the offending field, e.g. `iframe.sandbox`. */
|
|
17
|
+
field) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.field = field;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=manifestError.js.map
|