@civitai/blocks-react 0.6.0 → 0.8.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/LICENSE +21 -0
- package/dist/hooks/useResourcePicker.d.ts +38 -0
- package/dist/hooks/useResourcePicker.d.ts.map +1 -0
- package/dist/hooks/useResourcePicker.js +41 -0
- package/dist/hooks/useResourcePicker.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/mockHost.d.ts +138 -0
- package/dist/internal/mockHost.d.ts.map +1 -0
- package/dist/internal/mockHost.js +334 -0
- package/dist/internal/mockHost.js.map +1 -0
- package/dist/testing.d.ts +56 -2
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +82 -2
- package/dist/testing.js.map +1 -1
- package/package.json +11 -11
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Civitai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BlockResourceInfo, BlockResourcePickerType } from '@civitai/app-sdk/blocks';
|
|
2
|
+
/**
|
|
3
|
+
* Drives the platform-side resource picker for PAGE App Blocks (Design 1 —
|
|
4
|
+
* host-chrome). Generalizes {@link useCheckpointPicker} from Checkpoint-only to
|
|
5
|
+
* a typed allowlist (v1: `'Checkpoint' | 'LORA'`), so a page block can let the
|
|
6
|
+
* USER pick a checkpoint + LoRAs instead of the author hard-coding version IDs.
|
|
7
|
+
*
|
|
8
|
+
* `open` asks the host to open its OWN native resource modal filtered to the
|
|
9
|
+
* requested type (+ optional base-model family). The viewer searches in HOST
|
|
10
|
+
* chrome — the block never sees the catalog, a list, or any resource it didn't
|
|
11
|
+
* pick. Resolves with the chosen {@link BlockResourceInfo}, or `null` when the
|
|
12
|
+
* user dismissed without picking.
|
|
13
|
+
*
|
|
14
|
+
* DISCOVERY ONLY: the returned `versionId` is a hint, never an entitlement.
|
|
15
|
+
* Feed it into `body.modelVersionId` (Checkpoint) or
|
|
16
|
+
* `body.additionalResources` (LoRA) and submit — the host re-validates every id
|
|
17
|
+
* server-side at estimate/submit (the page gate + orchestrator belt). A block
|
|
18
|
+
* can POST any id regardless of what the picker showed; the spend path is the
|
|
19
|
+
* enforcement boundary, not the picker.
|
|
20
|
+
*
|
|
21
|
+
* Host-mediated, same trust model as `useCheckpointPicker` / `useBuzzWorkflow`:
|
|
22
|
+
* the block never touches the picker UI directly.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useResourcePicker(): {
|
|
25
|
+
open: (opts: {
|
|
26
|
+
/** Which resource type to pick. v1: `'Checkpoint' | 'LORA'` only — the
|
|
27
|
+
* host rejects any other type (the modal never opens). */
|
|
28
|
+
resourceType: BlockResourcePickerType;
|
|
29
|
+
/**
|
|
30
|
+
* Optional base-model family hint — an ecosystem key (e.g. 'Flux1', 'SDXL')
|
|
31
|
+
* OR a baseModel name (e.g. 'Flux.1 D'); the host collapses it to the
|
|
32
|
+
* ecosystem family. Use the chosen checkpoint's `baseModel` to constrain a
|
|
33
|
+
* LoRA pick to the same family. Omit for an unconstrained pick of the type.
|
|
34
|
+
*/
|
|
35
|
+
baseModelGroup?: string;
|
|
36
|
+
}) => Promise<BlockResourceInfo | null>;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=useResourcePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResourcePicker.d.ts","sourceRoot":"","sources":["../../src/hooks/useResourcePicker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAK1F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,IAAI,EAAE,CAAC,IAAI,EAAE;QACX;kEAC0D;QAC1D,YAAY,EAAE,uBAAuB,CAAC;QACtC;;;;;WAKG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,KAAK,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CACzC,CAsBA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { getTransport } from '../internal/singleton.js';
|
|
3
|
+
import { sendTypedRequest } from '../internal/transport.js';
|
|
4
|
+
/**
|
|
5
|
+
* Drives the platform-side resource picker for PAGE App Blocks (Design 1 —
|
|
6
|
+
* host-chrome). Generalizes {@link useCheckpointPicker} from Checkpoint-only to
|
|
7
|
+
* a typed allowlist (v1: `'Checkpoint' | 'LORA'`), so a page block can let the
|
|
8
|
+
* USER pick a checkpoint + LoRAs instead of the author hard-coding version IDs.
|
|
9
|
+
*
|
|
10
|
+
* `open` asks the host to open its OWN native resource modal filtered to the
|
|
11
|
+
* requested type (+ optional base-model family). The viewer searches in HOST
|
|
12
|
+
* chrome — the block never sees the catalog, a list, or any resource it didn't
|
|
13
|
+
* pick. Resolves with the chosen {@link BlockResourceInfo}, or `null` when the
|
|
14
|
+
* user dismissed without picking.
|
|
15
|
+
*
|
|
16
|
+
* DISCOVERY ONLY: the returned `versionId` is a hint, never an entitlement.
|
|
17
|
+
* Feed it into `body.modelVersionId` (Checkpoint) or
|
|
18
|
+
* `body.additionalResources` (LoRA) and submit — the host re-validates every id
|
|
19
|
+
* server-side at estimate/submit (the page gate + orchestrator belt). A block
|
|
20
|
+
* can POST any id regardless of what the picker showed; the spend path is the
|
|
21
|
+
* enforcement boundary, not the picker.
|
|
22
|
+
*
|
|
23
|
+
* Host-mediated, same trust model as `useCheckpointPicker` / `useBuzzWorkflow`:
|
|
24
|
+
* the block never touches the picker UI directly.
|
|
25
|
+
*/
|
|
26
|
+
export function useResourcePicker() {
|
|
27
|
+
const open = useCallback(async (opts) => {
|
|
28
|
+
const { selected } = await sendTypedRequest(getTransport(), {
|
|
29
|
+
type: 'OPEN_RESOURCE_PICKER',
|
|
30
|
+
payload: {
|
|
31
|
+
resourceType: opts.resourceType,
|
|
32
|
+
...(opts.baseModelGroup != null ? { baseModelGroup: opts.baseModelGroup } : {}),
|
|
33
|
+
},
|
|
34
|
+
}, 'RESOURCE_PICKER_RESULT');
|
|
35
|
+
// Normalize the "dismissed" case to an explicit null so callers can
|
|
36
|
+
// `if (!picked) return;` without an `undefined` ambiguity.
|
|
37
|
+
return selected ?? null;
|
|
38
|
+
}, []);
|
|
39
|
+
return { open };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=useResourcePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResourcePicker.js","sourceRoot":"","sources":["../../src/hooks/useResourcePicker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAIpC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB;IAc/B,MAAM,IAAI,GAAG,WAAW,CACtB,KAAK,EAAE,IAAwE,EAAE,EAAE;QACjF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,gBAAgB,CACzC,YAAY,EAAE,EACd;YACE,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE;gBACP,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChF;SACF,EACD,wBAAwB,CACzB,CAAC;QACF,oEAAoE;QACpE,2DAA2D;QAC3D,OAAO,QAAQ,IAAI,IAAI,CAAC;IAC1B,CAAC,EACD,EAAE,CACH,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export { useBuzzWorkflow } from './hooks/useBuzzWorkflow.js';
|
|
|
20
20
|
export { useBlockResize } from './hooks/useBlockResize.js';
|
|
21
21
|
export { useBuzzPurchase } from './hooks/useBuzzPurchase.js';
|
|
22
22
|
export { useCheckpointPicker } from './hooks/useCheckpointPicker.js';
|
|
23
|
+
export { useResourcePicker } from './hooks/useResourcePicker.js';
|
|
23
24
|
export { useCivitaiNavigate } from './hooks/useCivitaiNavigate.js';
|
|
24
25
|
export { useRequestSignIn } from './hooks/useRequestSignIn.js';
|
|
25
26
|
export { useRequestConsent } from './hooks/useRequestConsent.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,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,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,GACd,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export { useBuzzWorkflow } from './hooks/useBuzzWorkflow.js';
|
|
|
18
18
|
export { useBlockResize } from './hooks/useBlockResize.js';
|
|
19
19
|
export { useBuzzPurchase } from './hooks/useBuzzPurchase.js';
|
|
20
20
|
export { useCheckpointPicker } from './hooks/useCheckpointPicker.js';
|
|
21
|
+
export { useResourcePicker } from './hooks/useResourcePicker.js';
|
|
21
22
|
export { useCivitaiNavigate } from './hooks/useCivitaiNavigate.js';
|
|
22
23
|
export { useRequestSignIn } from './hooks/useRequestSignIn.js';
|
|
23
24
|
export { useRequestConsent } from './hooks/useRequestConsent.js';
|
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,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,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createMockHost` — a framework-agnostic, test-and-dev-only fake of the
|
|
3
|
+
* civitai.com embedding host.
|
|
4
|
+
*
|
|
5
|
+
* The real host (civitai/civitai `IframeHost.tsx` / `PageBlockHost.tsx`) mounts
|
|
6
|
+
* a block in a cross-origin iframe and answers its `postMessage` protocol:
|
|
7
|
+
* mints a token, runs the lazy-consent round-trip, brokers the orchestrator
|
|
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.
|
|
11
|
+
*
|
|
12
|
+
* It is the portable core that the React `<Harness>` (a.k.a. `<MockHostProvider>`
|
|
13
|
+
* in `../testing`) wraps. Every block app used to hand-roll ~250 lines of this;
|
|
14
|
+
* now they configure it with {@link MockHostOptions} instead.
|
|
15
|
+
*
|
|
16
|
+
* Mechanism (mirrors the gen-matrix reference Harness):
|
|
17
|
+
* 1. Patches `window.parent.postMessage` via `Object.defineProperty(window,
|
|
18
|
+
* 'parent', …)` so the block's OUTBOUND messages are intercepted.
|
|
19
|
+
* 2. Replies as `MessageEvent`s fired from `window.location.origin` — the SDK
|
|
20
|
+
* `IframeTransport` DROPS any inbound message whose `origin` ≠ the allowed
|
|
21
|
+
* parent origin, so a block using this in dev MUST allow
|
|
22
|
+
* `window.location.origin` (the React `<Harness>` is documented for that).
|
|
23
|
+
* 3. Dispatches a configurable `BLOCK_INIT`, then answers the full protocol.
|
|
24
|
+
*
|
|
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.
|
|
27
|
+
*/
|
|
28
|
+
import type { BlockContext, BlockResourceInfo, BlockResourcePickerType, Theme, ViewerInfo } from '@civitai/app-sdk/blocks';
|
|
29
|
+
/**
|
|
30
|
+
* How submits resolve. `'none'` = everything succeeds; `'all'` /
|
|
31
|
+
* `'insufficient'` = every submit returns an insufficient-Buzz `failed`
|
|
32
|
+
* snapshot (exercises the per-cell Top-Up CTA); `'some'` = ~1 in 3 submits
|
|
33
|
+
* fail (a mixed grid).
|
|
34
|
+
*/
|
|
35
|
+
export type MockHostFailMode = 'none' | 'some' | 'all' | 'insufficient';
|
|
36
|
+
/**
|
|
37
|
+
* A canned resource the mock host "returns" from `OPEN_RESOURCE_PICKER`.
|
|
38
|
+
* Mirrors the host's narrow `BlockResourceInfo` projection (versionId/modelId/
|
|
39
|
+
* names/baseModel/modelType). Returning `undefined`/`null` simulates a
|
|
40
|
+
* user-dismissed picker (→ `RESOURCE_PICKER_RESULT` with no `selected`).
|
|
41
|
+
*/
|
|
42
|
+
export type CannedPick = BlockResourceInfo;
|
|
43
|
+
/**
|
|
44
|
+
* Drives `createMockHost`. Every field is optional with a sensible default so
|
|
45
|
+
* `createMockHost()` works out of the box. Each block configures SCENARIOS
|
|
46
|
+
* here instead of forking the host code.
|
|
47
|
+
*/
|
|
48
|
+
export interface MockHostOptions {
|
|
49
|
+
/**
|
|
50
|
+
* The signed-in viewer, or `null` for anonymous (→ sign-in CTA). Defaults to
|
|
51
|
+
* a `dev-viewer`. Pass `null` to exercise the anon path.
|
|
52
|
+
*/
|
|
53
|
+
viewer?: ViewerInfo | null;
|
|
54
|
+
/**
|
|
55
|
+
* Start WITH the consent-gated `ai:write:budgeted` scope already granted. The
|
|
56
|
+
* real mint WITHHOLDS it until the viewer consents, so this defaults to
|
|
57
|
+
* `false` — the first token carries NO budgeted scope, and `REQUEST_CONSENT`
|
|
58
|
+
* grants it + pushes a `TOKEN_REFRESH` (the lazy-consent round-trip).
|
|
59
|
+
*/
|
|
60
|
+
consentGranted?: boolean;
|
|
61
|
+
/** How submits resolve. Default `'none'` (all succeed). */
|
|
62
|
+
failMode?: MockHostFailMode;
|
|
63
|
+
/**
|
|
64
|
+
* Canned picks keyed by requested resource type, returned from
|
|
65
|
+
* `OPEN_RESOURCE_PICKER`. A `null`/absent entry simulates a dismissed picker
|
|
66
|
+
* for that type. Defaults to a curated Checkpoint + LoRA pick.
|
|
67
|
+
*/
|
|
68
|
+
cannedPicks?: Partial<Record<BlockResourcePickerType, CannedPick | null>>;
|
|
69
|
+
/** Number of `POLL_WORKFLOW` round-trips before a workflow succeeds. Default 2. */
|
|
70
|
+
pollsUntilDone?: number;
|
|
71
|
+
/** The `cost.total` reported on estimate + succeeded snapshots. Default 8. */
|
|
72
|
+
cost?: number;
|
|
73
|
+
/** The Buzz budget reported on a granted token. Default 200. */
|
|
74
|
+
buzzBudget?: number;
|
|
75
|
+
/** Host theme delivered in `BLOCK_INIT` + context. Default `'dark'`. */
|
|
76
|
+
theme?: Theme;
|
|
77
|
+
/**
|
|
78
|
+
* The `BLOCK_INIT` context. Defaults to a PAGE context
|
|
79
|
+
* (`{ slotId: 'app.page' }`). Pass a `ModelSlotContext` for a model-slot
|
|
80
|
+
* block. `theme` is merged in from {@link MockHostOptions.theme}.
|
|
81
|
+
*/
|
|
82
|
+
context?: BlockContext;
|
|
83
|
+
/**
|
|
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.
|
|
88
|
+
*/
|
|
89
|
+
domain?: string;
|
|
90
|
+
/** @see {@link MockHostOptions.domain} */
|
|
91
|
+
maturity?: string;
|
|
92
|
+
/** Identity fields delivered in `BLOCK_INIT`. Sensible dev defaults. */
|
|
93
|
+
blockInstanceId?: string;
|
|
94
|
+
blockId?: string;
|
|
95
|
+
appId?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Called with every intercepted OUTBOUND message (`{ type, payload }`) — the
|
|
98
|
+
* React `<Harness>` uses this to render its on-screen message log. RESIZE
|
|
99
|
+
* messages are included; filter them out in the callback if undesired.
|
|
100
|
+
*/
|
|
101
|
+
onOutbound?: (msg: {
|
|
102
|
+
type: string;
|
|
103
|
+
payload?: unknown;
|
|
104
|
+
}) => void;
|
|
105
|
+
/**
|
|
106
|
+
* Override `window`. Defaults to `globalThis.window`. Tests pass happy-dom's
|
|
107
|
+
* window; the dev harness uses the default.
|
|
108
|
+
*/
|
|
109
|
+
window?: Window & typeof globalThis;
|
|
110
|
+
}
|
|
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. */
|
|
115
|
+
export interface MockHost {
|
|
116
|
+
install: () => () => void;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Reads the URL query toggles the gen-matrix dev harness uses, so a starter's
|
|
120
|
+
* dev harness keeps working with `?viewer/?consent/?fail/?theme/?pick/?pickCkpt`.
|
|
121
|
+
* Returns a partial overlay applied ON TOP of explicit {@link MockHostOptions}
|
|
122
|
+
* (URL wins — it's the interactive dev knob). No-op outside a browser.
|
|
123
|
+
*/
|
|
124
|
+
export declare function readMockHostUrlOptions(win?: (Window & typeof globalThis) | undefined): Partial<MockHostOptions>;
|
|
125
|
+
/**
|
|
126
|
+
* Create a framework-agnostic mock host. Call the returned `install()` to patch
|
|
127
|
+
* `window.parent` + start answering the block's protocol; it returns an
|
|
128
|
+
* `uninstall()` teardown (restores `window.parent`, clears timers). Safe to use
|
|
129
|
+
* from a node/jsdom/happy-dom test OR a browser dev harness.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* const host = createMockHost({ failMode: 'some', pollsUntilDone: 1 });
|
|
133
|
+
* const uninstall = host.install();
|
|
134
|
+
* // … drive the block / assertions …
|
|
135
|
+
* uninstall();
|
|
136
|
+
*/
|
|
137
|
+
export declare function createMockHost(options?: MockHostOptions): MockHost;
|
|
138
|
+
//# sourceMappingURL=mockHost.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createMockHost` — a framework-agnostic, test-and-dev-only fake of the
|
|
3
|
+
* civitai.com embedding host.
|
|
4
|
+
*
|
|
5
|
+
* The real host (civitai/civitai `IframeHost.tsx` / `PageBlockHost.tsx`) mounts
|
|
6
|
+
* a block in a cross-origin iframe and answers its `postMessage` protocol:
|
|
7
|
+
* mints a token, runs the lazy-consent round-trip, brokers the orchestrator
|
|
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.
|
|
11
|
+
*
|
|
12
|
+
* It is the portable core that the React `<Harness>` (a.k.a. `<MockHostProvider>`
|
|
13
|
+
* in `../testing`) wraps. Every block app used to hand-roll ~250 lines of this;
|
|
14
|
+
* now they configure it with {@link MockHostOptions} instead.
|
|
15
|
+
*
|
|
16
|
+
* Mechanism (mirrors the gen-matrix reference Harness):
|
|
17
|
+
* 1. Patches `window.parent.postMessage` via `Object.defineProperty(window,
|
|
18
|
+
* 'parent', …)` so the block's OUTBOUND messages are intercepted.
|
|
19
|
+
* 2. Replies as `MessageEvent`s fired from `window.location.origin` — the SDK
|
|
20
|
+
* `IframeTransport` DROPS any inbound message whose `origin` ≠ the allowed
|
|
21
|
+
* parent origin, so a block using this in dev MUST allow
|
|
22
|
+
* `window.location.origin` (the React `<Harness>` is documented for that).
|
|
23
|
+
* 3. Dispatches a configurable `BLOCK_INIT`, then answers the full protocol.
|
|
24
|
+
*
|
|
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.
|
|
27
|
+
*/
|
|
28
|
+
const DEV_TOKEN = 'dev.mockhost.mock.jwt.NOT.A.REAL.RS256';
|
|
29
|
+
const BUDGETED_SCOPE = 'ai:write:budgeted';
|
|
30
|
+
const DEFAULT_CHECKPOINT_PICK = {
|
|
31
|
+
versionId: 691639,
|
|
32
|
+
modelId: 618692,
|
|
33
|
+
modelName: 'FLUX.1 [dev]',
|
|
34
|
+
versionName: 'fp8',
|
|
35
|
+
baseModel: 'Flux.1 D',
|
|
36
|
+
modelType: 'Checkpoint',
|
|
37
|
+
};
|
|
38
|
+
const DEFAULT_LORA_PICK = {
|
|
39
|
+
versionId: 666002,
|
|
40
|
+
modelId: 555002,
|
|
41
|
+
modelName: 'Sinfully Stylish',
|
|
42
|
+
versionName: 'v2.0',
|
|
43
|
+
baseModel: 'SDXL 1.0',
|
|
44
|
+
modelType: 'LORA',
|
|
45
|
+
};
|
|
46
|
+
const DEFAULT_VIEWER = { id: 2, username: 'dev-viewer', status: 'active' };
|
|
47
|
+
/**
|
|
48
|
+
* Reads the URL query toggles the gen-matrix dev harness uses, so a starter's
|
|
49
|
+
* dev harness keeps working with `?viewer/?consent/?fail/?theme/?pick/?pickCkpt`.
|
|
50
|
+
* Returns a partial overlay applied ON TOP of explicit {@link MockHostOptions}
|
|
51
|
+
* (URL wins — it's the interactive dev knob). No-op outside a browser.
|
|
52
|
+
*/
|
|
53
|
+
export function readMockHostUrlOptions(win = globalThis
|
|
54
|
+
.window) {
|
|
55
|
+
if (!win?.location?.search)
|
|
56
|
+
return {};
|
|
57
|
+
const params = new URLSearchParams(win.location.search);
|
|
58
|
+
const out = {};
|
|
59
|
+
if (params.get('viewer') === 'anon')
|
|
60
|
+
out.viewer = null;
|
|
61
|
+
if (params.get('consent') === 'granted')
|
|
62
|
+
out.consentGranted = true;
|
|
63
|
+
const fail = params.get('fail');
|
|
64
|
+
if (fail === 'insufficient' || fail === 'some' || fail === 'all' || fail === 'none') {
|
|
65
|
+
out.failMode = fail;
|
|
66
|
+
}
|
|
67
|
+
if (params.get('theme') === 'light')
|
|
68
|
+
out.theme = 'light';
|
|
69
|
+
else if (params.get('theme') === 'dark')
|
|
70
|
+
out.theme = 'dark';
|
|
71
|
+
// ?pick (LoRA) / ?pickCkpt (Checkpoint): 'cancel' → dismissed; 'pony' → an
|
|
72
|
+
// incompatible Pony LoRA; any other value → the default curated pick.
|
|
73
|
+
const pick = params.get('pick');
|
|
74
|
+
const pickCkpt = params.get('pickCkpt');
|
|
75
|
+
if (pick || pickCkpt) {
|
|
76
|
+
const cannedPicks = {};
|
|
77
|
+
if (pick === 'cancel')
|
|
78
|
+
cannedPicks.LORA = null;
|
|
79
|
+
else if (pick === 'pony')
|
|
80
|
+
cannedPicks.LORA = {
|
|
81
|
+
versionId: 555001,
|
|
82
|
+
modelId: 444001,
|
|
83
|
+
modelName: 'Incompatible Pony LoRA',
|
|
84
|
+
versionName: 'v1.0',
|
|
85
|
+
baseModel: 'Pony',
|
|
86
|
+
modelType: 'LORA',
|
|
87
|
+
};
|
|
88
|
+
else if (pick)
|
|
89
|
+
cannedPicks.LORA = DEFAULT_LORA_PICK;
|
|
90
|
+
if (pickCkpt === 'cancel')
|
|
91
|
+
cannedPicks.Checkpoint = null;
|
|
92
|
+
else if (pickCkpt)
|
|
93
|
+
cannedPicks.Checkpoint = DEFAULT_CHECKPOINT_PICK;
|
|
94
|
+
out.cannedPicks = cannedPicks;
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create a framework-agnostic mock host. Call the returned `install()` to patch
|
|
100
|
+
* `window.parent` + start answering the block's protocol; it returns an
|
|
101
|
+
* `uninstall()` teardown (restores `window.parent`, clears timers). Safe to use
|
|
102
|
+
* from a node/jsdom/happy-dom test OR a browser dev harness.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const host = createMockHost({ failMode: 'some', pollsUntilDone: 1 });
|
|
106
|
+
* const uninstall = host.install();
|
|
107
|
+
* // … drive the block / assertions …
|
|
108
|
+
* uninstall();
|
|
109
|
+
*/
|
|
110
|
+
export function createMockHost(options = {}) {
|
|
111
|
+
const maybeWin = options.window ?? globalThis.window;
|
|
112
|
+
if (!maybeWin) {
|
|
113
|
+
throw new Error('createMockHost: no window available (call from a DOM environment).');
|
|
114
|
+
}
|
|
115
|
+
// Bind to a non-nullable local so the `install()` closure keeps the narrowing.
|
|
116
|
+
const win = maybeWin;
|
|
117
|
+
const viewer = options.viewer === undefined ? DEFAULT_VIEWER : options.viewer;
|
|
118
|
+
const failMode = options.failMode ?? 'none';
|
|
119
|
+
const pollsUntilDone = options.pollsUntilDone ?? 2;
|
|
120
|
+
const cost = options.cost ?? 8;
|
|
121
|
+
const buzzBudget = options.buzzBudget ?? 200;
|
|
122
|
+
const theme = options.theme ?? 'dark';
|
|
123
|
+
const cannedPicks = options.cannedPicks ?? { Checkpoint: DEFAULT_CHECKPOINT_PICK, LORA: DEFAULT_LORA_PICK };
|
|
124
|
+
const blockInstanceId = options.blockInstanceId ?? 'page_mock';
|
|
125
|
+
const blockId = options.blockId ?? 'mock-block';
|
|
126
|
+
const appId = options.appId ?? 'app_dev';
|
|
127
|
+
let installed = false;
|
|
128
|
+
let teardown = () => { };
|
|
129
|
+
function install() {
|
|
130
|
+
if (installed)
|
|
131
|
+
return teardown;
|
|
132
|
+
installed = true;
|
|
133
|
+
const parentOrigin = win.location.origin;
|
|
134
|
+
const originalParent = win.parent;
|
|
135
|
+
let consentGranted = !!options.consentGranted;
|
|
136
|
+
let tokenSerial = 0;
|
|
137
|
+
let submitCount = 0;
|
|
138
|
+
const workflows = new Map();
|
|
139
|
+
const timers = new Set();
|
|
140
|
+
const dispatchToBlock = (data) => {
|
|
141
|
+
win.dispatchEvent(new MessageEvent('message', { data, origin: parentOrigin }));
|
|
142
|
+
};
|
|
143
|
+
const nextToken = () => {
|
|
144
|
+
tokenSerial += 1;
|
|
145
|
+
return {
|
|
146
|
+
raw: `${DEV_TOKEN}.${tokenSerial}`,
|
|
147
|
+
scopes: consentGranted ? [BUDGETED_SCOPE] : [],
|
|
148
|
+
expiresAt: new Date(Date.now() + 15 * 60_000).toISOString(),
|
|
149
|
+
...(consentGranted ? { buzzBudget } : {}),
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const succeededSnapshot = (workflowId) => ({
|
|
153
|
+
workflowId,
|
|
154
|
+
status: 'succeeded',
|
|
155
|
+
cost: { total: cost },
|
|
156
|
+
imageUrls: [
|
|
157
|
+
`https://placehold.co/512x512/1971c2/ffffff/png?text=${encodeURIComponent(workflowId.slice(-4))}`,
|
|
158
|
+
],
|
|
159
|
+
});
|
|
160
|
+
const parentMock = {
|
|
161
|
+
postMessage: (msg) => {
|
|
162
|
+
if (typeof msg !== 'object' ||
|
|
163
|
+
msg === null ||
|
|
164
|
+
typeof msg.type !== 'string') {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const typed = msg;
|
|
168
|
+
options.onOutbound?.({ type: typed.type, payload: typed.payload });
|
|
169
|
+
const requestId = typed.payload?.requestId;
|
|
170
|
+
switch (typed.type) {
|
|
171
|
+
case 'REQUEST_TOKEN':
|
|
172
|
+
dispatchToBlock({
|
|
173
|
+
type: 'TOKEN_REFRESH_RESPONSE',
|
|
174
|
+
payload: { ...(requestId ? { requestId } : {}), token: nextToken() },
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
case 'REQUEST_CONSENT': {
|
|
178
|
+
// Lazy-consent round-trip: grant the scope, then push a
|
|
179
|
+
// host-initiated TOKEN_REFRESH carrying it (the App's auto-resume
|
|
180
|
+
// depends on seeing the new scope on its token).
|
|
181
|
+
consentGranted = true;
|
|
182
|
+
const t = setTimeout(() => {
|
|
183
|
+
dispatchToBlock({ type: 'TOKEN_REFRESH', payload: { token: nextToken() } });
|
|
184
|
+
}, 0);
|
|
185
|
+
timers.add(t);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
case 'REQUEST_SIGN_IN':
|
|
189
|
+
// The real host opens its login UI; nothing to reply.
|
|
190
|
+
return;
|
|
191
|
+
case 'ESTIMATE_WORKFLOW':
|
|
192
|
+
dispatchToBlock({
|
|
193
|
+
type: 'ESTIMATE_RESULT',
|
|
194
|
+
payload: {
|
|
195
|
+
requestId,
|
|
196
|
+
snapshot: { workflowId: 'wf_estimate', status: 'pending', cost: { total: cost } },
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
return;
|
|
200
|
+
case 'SUBMIT_WORKFLOW': {
|
|
201
|
+
submitCount += 1;
|
|
202
|
+
const failThis = failMode === 'all' ||
|
|
203
|
+
failMode === 'insufficient' ||
|
|
204
|
+
(failMode === 'some' && submitCount % 3 === 0);
|
|
205
|
+
if (failThis) {
|
|
206
|
+
dispatchToBlock({
|
|
207
|
+
type: 'WORKFLOW_SUBMITTED',
|
|
208
|
+
payload: {
|
|
209
|
+
requestId,
|
|
210
|
+
snapshot: {
|
|
211
|
+
workflowId: `wf_fail_${submitCount}`,
|
|
212
|
+
status: 'failed',
|
|
213
|
+
error: 'Insufficient Buzz to run this generation.',
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const workflowId = `wf_${submitCount}_${Date.now()}`;
|
|
220
|
+
workflows.set(workflowId, { polls: 0 });
|
|
221
|
+
dispatchToBlock({
|
|
222
|
+
type: 'WORKFLOW_SUBMITTED',
|
|
223
|
+
payload: { requestId, snapshot: { workflowId, status: 'pending' } },
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
case 'POLL_WORKFLOW': {
|
|
228
|
+
const workflowId = typed.payload?.workflowId ?? '';
|
|
229
|
+
const wf = workflows.get(workflowId);
|
|
230
|
+
const polls = (wf?.polls ?? 0) + 1;
|
|
231
|
+
if (wf)
|
|
232
|
+
wf.polls = polls;
|
|
233
|
+
const snapshot = polls >= pollsUntilDone
|
|
234
|
+
? succeededSnapshot(workflowId)
|
|
235
|
+
: { workflowId, status: 'processing' };
|
|
236
|
+
dispatchToBlock({ type: 'WORKFLOW_STATUS', payload: { requestId, snapshot } });
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
case 'CANCEL_WORKFLOW': {
|
|
240
|
+
const workflowId = typed.payload?.workflowId ?? '';
|
|
241
|
+
workflows.delete(workflowId);
|
|
242
|
+
dispatchToBlock({
|
|
243
|
+
type: 'WORKFLOW_CANCELED',
|
|
244
|
+
payload: { requestId, snapshot: { workflowId, status: 'canceled' } },
|
|
245
|
+
});
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
case 'OPEN_BUZZ_PURCHASE':
|
|
249
|
+
dispatchToBlock({
|
|
250
|
+
type: 'BUZZ_PURCHASE_RESULT',
|
|
251
|
+
payload: { requestId, purchased: true, newBalance: 1000 },
|
|
252
|
+
});
|
|
253
|
+
return;
|
|
254
|
+
case 'OPEN_CHECKPOINT_PICKER': {
|
|
255
|
+
const selected = cannedPicks.Checkpoint;
|
|
256
|
+
dispatchToBlock({
|
|
257
|
+
type: 'CHECKPOINT_PICKER_RESULT',
|
|
258
|
+
payload: {
|
|
259
|
+
requestId,
|
|
260
|
+
...(selected
|
|
261
|
+
? {
|
|
262
|
+
selected: {
|
|
263
|
+
versionId: selected.versionId,
|
|
264
|
+
modelId: selected.modelId,
|
|
265
|
+
modelName: selected.modelName,
|
|
266
|
+
versionName: selected.versionName,
|
|
267
|
+
baseModel: selected.baseModel,
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
: {}),
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
case 'OPEN_RESOURCE_PICKER': {
|
|
276
|
+
const rtype = typed.payload?.resourceType;
|
|
277
|
+
const selected = rtype ? cannedPicks[rtype] : undefined;
|
|
278
|
+
dispatchToBlock({
|
|
279
|
+
type: 'RESOURCE_PICKER_RESULT',
|
|
280
|
+
payload: { requestId, ...(selected ? { selected } : {}) },
|
|
281
|
+
});
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
default:
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
Object.defineProperty(win, 'parent', {
|
|
290
|
+
value: parentMock,
|
|
291
|
+
configurable: true,
|
|
292
|
+
writable: true,
|
|
293
|
+
});
|
|
294
|
+
// Merge theme + forward-compat domain/maturity into the init context.
|
|
295
|
+
const baseContext = options.context ?? { slotId: 'app.page' };
|
|
296
|
+
const context = {
|
|
297
|
+
...baseContext,
|
|
298
|
+
theme,
|
|
299
|
+
...(options.domain !== undefined ? { domain: options.domain } : {}),
|
|
300
|
+
...(options.maturity !== undefined ? { maturity: options.maturity } : {}),
|
|
301
|
+
};
|
|
302
|
+
const initPayload = {
|
|
303
|
+
blockInstanceId,
|
|
304
|
+
blockId,
|
|
305
|
+
appId,
|
|
306
|
+
token: nextToken(),
|
|
307
|
+
context,
|
|
308
|
+
settings: { publisherSettings: {}, userSettings: {} },
|
|
309
|
+
viewer,
|
|
310
|
+
theme,
|
|
311
|
+
renderMode: 'iframe',
|
|
312
|
+
};
|
|
313
|
+
const initTimer = setTimeout(() => dispatchToBlock({ type: 'BLOCK_INIT', payload: initPayload }), 0);
|
|
314
|
+
timers.add(initTimer);
|
|
315
|
+
let torn = false;
|
|
316
|
+
teardown = () => {
|
|
317
|
+
if (torn)
|
|
318
|
+
return;
|
|
319
|
+
torn = true;
|
|
320
|
+
installed = false;
|
|
321
|
+
for (const t of timers)
|
|
322
|
+
clearTimeout(t);
|
|
323
|
+
timers.clear();
|
|
324
|
+
Object.defineProperty(win, 'parent', {
|
|
325
|
+
value: originalParent,
|
|
326
|
+
configurable: true,
|
|
327
|
+
writable: true,
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
return teardown;
|
|
331
|
+
}
|
|
332
|
+
return { install };
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=mockHost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mockHost.js","sourceRoot":"","sources":["../../src/internal/mockHost.ts"],"names":[],"mappings":"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"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,14 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test-only helpers for `@civitai/blocks-react`. Not part of the runtime
|
|
3
|
-
* surface — block apps should never import from here
|
|
3
|
+
* surface — block apps should never import from here in production code (the
|
|
4
|
+
* `./testing` subpath keeps accidental prod imports visible in review).
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
+
* Exposes:
|
|
7
|
+
* - `resetTransport` / `mockParentMessage` — low-level test primitives.
|
|
8
|
+
* - `createMockHost` — a framework-agnostic fake of the civitai.com embedding
|
|
9
|
+
* host (usable from node/jsdom/happy-dom tests AND a dev harness).
|
|
10
|
+
* - `<Harness>` / `<MockHostProvider>` — a thin React wrapper that installs a
|
|
11
|
+
* mock host for local dev, with an optional on-screen message log.
|
|
12
|
+
*
|
|
13
|
+
* These replace the ~250-line per-block hand-rolled harness.
|
|
6
14
|
*/
|
|
15
|
+
import { type ReactNode } from 'react';
|
|
7
16
|
import { __resetTransport } from './internal/singleton.js';
|
|
17
|
+
import { type MockHostOptions } from './internal/mockHost.js';
|
|
8
18
|
export { __resetTransport as resetTransport };
|
|
19
|
+
export { createMockHost, readMockHostUrlOptions, type MockHost, type MockHostOptions, type MockHostFailMode, type CannedPick, } from './internal/mockHost.js';
|
|
9
20
|
/**
|
|
10
21
|
* Builds a `MessageEvent` that mimics a parent-frame postMessage so tests can
|
|
11
22
|
* exercise `IframeTransport.handleMessage` without a real cross-frame setup.
|
|
12
23
|
*/
|
|
13
24
|
export declare function mockParentMessage(data: unknown, origin: string): MessageEvent;
|
|
25
|
+
/**
|
|
26
|
+
* Props for the dev `<Harness>` (a.k.a. {@link MockHostProvider}).
|
|
27
|
+
*/
|
|
28
|
+
export interface HarnessProps extends MockHostOptions {
|
|
29
|
+
/** The block app to render inside the mocked host. */
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* Read the gen-matrix URL toggles (`?viewer/?consent/?fail/?theme/?pick/
|
|
33
|
+
* ?pickCkpt`) and apply them ON TOP of the props (URL wins). Default `true`
|
|
34
|
+
* so a dev harness stays interactive. Pass `false` in a deterministic test.
|
|
35
|
+
*/
|
|
36
|
+
applyUrlToggles?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Render the on-screen outbound-message log panel (bottom-right). Default
|
|
39
|
+
* `true`. Set `false` to mount the mock host with no chrome.
|
|
40
|
+
*/
|
|
41
|
+
showLog?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Thin React wrapper that installs a {@link createMockHost} on mount (and tears
|
|
45
|
+
* it down on unmount) so a block app renders against a fake civitai host for
|
|
46
|
+
* local dev — no real platform, no real Buzz.
|
|
47
|
+
*
|
|
48
|
+
* IMPORTANT: the SDK transport DROPS inbound host messages whose origin isn't
|
|
49
|
+
* in its allowlist, and the mock host fires from `window.location.origin`. So
|
|
50
|
+
* a block app using `<Harness>` in dev MUST include its OWN origin in the
|
|
51
|
+
* transport allowlist, e.g.:
|
|
52
|
+
*
|
|
53
|
+
* VITE_BLOCK_ALLOWED_PARENT_ORIGINS=http://localhost:5173
|
|
54
|
+
*
|
|
55
|
+
* (or pass it to `getTransport({ allowedParentOrigins: [window.location.origin] })`
|
|
56
|
+
* in the harness entrypoint). Otherwise BLOCK_INIT never lands.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* createRoot(el).render(
|
|
60
|
+
* <Harness failMode="some">
|
|
61
|
+
* <App />
|
|
62
|
+
* </Harness>,
|
|
63
|
+
* );
|
|
64
|
+
*/
|
|
65
|
+
export declare function Harness({ children, applyUrlToggles, showLog, ...options }: HarnessProps): import("react/jsx-runtime").JSX.Element;
|
|
66
|
+
/** Alias of {@link Harness} — same component, clearer name when used as a context provider. */
|
|
67
|
+
export declare const MockHostProvider: typeof Harness;
|
|
14
68
|
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,gBAAgB,IAAI,cAAc,EAAE,CAAC;AAE9C,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,wBAAwB,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAE7E;AAOD;;GAEG;AACH,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,sDAAsD;IACtD,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,eAAsB,EACtB,OAAc,EACd,GAAG,OAAO,EACX,EAAE,YAAY,2CAiDd;AAED,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB,gBAAU,CAAC"}
|
package/dist/testing.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
2
|
/**
|
|
2
3
|
* Test-only helpers for `@civitai/blocks-react`. Not part of the runtime
|
|
3
|
-
* surface — block apps should never import from here
|
|
4
|
+
* surface — block apps should never import from here in production code (the
|
|
5
|
+
* `./testing` subpath keeps accidental prod imports visible in review).
|
|
4
6
|
*
|
|
5
|
-
*
|
|
7
|
+
* Exposes:
|
|
8
|
+
* - `resetTransport` / `mockParentMessage` — low-level test primitives.
|
|
9
|
+
* - `createMockHost` — a framework-agnostic fake of the civitai.com embedding
|
|
10
|
+
* host (usable from node/jsdom/happy-dom tests AND a dev harness).
|
|
11
|
+
* - `<Harness>` / `<MockHostProvider>` — a thin React wrapper that installs a
|
|
12
|
+
* mock host for local dev, with an optional on-screen message log.
|
|
13
|
+
*
|
|
14
|
+
* These replace the ~250-line per-block hand-rolled harness.
|
|
6
15
|
*/
|
|
16
|
+
import { useEffect, useRef, useState } from 'react';
|
|
7
17
|
import { __resetTransport } from './internal/singleton.js';
|
|
18
|
+
import { createMockHost, readMockHostUrlOptions, } from './internal/mockHost.js';
|
|
8
19
|
export { __resetTransport as resetTransport };
|
|
20
|
+
export { createMockHost, readMockHostUrlOptions, } from './internal/mockHost.js';
|
|
9
21
|
/**
|
|
10
22
|
* Builds a `MessageEvent` that mimics a parent-frame postMessage so tests can
|
|
11
23
|
* exercise `IframeTransport.handleMessage` without a real cross-frame setup.
|
|
@@ -13,4 +25,72 @@ export { __resetTransport as resetTransport };
|
|
|
13
25
|
export function mockParentMessage(data, origin) {
|
|
14
26
|
return new MessageEvent('message', { data, origin, source: null });
|
|
15
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Thin React wrapper that installs a {@link createMockHost} on mount (and tears
|
|
30
|
+
* it down on unmount) so a block app renders against a fake civitai host for
|
|
31
|
+
* local dev — no real platform, no real Buzz.
|
|
32
|
+
*
|
|
33
|
+
* IMPORTANT: the SDK transport DROPS inbound host messages whose origin isn't
|
|
34
|
+
* in its allowlist, and the mock host fires from `window.location.origin`. So
|
|
35
|
+
* a block app using `<Harness>` in dev MUST include its OWN origin in the
|
|
36
|
+
* transport allowlist, e.g.:
|
|
37
|
+
*
|
|
38
|
+
* VITE_BLOCK_ALLOWED_PARENT_ORIGINS=http://localhost:5173
|
|
39
|
+
*
|
|
40
|
+
* (or pass it to `getTransport({ allowedParentOrigins: [window.location.origin] })`
|
|
41
|
+
* in the harness entrypoint). Otherwise BLOCK_INIT never lands.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* createRoot(el).render(
|
|
45
|
+
* <Harness failMode="some">
|
|
46
|
+
* <App />
|
|
47
|
+
* </Harness>,
|
|
48
|
+
* );
|
|
49
|
+
*/
|
|
50
|
+
export function Harness({ children, applyUrlToggles = true, showLog = true, ...options }) {
|
|
51
|
+
const [outbound, setOutbound] = useState([]);
|
|
52
|
+
// Snapshot the merged options once per mount so the effect's identity is
|
|
53
|
+
// stable (avoids re-installing the host on every render).
|
|
54
|
+
const optionsRef = useRef(null);
|
|
55
|
+
if (optionsRef.current === null) {
|
|
56
|
+
const urlOverlay = applyUrlToggles ? readMockHostUrlOptions() : {};
|
|
57
|
+
optionsRef.current = { ...options, ...urlOverlay };
|
|
58
|
+
}
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const host = createMockHost({
|
|
61
|
+
...optionsRef.current,
|
|
62
|
+
onOutbound: (msg) => {
|
|
63
|
+
optionsRef.current.onOutbound?.(msg);
|
|
64
|
+
if (msg.type === 'RESIZE_IFRAME')
|
|
65
|
+
return; // noise; skip the log
|
|
66
|
+
queueMicrotask(() => setOutbound((prev) => [...prev, msg]));
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
return host.install();
|
|
70
|
+
}, []);
|
|
71
|
+
const opts = optionsRef.current;
|
|
72
|
+
const anon = opts.viewer === null;
|
|
73
|
+
const theme = opts.theme ?? 'dark';
|
|
74
|
+
const consent = opts.consentGranted ? 'granted' : 'withheld';
|
|
75
|
+
return (_jsxs("div", { "data-harness": "true", style: { position: 'relative', width: '100vw', minHeight: '100dvh' }, children: [_jsx("main", { "data-harness-frame": "true", style: { width: '100%', minHeight: '100%' }, children: children }), showLog && (_jsxs("details", { style: harnessLogStyle, children: [_jsxs("summary", { style: { cursor: 'pointer' }, children: ["DEV HARNESS \u00B7 viewer=", anon ? 'anon' : 'dev-viewer', " \u00B7 consent=", consent, " \u00B7 theme=", theme, " \u00B7 outbound:", outbound.length] }), _jsx("pre", { style: { margin: 0, maxHeight: 200, overflow: 'auto' }, children: outbound.length === 0
|
|
76
|
+
? '// no outbound messages yet'
|
|
77
|
+
: outbound
|
|
78
|
+
.map((m, i) => `${i + 1}. ${m.type} ${JSON.stringify(m.payload ?? {})}`)
|
|
79
|
+
.join('\n') })] }))] }));
|
|
80
|
+
}
|
|
81
|
+
/** Alias of {@link Harness} — same component, clearer name when used as a context provider. */
|
|
82
|
+
export const MockHostProvider = Harness;
|
|
83
|
+
const harnessLogStyle = {
|
|
84
|
+
position: 'fixed',
|
|
85
|
+
bottom: 8,
|
|
86
|
+
right: 8,
|
|
87
|
+
zIndex: 9999,
|
|
88
|
+
maxWidth: 520,
|
|
89
|
+
background: 'rgba(17,17,17,0.92)',
|
|
90
|
+
color: '#7fc',
|
|
91
|
+
fontSize: 11,
|
|
92
|
+
fontFamily: 'ui-monospace, SFMono-Regular, monospace',
|
|
93
|
+
padding: '6px 10px',
|
|
94
|
+
borderRadius: 6,
|
|
95
|
+
};
|
|
16
96
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@civitai/blocks-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "React hooks and iframe transport for Civitai App Blocks. Pairs with @civitai/app-sdk/blocks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,21 +24,14 @@
|
|
|
24
24
|
"dist",
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsc -p tsconfig.json",
|
|
29
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
30
|
-
"test": "vitest run",
|
|
31
|
-
"test:watch": "vitest"
|
|
32
|
-
},
|
|
33
27
|
"engines": {
|
|
34
28
|
"node": ">=20"
|
|
35
29
|
},
|
|
36
30
|
"peerDependencies": {
|
|
37
|
-
"@civitai/app-sdk": ">=0.
|
|
31
|
+
"@civitai/app-sdk": ">=0.10.0",
|
|
38
32
|
"react": "^18.0.0 || ^19.0.0"
|
|
39
33
|
},
|
|
40
34
|
"devDependencies": {
|
|
41
|
-
"@civitai/app-sdk": "workspace:^",
|
|
42
35
|
"@testing-library/react": "^16.0.0",
|
|
43
36
|
"@types/node": "^25.9.1",
|
|
44
37
|
"@types/react": "^19.2.15",
|
|
@@ -46,7 +39,8 @@
|
|
|
46
39
|
"react": "^19.0.0",
|
|
47
40
|
"react-dom": "^19.0.0",
|
|
48
41
|
"typescript": "^5.9.2",
|
|
49
|
-
"vitest": "^4.1.7"
|
|
42
|
+
"vitest": "^4.1.7",
|
|
43
|
+
"@civitai/app-sdk": "^0.12.0"
|
|
50
44
|
},
|
|
51
45
|
"publishConfig": {
|
|
52
46
|
"access": "public"
|
|
@@ -65,5 +59,11 @@
|
|
|
65
59
|
"type": "git",
|
|
66
60
|
"url": "git+https://github.com/civitai/civitai-app-starters.git",
|
|
67
61
|
"directory": "packages/civitai-blocks-react"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsc -p tsconfig.json",
|
|
65
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
66
|
+
"test": "vitest run",
|
|
67
|
+
"test:watch": "vitest"
|
|
68
68
|
}
|
|
69
|
-
}
|
|
69
|
+
}
|