@civitai/blocks-react 0.8.0 → 0.10.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.
@@ -0,0 +1,44 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * Props for {@link SfwGate}.
4
+ */
5
+ export interface SfwGateProps {
6
+ /** Rendered only when the gate is open (domain is SFW, or `level` allowed). */
7
+ children: ReactNode;
8
+ /**
9
+ * When set, gate on `isLevelAllowed(level)` (a single `BrowsingLevel` bit)
10
+ * instead of the coarse `isSfw`. Lets a block reveal a level-specific
11
+ * affordance (e.g. an R-rated toggle) only when the domain permits that level.
12
+ */
13
+ level?: number;
14
+ /** Rendered when the gate is closed. Defaults to `null` (render nothing). */
15
+ fallback?: ReactNode;
16
+ }
17
+ /**
18
+ * Convenience wrapper that renders `children` only when the surrounding
19
+ * color-domain permits it, else `fallback` — so a block can hide/blur mature
20
+ * affordances on a SFW domain without wiring {@link useDomainMaturity} by hand.
21
+ *
22
+ * Gating:
23
+ * - no `level` prop → renders `children` when the domain is SFW (`isSfw`).
24
+ * - `level` prop set → renders `children` when that browsing-level bit is
25
+ * allowed by the domain ceiling (`isLevelAllowed(level)`).
26
+ *
27
+ * **Fail-closed SFW**: before `BLOCK_INIT` lands, and against a host that
28
+ * predates civitai #2670 (no ceiling field), the gate is treated as SFW —
29
+ * `children` show only for SFW content, mature content shows `fallback`.
30
+ *
31
+ * @example
32
+ * // Hide a mature-only carousel on a SFW domain:
33
+ * <SfwGate fallback={<SafePlaceholder />}>
34
+ * <MatureCarousel />
35
+ * </SfwGate>
36
+ *
37
+ * @example
38
+ * // Reveal an R-rated control only when the domain allows R:
39
+ * <SfwGate level={BrowsingLevel.R}>
40
+ * <RRatedToggle />
41
+ * </SfwGate>
42
+ */
43
+ export declare function SfwGate({ children, level, fallback }: SfwGateProps): ReactNode;
44
+ //# sourceMappingURL=SfwGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SfwGate.d.ts","sourceRoot":"","sources":["../../src/hooks/SfwGate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAe,EAAE,EAAE,YAAY,GAAG,SAAS,CAIrF"}
@@ -0,0 +1,33 @@
1
+ import { useDomainMaturity } from './useDomainMaturity.js';
2
+ /**
3
+ * Convenience wrapper that renders `children` only when the surrounding
4
+ * color-domain permits it, else `fallback` — so a block can hide/blur mature
5
+ * affordances on a SFW domain without wiring {@link useDomainMaturity} by hand.
6
+ *
7
+ * Gating:
8
+ * - no `level` prop → renders `children` when the domain is SFW (`isSfw`).
9
+ * - `level` prop set → renders `children` when that browsing-level bit is
10
+ * allowed by the domain ceiling (`isLevelAllowed(level)`).
11
+ *
12
+ * **Fail-closed SFW**: before `BLOCK_INIT` lands, and against a host that
13
+ * predates civitai #2670 (no ceiling field), the gate is treated as SFW —
14
+ * `children` show only for SFW content, mature content shows `fallback`.
15
+ *
16
+ * @example
17
+ * // Hide a mature-only carousel on a SFW domain:
18
+ * <SfwGate fallback={<SafePlaceholder />}>
19
+ * <MatureCarousel />
20
+ * </SfwGate>
21
+ *
22
+ * @example
23
+ * // Reveal an R-rated control only when the domain allows R:
24
+ * <SfwGate level={BrowsingLevel.R}>
25
+ * <RRatedToggle />
26
+ * </SfwGate>
27
+ */
28
+ export function SfwGate({ children, level, fallback = null }) {
29
+ const { isSfw, isLevelAllowed } = useDomainMaturity();
30
+ const open = level === undefined ? isSfw : isLevelAllowed(level);
31
+ return open ? children : fallback;
32
+ }
33
+ //# sourceMappingURL=SfwGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SfwGate.js","sourceRoot":"","sources":["../../src/hooks/SfwGate.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAkB3D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAgB;IACxE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAAC;IACtD,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpC,CAAC"}
@@ -0,0 +1,56 @@
1
+ import type { ColorDomain } from '@civitai/app-sdk/blocks';
2
+ /**
3
+ * What {@link useDomainMaturity} returns.
4
+ */
5
+ export interface DomainMaturity {
6
+ /**
7
+ * The color-domain the block is rendered inside (`green`|`blue`|`red`), or
8
+ * `null`/`undefined` when the host didn't project one (anon read, or a host
9
+ * that predates civitai #2670). Informational ONLY — gate UI on {@link isSfw}
10
+ * / {@link isLevelAllowed}, not on this string.
11
+ */
12
+ domain?: ColorDomain | null;
13
+ /**
14
+ * Authoritative browsing-level ceiling BITMASK from `BLOCK_INIT`
15
+ * (`undefined` before init / when the host doesn't send it). The bits mirror
16
+ * the server `NsfwLevel` (see `BrowsingLevel` in `@civitai/app-sdk/blocks`).
17
+ */
18
+ maxBrowsingLevel?: number;
19
+ /**
20
+ * `true` when the surrounding domain permits NO NSFW content — derived from
21
+ * the {@link maxBrowsingLevel} bitmask (NOT the `domain` string, so the policy
22
+ * stays server-side). **Fail-closed SFW**: `true` before `BLOCK_INIT` lands
23
+ * and whenever the ceiling is absent/non-finite.
24
+ */
25
+ isSfw: boolean;
26
+ /**
27
+ * `true` when a specific browsing-level bit (e.g. `BrowsingLevel.R`) is
28
+ * permitted by the domain ceiling. Fail-closed to SFW-only when the ceiling
29
+ * is absent.
30
+ */
31
+ isLevelAllowed: (level: number) => boolean;
32
+ }
33
+ /**
34
+ * Read the surrounding color-domain's maturity ceiling that the host projects
35
+ * into `BLOCK_INIT` (civitai #2670), so a block can hide/blur mature
36
+ * affordances on a SFW domain.
37
+ *
38
+ * Reads from the SAME init state as {@link useBlockContext} (the singleton
39
+ * transport snapshot), so it re-renders when `BLOCK_INIT` lands.
40
+ *
41
+ * The SFW decision is derived from the `maxBrowsingLevel` BITMASK — never from
42
+ * the `domain` string — so the policy stays server-side and the SDK won't rot
43
+ * if a domain's policy flips. **Fail-closed SFW**: until `BLOCK_INIT` arrives,
44
+ * or against a host that predates #2670 (fields read `undefined`), `isSfw` is
45
+ * `true` and only SFW levels are allowed.
46
+ *
47
+ * @example
48
+ * const { isSfw } = useDomainMaturity();
49
+ * return isSfw ? <SafeUI /> : <MatureUI />;
50
+ *
51
+ * @example
52
+ * const { isLevelAllowed } = useDomainMaturity();
53
+ * if (isLevelAllowed(BrowsingLevel.R)) showRSlider();
54
+ */
55
+ export declare function useDomainMaturity(): DomainMaturity;
56
+ //# sourceMappingURL=useDomainMaturity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDomainMaturity.d.ts","sourceRoot":"","sources":["../../src/hooks/useDomainMaturity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAI3D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CASlD"}
@@ -0,0 +1,35 @@
1
+ import { isSfwCeiling, isLevelAllowed as isLevelAllowedCeiling } from '@civitai/app-sdk/blocks';
2
+ import { useTransportSnapshot } from './useBlockContext.js';
3
+ /**
4
+ * Read the surrounding color-domain's maturity ceiling that the host projects
5
+ * into `BLOCK_INIT` (civitai #2670), so a block can hide/blur mature
6
+ * affordances on a SFW domain.
7
+ *
8
+ * Reads from the SAME init state as {@link useBlockContext} (the singleton
9
+ * transport snapshot), so it re-renders when `BLOCK_INIT` lands.
10
+ *
11
+ * The SFW decision is derived from the `maxBrowsingLevel` BITMASK — never from
12
+ * the `domain` string — so the policy stays server-side and the SDK won't rot
13
+ * if a domain's policy flips. **Fail-closed SFW**: until `BLOCK_INIT` arrives,
14
+ * or against a host that predates #2670 (fields read `undefined`), `isSfw` is
15
+ * `true` and only SFW levels are allowed.
16
+ *
17
+ * @example
18
+ * const { isSfw } = useDomainMaturity();
19
+ * return isSfw ? <SafeUI /> : <MatureUI />;
20
+ *
21
+ * @example
22
+ * const { isLevelAllowed } = useDomainMaturity();
23
+ * if (isLevelAllowed(BrowsingLevel.R)) showRSlider();
24
+ */
25
+ export function useDomainMaturity() {
26
+ const snap = useTransportSnapshot();
27
+ const maxBrowsingLevel = snap.maxBrowsingLevel;
28
+ return {
29
+ domain: snap.domain,
30
+ maxBrowsingLevel,
31
+ isSfw: isSfwCeiling(maxBrowsingLevel),
32
+ isLevelAllowed: (level) => isLevelAllowedCeiling(level, maxBrowsingLevel),
33
+ };
34
+ }
35
+ //# sourceMappingURL=useDomainMaturity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDomainMaturity.js","sourceRoot":"","sources":["../../src/hooks/useDomainMaturity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGhG,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAkC5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC;IACpC,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;IAC/C,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,gBAAgB;QAChB,KAAK,EAAE,YAAY,CAAC,gBAAgB,CAAC;QACrC,cAAc,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,CAAC;KAClF,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -25,6 +25,10 @@ export { useCivitaiNavigate } from './hooks/useCivitaiNavigate.js';
25
25
  export { useRequestSignIn } from './hooks/useRequestSignIn.js';
