@civitai/blocks-react 0.31.0 → 0.32.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 +41 -0
- package/dist/hooks/useDirectLoad.d.ts +32 -0
- package/dist/hooks/useDirectLoad.d.ts.map +1 -0
- package/dist/hooks/useDirectLoad.js +64 -0
- package/dist/hooks/useDirectLoad.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/directLoad.d.ts +54 -0
- package/dist/internal/directLoad.d.ts.map +1 -0
- package/dist/internal/directLoad.js +76 -0
- package/dist/internal/directLoad.js.map +1 -0
- package/dist/ui/BlockGate.d.ts +79 -0
- package/dist/ui/BlockGate.d.ts.map +1 -0
- package/dist/ui/BlockGate.js +143 -0
- package/dist/ui/BlockGate.js.map +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +4 -0
- package/dist/ui/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -479,6 +479,47 @@ function MatureSection() {
|
|
|
479
479
|
}
|
|
480
480
|
```
|
|
481
481
|
|
|
482
|
+
## Direct-load fallback ("Open on Civitai")
|
|
483
|
+
|
|
484
|
+
A block is served from its own origin `<slug>.civit.ai` but is designed to run
|
|
485
|
+
**embedded** in the Civitai host iframe at `civitai.com/apps/run/<slug>`, which
|
|
486
|
+
delivers the runtime context via the `BLOCK_INIT` handshake. If someone opens the
|
|
487
|
+
bare `<slug>.civit.ai` URL **directly** (a shared link, a social crawl), no parent
|
|
488
|
+
ever sends `BLOCK_INIT`, so `ready` never flips and the block hangs on its loading
|
|
489
|
+
spinner forever.
|
|
490
|
+
|
|
491
|
+
Wrap your app root once in `<BlockGate>` (from `/ui`) to degrade that into a
|
|
492
|
+
branded landing instead:
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
import { BlockGate } from '@civitai/blocks-react/ui';
|
|
496
|
+
|
|
497
|
+
// A DIRECT (unembedded) top-level load shows an "Open on Civitai" card linking to
|
|
498
|
+
// civitai.com/apps/run/<slug>. Embedded — and the dev harness, which posts a fake
|
|
499
|
+
// BLOCK_INIT — are a transparent pass-through, so the happy path is unchanged.
|
|
500
|
+
createRoot(container).render(
|
|
501
|
+
<BlockGate>
|
|
502
|
+
<App />
|
|
503
|
+
</BlockGate>,
|
|
504
|
+
);
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
The trigger is precise: the fallback shows **only** when the block is top-level
|
|
508
|
+
(`window.self === window.top`) **and** no `BLOCK_INIT` arrives within a short
|
|
509
|
+
timeout (`~2s`, override with `<BlockGate timeoutMs={…}>`). Framed blocks never
|
|
510
|
+
trip it; the harness posts `BLOCK_INIT` immediately, so it never trips there
|
|
511
|
+
either. On a non-`*.civit.ai` host (e.g. `localhost` in dev), it shows a neutral
|
|
512
|
+
"waiting for the host" state — never a broken `apps/run/localhost` link.
|
|
513
|
+
|
|
514
|
+
Building your own landing? The primitives are exported from the package root:
|
|
515
|
+
|
|
516
|
+
```tsx
|
|
517
|
+
import { useDirectLoad, hostToRunUrl } from '@civitai/blocks-react';
|
|
518
|
+
|
|
519
|
+
const directLoad = useDirectLoad(); // true iff top-level AND no BLOCK_INIT within the timeout
|
|
520
|
+
const runUrl = hostToRunUrl('my-app.civit.ai'); // 'https://civitai.com/apps/run/my-app' | null (null = not a civit.ai host)
|
|
521
|
+
```
|
|
522
|
+
|
|
482
523
|
## The `/ui` subexport
|
|
483
524
|
|
|
484
525
|
Opinionated components, imported separately so a transport-only block stays lean.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface UseDirectLoadOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Milliseconds to wait for `BLOCK_INIT` before treating a top-level load as a
|
|
4
|
+
* direct (unembedded) load. Defaults to {@link DIRECT_LOAD_TIMEOUT_MS}.
|
|
5
|
+
*/
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Detect a DIRECT (unembedded) top-level load of a block and, after a short
|
|
10
|
+
* grace period, report it so the SDK can show an "Open on Civitai" fallback
|
|
11
|
+
* instead of hanging on the perpetual loading state.
|
|
12
|
+
*
|
|
13
|
+
* Returns `true` ONLY when BOTH hold:
|
|
14
|
+
* 1. The block is TOP-LEVEL (`window.self === window.top` — not in the host
|
|
15
|
+
* iframe), AND
|
|
16
|
+
* 2. No `BLOCK_INIT` has landed (`ready` is still `false`) within `timeoutMs`.
|
|
17
|
+
*
|
|
18
|
+
* This is precise by construction:
|
|
19
|
+
* - An EMBEDDED block (framed) is never top-level → always `false`, even before
|
|
20
|
+
* `ready`. The embedded happy path is untouched.
|
|
21
|
+
* - The dev harness / `createMockHost` runs the block top-level BUT posts
|
|
22
|
+
* `BLOCK_INIT` immediately (a `setTimeout(0)` macrotask), so `ready` flips
|
|
23
|
+
* long before `timeoutMs` and the timer is cleared → always `false`. The dev
|
|
24
|
+
* flow is untouched.
|
|
25
|
+
* - A real direct load (nobody sends `BLOCK_INIT`) stays top-level + not-ready
|
|
26
|
+
* past `timeoutMs` → `true`.
|
|
27
|
+
*
|
|
28
|
+
* Once `ready` flips it stays authoritative: this can never return `true` while
|
|
29
|
+
* `ready` is `true`, so a late init can't leave a stuck fallback.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useDirectLoad(options?: UseDirectLoadOptions): boolean;
|
|
32
|
+
//# sourceMappingURL=useDirectLoad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDirectLoad.d.ts","sourceRoot":"","sources":["../../src/hooks/useDirectLoad.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAerE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { DIRECT_LOAD_TIMEOUT_MS } from '../internal/directLoad.js';
|
|
3
|
+
import { useTransportSnapshot } from './useBlockContext.js';
|
|
4
|
+
/**
|
|
5
|
+
* True iff the current window is the TOP-LEVEL browsing context — i.e. the
|
|
6
|
+
* block is NOT running inside an iframe.
|
|
7
|
+
*
|
|
8
|
+
* Uses the `window.self === window.top` IDENTITY comparison, which is always
|
|
9
|
+
* safe: it never reads a property off a (potentially cross-origin) parent, so
|
|
10
|
+
* it cannot throw a SecurityError the way `window.top.location` would. When
|
|
11
|
+
* embedded in the civitai host, `window.top` is the host's top frame — a
|
|
12
|
+
* different object — so this is `false`; when loaded directly it is `true`.
|
|
13
|
+
*/
|
|
14
|
+
function isTopLevel() {
|
|
15
|
+
if (typeof window === 'undefined')
|
|
16
|
+
return false; // SSR / no DOM → not a direct browser load
|
|
17
|
+
try {
|
|
18
|
+
return window.self === window.top;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Defensive: if some exotic engine throws on the identity read, treat it as
|
|
22
|
+
// embedded (fail safe — never show the fallback to a genuinely-framed block).
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Detect a DIRECT (unembedded) top-level load of a block and, after a short
|
|
28
|
+
* grace period, report it so the SDK can show an "Open on Civitai" fallback
|
|
29
|
+
* instead of hanging on the perpetual loading state.
|
|
30
|
+
*
|
|
31
|
+
* Returns `true` ONLY when BOTH hold:
|
|
32
|
+
* 1. The block is TOP-LEVEL (`window.self === window.top` — not in the host
|
|
33
|
+
* iframe), AND
|
|
34
|
+
* 2. No `BLOCK_INIT` has landed (`ready` is still `false`) within `timeoutMs`.
|
|
35
|
+
*
|
|
36
|
+
* This is precise by construction:
|
|
37
|
+
* - An EMBEDDED block (framed) is never top-level → always `false`, even before
|
|
38
|
+
* `ready`. The embedded happy path is untouched.
|
|
39
|
+
* - The dev harness / `createMockHost` runs the block top-level BUT posts
|
|
40
|
+
* `BLOCK_INIT` immediately (a `setTimeout(0)` macrotask), so `ready` flips
|
|
41
|
+
* long before `timeoutMs` and the timer is cleared → always `false`. The dev
|
|
42
|
+
* flow is untouched.
|
|
43
|
+
* - A real direct load (nobody sends `BLOCK_INIT`) stays top-level + not-ready
|
|
44
|
+
* past `timeoutMs` → `true`.
|
|
45
|
+
*
|
|
46
|
+
* Once `ready` flips it stays authoritative: this can never return `true` while
|
|
47
|
+
* `ready` is `true`, so a late init can't leave a stuck fallback.
|
|
48
|
+
*/
|
|
49
|
+
export function useDirectLoad(options) {
|
|
50
|
+
const timeoutMs = options?.timeoutMs ?? DIRECT_LOAD_TIMEOUT_MS;
|
|
51
|
+
const ready = useTransportSnapshot().ready;
|
|
52
|
+
// Sampled once per mount — top-level-ness doesn't change during a page's life.
|
|
53
|
+
const [topLevel] = useState(isTopLevel);
|
|
54
|
+
const [elapsed, setElapsed] = useState(false);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
// No timer needed when embedded, or once BLOCK_INIT has already landed.
|
|
57
|
+
if (ready || !topLevel)
|
|
58
|
+
return;
|
|
59
|
+
const id = setTimeout(() => setElapsed(true), timeoutMs);
|
|
60
|
+
return () => clearTimeout(id);
|
|
61
|
+
}, [ready, topLevel, timeoutMs]);
|
|
62
|
+
return topLevel && !ready && elapsed;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=useDirectLoad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDirectLoad.js","sourceRoot":"","sources":["../../src/hooks/useDirectLoad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAU5D;;;;;;;;;GASG;AACH,SAAS,UAAU;IACjB,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC,CAAC,2CAA2C;IAC5F,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,8EAA8E;QAC9E,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,aAAa,CAAC,OAA8B;IAC1D,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,sBAAsB,CAAC;IAC/D,MAAM,KAAK,GAAG,oBAAoB,EAAE,CAAC,KAAK,CAAC;IAC3C,+EAA+E;IAC/E,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAU,UAAU,CAAC,CAAC;IACjD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE;QACb,wEAAwE;QACxE,IAAI,KAAK,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC/B,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;QACzD,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAEjC,OAAO,QAAQ,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC;AACvC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -52,6 +52,9 @@ export { useDomainMaturity } from './hooks/useDomainMaturity.js';
|
|
|
52
52
|
export type { DomainMaturity } from './hooks/useDomainMaturity.js';
|
|
53
53
|
export { SfwGate } from './hooks/SfwGate.js';
|
|
54
54
|
export type { SfwGateProps } from './hooks/SfwGate.js';
|
|
55
|
+
export { useDirectLoad } from './hooks/useDirectLoad.js';
|
|
56
|
+
export type { UseDirectLoadOptions } from './hooks/useDirectLoad.js';
|
|
57
|
+
export { hostToRunUrl, DIRECT_LOAD_TIMEOUT_MS } from './internal/directLoad.js';
|
|
55
58
|
export { useAppStorage } from './hooks/useAppStorage.js';
|
|
56
59
|
export type { AppStorageKeyEntry, AppStorageListResult, AppStorageQuota, UseAppStorage, } from './hooks/useAppStorage.js';
|
|
57
60
|
export { useSharedStorage } from './hooks/useSharedStorage.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
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,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,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,YAAY,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAChF,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,YAAY,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,8BAA8B,EAC9B,iBAAiB,EACjB,0BAA0B,EAC1B,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,GAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EACL,6BAA6B,EAC7B,2BAA2B,EAC3B,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AACtC,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,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,8 @@ export { useRequestConsent } from './hooks/useRequestConsent.js';
|
|
|
38
38
|
export { useBlockAnalytics } from './hooks/useBlockAnalytics.js';
|
|
39
39
|
export { useDomainMaturity } from './hooks/useDomainMaturity.js';
|
|
40
40
|
export { SfwGate } from './hooks/SfwGate.js';
|
|
41
|
+
export { useDirectLoad } from './hooks/useDirectLoad.js';
|
|
42
|
+
export { hostToRunUrl, DIRECT_LOAD_TIMEOUT_MS } from './internal/directLoad.js';
|
|
41
43
|
export { useAppStorage } from './hooks/useAppStorage.js';
|
|
42
44
|
export { useSharedStorage } from './hooks/useSharedStorage.js';
|
|
43
45
|
//# 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,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,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEhF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAErF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAa3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EACL,6BAA6B,EAC7B,2BAA2B,EAC3B,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AACtC,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;AAOzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,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,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,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEhF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAErF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAa3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EACL,6BAA6B,EAC7B,2BAA2B,EAC3B,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AACtC,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;AAEzD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAOzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct-load (unembedded) detection helpers.
|
|
3
|
+
*
|
|
4
|
+
* A block is served from its OWN origin `<slug>.civit.ai` but is designed to
|
|
5
|
+
* run EMBEDDED inside the civitai.com host iframe at
|
|
6
|
+
* `civitai.com/apps/run/<slug>`, which delivers the runtime context (viewer,
|
|
7
|
+
* scoped token, theme) via the postMessage `BLOCK_INIT` handshake. When a block
|
|
8
|
+
* is opened DIRECTLY — a top-level navigation to its bare `<slug>.civit.ai`
|
|
9
|
+
* origin (shared link, social crawl, someone pasting the URL) — no parent ever
|
|
10
|
+
* sends `BLOCK_INIT`, so the block's `ready` gate never flips and it hangs on a
|
|
11
|
+
* loading spinner forever. These helpers let the SDK degrade that into a
|
|
12
|
+
* branded "Open on Civitai" landing.
|
|
13
|
+
*
|
|
14
|
+
* Pure + framework-agnostic on purpose — {@link hostToRunUrl} is exhaustively
|
|
15
|
+
* unit-testable, and the React glue (the `useDirectLoad` hook + the
|
|
16
|
+
* `<BlockGate>` / `<DirectLoadFallback>` UI) builds on it.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Default milliseconds to wait for `BLOCK_INIT` before concluding a TOP-LEVEL
|
|
20
|
+
* load is a direct (unembedded) load and showing the fallback.
|
|
21
|
+
*
|
|
22
|
+
* Chosen well ABOVE the dev harness's init latency and below anything a human
|
|
23
|
+
* would tolerate staring at a spinner. The `createMockHost` / `<Harness>` dev
|
|
24
|
+
* host posts `BLOCK_INIT` on a `setTimeout(0)` macrotask (see
|
|
25
|
+
* `mockHost.ts` → `after(0, … BLOCK_INIT …)`), so `ready` flips almost
|
|
26
|
+
* immediately there and this timeout NEVER elapses in the harness — the
|
|
27
|
+
* fallback is reserved for the genuine "nobody is ever going to send
|
|
28
|
+
* BLOCK_INIT" case. Overridable via the hook/component `timeoutMs` prop.
|
|
29
|
+
*/
|
|
30
|
+
export declare const DIRECT_LOAD_TIMEOUT_MS = 2000;
|
|
31
|
+
/** The Civitai host that serves the embedded block run route. */
|
|
32
|
+
export declare const CIVITAI_HOST = "civitai.com";
|
|
33
|
+
/** The deployed-block origin suffix (`<slug>.civit.ai`). */
|
|
34
|
+
export declare const CIVIT_AI_SUFFIX = ".civit.ai";
|
|
35
|
+
/**
|
|
36
|
+
* Derive the canonical Civitai host route for a block served from a
|
|
37
|
+
* `<slug>.civit.ai` origin.
|
|
38
|
+
*
|
|
39
|
+
* - A deployed block host (`<slug>.civit.ai`) → `https://civitai.com/apps/run/<slug>`,
|
|
40
|
+
* where the slug is the FIRST DNS label of the hostname.
|
|
41
|
+
* - Anything else — `localhost` (dev without the harness), an IP, a bare
|
|
42
|
+
* `civit.ai`, or a non-civit.ai host — → `null`. The caller MUST NOT render a
|
|
43
|
+
* `civitai.com/apps/run/…` redirect in that case (there is no meaningful
|
|
44
|
+
* target — never a broken `apps/run/localhost` link); show a neutral
|
|
45
|
+
* "waiting for the host" state instead.
|
|
46
|
+
*
|
|
47
|
+
* Case-insensitive (hostnames are), tolerant of a trailing FQDN dot.
|
|
48
|
+
*
|
|
49
|
+
* @example hostToRunUrl('model-benchmarking.civit.ai') // 'https://civitai.com/apps/run/model-benchmarking'
|
|
50
|
+
* @example hostToRunUrl('localhost') // null
|
|
51
|
+
* @example hostToRunUrl('civit.ai') // null
|
|
52
|
+
*/
|
|
53
|
+
export declare function hostToRunUrl(hostname: string | null | undefined): string | null;
|
|
54
|
+
//# sourceMappingURL=directLoad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directLoad.d.ts","sourceRoot":"","sources":["../../src/internal/directLoad.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C,iEAAiE;AACjE,eAAO,MAAM,YAAY,gBAAgB,CAAC;AAE1C,4DAA4D;AAC5D,eAAO,MAAM,eAAe,cAAc,CAAC;AAK3C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAgB/E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct-load (unembedded) detection helpers.
|
|
3
|
+
*
|
|
4
|
+
* A block is served from its OWN origin `<slug>.civit.ai` but is designed to
|
|
5
|
+
* run EMBEDDED inside the civitai.com host iframe at
|
|
6
|
+
* `civitai.com/apps/run/<slug>`, which delivers the runtime context (viewer,
|
|
7
|
+
* scoped token, theme) via the postMessage `BLOCK_INIT` handshake. When a block
|
|
8
|
+
* is opened DIRECTLY — a top-level navigation to its bare `<slug>.civit.ai`
|
|
9
|
+
* origin (shared link, social crawl, someone pasting the URL) — no parent ever
|
|
10
|
+
* sends `BLOCK_INIT`, so the block's `ready` gate never flips and it hangs on a
|
|
11
|
+
* loading spinner forever. These helpers let the SDK degrade that into a
|
|
12
|
+
* branded "Open on Civitai" landing.
|
|
13
|
+
*
|
|
14
|
+
* Pure + framework-agnostic on purpose — {@link hostToRunUrl} is exhaustively
|
|
15
|
+
* unit-testable, and the React glue (the `useDirectLoad` hook + the
|
|
16
|
+
* `<BlockGate>` / `<DirectLoadFallback>` UI) builds on it.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Default milliseconds to wait for `BLOCK_INIT` before concluding a TOP-LEVEL
|
|
20
|
+
* load is a direct (unembedded) load and showing the fallback.
|
|
21
|
+
*
|
|
22
|
+
* Chosen well ABOVE the dev harness's init latency and below anything a human
|
|
23
|
+
* would tolerate staring at a spinner. The `createMockHost` / `<Harness>` dev
|
|
24
|
+
* host posts `BLOCK_INIT` on a `setTimeout(0)` macrotask (see
|
|
25
|
+
* `mockHost.ts` → `after(0, … BLOCK_INIT …)`), so `ready` flips almost
|
|
26
|
+
* immediately there and this timeout NEVER elapses in the harness — the
|
|
27
|
+
* fallback is reserved for the genuine "nobody is ever going to send
|
|
28
|
+
* BLOCK_INIT" case. Overridable via the hook/component `timeoutMs` prop.
|
|
29
|
+
*/
|
|
30
|
+
export const DIRECT_LOAD_TIMEOUT_MS = 2000;
|
|
31
|
+
/** The Civitai host that serves the embedded block run route. */
|
|
32
|
+
export const CIVITAI_HOST = 'civitai.com';
|
|
33
|
+
/** The deployed-block origin suffix (`<slug>.civit.ai`). */
|
|
34
|
+
export const CIVIT_AI_SUFFIX = '.civit.ai';
|
|
35
|
+
/** A single DNS label (the slug), lowercased. */
|
|
36
|
+
const DNS_LABEL = /^[a-z0-9-]+$/;
|
|
37
|
+
/**
|
|
38
|
+
* Derive the canonical Civitai host route for a block served from a
|
|
39
|
+
* `<slug>.civit.ai` origin.
|
|
40
|
+
*
|
|
41
|
+
* - A deployed block host (`<slug>.civit.ai`) → `https://civitai.com/apps/run/<slug>`,
|
|
42
|
+
* where the slug is the FIRST DNS label of the hostname.
|
|
43
|
+
* - Anything else — `localhost` (dev without the harness), an IP, a bare
|
|
44
|
+
* `civit.ai`, or a non-civit.ai host — → `null`. The caller MUST NOT render a
|
|
45
|
+
* `civitai.com/apps/run/…` redirect in that case (there is no meaningful
|
|
46
|
+
* target — never a broken `apps/run/localhost` link); show a neutral
|
|
47
|
+
* "waiting for the host" state instead.
|
|
48
|
+
*
|
|
49
|
+
* Case-insensitive (hostnames are), tolerant of a trailing FQDN dot.
|
|
50
|
+
*
|
|
51
|
+
* @example hostToRunUrl('model-benchmarking.civit.ai') // 'https://civitai.com/apps/run/model-benchmarking'
|
|
52
|
+
* @example hostToRunUrl('localhost') // null
|
|
53
|
+
* @example hostToRunUrl('civit.ai') // null
|
|
54
|
+
*/
|
|
55
|
+
export function hostToRunUrl(hostname) {
|
|
56
|
+
if (!hostname)
|
|
57
|
+
return null;
|
|
58
|
+
// Normalize: trim, lowercase, strip any trailing FQDN dot(s). The trailing-dot
|
|
59
|
+
// strip is a manual linear trim rather than a `/\.+$/` regex, which backtracks
|
|
60
|
+
// O(n^2) on a string of many dots (ReDoS — CodeQL js/polynomial-redos).
|
|
61
|
+
const normalized = hostname.trim().toLowerCase();
|
|
62
|
+
let end = normalized.length;
|
|
63
|
+
while (end > 0 && normalized.charCodeAt(end - 1) === 46 /* '.' */)
|
|
64
|
+
end -= 1;
|
|
65
|
+
const host = normalized.slice(0, end);
|
|
66
|
+
if (!host.endsWith(CIVIT_AI_SUFFIX))
|
|
67
|
+
return null; // not a deployed block host
|
|
68
|
+
// The slug is the FIRST DNS label (`<slug>.civit.ai`). Extra labels beyond
|
|
69
|
+
// the first are ignored — deployed block origins are single-label — but the
|
|
70
|
+
// first label must be a valid, non-empty DNS label.
|
|
71
|
+
const slug = host.slice(0, host.length - CIVIT_AI_SUFFIX.length).split('.')[0] ?? '';
|
|
72
|
+
if (!slug || !DNS_LABEL.test(slug))
|
|
73
|
+
return null;
|
|
74
|
+
return `https://${CIVITAI_HOST}/apps/run/${slug}`;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=directLoad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directLoad.js","sourceRoot":"","sources":["../../src/internal/directLoad.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAE3C,iEAAiE;AACjE,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAC;AAE1C,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAE3C,iDAAiD;AACjD,MAAM,SAAS,GAAG,cAAc,CAAC;AAEjC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,YAAY,CAAC,QAAmC;IAC9D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,+EAA+E;IAC/E,+EAA+E;IAC/E,wEAAwE;IACxE,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjD,IAAI,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC;IAC5B,OAAO,GAAG,GAAG,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,SAAS;QAAE,GAAG,IAAI,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,4BAA4B;IAC9E,2EAA2E;IAC3E,4EAA4E;IAC5E,oDAAoD;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrF,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,WAAW,YAAY,aAAa,IAAI,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for {@link DirectLoadFallback}.
|
|
4
|
+
*/
|
|
5
|
+
export interface DirectLoadFallbackProps {
|
|
6
|
+
/**
|
|
7
|
+
* Override the hostname used to derive the `civitai.com/apps/run/<slug>` URL.
|
|
8
|
+
* Defaults to `window.location.hostname`. Primarily a testing seam.
|
|
9
|
+
*/
|
|
10
|
+
hostname?: string;
|
|
11
|
+
/**
|
|
12
|
+
* When set (and a run URL could be derived), auto-navigate the top window to
|
|
13
|
+
* the run URL after this many milliseconds. OFF by default — a click-to-open
|
|
14
|
+
* landing is the safe default (no surprise navigation; good for shared links,
|
|
15
|
+
* social unfurls, and SEO). The visible button is always the primary path.
|
|
16
|
+
*/
|
|
17
|
+
autoRedirectMs?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The branded "Open on Civitai" landing shown when a block is loaded DIRECTLY
|
|
21
|
+
* (top-level at its bare `<slug>.civit.ai` origin) instead of embedded in the
|
|
22
|
+
* civitai host — the graceful degrade for what would otherwise be a perpetual
|
|
23
|
+
* loading spinner.
|
|
24
|
+
*
|
|
25
|
+
* Two states, chosen from the (overridable) hostname:
|
|
26
|
+
* - Deployed block host (`<slug>.civit.ai`): a card with an "Open on Civitai"
|
|
27
|
+
* link to `https://civitai.com/apps/run/<slug>` (a real anchor — right/middle
|
|
28
|
+
* click, shareable, crawlable). Optional {@link DirectLoadFallbackProps.autoRedirectMs}
|
|
29
|
+
* auto-redirect on top of the button.
|
|
30
|
+
* - Non-civit.ai host (e.g. `localhost` in dev without the harness): a neutral
|
|
31
|
+
* "waiting for the Civitai host" card with a dev hint — NEVER a broken
|
|
32
|
+
* `apps/run/localhost` link.
|
|
33
|
+
*
|
|
34
|
+
* Theme-aware via `prefers-color-scheme` (there is no host `theme` on a direct
|
|
35
|
+
* load) and styled with the `/ui` pack's tokens.
|
|
36
|
+
*/
|
|
37
|
+
export declare function DirectLoadFallback({ hostname, autoRedirectMs, }: DirectLoadFallbackProps): React.JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* Props for {@link BlockGate}.
|
|
40
|
+
*/
|
|
41
|
+
export interface BlockGateProps {
|
|
42
|
+
/** The block app. Rendered whenever the block is NOT a direct (unembedded) load. */
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
/**
|
|
45
|
+
* Milliseconds to wait for `BLOCK_INIT` before treating a top-level load as a
|
|
46
|
+
* direct load. Forwarded to {@link useDirectLoad}. Defaults to 2000ms.
|
|
47
|
+
*/
|
|
48
|
+
timeoutMs?: number;
|
|
49
|
+
/** Override the fallback rendered on a direct load. Defaults to {@link DirectLoadFallback}. */
|
|
50
|
+
fallback?: ReactNode;
|
|
51
|
+
/** Forwarded to the default {@link DirectLoadFallback} (testing seam). */
|
|
52
|
+
hostname?: string;
|
|
53
|
+
/** Forwarded to the default {@link DirectLoadFallback}. */
|
|
54
|
+
autoRedirectMs?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Drop-in wrapper that shows the {@link DirectLoadFallback} when a block is
|
|
58
|
+
* loaded DIRECTLY (top-level, no `BLOCK_INIT` within the timeout) and otherwise
|
|
59
|
+
* renders `children` unchanged.
|
|
60
|
+
*
|
|
61
|
+
* Wrap your app root once so EVERY SDK-built block degrades gracefully instead
|
|
62
|
+
* of hanging on a loading spinner when its `<slug>.civit.ai` URL is opened
|
|
63
|
+
* directly:
|
|
64
|
+
*
|
|
65
|
+
* ```tsx
|
|
66
|
+
* import { BlockGate } from '@civitai/blocks-react/ui';
|
|
67
|
+
*
|
|
68
|
+
* createRoot(el).render(
|
|
69
|
+
* <BlockGate>
|
|
70
|
+
* <App />
|
|
71
|
+
* </BlockGate>,
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* The embedded happy path and the dev harness are untouched — see
|
|
76
|
+
* {@link useDirectLoad} for exactly why the trigger can't fire in either.
|
|
77
|
+
*/
|
|
78
|
+
export declare function BlockGate({ children, timeoutMs, fallback, hostname, autoRedirectMs, }: BlockGateProps): React.JSX.Element;
|
|
79
|
+
//# sourceMappingURL=BlockGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockGate.d.ts","sourceRoot":"","sources":["../../src/ui/BlockGate.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAkD5D;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA8BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,cAAc,GACf,EAAE,uBAAuB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA+D7C;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,cAAc,GACf,EAAE,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAQpC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { hostToRunUrl } from '../internal/directLoad.js';
|
|
4
|
+
import { useDirectLoad } from '../hooks/useDirectLoad.js';
|
|
5
|
+
import { Card } from './Card.js';
|
|
6
|
+
import { Stack } from './Stack.js';
|
|
7
|
+
import { useBlocksStyles } from './styles.js';
|
|
8
|
+
/**
|
|
9
|
+
* Read the OS/browser color-scheme preference, live.
|
|
10
|
+
*
|
|
11
|
+
* A directly-loaded block has NO `BLOCK_INIT`, so there is no host `theme` to
|
|
12
|
+
* set `data-theme` from (the usual gotcha-#60 path). We fall back to
|
|
13
|
+
* `prefers-color-scheme` so the fallback card still themes correctly in light
|
|
14
|
+
* AND dark. Guarded for SSR / engines without `matchMedia`.
|
|
15
|
+
*/
|
|
16
|
+
function usePrefersColorScheme() {
|
|
17
|
+
const [dark, setDark] = useState(() => {
|
|
18
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function')
|
|
19
|
+
return false;
|
|
20
|
+
try {
|
|
21
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function')
|
|
29
|
+
return;
|
|
30
|
+
let mql;
|
|
31
|
+
try {
|
|
32
|
+
mql = window.matchMedia('(prefers-color-scheme: dark)');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const onChange = (e) => setDark(e.matches);
|
|
38
|
+
// Modern browsers: addEventListener. Older Safari: addListener.
|
|
39
|
+
if (typeof mql.addEventListener === 'function') {
|
|
40
|
+
mql.addEventListener('change', onChange);
|
|
41
|
+
return () => mql.removeEventListener('change', onChange);
|
|
42
|
+
}
|
|
43
|
+
if (typeof mql.addListener === 'function') {
|
|
44
|
+
mql.addListener(onChange);
|
|
45
|
+
return () => mql.removeListener(onChange);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}, []);
|
|
49
|
+
return dark ? 'dark' : 'light';
|
|
50
|
+
}
|
|
51
|
+
const wrapperStyle = {
|
|
52
|
+
minHeight: '100%',
|
|
53
|
+
minWidth: 0,
|
|
54
|
+
display: 'flex',
|
|
55
|
+
alignItems: 'center',
|
|
56
|
+
justifyContent: 'center',
|
|
57
|
+
padding: 24,
|
|
58
|
+
boxSizing: 'border-box',
|
|
59
|
+
background: 'var(--ci-color-surface-2)',
|
|
60
|
+
color: 'var(--ci-color-text)',
|
|
61
|
+
};
|
|
62
|
+
const brandStyle = {
|
|
63
|
+
fontSize: 12,
|
|
64
|
+
fontWeight: 700,
|
|
65
|
+
letterSpacing: '0.08em',
|
|
66
|
+
textTransform: 'uppercase',
|
|
67
|
+
color: 'var(--ci-color-primary)',
|
|
68
|
+
};
|
|
69
|
+
const titleStyle = { fontSize: 18, fontWeight: 700 };
|
|
70
|
+
const bodyStyle = {
|
|
71
|
+
fontSize: 14,
|
|
72
|
+
lineHeight: 1.5,
|
|
73
|
+
color: 'var(--ci-color-text-dimmed)',
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* The branded "Open on Civitai" landing shown when a block is loaded DIRECTLY
|
|
77
|
+
* (top-level at its bare `<slug>.civit.ai` origin) instead of embedded in the
|
|
78
|
+
* civitai host — the graceful degrade for what would otherwise be a perpetual
|
|
79
|
+
* loading spinner.
|
|
80
|
+
*
|
|
81
|
+
* Two states, chosen from the (overridable) hostname:
|
|
82
|
+
* - Deployed block host (`<slug>.civit.ai`): a card with an "Open on Civitai"
|
|
83
|
+
* link to `https://civitai.com/apps/run/<slug>` (a real anchor — right/middle
|
|
84
|
+
* click, shareable, crawlable). Optional {@link DirectLoadFallbackProps.autoRedirectMs}
|
|
85
|
+
* auto-redirect on top of the button.
|
|
86
|
+
* - Non-civit.ai host (e.g. `localhost` in dev without the harness): a neutral
|
|
87
|
+
* "waiting for the Civitai host" card with a dev hint — NEVER a broken
|
|
88
|
+
* `apps/run/localhost` link.
|
|
89
|
+
*
|
|
90
|
+
* Theme-aware via `prefers-color-scheme` (there is no host `theme` on a direct
|
|
91
|
+
* load) and styled with the `/ui` pack's tokens.
|
|
92
|
+
*/
|
|
93
|
+
export function DirectLoadFallback({ hostname, autoRedirectMs, }) {
|
|
94
|
+
useBlocksStyles();
|
|
95
|
+
const theme = usePrefersColorScheme();
|
|
96
|
+
const resolvedHost = hostname ?? (typeof window !== 'undefined' ? window.location?.hostname : undefined);
|
|
97
|
+
const runUrl = hostToRunUrl(resolvedHost);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (!runUrl || autoRedirectMs == null || typeof window === 'undefined')
|
|
100
|
+
return;
|
|
101
|
+
const id = setTimeout(() => {
|
|
102
|
+
try {
|
|
103
|
+
// Navigate the TOP frame (equals self on a direct load; correct either way).
|
|
104
|
+
(window.top ?? window).location.href = runUrl;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
window.location.href = runUrl;
|
|
108
|
+
}
|
|
109
|
+
}, autoRedirectMs);
|
|
110
|
+
return () => clearTimeout(id);
|
|
111
|
+
}, [runUrl, autoRedirectMs]);
|
|
112
|
+
return (_jsx("div", { "data-theme": theme, "data-civitai-block-direct-load": "true", style: wrapperStyle, children: _jsx(Card, { withBorder: true, padding: "lg", style: { maxWidth: 420, width: '100%', textAlign: 'center' }, children: _jsxs(Stack, { gap: 12, align: "center", children: [_jsx("span", { style: brandStyle, children: "Civitai App" }), runUrl ? (_jsxs(_Fragment, { children: [_jsx("strong", { style: titleStyle, children: "Open this app on Civitai" }), _jsx("span", { style: bodyStyle, children: "This is a Civitai App. It runs inside Civitai, where you can sign in and use it." }), _jsx("a", { "data-civitai-ui": "button", "data-variant": "filled", "data-size": "lg", "data-full-width": "true", "data-civitai-block-open-on-civitai": "true", href: runUrl, target: "_top", rel: "noopener", children: "Open on Civitai" })] })) : (_jsxs(_Fragment, { children: [_jsx("strong", { style: titleStyle, children: "Waiting for the Civitai host\u2026" }), _jsx("span", { style: bodyStyle, role: "status", children: "This is a Civitai App. It\u2019s meant to run inside the Civitai host. In local development, load it through the block dev harness." })] }))] }) }) }));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Drop-in wrapper that shows the {@link DirectLoadFallback} when a block is
|
|
116
|
+
* loaded DIRECTLY (top-level, no `BLOCK_INIT` within the timeout) and otherwise
|
|
117
|
+
* renders `children` unchanged.
|
|
118
|
+
*
|
|
119
|
+
* Wrap your app root once so EVERY SDK-built block degrades gracefully instead
|
|
120
|
+
* of hanging on a loading spinner when its `<slug>.civit.ai` URL is opened
|
|
121
|
+
* directly:
|
|
122
|
+
*
|
|
123
|
+
* ```tsx
|
|
124
|
+
* import { BlockGate } from '@civitai/blocks-react/ui';
|
|
125
|
+
*
|
|
126
|
+
* createRoot(el).render(
|
|
127
|
+
* <BlockGate>
|
|
128
|
+
* <App />
|
|
129
|
+
* </BlockGate>,
|
|
130
|
+
* );
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* The embedded happy path and the dev harness are untouched — see
|
|
134
|
+
* {@link useDirectLoad} for exactly why the trigger can't fire in either.
|
|
135
|
+
*/
|
|
136
|
+
export function BlockGate({ children, timeoutMs, fallback, hostname, autoRedirectMs, }) {
|
|
137
|
+
const directLoad = useDirectLoad({ timeoutMs });
|
|
138
|
+
if (directLoad) {
|
|
139
|
+
return (_jsx(_Fragment, { children: fallback ?? _jsx(DirectLoadFallback, { hostname: hostname, autoRedirectMs: autoRedirectMs }) }));
|
|
140
|
+
}
|
|
141
|
+
return _jsx(_Fragment, { children: children });
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=BlockGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockGate.js","sourceRoot":"","sources":["../../src/ui/BlockGate.tsx"],"names":[],"mappings":"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"}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
export { SettingsForm, SettingsFormError, isFieldVisible } from './SettingsForm.js';
|
|
19
19
|
export type { SettingsFormProps } from './SettingsForm.js';
|
|
20
|
+
export { BlockGate, DirectLoadFallback } from './BlockGate.js';
|
|
21
|
+
export type { BlockGateProps, DirectLoadFallbackProps } from './BlockGate.js';
|
|
20
22
|
export { injectBlocksStyles, useBlocksStyles, BLOCKS_UI_STYLES, } from './styles.js';
|
|
21
23
|
export { Button } from './Button.js';
|
|
22
24
|
export type { ButtonProps, ButtonVariant, ButtonSize } from './Button.js';
|
package/dist/ui/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpF,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpF,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAK3D,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9E,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC"}
|
package/dist/ui/index.js
CHANGED
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
*/
|
|
18
18
|
// W3 — manifest-driven settings form (host-themed native controls).
|
|
19
19
|
export { SettingsForm, SettingsFormError, isFieldVisible } from './SettingsForm.js';
|
|
20
|
+
// Direct-load (unembedded) fallback — the branded "Open on Civitai" landing
|
|
21
|
+
// that replaces the perpetual loading spinner when a block's <slug>.civit.ai
|
|
22
|
+
// URL is opened top-level instead of embedded in the Civitai host.
|
|
23
|
+
export { BlockGate, DirectLoadFallback } from './BlockGate.js';
|
|
20
24
|
// W6 — runtime style injection.
|
|
21
25
|
export { injectBlocksStyles, useBlocksStyles, BLOCKS_UI_STYLES, } from './styles.js';
|
|
22
26
|
// W6 — component pack.
|
package/dist/ui/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGpF,gCAAgC;AAChC,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,uBAAuB;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGpF,4EAA4E;AAC5E,6EAA6E;AAC7E,mEAAmE;AACnE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG/D,gCAAgC;AAChC,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,uBAAuB;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@civitai/blocks-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "React hooks and iframe transport for Civitai Apps. Pairs with @civitai/app-sdk/blocks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"react-dom": "^19.0.0",
|
|
44
44
|
"typescript": "^5.9.2",
|
|
45
45
|
"vitest": "^4.1.7",
|
|
46
|
-
"@civitai/app-sdk": "^0.25.
|
|
46
|
+
"@civitai/app-sdk": "^0.25.1"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|