@civitai/blocks-react 0.24.0 → 0.26.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 +70 -0
- package/dist/hooks/useBuzzAccounts.d.ts +39 -0
- package/dist/hooks/useBuzzAccounts.d.ts.map +1 -0
- package/dist/hooks/useBuzzAccounts.js +57 -0
- package/dist/hooks/useBuzzAccounts.js.map +1 -0
- package/dist/hooks/useBuzzTransactions.d.ts +52 -0
- package/dist/hooks/useBuzzTransactions.d.ts.map +1 -0
- package/dist/hooks/useBuzzTransactions.js +77 -0
- package/dist/hooks/useBuzzTransactions.js.map +1 -0
- package/dist/hooks/useDailyCompensation.d.ts +44 -0
- package/dist/hooks/useDailyCompensation.d.ts.map +1 -0
- package/dist/hooks/useDailyCompensation.js +62 -0
- package/dist/hooks/useDailyCompensation.js.map +1 -0
- package/dist/hooks/useViewer.d.ts +45 -0
- package/dist/hooks/useViewer.d.ts.map +1 -0
- package/dist/hooks/useViewer.js +70 -0
- package/dist/hooks/useViewer.js.map +1 -0
- package/dist/hooks/useWildcardPack.d.ts +49 -0
- package/dist/hooks/useWildcardPack.d.ts.map +1 -0
- package/dist/hooks/useWildcardPack.js +81 -0
- package/dist/hooks/useWildcardPack.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/liveHost.d.ts.map +1 -1
- package/dist/internal/liveHost.js +84 -0
- package/dist/internal/liveHost.js.map +1 -1
- package/dist/internal/mockHost.d.ts +66 -2
- package/dist/internal/mockHost.d.ts.map +1 -1
- package/dist/internal/mockHost.js +246 -0
- package/dist/internal/mockHost.js.map +1 -1
- package/dist/internal/validate.d.ts +53 -0
- package/dist/internal/validate.d.ts.map +1 -1
- package/dist/internal/validate.js +215 -0
- package/dist/internal/validate.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -223,6 +223,76 @@ if (!loading && balance) console.log(`Yellow: ${balance.yellow}`);
|
|
|
223
223
|
> `body.accountType` (`'blue' | 'green' | 'yellow'`) — a *preference* for which
|
|
224
224
|
> pool funds the generation; the host clamps it server-side.
|
|
225
225
|
|
|
226
|
+
### `useViewer()`
|
|
227
|
+
|
|
228
|
+
The signed-in viewer as an on-demand authoritative self-read (`{ id, username,
|
|
229
|
+
status, buzzBudget }`) — distinct from `useBlockContext().viewer`, the coarse
|
|
230
|
+
`BLOCK_INIT`-time snapshot. `status` is `'active' | 'muted'`; `username`
|
|
231
|
+
(`string | null`) and `buzzBudget` (`number | null`) are present-but-nullable, so
|
|
232
|
+
handle the null case. Host-mediated over `GET_VIEWER` → `VIEWER_RESULT` (the host
|
|
233
|
+
resolves the viewer from the block token via `blocks.getMyViewer`); an anonymous /
|
|
234
|
+
banned viewer comes back as `error`. Fetches on mount; `refetch` for on-demand
|
|
235
|
+
refreshes.
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
const { viewer, loading, error, refetch } = useViewer();
|
|
239
|
+
// `viewer` is null until the first successful fetch. An anon / banned viewer,
|
|
240
|
+
// missing scope, or host failure → `error`. `username`/`buzzBudget` may be null.
|
|
241
|
+
if (!loading && viewer) console.log(`${viewer.username ?? 'anon'} · budget ${viewer.buzzBudget ?? 0}`);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### `useBuzzTransactions(params?)`
|
|
245
|
+
|
|
246
|
+
The signed-in viewer's Buzz-transaction ledger (a paged, host-projected read of
|
|
247
|
+
the Buzz dashboard). Returns `{ transactions, cursor, loading, error, refetch }`;
|
|
248
|
+
`transactions` rows are rehydrated so `date` is a `Date`. Pass the returned
|
|
249
|
+
`cursor` back as `params.cursor` to page forward. Requires the `buzz:read:self`
|
|
250
|
+
scope; host-mediated over `GET_BUZZ_TRANSACTIONS`.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
const { transactions, cursor, loading, error } = useBuzzTransactions({ type: 'Tip', limit: 20 });
|
|
254
|
+
if (!loading && transactions) transactions.forEach((t) => console.log(t.type, t.amount, t.date));
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### `useBuzzAccounts()`
|
|
258
|
+
|
|
259
|
+
The viewer's all-pool Buzz balances — the three spendable pools **plus** the
|
|
260
|
+
creator payout pools (`{ accountType, balance }[]`), a superset of
|
|
261
|
+
`useBuzzBalance`. Returns `{ accounts, loading, error, refetch }`. Requires
|
|
262
|
+
`buzz:read:self`; host-mediated over `GET_BUZZ_ACCOUNTS`.
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
const { accounts, loading, error } = useBuzzAccounts();
|
|
266
|
+
if (!loading && accounts) accounts.forEach((a) => console.log(a.accountType, a.balance));
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### `useDailyCompensation(params)`
|
|
270
|
+
|
|
271
|
+
Per-modelVersion generation-compensation for the month containing `params.date`
|
|
272
|
+
(Buzz totals + cash totals in pennies). Returns `{ resources,
|
|
273
|
+
hasPublishedResources, loading, error, refetch }`. Requires `buzz:read:self`;
|
|
274
|
+
host-mediated over `GET_DAILY_COMPENSATION`.
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
const { resources, hasPublishedResources } = useDailyCompensation({ date: '2026-07-01' });
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### `useWildcardPack(modelVersionId)`
|
|
281
|
+
|
|
282
|
+
Import a wildcard pack's parsed prompt lists by model version — the host
|
|
283
|
+
resolves + fetches + unzips + parses it **in the user's own page session** (every
|
|
284
|
+
download gate enforced), so the untrusted iframe never sees the bytes. Returns
|
|
285
|
+
`{ pack, loading, error, refetch }`. On failure `error` is a `WildcardPackError`
|
|
286
|
+
with a discriminated `code` (`not-found` / `forbidden` / `too-large` /
|
|
287
|
+
`parse-failed` / `busy` — `busy` is retryable), not free text.
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
const { pack, loading, error, refetch } = useWildcardPack(modelVersionId);
|
|
291
|
+
// `error.code === 'busy'` is retryable — call refetch(); the other codes are terminal.
|
|
292
|
+
if (error instanceof WildcardPackError && error.code === 'busy') void refetch();
|
|
293
|
+
if (!loading && pack) console.log(Object.keys(pack.lists));
|
|
294
|
+
```
|
|
295
|
+
|
|
226
296
|
### `useAppStorage()`
|
|
227
297
|
|
|
228
298
|
Per-(block instance, viewer) KV datastore, host-mediated. 64 KB per value,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BlockBuzzAccount } from '@civitai/app-sdk/blocks';
|
|
2
|
+
/**
|
|
3
|
+
* What {@link useBuzzAccounts} returns.
|
|
4
|
+
*/
|
|
5
|
+
export interface UseBuzzAccounts {
|
|
6
|
+
/**
|
|
7
|
+
* The viewer's all-pool balances — the three spendable pools PLUS the creator
|
|
8
|
+
* payout pools (`creatorProgramBank`, `cashSettled`, …) the spendable-only
|
|
9
|
+
* {@link useBuzzBalance} omits. `null` until the first successful fetch.
|
|
10
|
+
*/
|
|
11
|
+
accounts: BlockBuzzAccount[] | null;
|
|
12
|
+
/** `true` while a fetch (initial or `refetch`) is in flight. */
|
|
13
|
+
loading: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The last fetch's failure — a host-reported error (anon viewer / missing
|
|
16
|
+
* `buzz:read:self` scope / host failure) or the transport timeout. Free-text.
|
|
17
|
+
* Cleared at the start of the next fetch.
|
|
18
|
+
*/
|
|
19
|
+
error: Error | null;
|
|
20
|
+
/** Re-request the balances. */
|
|
21
|
+
refetch: () => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read the signed-in viewer's ALL-pool Buzz balances through the host-mediated
|
|
25
|
+
* `GET_BUZZ_ACCOUNTS` → `BUZZ_ACCOUNTS_RESULT` bridge. Token-bound: the host
|
|
26
|
+
* self-binds off the block token and reads via its `blocks.getMyBuzzAccounts`
|
|
27
|
+
* mutation (scope `buzz:read:self`). Unlike {@link useBuzzBalance} (the three
|
|
28
|
+
* spendable pools), this returns every pool in the block API's set — including
|
|
29
|
+
* the creator payout pools — as `{ accountType, balance }` rows.
|
|
30
|
+
*
|
|
31
|
+
* Fetches once on mount and exposes `refetch`. A host that never answers surfaces
|
|
32
|
+
* as an `error` after the transport timeout; late post-unmount responses are
|
|
33
|
+
* ignored.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const { accounts, loading, error } = useBuzzAccounts();
|
|
37
|
+
*/
|
|
38
|
+
export declare function useBuzzAccounts(): UseBuzzAccounts;
|
|
39
|
+
//# sourceMappingURL=useBuzzAccounts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBuzzAccounts.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuzzAccounts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAKhE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACpC,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,IAAI,eAAe,CA2CjD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { getTransport } from '../internal/singleton.js';
|
|
3
|
+
import { sendTypedRequest } from '../internal/transport.js';
|
|
4
|
+
/**
|
|
5
|
+
* Read the signed-in viewer's ALL-pool Buzz balances through the host-mediated
|
|
6
|
+
* `GET_BUZZ_ACCOUNTS` → `BUZZ_ACCOUNTS_RESULT` bridge. Token-bound: the host
|
|
7
|
+
* self-binds off the block token and reads via its `blocks.getMyBuzzAccounts`
|
|
8
|
+
* mutation (scope `buzz:read:self`). Unlike {@link useBuzzBalance} (the three
|
|
9
|
+
* spendable pools), this returns every pool in the block API's set — including
|
|
10
|
+
* the creator payout pools — as `{ accountType, balance }` rows.
|
|
11
|
+
*
|
|
12
|
+
* Fetches once on mount and exposes `refetch`. A host that never answers surfaces
|
|
13
|
+
* as an `error` after the transport timeout; late post-unmount responses are
|
|
14
|
+
* ignored.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const { accounts, loading, error } = useBuzzAccounts();
|
|
18
|
+
*/
|
|
19
|
+
export function useBuzzAccounts() {
|
|
20
|
+
const [accounts, setAccounts] = useState(null);
|
|
21
|
+
const [loading, setLoading] = useState(true);
|
|
22
|
+
const [error, setError] = useState(null);
|
|
23
|
+
const mountedRef = useRef(true);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
mountedRef.current = true;
|
|
26
|
+
return () => {
|
|
27
|
+
mountedRef.current = false;
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
const refetch = useCallback(() => {
|
|
31
|
+
setLoading(true);
|
|
32
|
+
setError(null);
|
|
33
|
+
sendTypedRequest(getTransport(), { type: 'GET_BUZZ_ACCOUNTS', payload: {} }, 'BUZZ_ACCOUNTS_RESULT')
|
|
34
|
+
.then((result) => {
|
|
35
|
+
if (!mountedRef.current)
|
|
36
|
+
return;
|
|
37
|
+
if (result.error || !result.result) {
|
|
38
|
+
setError(new Error(result.error ?? 'failed to fetch buzz accounts'));
|
|
39
|
+
setLoading(false);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
setAccounts(result.result.accounts);
|
|
43
|
+
setLoading(false);
|
|
44
|
+
})
|
|
45
|
+
.catch((err) => {
|
|
46
|
+
if (!mountedRef.current)
|
|
47
|
+
return;
|
|
48
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
49
|
+
setLoading(false);
|
|
50
|
+
});
|
|
51
|
+
}, []);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
refetch();
|
|
54
|
+
}, [refetch]);
|
|
55
|
+
return { accounts, loading, error, refetch };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=useBuzzAccounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBuzzAccounts.js","sourceRoot":"","sources":["../../src/hooks/useBuzzAccounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAIjE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAwB5D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAA4B,IAAI,CAAC,CAAC;IAC1E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,gBAAgB,CACd,YAAY,EAAE,EACd,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,EAC1C,sBAAsB,CACvB;aACE,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO;YAChC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnC,QAAQ,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,+BAA+B,CAAC,CAAC,CAAC;gBACrE,UAAU,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACpC,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO;YAChC,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9D,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,EAAE,CAAC;IACZ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { BlockBuzzTransaction, BlockBuzzTransactionsParams } from '@civitai/app-sdk/blocks';
|
|
2
|
+
/**
|
|
3
|
+
* One Buzz-transaction row, REHYDRATED for block consumption: identical to the
|
|
4
|
+
* wire {@link BlockBuzzTransaction} except `date` is a `Date` (rehydrated from
|
|
5
|
+
* the ISO string / `Date` the host sends — see the DATE WIRE CAVEAT on
|
|
6
|
+
* `BlockBuzzTransaction`).
|
|
7
|
+
*/
|
|
8
|
+
export interface BuzzTransaction extends Omit<BlockBuzzTransaction, 'date'> {
|
|
9
|
+
date: Date;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* What {@link useBuzzTransactions} returns.
|
|
13
|
+
*/
|
|
14
|
+
export interface UseBuzzTransactions {
|
|
15
|
+
/** The current page's rows (newest-first), or `null` until the first successful fetch. */
|
|
16
|
+
transactions: BuzzTransaction[] | null;
|
|
17
|
+
/**
|
|
18
|
+
* The next-page cursor (ISO-8601), or `null` when there's no further page.
|
|
19
|
+
* Pass it back as `params.cursor` on a subsequent call to page forward.
|
|
20
|
+
*/
|
|
21
|
+
cursor: string | null;
|
|
22
|
+
/** `true` while a fetch (initial or `refetch`) is in flight. */
|
|
23
|
+
loading: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The last fetch's failure — a host-reported error (anon viewer / missing
|
|
26
|
+
* `buzz:read:self` scope / host failure) or the transport timeout. Free-text
|
|
27
|
+
* (the buzz bridge does not use a discriminated error enum). Cleared at the
|
|
28
|
+
* start of the next fetch.
|
|
29
|
+
*/
|
|
30
|
+
error: Error | null;
|
|
31
|
+
/** Re-request the current page. */
|
|
32
|
+
refetch: () => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Read the signed-in viewer's Buzz-transaction ledger through the host-mediated
|
|
36
|
+
* `GET_BUZZ_TRANSACTIONS` → `BUZZ_TRANSACTIONS_RESULT` bridge. Token-bound: the
|
|
37
|
+
* host self-binds the account off the block token and reads via its
|
|
38
|
+
* `blocks.getMyBuzzTransactions` mutation (scope `buzz:read:self`) — the block
|
|
39
|
+
* never touches the ledger API or credentials directly (same trust model as
|
|
40
|
+
* {@link useBuzzBalance}).
|
|
41
|
+
*
|
|
42
|
+
* Fetches on mount and whenever `params` change (by value), and exposes `refetch`.
|
|
43
|
+
* A host that never answers surfaces as an `error` after the transport's request
|
|
44
|
+
* timeout — the hook never hangs. Late responses that arrive after unmount are
|
|
45
|
+
* ignored. Transaction `date`s are rehydrated to `Date`; `cursor` is normalized
|
|
46
|
+
* to an ISO string for round-tripping.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const { transactions, cursor, loading, error } = useBuzzTransactions({ type: 'Tip', limit: 20 });
|
|
50
|
+
*/
|
|
51
|
+
export declare function useBuzzTransactions(params?: BlockBuzzTransactionsParams): UseBuzzTransactions;
|
|
52
|
+
//# sourceMappingURL=useBuzzTransactions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBuzzTransactions.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuzzTransactions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAKjG;;;;;GAKG;AACH,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACzE,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0FAA0F;IAC1F,YAAY,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACvC;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,mCAAmC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAWD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,2BAA2B,GAAG,mBAAmB,CAqD7F"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { getTransport } from '../internal/singleton.js';
|
|
3
|
+
import { sendTypedRequest } from '../internal/transport.js';
|
|
4
|
+
/** Rehydrate the host's `date`/`cursor` (a `Date` instance OR an ISO string). */
|
|
5
|
+
function toDate(v) {
|
|
6
|
+
return v instanceof Date ? v : new Date(v);
|
|
7
|
+
}
|
|
8
|
+
function toIso(v) {
|
|
9
|
+
if (v === undefined || v === null)
|
|
10
|
+
return null;
|
|
11
|
+
return v instanceof Date ? v.toISOString() : String(v);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Read the signed-in viewer's Buzz-transaction ledger through the host-mediated
|
|
15
|
+
* `GET_BUZZ_TRANSACTIONS` → `BUZZ_TRANSACTIONS_RESULT` bridge. Token-bound: the
|
|
16
|
+
* host self-binds the account off the block token and reads via its
|
|
17
|
+
* `blocks.getMyBuzzTransactions` mutation (scope `buzz:read:self`) — the block
|
|
18
|
+
* never touches the ledger API or credentials directly (same trust model as
|
|
19
|
+
* {@link useBuzzBalance}).
|
|
20
|
+
*
|
|
21
|
+
* Fetches on mount and whenever `params` change (by value), and exposes `refetch`.
|
|
22
|
+
* A host that never answers surfaces as an `error` after the transport's request
|
|
23
|
+
* timeout — the hook never hangs. Late responses that arrive after unmount are
|
|
24
|
+
* ignored. Transaction `date`s are rehydrated to `Date`; `cursor` is normalized
|
|
25
|
+
* to an ISO string for round-tripping.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const { transactions, cursor, loading, error } = useBuzzTransactions({ type: 'Tip', limit: 20 });
|
|
29
|
+
*/
|
|
30
|
+
export function useBuzzTransactions(params) {
|
|
31
|
+
const [transactions, setTransactions] = useState(null);
|
|
32
|
+
const [cursor, setCursor] = useState(null);
|
|
33
|
+
const [loading, setLoading] = useState(true);
|
|
34
|
+
const [error, setError] = useState(null);
|
|
35
|
+
const mountedRef = useRef(true);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
mountedRef.current = true;
|
|
38
|
+
return () => {
|
|
39
|
+
mountedRef.current = false;
|
|
40
|
+
};
|
|
41
|
+
}, []);
|
|
42
|
+
// Serialize the params to a stable key so `refetch`'s identity only changes
|
|
43
|
+
// when the params VALUE changes (not on every render's fresh object). The
|
|
44
|
+
// callback re-parses the key so it closes over NOTHING but the key.
|
|
45
|
+
const paramsKey = params ? JSON.stringify(params) : '';
|
|
46
|
+
const refetch = useCallback(() => {
|
|
47
|
+
setLoading(true);
|
|
48
|
+
setError(null);
|
|
49
|
+
const parsed = paramsKey ? JSON.parse(paramsKey) : undefined;
|
|
50
|
+
const payload = parsed ? { params: parsed } : {};
|
|
51
|
+
sendTypedRequest(getTransport(), { type: 'GET_BUZZ_TRANSACTIONS', payload }, 'BUZZ_TRANSACTIONS_RESULT')
|
|
52
|
+
.then((result) => {
|
|
53
|
+
if (!mountedRef.current)
|
|
54
|
+
return;
|
|
55
|
+
if (result.error || !result.result) {
|
|
56
|
+
setError(new Error(result.error ?? 'failed to fetch buzz transactions'));
|
|
57
|
+
setLoading(false);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const wire = result.result;
|
|
61
|
+
setTransactions(wire.transactions.map((t) => ({ ...t, date: toDate(t.date) })));
|
|
62
|
+
setCursor(toIso(wire.cursor));
|
|
63
|
+
setLoading(false);
|
|
64
|
+
})
|
|
65
|
+
.catch((err) => {
|
|
66
|
+
if (!mountedRef.current)
|
|
67
|
+
return;
|
|
68
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
69
|
+
setLoading(false);
|
|
70
|
+
});
|
|
71
|
+
}, [paramsKey]);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
refetch();
|
|
74
|
+
}, [refetch]);
|
|
75
|
+
return { transactions, cursor, loading, error, refetch };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=useBuzzTransactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBuzzTransactions.js","sourceRoot":"","sources":["../../src/hooks/useBuzzTransactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { BlockDailyCompensationParams, BlockDailyCompensationResource } from '@civitai/app-sdk/blocks';
|
|
2
|
+
/**
|
|
3
|
+
* What {@link useDailyCompensation} returns.
|
|
4
|
+
*/
|
|
5
|
+
export interface UseDailyCompensation {
|
|
6
|
+
/**
|
|
7
|
+
* Per-modelVersion generation-compensation rows for the month of the requested
|
|
8
|
+
* `date`, or `null` until the first successful fetch. `data`/`cashData`
|
|
9
|
+
* `createdAt` are `YYYY-MM-DD` day-strings (NOT rehydrated to `Date`).
|
|
10
|
+
*/
|
|
11
|
+
resources: BlockDailyCompensationResource[] | null;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the viewer has ANY published resource — `false` distinguishes "no
|
|
14
|
+
* published models" from "published models that earned nothing this month"
|
|
15
|
+
* (both give `resources: []`). `null` until the first successful fetch.
|
|
16
|
+
*/
|
|
17
|
+
hasPublishedResources: boolean | null;
|
|
18
|
+
/** `true` while a fetch (initial or `refetch`) is in flight. */
|
|
19
|
+
loading: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The last fetch's failure — a host-reported error (anon viewer / missing
|
|
22
|
+
* `buzz:read:self` scope / a ClickHouse blip surfaced as a retryable error) or
|
|
23
|
+
* the transport timeout. Free-text. Cleared at the start of the next fetch.
|
|
24
|
+
*/
|
|
25
|
+
error: Error | null;
|
|
26
|
+
/** Re-request the compensation for the current `params`. */
|
|
27
|
+
refetch: () => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read the signed-in viewer's per-modelVersion generation compensation for the
|
|
31
|
+
* MONTH containing `params.date`, through the host-mediated
|
|
32
|
+
* `GET_DAILY_COMPENSATION` → `DAILY_COMPENSATION_RESULT` bridge. Token-bound: the
|
|
33
|
+
* host self-binds off the block token and reads via its
|
|
34
|
+
* `blocks.getMyDailyCompensation` mutation (scope `buzz:read:self`).
|
|
35
|
+
*
|
|
36
|
+
* Fetches on mount and whenever `params` change (by value), and exposes `refetch`.
|
|
37
|
+
* A host that never answers surfaces as an `error` after the transport timeout;
|
|
38
|
+
* late post-unmount responses are ignored.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* const { resources, hasPublishedResources } = useDailyCompensation({ date: '2026-07-01' });
|
|
42
|
+
*/
|
|
43
|
+
export declare function useDailyCompensation(params: BlockDailyCompensationParams): UseDailyCompensation;
|
|
44
|
+
//# sourceMappingURL=useDailyCompensation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDailyCompensation.d.ts","sourceRoot":"","sources":["../../src/hooks/useDailyCompensation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,4BAA4B,EAC5B,8BAA8B,EAC/B,MAAM,yBAAyB,CAAC;AAKjC;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,SAAS,EAAE,8BAA8B,EAAE,GAAG,IAAI,CAAC;IACnD;;;;OAIG;IACH,qBAAqB,EAAE,OAAO,GAAG,IAAI,CAAC;IACtC,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,4BAA4B,GAAG,oBAAoB,CAkD/F"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { getTransport } from '../internal/singleton.js';
|
|
3
|
+
import { sendTypedRequest } from '../internal/transport.js';
|
|
4
|
+
/**
|
|
5
|
+
* Read the signed-in viewer's per-modelVersion generation compensation for the
|
|
6
|
+
* MONTH containing `params.date`, through the host-mediated
|
|
7
|
+
* `GET_DAILY_COMPENSATION` → `DAILY_COMPENSATION_RESULT` bridge. Token-bound: the
|
|
8
|
+
* host self-binds off the block token and reads via its
|
|
9
|
+
* `blocks.getMyDailyCompensation` mutation (scope `buzz:read:self`).
|
|
10
|
+
*
|
|
11
|
+
* Fetches on mount and whenever `params` change (by value), and exposes `refetch`.
|
|
12
|
+
* A host that never answers surfaces as an `error` after the transport timeout;
|
|
13
|
+
* late post-unmount responses are ignored.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const { resources, hasPublishedResources } = useDailyCompensation({ date: '2026-07-01' });
|
|
17
|
+
*/
|
|
18
|
+
export function useDailyCompensation(params) {
|
|
19
|
+
const [resources, setResources] = useState(null);
|
|
20
|
+
const [hasPublishedResources, setHasPublishedResources] = useState(null);
|
|
21
|
+
const [loading, setLoading] = useState(true);
|
|
22
|
+
const [error, setError] = useState(null);
|
|
23
|
+
const mountedRef = useRef(true);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
mountedRef.current = true;
|
|
26
|
+
return () => {
|
|
27
|
+
mountedRef.current = false;
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
// Stable params key so `refetch`'s identity only changes when the params VALUE
|
|
31
|
+
// changes; the callback re-parses it so it closes over nothing but the key.
|
|
32
|
+
const paramsKey = JSON.stringify(params);
|
|
33
|
+
const refetch = useCallback(() => {
|
|
34
|
+
setLoading(true);
|
|
35
|
+
setError(null);
|
|
36
|
+
const parsed = JSON.parse(paramsKey);
|
|
37
|
+
sendTypedRequest(getTransport(), { type: 'GET_DAILY_COMPENSATION', payload: { params: parsed } }, 'DAILY_COMPENSATION_RESULT')
|
|
38
|
+
.then((result) => {
|
|
39
|
+
if (!mountedRef.current)
|
|
40
|
+
return;
|
|
41
|
+
if (result.error || !result.result) {
|
|
42
|
+
setError(new Error(result.error ?? 'failed to fetch daily compensation'));
|
|
43
|
+
setLoading(false);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
setResources(result.result.resources);
|
|
47
|
+
setHasPublishedResources(result.result.hasPublishedResources);
|
|
48
|
+
setLoading(false);
|
|
49
|
+
})
|
|
50
|
+
.catch((err) => {
|
|
51
|
+
if (!mountedRef.current)
|
|
52
|
+
return;
|
|
53
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
54
|
+
setLoading(false);
|
|
55
|
+
});
|
|
56
|
+
}, [paramsKey]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
refetch();
|
|
59
|
+
}, [refetch]);
|
|
60
|
+
return { resources, hasPublishedResources, loading, error, refetch };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=useDailyCompensation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDailyCompensation.js","sourceRoot":"","sources":["../../src/hooks/useDailyCompensation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAOjE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AA8B5D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAoC;IACvE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAA0C,IAAI,CAAC,CAAC;IAC1F,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAiB,IAAI,CAAC,CAAC;IACzF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,+EAA+E;IAC/E,4EAA4E;IAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEzC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAiC,CAAC;QACrE,gBAAgB,CACd,YAAY,EAAE,EACd,EAAE,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAC/D,2BAA2B,CAC5B;aACE,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO;YAChC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnC,QAAQ,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,oCAAoC,CAAC,CAAC,CAAC;gBAC1E,UAAU,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACtC,wBAAwB,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;YAC9D,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO;YAChC,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9D,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,EAAE,CAAC;IACZ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { BlockViewer } from '@civitai/app-sdk/blocks';
|
|
2
|
+
/**
|
|
3
|
+
* What {@link useViewer} returns.
|
|
4
|
+
*/
|
|
5
|
+
export interface UseViewer {
|
|
6
|
+
/** The signed-in viewer, or `null` until the first successful fetch. */
|
|
7
|
+
viewer: BlockViewer | null;
|
|
8
|
+
/** `true` while a fetch (initial or `refetch`) is in flight. */
|
|
9
|
+
loading: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The last fetch's failure — a host-reported error (anon / banned viewer /
|
|
12
|
+
* missing scope / host failure) or the transport timeout when the host never
|
|
13
|
+
* answers. Cleared at the start of the next fetch.
|
|
14
|
+
*/
|
|
15
|
+
error: Error | null;
|
|
16
|
+
/** Re-request the viewer. */
|
|
17
|
+
refetch: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read the signed-in viewer (id / username / status + optional buzzBudget)
|
|
21
|
+
* through the host-mediated `GET_VIEWER` → `VIEWER_RESULT` bridge. Token-bound:
|
|
22
|
+
* the host resolves the viewer from the block token and reads via its
|
|
23
|
+
* `blocks.getMyViewer` tRPC mutation — the block never touches the viewer API or
|
|
24
|
+
* credentials directly (same trust model as {@link useBuzzBalance}).
|
|
25
|
+
*
|
|
26
|
+
* Distinct from `useBlockContext().viewer`, which is the coarse BLOCK_INIT-time
|
|
27
|
+
* snapshot ({@link ViewerInfo}, `status` optional): `useViewer` is the on-demand
|
|
28
|
+
* authoritative self-read (`active`/`muted` status + the viewer's current
|
|
29
|
+
* `buzzBudget`). `username` and `buzzBudget` are surfaced as-is and may be `null`
|
|
30
|
+
* (a viewer with no handle / a token lacking the budget claim) — the block
|
|
31
|
+
* handles the null case.
|
|
32
|
+
*
|
|
33
|
+
* Fetches once on mount and exposes `refetch` for on-demand refreshes. A host
|
|
34
|
+
* that never answers surfaces as an `error` after the transport's request
|
|
35
|
+
* timeout — the hook never hangs. Late responses that arrive after unmount are
|
|
36
|
+
* ignored (no state update).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const { viewer, loading, error, refetch } = useViewer();
|
|
40
|
+
* if (loading) return <Spinner />;
|
|
41
|
+
* if (error) return <RetryButton onClick={refetch} />;
|
|
42
|
+
* return <span>{viewer?.username}</span>;
|
|
43
|
+
*/
|
|
44
|
+
export declare function useViewer(): UseViewer;
|
|
45
|
+
//# sourceMappingURL=useViewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useViewer.d.ts","sourceRoot":"","sources":["../../src/hooks/useViewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAK3D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,wEAAwE;IACxE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,IAAI,SAAS,CA0CrC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { getTransport } from '../internal/singleton.js';
|
|
3
|
+
import { sendTypedRequest } from '../internal/transport.js';
|
|
4
|
+
/**
|
|
5
|
+
* Read the signed-in viewer (id / username / status + optional buzzBudget)
|
|
6
|
+
* through the host-mediated `GET_VIEWER` → `VIEWER_RESULT` bridge. Token-bound:
|
|
7
|
+
* the host resolves the viewer from the block token and reads via its
|
|
8
|
+
* `blocks.getMyViewer` tRPC mutation — the block never touches the viewer API or
|
|
9
|
+
* credentials directly (same trust model as {@link useBuzzBalance}).
|
|
10
|
+
*
|
|
11
|
+
* Distinct from `useBlockContext().viewer`, which is the coarse BLOCK_INIT-time
|
|
12
|
+
* snapshot ({@link ViewerInfo}, `status` optional): `useViewer` is the on-demand
|
|
13
|
+
* authoritative self-read (`active`/`muted` status + the viewer's current
|
|
14
|
+
* `buzzBudget`). `username` and `buzzBudget` are surfaced as-is and may be `null`
|
|
15
|
+
* (a viewer with no handle / a token lacking the budget claim) — the block
|
|
16
|
+
* handles the null case.
|
|
17
|
+
*
|
|
18
|
+
* Fetches once on mount and exposes `refetch` for on-demand refreshes. A host
|
|
19
|
+
* that never answers surfaces as an `error` after the transport's request
|
|
20
|
+
* timeout — the hook never hangs. Late responses that arrive after unmount are
|
|
21
|
+
* ignored (no state update).
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const { viewer, loading, error, refetch } = useViewer();
|
|
25
|
+
* if (loading) return <Spinner />;
|
|
26
|
+
* if (error) return <RetryButton onClick={refetch} />;
|
|
27
|
+
* return <span>{viewer?.username}</span>;
|
|
28
|
+
*/
|
|
29
|
+
export function useViewer() {
|
|
30
|
+
const [viewer, setViewer] = useState(null);
|
|
31
|
+
const [loading, setLoading] = useState(true);
|
|
32
|
+
const [error, setError] = useState(null);
|
|
33
|
+
// Guards against a late response resolving after the component unmounted
|
|
34
|
+
// (React would warn about a state update on an unmounted component, and the
|
|
35
|
+
// work is wasted anyway).
|
|
36
|
+
const mountedRef = useRef(true);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
mountedRef.current = true;
|
|
39
|
+
return () => {
|
|
40
|
+
mountedRef.current = false;
|
|
41
|
+
};
|
|
42
|
+
}, []);
|
|
43
|
+
const refetch = useCallback(() => {
|
|
44
|
+
setLoading(true);
|
|
45
|
+
setError(null);
|
|
46
|
+
sendTypedRequest(getTransport(), { type: 'GET_VIEWER', payload: {} }, 'VIEWER_RESULT')
|
|
47
|
+
.then((result) => {
|
|
48
|
+
if (!mountedRef.current)
|
|
49
|
+
return;
|
|
50
|
+
if (result.error || !result.viewer) {
|
|
51
|
+
setError(new Error(result.error ?? 'failed to fetch viewer'));
|
|
52
|
+
setLoading(false);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
setViewer(result.viewer);
|
|
56
|
+
setLoading(false);
|
|
57
|
+
})
|
|
58
|
+
.catch((err) => {
|
|
59
|
+
if (!mountedRef.current)
|
|
60
|
+
return;
|
|
61
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
62
|
+
setLoading(false);
|
|
63
|
+
});
|
|
64
|
+
}, []);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
refetch();
|
|
67
|
+
}, [refetch]);
|
|
68
|
+
return { viewer, loading, error, refetch };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=useViewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useViewer.js","sourceRoot":"","sources":["../../src/hooks/useViewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAIjE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAoB5D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAC/D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,yEAAyE;IACzE,4EAA4E;IAC5E,0BAA0B;IAC1B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,gBAAgB,CAAC,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC;aACnF,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO;YAChC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnC,QAAQ,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,wBAAwB,CAAC,CAAC,CAAC;gBAC9D,UAAU,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACzB,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO;YAChC,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9D,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,EAAE,CAAC;IACZ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { BlockWildcardPack, BlockWildcardPackErrorCode } from '@civitai/app-sdk/blocks';
|
|
2
|
+
export type { BlockWildcardPack, BlockWildcardPackErrorCode };
|
|
3
|
+
/**
|
|
4
|
+
* A wildcard-pack import failure. Unlike the buzz bridges' free-text errors, the
|
|
5
|
+
* host returns a DISCRIMINATED code — this error carries it on `.code` so a block
|
|
6
|
+
* can branch on the exact reason (`busy` is retryable; `too-large`/`forbidden`/
|
|
7
|
+
* `not-found`/`parse-failed` are terminal). `.message` equals the code.
|
|
8
|
+
*/
|
|
9
|
+
export declare class WildcardPackError extends Error {
|
|
10
|
+
readonly code: BlockWildcardPackErrorCode;
|
|
11
|
+
constructor(code: BlockWildcardPackErrorCode);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* What {@link useWildcardPack} returns.
|
|
15
|
+
*/
|
|
16
|
+
export interface UseWildcardPack {
|
|
17
|
+
/** The parsed pack, or `null` until the first successful fetch. */
|
|
18
|
+
pack: BlockWildcardPack | null;
|
|
19
|
+
/** `true` while a fetch (initial or `refetch`) is in flight. */
|
|
20
|
+
loading: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The last fetch's failure as a {@link WildcardPackError} (`.code` is the
|
|
23
|
+
* discriminated reason), or a plain `Error` on a transport timeout. Cleared at
|
|
24
|
+
* the start of the next fetch.
|
|
25
|
+
*/
|
|
26
|
+
error: Error | null;
|
|
27
|
+
/** Re-request the pack. */
|
|
28
|
+
refetch: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Import a wildcard pack's parsed prompt lists by model-version id, through the
|
|
32
|
+
* host-mediated `GET_WILDCARD_PACK` → `WILDCARD_PACK_RESULT` bridge.
|
|
33
|
+
* TOKEN-INDEPENDENT (no block scope): the host resolves + fetches + unzips +
|
|
34
|
+
* parses the pack in the viewer's authenticated page session — enforcing every
|
|
35
|
+
* real download gate — and returns only the parsed JSON. The untrusted iframe
|
|
36
|
+
* never sees the session, the signed URL, or the raw bytes.
|
|
37
|
+
*
|
|
38
|
+
* Fetches on mount and whenever `modelVersionId` changes; exposes `refetch` (e.g.
|
|
39
|
+
* to retry a `busy` result). On failure `error` is a {@link WildcardPackError}
|
|
40
|
+
* whose `.code` is the discriminated reason. A non-positive `modelVersionId` is a
|
|
41
|
+
* no-op (nothing to fetch). A host that never answers surfaces as an `error`
|
|
42
|
+
* after the transport timeout; late post-unmount responses are ignored.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const { pack, loading, error } = useWildcardPack(modelVersionId);
|
|
46
|
+
* if (error instanceof WildcardPackError && error.code === 'busy') return <RetryLater />;
|
|
47
|
+
*/
|
|
48
|
+
export declare function useWildcardPack(modelVersionId: number): UseWildcardPack;
|
|
49
|
+
//# sourceMappingURL=useWildcardPack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWildcardPack.d.ts","sourceRoot":"","sources":["../../src/hooks/useWildcardPack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAK7F,YAAY,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,CAAC;AAE9D;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;gBAC9B,IAAI,EAAE,0BAA0B;CAK7C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,eAAe,CAmDvE"}
|