26
26
  export { useRequestConsent } from './hooks/useRequestConsent.js';
27
27
  export { useBlockAnalytics } from './hooks/useBlockAnalytics.js';
28
+ export { useDomainMaturity } from './hooks/useDomainMaturity.js';
29
+ export type { DomainMaturity } from './hooks/useDomainMaturity.js';
30
+ export { SfwGate } from './hooks/SfwGate.js';
31
+ export type { SfwGateProps } from './hooks/SfwGate.js';
28
32
  export { useAppStorage } from './hooks/useAppStorage.js';
29
33
  export type { AppStorageKeyEntry, AppStorageListResult, AppStorageQuota, UseAppStorage, } from './hooks/useAppStorage.js';
30
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EACV,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,GACd,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EACV,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,GACd,MAAM,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -23,5 +23,7 @@ export { useCivitaiNavigate } from './hooks/useCivitaiNavigate.js';
23
23
  export { useRequestSignIn } from './hooks/useRequestSignIn.js';
24
24
  export { useRequestConsent } from './hooks/useRequestConsent.js';
25
25
  export { useBlockAnalytics } from './hooks/useBlockAnalytics.js';
26
+ export { useDomainMaturity } from './hooks/useDomainMaturity.js';
27
+ export { SfwGate } from './hooks/SfwGate.js';
26
28
  export { useAppStorage } from './hooks/useAppStorage.js';
27
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGhE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAG3F,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAO3D,QAAQ;AACR,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGhE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAG3F,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAO3D,QAAQ;AACR,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
@@ -6,8 +6,9 @@
6
6
  * a block in a cross-origin iframe and answers its `postMessage` protocol:
7
7
  * mints a token, runs the lazy-consent round-trip, brokers the orchestrator
8
8
  * money path (estimate → submit → poll), opens the native Buzz-purchase and
9
- * resource-picker modals. Locally in a `vitest` test OR a starter's dev
10
- * harness — there is no host, so this plays one.
9
+ * resource-picker modals, and serves the App-Blocks KV datastore. Locally in
10
+ * a `vitest` test OR a starter's dev harness — there is no host, so this plays
11
+ * one.
11
12
  *
12
13
  * It is the portable core that the React `<Harness>` (a.k.a. `<MockHostProvider>`
13
14
  * in `../testing`) wraps. Every block app used to hand-roll ~250 lines of this;
@@ -22,10 +23,21 @@
22
23
  * `window.location.origin` (the React `<Harness>` is documented for that).
23
24
  * 3. Dispatches a configurable `BLOCK_INIT`, then answers the full protocol.
24
25
  *
25
- * NOT a real RS256 JWT, NO real Buzz, NO orchestrator — only the bridge
26
- * round-trips are exercised. Never import this from production code.
26
+ * SCENARIOS (Layer 1 of the local-dev DX): the {@link MockHostOptions.generation},
27
+ * {@link MockHostOptions.buzz}, and {@link MockHostOptions.storage} groups let a
28
+ * dev simulate REAL costs, slow gens, FAILURES, an insufficient-Buzz balance,
29
+ * and a working KV store with a quota — entirely synthetically, so the full
30
+ * money / error / storage UX is exercisable locally without spending a single
31
+ * Buzz or touching the network. The returned {@link MockHost} exposes
32
+ * `setScenario()` + a `buzz` handle so a harness UI can flip scenarios
33
+ * mid-session.
34
+ *
35
+ * PURE + SYNTHETIC: NOT a real RS256 JWT, NO real Buzz, NO orchestrator, and
36
+ * — asserted by the test suite — NO network (`fetch`/`XMLHttpRequest` are never
37
+ * called). Only the postMessage bridge round-trips are exercised. Never import
38
+ * this from production code.
27
39
  */
28
- import type { BlockContext, BlockResourceInfo, BlockResourcePickerType, Theme, ViewerInfo } from '@civitai/app-sdk/blocks';
40
+ import { type BlockContext, type BlockResourceInfo, type BlockResourcePickerType, type ColorDomain, type Theme, type ViewerInfo, type WorkflowBody } from '@civitai/app-sdk/blocks';
29
41
  /**
30
42
  * How submits resolve. `'none'` = everything succeeds; `'all'` /
31
43
  * `'insufficient'` = every submit returns an insufficient-Buzz `failed`
@@ -40,10 +52,111 @@ export type MockHostFailMode = 'none' | 'some' | 'all' | 'insufficient';
40
52
  * user-dismissed picker (→ `RESOURCE_PICKER_RESULT` with no `selected`).
41
53
  */
42
54
  export type CannedPick = BlockResourceInfo;
55
+ /**
56
+ * A per-generation cost: a fixed number, or a function of the submitted
57
+ * {@link WorkflowBody} (so a dev can vary cost by model / step count).
58
+ */
59
+ export type CostSpec = number | ((req: WorkflowBody) => number);
60
+ /**
61
+ * A result image url: a fixed string, or a function of the submitted body
62
+ * (so a dev can echo the prompt into a placeholder).
63
+ */
64
+ export type ImageSpec = string | ((req: WorkflowBody) => string);
65
+ /**
66
+ * GENERATION scenario controls — simulate real costs, slow gens, and failures
67
+ * on the orchestrator money path WITHOUT a real orchestrator. All optional.
68
+ */
69
+ export interface MockGenerationScenario {
70
+ /**
71
+ * Cost reported on `ESTIMATE_RESULT` + the succeeded snapshot. A number, or
72
+ * a `(body) => number`. Overrides the legacy top-level `cost`. Default `8`.
73
+ */
74
+ costPerGen?: CostSpec;
75
+ /**
76
+ * Synthetic latency before the SUBMITTED→succeeded transition lands, in ms.
77
+ * A single number, or a `[min, max]` range (uniform random). Applied to the
78
+ * poll that flips a workflow to `succeeded`. Default `0` (immediate).
79
+ */
80
+ latencyMs?: number | [number, number];
81
+ /**
82
+ * Probability (0..1) that any given submit fails with a generic generation
83
+ * error. Independent of {@link failRate}'s sibling controls. Default `0`.
84
+ */
85
+ failRate?: number;
86
+ /**
87
+ * Force the next N submits to fail (counts down). Deterministic companion to
88
+ * {@link failRate} — handy for "first try fails, retry succeeds" UX tests.
89
+ */
90
+ failNext?: number;
91
+ /** A single result image url (or `(body) => url`). */
92
+ image?: ImageSpec;
93
+ /**
94
+ * Multiple result image urls (or `(body) => url[]`). Takes precedence over
95
+ * {@link image} when both are set.
96
+ */
97
+ images?: string[] | ((req: WorkflowBody) => string[]);
98
+ }
99
+ /**
100
+ * BUZZ scenario controls — simulate a balance so the insufficient-Buzz / top-up
101
+ * UX is exercisable. The mock host treats `balance` as a spendable wallet:
102
+ * each succeeding generation DEBITS its cost; a submit whose cost would exceed
103
+ * the remaining balance resolves to an insufficient-Buzz `failed` snapshot
104
+ * (exercising the Top-Up CTA), and `OPEN_BUZZ_PURCHASE` REFILLS the balance.
105
+ */
106
+ export interface MockBuzzScenario {
107
+ /**
108
+ * Simulated spendable balance. When set, generations debit against it and a
109
+ * gen that would exceed it returns an insufficient-Buzz outcome. When
110
+ * `undefined`, balance is NOT simulated (back-compat: only the legacy
111
+ * `failMode` drives insufficiency).
112
+ */
113
+ balance?: number;
114
+ /**
115
+ * Force every submit down the insufficient-Buzz path regardless of balance.
116
+ * Equivalent to the legacy `failMode: 'insufficient'`; provided here so the
117
+ * insufficient UX is reachable from the `buzz` group alone.
118
+ */
119
+ insufficient?: boolean;
120
+ }
121
+ /**
122
+ * STORAGE scenario controls — drive the in-memory KV backend that answers the
123
+ * `APP_STORAGE_*` protocol, so the W4 KV apps (e.g. Prompt Library) can test
124
+ * load / quota / error states against `createMockHost` directly instead of
125
+ * hand-injecting a fake store.
126
+ */
127
+ export interface MockStorageScenario {
128
+ /**
129
+ * Initial KV contents (key → JSON value) the store is seeded with. `get`
130
+ * returns these immediately; they count against the simulated quota.
131
+ */
132
+ seed?: Record<string, unknown>;
133
+ /**
134
+ * Simulated per-app quota in bytes. A `set` that would cross it resolves
135
+ * `{ ok: false, error: 'PAYLOAD_TOO_LARGE' }` (the host doesn't leak which
136
+ * cap tripped). Default 50 MB.
137
+ */
138
+ quotaBytes?: number;
139
+ /**
140
+ * Per-value byte cap. A `set` whose serialized value exceeds it resolves
141
+ * `{ ok: false, error: 'PAYLOAD_TOO_LARGE' }`. Default 64 KB.
142
+ */
143
+ valueCapBytes?: number;
144
+ /** Simulated row ceiling reported by `getQuota`. Default 1,000,000. */
145
+ limitRows?: number;
146
+ /**
147
+ * Force the next N storage MUTATIONS (`set`/`delete`) to fail with a generic
148
+ * `STORAGE_UNAVAILABLE` error (counts down) — exercises the error UX.
149
+ */
150
+ failNext?: number;
151
+ }
43
152
  /**
44
153
  * Drives `createMockHost`. Every field is optional with a sensible default so
45
154
  * `createMockHost()` works out of the box. Each block configures SCENARIOS
46
155
  * here instead of forking the host code.
156
+ *
157
+ * Backward-compatible: the legacy top-level `cost`/`failMode`/`buzzBudget`/
158
+ * `pollsUntilDone` knobs still work. When BOTH a legacy knob and its scenario
159
+ * equivalent are set, the SCENARIO wins (it's the newer, richer control).
47
160
  */
48
161
  export interface MockHostOptions {
49
162
  /**
@@ -68,10 +181,30 @@ export interface MockHostOptions {
68
181
  cannedPicks?: Partial<Record<BlockResourcePickerType, CannedPick | null>>;
69
182
  /** Number of `POLL_WORKFLOW` round-trips before a workflow succeeds. Default 2. */
70
183
  pollsUntilDone?: number;
71
- /** The `cost.total` reported on estimate + succeeded snapshots. Default 8. */
184
+ /**
185
+ * The `cost.total` reported on estimate + succeeded snapshots. Default 8.
186
+ * @deprecated Prefer {@link MockGenerationScenario.costPerGen} on `generation`.
187
+ */
72
188
  cost?: number;
73
189
  /** The Buzz budget reported on a granted token. Default 200. */
74
190
  buzzBudget?: number;
191
+ /**
192
+ * GENERATION scenario: cost / latency / failure / result-image controls. See
193
+ * {@link MockGenerationScenario}.
194
+ */
195
+ generation?: MockGenerationScenario;
196
+ /**
197
+ * BUZZ scenario: simulated balance + force-insufficient. See
198
+ * {@link MockBuzzScenario}.
199
+ */
200
+ buzz?: MockBuzzScenario;
201
+ /**
202
+ * STORAGE scenario: in-memory KV backend (seed / quota / failNext). See
203
+ * {@link MockStorageScenario}. When omitted, the store starts EMPTY with the
204
+ * v0 defaults — `APP_STORAGE_*` is answered either way (the mock host always
205
+ * serves storage now).
206
+ */
207
+ storage?: MockStorageScenario;
75
208
  /** Host theme delivered in `BLOCK_INIT` + context. Default `'dark'`. */
76
209
  theme?: Theme;
77
210
  /**
@@ -81,14 +214,28 @@ export interface MockHostOptions {
81
214
  */
82
215
  context?: BlockContext;
83
216
  /**
84
- * Forward-compat hook for a future content-domain / maturity field on
85
- * `BLOCK_INIT`. Stored verbatim and surfaced on the init payload's context
86
- * under `domain` / `maturity` so a block can read it once the platform ships
87
- * the field inert until then.
217
+ * The color-domain the host projects into `BLOCK_INIT` (civitai #2670),
218
+ * surfaced on the top-level `domain` field. When set WITHOUT an explicit
219
+ * {@link MockHostOptions.maxBrowsingLevel}, the mock host derives a matching
220
+ * ceiling: `green`/`blue` SFW (`SFW_LEVELS`), `red` → all levels — so
221
+ * `useDomainMaturity()`/`<SfwGate>` are exercisable. Omit for a host that
222
+ * predates #2670 (neither field is emitted → the hook fail-closes to SFW).
223
+ */
224
+ domain?: ColorDomain;
225
+ /**
226
+ * The authoritative browsing-level ceiling BITMASK emitted on `BLOCK_INIT`
227
+ * (`maxBrowsingLevel`). Overrides whatever {@link MockHostOptions.domain} /
228
+ * {@link MockHostOptions.maturity} would derive. Use `BrowsingLevel` bits
229
+ * from `@civitai/app-sdk/blocks` to compose one.
230
+ */
231
+ maxBrowsingLevel?: number;
232
+ /**
233
+ * Convenience for the common case: `'sfw'` → an SFW ceiling (`SFW_LEVELS`),
234
+ * `'mature'` → an all-levels ceiling. Lower precedence than an explicit
235
+ * {@link MockHostOptions.maxBrowsingLevel}, higher than the
236
+ * {@link MockHostOptions.domain}-derived default.
88
237
  */
89
- domain?: string;
90
- /** @see {@link MockHostOptions.domain} */
91
- maturity?: string;
238
+ maturity?: 'sfw' | 'mature';
92
239
  /** Identity fields delivered in `BLOCK_INIT`. Sensible dev defaults. */
93
240
  blockInstanceId?: string;
94
241
  blockId?: string;
@@ -108,16 +255,46 @@ export interface MockHostOptions {
108
255
  */
109
256
  window?: Window & typeof globalThis;
110
257
  }
111
- /** Handle returned by {@link createMockHost}. Call `install()` to patch the
112
- * host in; it returns the `uninstall()` that restores `window.parent` and
113
- * removes timers. Idempotent calling `install()` twice returns the same
114
- * teardown; `uninstall()` is safe to call more than once. */
258
+ /**
259
+ * The mutable slice of {@link MockHostOptions} a harness UI can flip mid-session
260
+ * via {@link MockHost.setScenario}. (Identity/init-only fields like `viewer`,
261
+ * `context`, `theme`, and `appId` are fixed at install time change them by
262
+ * re-installing.)
263
+ */
264
+ export type MockHostScenarioPatch = Pick<MockHostOptions, 'failMode' | 'cost' | 'pollsUntilDone' | 'cannedPicks' | 'generation' | 'buzz' | 'storage'>;
265
+ /** Runtime Buzz-balance handle exposed on {@link MockHost.buzz}. */
266
+ export interface MockBuzzHandle {
267
+ /** Current simulated balance, or `undefined` when balance isn't simulated. */
268
+ getBalance: () => number | undefined;
269
+ /** Set (or start simulating) the balance. Pass `undefined` to stop simulating. */
270
+ setBalance: (n: number | undefined) => void;
271
+ }
272
+ /** Handle returned by {@link createMockHost}.
273
+ *
274
+ * Call `install()` to patch the host in; it returns the `uninstall()` that
275
+ * restores `window.parent` and removes timers (so the historical
276
+ * `const uninstall = createMockHost(opts).install()` keeps working unchanged).
277
+ *
278
+ * After install, a harness UI can drive scenarios live:
279
+ * - `setScenario(patch)` — merge new generation/buzz/storage/failMode controls.
280
+ * - `buzz.setBalance(n)` / `buzz.getBalance()` — flip the simulated wallet.
281
+ *
282
+ * `install()` is idempotent — calling it twice returns the same teardown;
283
+ * `uninstall()` is safe to call more than once. */
115
284
  export interface MockHost {
116
285
  install: () => () => void;
286
+ /** Merge a partial scenario into the live mock host (no re-install). */
287
+ setScenario: (patch: MockHostScenarioPatch) => void;
288
+ /** Runtime Buzz-balance control for a harness UI. */
289
+ buzz: MockBuzzHandle;
117
290
  }
118
291
  /**
119
292
  * Reads the URL query toggles the gen-matrix dev harness uses, so a starter's
120
293
  * dev harness keeps working with `?viewer/?consent/?fail/?theme/?pick/?pickCkpt`.
294
+ * Layer-1 additions: `?balance/?latency/?costPerGen/?failNext/?failRate/?seed`
295
+ * map onto the new scenario groups so a dev can flip insufficient-buzz /
296
+ * failures / latency without editing code.
297
+ *
121
298
  * Returns a partial overlay applied ON TOP of explicit {@link MockHostOptions}
122
299
  * (URL wins — it's the interactive dev knob). No-op outside a browser.
123
300
  */
@@ -129,9 +306,11 @@ export declare function readMockHostUrlOptions(win?: (Window & typeof globalThis
129
306
  * from a node/jsdom/happy-dom test OR a browser dev harness.
130
307
  *
131
308
  * @example
132
- * const host = createMockHost({ failMode: 'some', pollsUntilDone: 1 });
309
+ * const host = createMockHost({ generation: { failNext: 1, latencyMs: 1500 }, buzz: { balance: 5 } });
133
310
  * const uninstall = host.install();
134
311
  * // … drive the block / assertions …
312
+ * host.buzz.setBalance(0); // flip to insufficient mid-session
313
+ * host.setScenario({ generation: { failRate: 1 } });
135
314
  * uninstall();
136
315
  */
137
316
  export declare function createMockHost(options?: MockHostOptions): MockHost;
@@ -1 +1 @@
1
- {"version":3,"file":"mockHost.d.ts","sourceRoot":"","sources":["../../src/internal/mockHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EACV,YAAY,EAEZ,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,EACL,UAAU,EAEX,MAAM,yBAAyB,CAAC;AAKjC;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,cAAc,CAAC;AAExE;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAE3C;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC3B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,uBAAuB,EAAE,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;OAIG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,UAAU,CAAC;CACrC;AAED;;;6DAG6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,MAAM,IAAI,CAAC;CAC3B;AAsBD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,CAAC,MAAM,GAAG,OAAO,UAAU,CAAC,GAAG,SAC3B,GACR,OAAO,CAAC,eAAe,CAAC,CAsC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAqQtE"}
1
+ {"version":3,"file":"mockHost.d.ts","sourceRoot":"","sources":["../../src/internal/mockHost.ts"],"names":[],"mappings":"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"}