@civitai/blocks-react 0.40.0 → 0.41.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 +99 -0
- package/dist/hooks/useBuzzWorkflow.d.ts +13 -1
- package/dist/hooks/useBuzzWorkflow.d.ts.map +1 -1
- package/dist/hooks/useBuzzWorkflow.js +13 -1
- package/dist/hooks/useBuzzWorkflow.js.map +1 -1
- package/dist/hooks/useConsentUnavailable.d.ts +92 -0
- package/dist/hooks/useConsentUnavailable.d.ts.map +1 -0
- package/dist/hooks/useConsentUnavailable.js +93 -0
- package/dist/hooks/useConsentUnavailable.js.map +1 -0
- package/dist/hooks/useRequestConsent.d.ts +21 -3
- package/dist/hooks/useRequestConsent.d.ts.map +1 -1
- package/dist/hooks/useRequestConsent.js +30 -4
- package/dist/hooks/useRequestConsent.js.map +1 -1
- package/dist/index.d.ts +2 -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/consent.d.ts +71 -0
- package/dist/internal/consent.d.ts.map +1 -0
- package/dist/internal/consent.js +88 -0
- package/dist/internal/consent.js.map +1 -0
- package/dist/internal/consentRefusalLatch.d.ts +19 -0
- package/dist/internal/consentRefusalLatch.d.ts.map +1 -0
- package/dist/internal/consentRefusalLatch.js +38 -0
- package/dist/internal/consentRefusalLatch.js.map +1 -0
- package/dist/internal/liveHost.d.ts.map +1 -1
- package/dist/internal/liveHost.js +27 -0
- package/dist/internal/liveHost.js.map +1 -1
- package/dist/internal/mockHost.d.ts +37 -8
- package/dist/internal/mockHost.d.ts.map +1 -1
- package/dist/internal/mockHost.js +84 -17
- package/dist/internal/mockHost.js.map +1 -1
- package/dist/internal/validate.d.ts +26 -0
- package/dist/internal/validate.d.ts.map +1 -1
- package/dist/internal/validate.js +36 -0
- package/dist/internal/validate.js.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +41 -2
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -502,10 +502,109 @@ needs `ai:write:budgeted` but the viewer hasn't granted it). Fire-and-forget —
|
|
|
502
502
|
on grant the host pushes a new token; observe `useBlockToken().scopes` and retry.
|
|
503
503
|
|
|
504
504
|
```tsx
|
|
505
|
+
import { useRequestConsent } from '@civitai/blocks-react';
|
|
506
|
+
|
|
505
507
|
const { requestConsent } = useRequestConsent();
|
|
506
508
|
requestConsent({ scopes: ['ai:write:budgeted', 'buzz:read:self'] });
|
|
507
509
|
```
|
|
508
510
|
|
|
511
|
+
🔴 **Always pass `scopes`, with a real scope name in it — it is optional in the
|
|
512
|
+
signature but a precondition for the refusal path below.** The host grants the
|
|
513
|
+
missing set it computed at mint, so a bare `requestConsent()` still opens the
|
|
514
|
+
consent dialog. But `CONSENT_UNAVAILABLE` is computed *from the hint*: with no
|
|
515
|
+
explicit scope proven un-grantable, the host cannot tell "can never be granted"
|
|
516
|
+
from "the viewer hasn't confirmed yet", so it stays silent rather than guess.
|
|
517
|
+
|
|
518
|
+
The bar is an array holding **at least one non-empty string** — not merely "an
|
|
519
|
+
array is present". `undefined`, a non-array, `[]`, `['']` and `[1, 2]` all
|
|
520
|
+
produce silence, in `pnpm dev` and in production alike, so
|
|
521
|
+
`requestConsent({ scopes: [] })` follows the instruction and still receives
|
|
522
|
+
nothing. To its author that reads as a broken message rather than a thin
|
|
523
|
+
argument.
|
|
524
|
+
|
|
525
|
+
### `useConsentUnavailable()`
|
|
526
|
+
|
|
527
|
+
Some environments withhold a scope at mint (a dev-tunnel preview token, a surface
|
|
528
|
+
that carries no money scope), so no consent round-trip can ever add it. The host
|
|
529
|
+
then pushes an uncorrelated `CONSENT_UNAVAILABLE` — *not* a reply, because
|
|
530
|
+
`REQUEST_CONSENT` carries no `requestId`. Consume it and stop telling the user to
|
|
531
|
+
retry something that can't succeed:
|
|
532
|
+
|
|
533
|
+
```tsx
|
|
534
|
+
import { useConsentUnavailable, useRequestConsent } from '@civitai/blocks-react';
|
|
535
|
+
|
|
536
|
+
function ConsentAwareGenerate() {
|
|
537
|
+
const { requestConsent } = useRequestConsent();
|
|
538
|
+
const { refusal, reset } = useConsentUnavailable();
|
|
539
|
+
|
|
540
|
+
// 🔴 Branch on `refusal !== null`, NEVER on `refusal.scopes.length`. The host
|
|
541
|
+
// refuses on its own unfiltered set but names only scopes in the public
|
|
542
|
+
// vocabulary, so `scopes: []` is a legitimate refusal — gating on the length
|
|
543
|
+
// silently drops the very message you subscribed for. Use the names for copy.
|
|
544
|
+
if (refusal) {
|
|
545
|
+
return (
|
|
546
|
+
<div>
|
|
547
|
+
<p>Generating isn't available on this page.</p>
|
|
548
|
+
<button onClick={reset}>Try again</button>
|
|
549
|
+
</div>
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
// 🔴 `scopes` is REQUIRED for a refusal to ever arrive — see above.
|
|
553
|
+
return <button onClick={() => requestConsent({ scopes: ['ai:write:budgeted'] })}>Generate</button>;
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
`refusal` holds the latest `ConsentUnavailablePayload` (`{ reason, scopes }`) or
|
|
558
|
+
`null`; `reset()` clears it, since a refusal is scoped to the scopes that were
|
|
559
|
+
asked for and shouldn't latch for the life of the block. Against a host that
|
|
560
|
+
never sends the message the hook simply stays `null` — nothing awaits it, so
|
|
561
|
+
there is no timeout to hit.
|
|
562
|
+
|
|
563
|
+
🔴 **The push is UNCORRELATED, and that is the permanent shape of this API.**
|
|
564
|
+
`REQUEST_CONSENT` carries no `requestId`, so a refusal cannot be matched to the
|
|
565
|
+
request that provoked it. Two consequences to design around:
|
|
566
|
+
|
|
567
|
+
- **Every mounted `useConsentUnavailable()` sees every refusal.** There is no
|
|
568
|
+
reliable filter: `scopes` is advisory and may legitimately be `[]`, so it
|
|
569
|
+
cannot serve as a correlation key. If two independent parts of your block
|
|
570
|
+
request different scopes, both will see both refusals. Keep a request and its
|
|
571
|
+
refusal UI in one component, or track the outstanding request yourself.
|
|
572
|
+
- **A refusal is buffered across mounts, so one that arrives while the consumer
|
|
573
|
+
is unmounted is not lost.** The transport hands an unsolicited push only to
|
|
574
|
+
handlers registered at the instant it arrives, so without this a refusal that
|
|
575
|
+
landed before the consumer mounted — the requester and the consumer being
|
|
576
|
+
different components, or the consumer being conditionally rendered — vanished,
|
|
577
|
+
and the block went back to showing "click Generate again" beside the host's
|
|
578
|
+
"unavailable". `requestConsent()` arms the buffer as it sends. It keeps only
|
|
579
|
+
the latest refusal, is dropped when the block token changes (a refusal is a
|
|
580
|
+
claim about *that* token's scopes, and the grant path re-mints), and is cleared
|
|
581
|
+
by `reset()` — so the "Try again" button above genuinely resets, rather than
|
|
582
|
+
having the refusal reappear on the next mount. A `REQUEST_CONSENT` you post
|
|
583
|
+
through the raw transport instead of the hook does not arm it.
|
|
584
|
+
|
|
585
|
+
Without the hook (a non-React consumer, or one wiring the transport directly),
|
|
586
|
+
the same push is available untyped — note the explicit type import, which the
|
|
587
|
+
cast needs and which the hook makes unnecessary:
|
|
588
|
+
|
|
589
|
+
```tsx
|
|
590
|
+
import { getTransport } from '@civitai/blocks-react';
|
|
591
|
+
import type { ConsentUnavailablePayload } from '@civitai/app-sdk/blocks';
|
|
592
|
+
|
|
593
|
+
const unsubscribe = getTransport().onMessage('CONSENT_UNAVAILABLE', (payload) => {
|
|
594
|
+
// `onMessage` hands you `unknown`; this cast is UNCHECKED, which is why
|
|
595
|
+
// `useConsentUnavailable()` is the preferred path.
|
|
596
|
+
const { reason, scopes } = payload as ConsentUnavailablePayload;
|
|
597
|
+
console.info('permission unavailable', reason, scopes);
|
|
598
|
+
});
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
To exercise the refusal locally, run the mock host with
|
|
602
|
+
`createMockHost({ consentGrantable: false })`, flip it live with
|
|
603
|
+
`host.setScenario({ consentGrantable: false })`, or append `?consent=ungrantable`
|
|
604
|
+
to the dev harness URL — the `<Harness>` chrome then reads `consent=ungrantable`
|
|
605
|
+
rather than `withheld`. `dev:live` emits it too: live mode can grant nothing, so
|
|
606
|
+
any request for a scope your dev token lacks produces one.
|
|
607
|
+
|
|
509
608
|
### `useDomainMaturity()`
|
|
510
609
|
|
|
511
610
|
Read the surrounding color-domain's maturity ceiling (civitai #2670) so a block
|
|
@@ -150,12 +150,24 @@ interface UseBuzzWorkflowReturn {
|
|
|
150
150
|
* `estimate`/`submit` take a full {@link WorkflowBody} — the discriminated
|
|
151
151
|
* union keyed by `kind`, with THREE members as of `@civitai/app-sdk@0.30.0`:
|
|
152
152
|
* a `textToImage` body (`{ kind, modelId, modelVersionId, params }`), a
|
|
153
|
-
* `customComfy`
|
|
153
|
+
* `customComfy` body (`kind: 'customComfy'`), or a `step` body
|
|
154
154
|
* (`{ kind: 'step', step, params }` — a server-registered orchestrator step
|
|
155
155
|
* such as `'chat-completion'`), never a bare `{ prompt }`. The hook forwards
|
|
156
156
|
* the body to the host verbatim and never reads variant-specific fields, so
|
|
157
157
|
* every member flows through unchanged, including any member added later.
|
|
158
158
|
*
|
|
159
|
+
* 🔴 `customComfy` IS ITSELF A UNION, on `mode` — an app CAN ship its own
|
|
160
|
+
* ComfyUI graph. `WorkflowBodyCustomComfyRecipe` (`mode` omitted or `'recipe'`)
|
|
161
|
+
* names a server-registered recipe; `WorkflowBodyCustomComfyInline`
|
|
162
|
+
* (`mode: 'inline'`) carries the graph itself, plus its declared AIR
|
|
163
|
+
* `resources` and a `maxBuzz` bound. The inline arm is LIVE in production
|
|
164
|
+
* (developer-only) and this comment used to describe `customComfy` as a
|
|
165
|
+
* recipe-only `{ kind, recipe, params }` shape — written when that was true and
|
|
166
|
+
* never revisited once the arm shipped. A developer working against the live
|
|
167
|
+
* feature read the equivalent claim on the type, believed it over their own
|
|
168
|
+
* instinct, and concluded the capability did not exist. `@civitai/app-sdk`
|
|
169
|
+
* 0.30.0 predates the inline arm; the union above is otherwise unchanged.
|
|
170
|
+
*
|
|
159
171
|
* @returns `{ estimate, submit, poll, watch, cancel, status, result, error }`.
|
|
160
172
|
*
|
|
161
173
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBuzzWorkflow.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuzzWorkflow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AA8BnG;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAW7C,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACrD;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyBD,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjE,MAAM,EAAE,CACN,IAAI,EAAE,YAAY,EAClB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpC;;;OAGG;IACH,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC7D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,EAAE,CACL,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpC;;;;;;OAMG;IACH,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/D,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACrC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED
|
|
1
|
+
{"version":3,"file":"useBuzzWorkflow.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuzzWorkflow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AA8BnG;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAW7C,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACrD;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyBD,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjE,MAAM,EAAE,CACN,IAAI,EAAE,YAAY,EAClB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpC;;;OAGG;IACH,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC7D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,EAAE,CACL,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpC;;;;;;OAMG;IACH,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/D,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACrC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,eAAe,IAAI,qBAAqB,CA+MvD"}
|
|
@@ -94,12 +94,24 @@ function sleep(ms, signal) {
|
|
|
94
94
|
* `estimate`/`submit` take a full {@link WorkflowBody} — the discriminated
|
|
95
95
|
* union keyed by `kind`, with THREE members as of `@civitai/app-sdk@0.30.0`:
|
|
96
96
|
* a `textToImage` body (`{ kind, modelId, modelVersionId, params }`), a
|
|
97
|
-
* `customComfy`
|
|
97
|
+
* `customComfy` body (`kind: 'customComfy'`), or a `step` body
|
|
98
98
|
* (`{ kind: 'step', step, params }` — a server-registered orchestrator step
|
|
99
99
|
* such as `'chat-completion'`), never a bare `{ prompt }`. The hook forwards
|
|
100
100
|
* the body to the host verbatim and never reads variant-specific fields, so
|
|
101
101
|
* every member flows through unchanged, including any member added later.
|
|
102
102
|
*
|
|
103
|
+
* 🔴 `customComfy` IS ITSELF A UNION, on `mode` — an app CAN ship its own
|
|
104
|
+
* ComfyUI graph. `WorkflowBodyCustomComfyRecipe` (`mode` omitted or `'recipe'`)
|
|
105
|
+
* names a server-registered recipe; `WorkflowBodyCustomComfyInline`
|
|
106
|
+
* (`mode: 'inline'`) carries the graph itself, plus its declared AIR
|
|
107
|
+
* `resources` and a `maxBuzz` bound. The inline arm is LIVE in production
|
|
108
|
+
* (developer-only) and this comment used to describe `customComfy` as a
|
|
109
|
+
* recipe-only `{ kind, recipe, params }` shape — written when that was true and
|
|
110
|
+
* never revisited once the arm shipped. A developer working against the live
|
|
111
|
+
* feature read the equivalent claim on the type, believed it over their own
|
|
112
|
+
* instinct, and concluded the capability did not exist. `@civitai/app-sdk`
|
|
113
|
+
* 0.30.0 predates the inline arm; the union above is otherwise unchanged.
|
|
114
|
+
*
|
|
103
115
|
* @returns `{ estimate, submit, poll, watch, cancel, status, result, error }`.
|
|
104
116
|
*
|
|
105
117
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBuzzWorkflow.js","sourceRoot":"","sources":["../../src/hooks/useBuzzWorkflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAI9C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEpF;;;;GAIG;AACH,MAAM,iBAAiB,GAAiD,IAAI,GAAG,CAAC;IAC9E,WAAW;IACX,QAAQ;IACR,UAAU;IACV,SAAS;CACV,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,2BAA2B,GAAG,OAAO,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAE7C,qFAAqF;AACrF,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAExC,6EAA6E;AAC7E,MAAM,wBAAwB,GAAG,EAAE,GAAG,MAAM,CAAC;AAE7C,gFAAgF;AAChF,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAwDpC;;;;;;;;;GASG;AACH,SAAS,KAAK,CAAC,EAAU,EAAE,MAAoB;IAC7C,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC9C,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC3C,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC;AAmED
|
|
1
|
+
{"version":3,"file":"useBuzzWorkflow.js","sourceRoot":"","sources":["../../src/hooks/useBuzzWorkflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ConsentUnavailablePayload } from '@civitai/app-sdk/blocks';
|
|
2
|
+
export type { ConsentUnavailablePayload };
|
|
3
|
+
/** What {@link useConsentUnavailable} returns. */
|
|
4
|
+
export interface UseConsentUnavailable {
|
|
5
|
+
/**
|
|
6
|
+
* The most recent `CONSENT_UNAVAILABLE` push, or `null` if the host has not
|
|
7
|
+
* refused (the normal case — nothing to render differently).
|
|
8
|
+
*
|
|
9
|
+
* 🔴 `refusal.scopes` CAN BE EMPTY and that is still a refusal. The host
|
|
10
|
+
* decides to refuse on its own UNFILTERED un-grantable set, then filters the
|
|
11
|
+
* names it puts on the wire down to the public block-scope vocabulary — so a
|
|
12
|
+
* request naming nothing the platform recognises refuses with `scopes: []`.
|
|
13
|
+
* Branch on `refusal !== null`; use `refusal.scopes` only to word the copy.
|
|
14
|
+
*/
|
|
15
|
+
refusal: ConsentUnavailablePayload | null;
|
|
16
|
+
/**
|
|
17
|
+
* Clear the stored refusal — this hook's state AND the buffered copy.
|
|
18
|
+
*
|
|
19
|
+
* A refusal is scoped to the scopes that were asked for, not to the block, so
|
|
20
|
+
* it must not latch forever: a block that is refused `ai:write:budgeted` may
|
|
21
|
+
* still legitimately request something else later, and a long-lived block
|
|
22
|
+
* whose host re-inits (sign-in, a new token) can find itself grantable again.
|
|
23
|
+
* Call this when you move on from the refused action.
|
|
24
|
+
*
|
|
25
|
+
* Clearing the BUFFER too is load-bearing, not tidiness: the refusal is
|
|
26
|
+
* retained across mounts (see the hook docblock), so a `reset()` that cleared
|
|
27
|
+
* only local state would be silently undone the next time this hook mounted —
|
|
28
|
+
* the documented "Try again" button would put the refusal straight back.
|
|
29
|
+
*/
|
|
30
|
+
reset: () => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to the host's `CONSENT_UNAVAILABLE` push — the signal that a
|
|
34
|
+
* `REQUEST_CONSENT` this block sent can **never** be granted in this
|
|
35
|
+
* environment, because the scope was clamped or withheld at mint. Distinct from
|
|
36
|
+
* "the viewer hasn't confirmed the dialog yet", which produces no message at
|
|
37
|
+
* all.
|
|
38
|
+
*
|
|
39
|
+
* This is the whole point of the message: without it a block keeps telling the
|
|
40
|
+
* user *"Confirm in the Civitai dialog. If you dismissed it, click Generate
|
|
41
|
+
* again"* while the host says the permission is unavailable — two contradictory
|
|
42
|
+
* messages on one screen, and the misleading one is the block's.
|
|
43
|
+
*
|
|
44
|
+
* 🔴 **PRECONDITION — pass `scopes` to `requestConsent()`, with a real scope
|
|
45
|
+
* name in it.** The refusal is computed from the request's `scopes` hint, and
|
|
46
|
+
* both dev hosts and the real host (`resolveUngrantableConsentNotice`) return
|
|
47
|
+
* "no notice" unless that hint is an array holding AT LEAST ONE NON-EMPTY
|
|
48
|
+
* STRING. Measured on this package's implementation: `undefined`, a non-array,
|
|
49
|
+
* `[]`, `['']` and `[1, 2]` ALL yield `notify: false`, and the real host applies
|
|
50
|
+
* the same `requested.length === 0` guard. So `requestConsent({ scopes: [] })`
|
|
51
|
+
* follows the letter of "always pass scopes" and still produces silence — no
|
|
52
|
+
* grant, no refusal, no error — and this hook sits at `null` forever. The reason
|
|
53
|
+
* is that without a named scope proven un-grantable there is no way to
|
|
54
|
+
* distinguish "never" from "not confirmed yet", and guessing is what produced
|
|
55
|
+
* the contradictory screen. Call `requestConsent({ scopes: ['ai:write:budgeted'] })`.
|
|
56
|
+
*
|
|
57
|
+
* 🔴 **UNCORRELATED, AND THAT IS THE SHAPE OF THE PUBLIC API — not an oversight
|
|
58
|
+
* that can be fixed later.** `REQUEST_CONSENT` carries no `requestId`, so
|
|
59
|
+
* `CONSENT_UNAVAILABLE` is a fire-and-forget push and not a reply. Two
|
|
60
|
+
* consequences a block author has to design around: EVERY mounted
|
|
61
|
+
* `useConsentUnavailable()` observes EVERY refusal, and there is no reliable way
|
|
62
|
+
* to filter one out — `scopes` cannot serve as a correlation key because it may
|
|
63
|
+
* legitimately be `[]` and is in any case only advisory. If two independent
|
|
64
|
+
* parts of your block request different scopes, both will see both refusals;
|
|
65
|
+
* keep the request and its refusal UI in one component, or track which request
|
|
66
|
+
* is outstanding yourself. Nothing here awaits anything — against a host that
|
|
67
|
+
* never sends the message the hook simply stays `null`, which is today's
|
|
68
|
+
* behaviour.
|
|
69
|
+
*
|
|
70
|
+
* 🔴 **A refusal is BUFFERED, so one that arrives while this hook is unmounted
|
|
71
|
+
* is not lost.** The transport delivers an unsolicited push only to handlers
|
|
72
|
+
* registered at the moment it arrives, so without a buffer a refusal that landed
|
|
73
|
+
* before mount (or between unmount and remount) vanished — and a dropped refusal
|
|
74
|
+
* puts back the two-message screen above. `requestConsent()` arms the buffer as
|
|
75
|
+
* it sends, and a mounting hook seeds from it. The buffer holds at most the
|
|
76
|
+
* LATEST refusal, is discarded when the block token changes (its premise is that
|
|
77
|
+
* token's scopes), and is cleared by `reset()`. See
|
|
78
|
+
* `internal/consentRefusalLatch.ts`.
|
|
79
|
+
*
|
|
80
|
+
* The subscription goes through the transport, so the handler runs only after
|
|
81
|
+
* the message has cleared the origin allowlist AND the payload validator; the
|
|
82
|
+
* hook never adds its own `window` listener behind that boundary.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const { requestConsent } = useRequestConsent();
|
|
86
|
+
* const { refusal } = useConsentUnavailable();
|
|
87
|
+
*
|
|
88
|
+
* if (refusal) return <p>Generating isn't available on this page.</p>;
|
|
89
|
+
* return <button onClick={() => requestConsent({ scopes: ['ai:write:budgeted'] })}>Generate</button>;
|
|
90
|
+
*/
|
|
91
|
+
export declare function useConsentUnavailable(): UseConsentUnavailable;
|
|
92
|
+
//# sourceMappingURL=useConsentUnavailable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConsentUnavailable.d.ts","sourceRoot":"","sources":["../../src/hooks/useConsentUnavailable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAUzE,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAE1C,kDAAkD;AAClD,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;OASG;IACH,OAAO,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC1C;;;;;;;;;;;;;OAaG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAgB,qBAAqB,IAAI,qBAAqB,CA+B7D"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { armConsentRefusalLatch, clearConsentRefusalLatch, readConsentRefusalLatch, } from '../internal/consentRefusalLatch.js';
|
|
3
|
+
import { getTransport } from '../internal/singleton.js';
|
|
4
|
+
import { subscribeTyped } from '../internal/transport.js';
|
|
5
|
+
/**
|
|
6
|
+
* Subscribe to the host's `CONSENT_UNAVAILABLE` push — the signal that a
|
|
7
|
+
* `REQUEST_CONSENT` this block sent can **never** be granted in this
|
|
8
|
+
* environment, because the scope was clamped or withheld at mint. Distinct from
|
|
9
|
+
* "the viewer hasn't confirmed the dialog yet", which produces no message at
|
|
10
|
+
* all.
|
|
11
|
+
*
|
|
12
|
+
* This is the whole point of the message: without it a block keeps telling the
|
|
13
|
+
* user *"Confirm in the Civitai dialog. If you dismissed it, click Generate
|
|
14
|
+
* again"* while the host says the permission is unavailable — two contradictory
|
|
15
|
+
* messages on one screen, and the misleading one is the block's.
|
|
16
|
+
*
|
|
17
|
+
* 🔴 **PRECONDITION — pass `scopes` to `requestConsent()`, with a real scope
|
|
18
|
+
* name in it.** The refusal is computed from the request's `scopes` hint, and
|
|
19
|
+
* both dev hosts and the real host (`resolveUngrantableConsentNotice`) return
|
|
20
|
+
* "no notice" unless that hint is an array holding AT LEAST ONE NON-EMPTY
|
|
21
|
+
* STRING. Measured on this package's implementation: `undefined`, a non-array,
|
|
22
|
+
* `[]`, `['']` and `[1, 2]` ALL yield `notify: false`, and the real host applies
|
|
23
|
+
* the same `requested.length === 0` guard. So `requestConsent({ scopes: [] })`
|
|
24
|
+
* follows the letter of "always pass scopes" and still produces silence — no
|
|
25
|
+
* grant, no refusal, no error — and this hook sits at `null` forever. The reason
|
|
26
|
+
* is that without a named scope proven un-grantable there is no way to
|
|
27
|
+
* distinguish "never" from "not confirmed yet", and guessing is what produced
|
|
28
|
+
* the contradictory screen. Call `requestConsent({ scopes: ['ai:write:budgeted'] })`.
|
|
29
|
+
*
|
|
30
|
+
* 🔴 **UNCORRELATED, AND THAT IS THE SHAPE OF THE PUBLIC API — not an oversight
|
|
31
|
+
* that can be fixed later.** `REQUEST_CONSENT` carries no `requestId`, so
|
|
32
|
+
* `CONSENT_UNAVAILABLE` is a fire-and-forget push and not a reply. Two
|
|
33
|
+
* consequences a block author has to design around: EVERY mounted
|
|
34
|
+
* `useConsentUnavailable()` observes EVERY refusal, and there is no reliable way
|
|
35
|
+
* to filter one out — `scopes` cannot serve as a correlation key because it may
|
|
36
|
+
* legitimately be `[]` and is in any case only advisory. If two independent
|
|
37
|
+
* parts of your block request different scopes, both will see both refusals;
|
|
38
|
+
* keep the request and its refusal UI in one component, or track which request
|
|
39
|
+
* is outstanding yourself. Nothing here awaits anything — against a host that
|
|
40
|
+
* never sends the message the hook simply stays `null`, which is today's
|
|
41
|
+
* behaviour.
|
|
42
|
+
*
|
|
43
|
+
* 🔴 **A refusal is BUFFERED, so one that arrives while this hook is unmounted
|
|
44
|
+
* is not lost.** The transport delivers an unsolicited push only to handlers
|
|
45
|
+
* registered at the moment it arrives, so without a buffer a refusal that landed
|
|
46
|
+
* before mount (or between unmount and remount) vanished — and a dropped refusal
|
|
47
|
+
* puts back the two-message screen above. `requestConsent()` arms the buffer as
|
|
48
|
+
* it sends, and a mounting hook seeds from it. The buffer holds at most the
|
|
49
|
+
* LATEST refusal, is discarded when the block token changes (its premise is that
|
|
50
|
+
* token's scopes), and is cleared by `reset()`. See
|
|
51
|
+
* `internal/consentRefusalLatch.ts`.
|
|
52
|
+
*
|
|
53
|
+
* The subscription goes through the transport, so the handler runs only after
|
|
54
|
+
* the message has cleared the origin allowlist AND the payload validator; the
|
|
55
|
+
* hook never adds its own `window` listener behind that boundary.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const { requestConsent } = useRequestConsent();
|
|
59
|
+
* const { refusal } = useConsentUnavailable();
|
|
60
|
+
*
|
|
61
|
+
* if (refusal) return <p>Generating isn't available on this page.</p>;
|
|
62
|
+
* return <button onClick={() => requestConsent({ scopes: ['ai:write:budgeted'] })}>Generate</button>;
|
|
63
|
+
*/
|
|
64
|
+
export function useConsentUnavailable() {
|
|
65
|
+
const [refusal, setRefusal] = useState(null);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const transport = getTransport();
|
|
68
|
+
// Keep recording even while nothing is mounted, and seed from anything
|
|
69
|
+
// recorded before this mount. Seeding in the effect (not lazy `useState`)
|
|
70
|
+
// is deliberate: the latch is armed here too, so the read has to happen
|
|
71
|
+
// after the arm, and an effect is the only place both can be ordered.
|
|
72
|
+
armConsentRefusalLatch(transport);
|
|
73
|
+
const buffered = readConsentRefusalLatch(transport);
|
|
74
|
+
if (buffered)
|
|
75
|
+
setRefusal(buffered);
|
|
76
|
+
// `subscribeTyped` (not the raw `onMessage`) is what makes `payload` a
|
|
77
|
+
// `ConsentUnavailablePayload` here instead of `unknown` + a cast at the call
|
|
78
|
+
// site — the cast is unchecked, so a payload shape change would compile
|
|
79
|
+
// straight through it in every consuming block.
|
|
80
|
+
return subscribeTyped(transport, 'CONSENT_UNAVAILABLE', (payload) => {
|
|
81
|
+
// Store the payload UNCONDITIONALLY. No `payload.scopes.length` gate: an
|
|
82
|
+
// empty `scopes` is a legitimate refusal (see `UseConsentUnavailable`),
|
|
83
|
+
// and gating on it would drop the message this hook exists to deliver.
|
|
84
|
+
setRefusal(payload);
|
|
85
|
+
});
|
|
86
|
+
}, []);
|
|
87
|
+
const reset = useCallback(() => {
|
|
88
|
+
clearConsentRefusalLatch();
|
|
89
|
+
setRefusal(null);
|
|
90
|
+
}, []);
|
|
91
|
+
return { refusal, reset };
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=useConsentUnavailable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConsentUnavailable.js","sourceRoot":"","sources":["../../src/hooks/useConsentUnavailable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAIzD,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAkC1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAmC,IAAI,CAAC,CAAC;IAE/E,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QACjC,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,sEAAsE;QACtE,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,QAAQ;YAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;QAEnC,uEAAuE;QACvE,6EAA6E;QAC7E,wEAAwE;QACxE,gDAAgD;QAChD,OAAO,cAAc,CAAC,SAAS,EAAE,qBAAqB,EAAE,CAAC,OAAO,EAAE,EAAE;YAClE,yEAAyE;YACzE,wEAAwE;YACxE,uEAAuE;YACvE,UAAU,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,wBAAwB,EAAE,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -7,9 +7,27 @@
|
|
|
7
7
|
* the message like every inbound one (origin + `event.source` pinned, only
|
|
8
8
|
* honored after BLOCK_READY) and opens its consent UI.
|
|
9
9
|
*
|
|
10
|
-
* `scopes` is an
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* `scopes` is an advisory hint of which scopes the action needs. It is optional
|
|
11
|
+
* in the signature, and for the GRANT path it genuinely is: the host
|
|
12
|
+
* independently grants the missing set it computed at mint, so a bare
|
|
13
|
+
* `requestConsent()` still opens the consent dialog.
|
|
14
|
+
*
|
|
15
|
+
* 🔴 BUT OMITTING IT DISABLES THE REFUSAL PATH ENTIRELY — pass `scopes`, AND
|
|
16
|
+
* PUT A REAL SCOPE NAME IN IT. The host's `CONSENT_UNAVAILABLE` push (see
|
|
17
|
+
* `useConsentUnavailable`) is computed FROM this hint, and the bar is higher
|
|
18
|
+
* than "an array is present": `resolveUngrantableConsentNotice` returns "no
|
|
19
|
+
* notice" unless the hint is an array containing AT LEAST ONE NON-EMPTY STRING.
|
|
20
|
+
* `undefined`, a non-array, `[]`, `['']` and `[1, 2]` all produce silence —
|
|
21
|
+
* measured on this package's implementation, and the real host has the identical
|
|
22
|
+
* `requested.length === 0` guard, so `requestConsent({ scopes: [] })` obeys the
|
|
23
|
+
* instruction above and STILL gets nothing back. That is deliberate — without a
|
|
24
|
+
* named scope proven un-grantable there is no way to distinguish "can NEVER be
|
|
25
|
+
* granted here" from "the viewer hasn't confirmed the dialog yet", and guessing
|
|
26
|
+
* is what produced the contradictory two-message screen this path exists to
|
|
27
|
+
* remove. The consequence for a block author: call `requestConsent()` bare (or
|
|
28
|
+
* with an empty hint) on an un-grantable surface and you get SILENCE — no grant,
|
|
29
|
+
* no refusal, no error — which reads as a broken message rather than a thin
|
|
30
|
+
* argument.
|
|
13
31
|
*
|
|
14
32
|
* Fire-and-forget: the host doesn't reply. On grant the host re-mints the block
|
|
15
33
|
* token and pushes a TOKEN_REFRESH carrying the now-granted scopes — observe
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRequestConsent.d.ts","sourceRoot":"","sources":["../../src/hooks/useRequestConsent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useRequestConsent.d.ts","sourceRoot":"","sources":["../../src/hooks/useRequestConsent.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;CAC3D,CAeA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
+
import { armConsentRefusalLatch } from '../internal/consentRefusalLatch.js';
|
|
2
3
|
import { getTransport } from '../internal/singleton.js';
|
|
3
4
|
/**
|
|
4
5
|
* Lazy consent. Asks the host to open civitai.com's consent UI when a
|
|
@@ -9,9 +10,27 @@ import { getTransport } from '../internal/singleton.js';
|
|
|
9
10
|
* the message like every inbound one (origin + `event.source` pinned, only
|
|
10
11
|
* honored after BLOCK_READY) and opens its consent UI.
|
|
11
12
|
*
|
|
12
|
-
* `scopes` is an
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* `scopes` is an advisory hint of which scopes the action needs. It is optional
|
|
14
|
+
* in the signature, and for the GRANT path it genuinely is: the host
|
|
15
|
+
* independently grants the missing set it computed at mint, so a bare
|
|
16
|
+
* `requestConsent()` still opens the consent dialog.
|
|
17
|
+
*
|
|
18
|
+
* 🔴 BUT OMITTING IT DISABLES THE REFUSAL PATH ENTIRELY — pass `scopes`, AND
|
|
19
|
+
* PUT A REAL SCOPE NAME IN IT. The host's `CONSENT_UNAVAILABLE` push (see
|
|
20
|
+
* `useConsentUnavailable`) is computed FROM this hint, and the bar is higher
|
|
21
|
+
* than "an array is present": `resolveUngrantableConsentNotice` returns "no
|
|
22
|
+
* notice" unless the hint is an array containing AT LEAST ONE NON-EMPTY STRING.
|
|
23
|
+
* `undefined`, a non-array, `[]`, `['']` and `[1, 2]` all produce silence —
|
|
24
|
+
* measured on this package's implementation, and the real host has the identical
|
|
25
|
+
* `requested.length === 0` guard, so `requestConsent({ scopes: [] })` obeys the
|
|
26
|
+
* instruction above and STILL gets nothing back. That is deliberate — without a
|
|
27
|
+
* named scope proven un-grantable there is no way to distinguish "can NEVER be
|
|
28
|
+
* granted here" from "the viewer hasn't confirmed the dialog yet", and guessing
|
|
29
|
+
* is what produced the contradictory two-message screen this path exists to
|
|
30
|
+
* remove. The consequence for a block author: call `requestConsent()` bare (or
|
|
31
|
+
* with an empty hint) on an un-grantable surface and you get SILENCE — no grant,
|
|
32
|
+
* no refusal, no error — which reads as a broken message rather than a thin
|
|
33
|
+
* argument.
|
|
15
34
|
*
|
|
16
35
|
* Fire-and-forget: the host doesn't reply. On grant the host re-mints the block
|
|
17
36
|
* token and pushes a TOKEN_REFRESH carrying the now-granted scopes — observe
|
|
@@ -25,7 +44,14 @@ import { getTransport } from '../internal/singleton.js';
|
|
|
25
44
|
*/
|
|
26
45
|
export function useRequestConsent() {
|
|
27
46
|
const requestConsent = useCallback((payload) => {
|
|
28
|
-
getTransport()
|
|
47
|
+
const transport = getTransport();
|
|
48
|
+
// Arm the refusal buffer BEFORE the request goes out. A `CONSENT_UNAVAILABLE`
|
|
49
|
+
// can only ever follow a `REQUEST_CONSENT`, and the transport drops an
|
|
50
|
+
// unsolicited push that has no listener at the instant it arrives — so this
|
|
51
|
+
// ordering is what lets a refusal survive until a `useConsentUnavailable()`
|
|
52
|
+
// mounts, instead of requiring one to already be mounted. Idempotent.
|
|
53
|
+
armConsentRefusalLatch(transport);
|
|
54
|
+
transport.sendMessage({
|
|
29
55
|
type: 'REQUEST_CONSENT',
|
|
30
56
|
...(payload ? { payload } : {}),
|
|
31
57
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRequestConsent.js","sourceRoot":"","sources":["../../src/hooks/useRequestConsent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"useRequestConsent.js","sourceRoot":"","sources":["../../src/hooks/useRequestConsent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,UAAU,iBAAiB;IAG/B,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,OAA+B,EAAE,EAAE;QACrE,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QACjC,8EAA8E;QAC9E,uEAAuE;QACvE,4EAA4E;QAC5E,4EAA4E;QAC5E,sEAAsE;QACtE,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAClC,SAAS,CAAC,WAAW,CAAC;YACpB,IAAI,EAAE,iBAAiB;YACvB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,EAAE,cAAc,EAAE,CAAC;AAC5B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,8 @@ export { GENERATION_RESOURCES_API_BASE, MAX_GENERATION_RESOURCE_IDS, buildGenera
|
|
|
56
56
|
export { useCivitaiNavigate } from './hooks/useCivitaiNavigate.js';
|
|
57
57
|
export { useRequestSignIn } from './hooks/useRequestSignIn.js';
|
|
58
58
|
export { useRequestConsent } from './hooks/useRequestConsent.js';
|
|
59
|
+
export { useConsentUnavailable } from './hooks/useConsentUnavailable.js';
|
|
60
|
+
export type { UseConsentUnavailable, ConsentUnavailablePayload, } from './hooks/useConsentUnavailable.js';
|
|
59
61
|
export { useBlockAnalytics } from './hooks/useBlockAnalytics.js';
|
|
60
62
|
export { useDomainMaturity } from './hooks/useDomainMaturity.js';
|
|
61
63
|
export type { DomainMaturity } from './hooks/useDomainMaturity.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;AAQH,OAAO,+BAA+B,CAAC;AAEvC,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,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,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,0BAA0B,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACzF,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAChF,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,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC5E,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,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,YAAY,EACV,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,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
|
@@ -46,6 +46,7 @@ export { GENERATION_RESOURCES_API_BASE, MAX_GENERATION_RESOURCE_IDS, buildGenera
|
|
|
46
46
|
export { useCivitaiNavigate } from './hooks/useCivitaiNavigate.js';
|
|
47
47
|
export { useRequestSignIn } from './hooks/useRequestSignIn.js';
|
|
48
48
|
export { useRequestConsent } from './hooks/useRequestConsent.js';
|
|
49
|
+
export { useConsentUnavailable } from './hooks/useConsentUnavailable.js';
|
|
49
50
|
export { useBlockAnalytics } from './hooks/useBlockAnalytics.js';
|
|
50
51
|
export { useDomainMaturity } from './hooks/useDomainMaturity.js';
|
|
51
52
|
export { SfwGate } from './hooks/SfwGate.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,8EAA8E;AAC9E,mEAAmE;AACnE,yEAAyE;AACzE,6EAA6E;AAC7E,+EAA+E;AAC/E,yEAAyE;AACzE,OAAO,+BAA+B,CAAC;AAEvC,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,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,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,0BAA0B,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAEzF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,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;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAavD,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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,8EAA8E;AAC9E,mEAAmE;AACnE,yEAAyE;AACzE,6EAA6E;AAC7E,+EAA+E;AAC/E,yEAAyE;AACzE,OAAO,+BAA+B,CAAC;AAEvC,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,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,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,0BAA0B,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAEzF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,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;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAavD,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,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAKzE,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,71 @@
|
|
|
1
|
+
import type { ConsentUnavailablePayload } from '@civitai/app-sdk/blocks';
|
|
2
|
+
/** Whether `scope` is one of the fixed platform block scopes. */
|
|
3
|
+
export declare function isKnownBlockScope(scope: string): boolean;
|
|
4
|
+
/** What an un-grantable `REQUEST_CONSENT` should produce on a dev host. */
|
|
5
|
+
export interface UngrantableConsentNotice {
|
|
6
|
+
/**
|
|
7
|
+
* Whether the refusal is surfaced at all. Computed on the UNFILTERED
|
|
8
|
+
* un-grantable set, so a scope outside the known vocabulary still refuses out
|
|
9
|
+
* loud instead of vanishing.
|
|
10
|
+
*/
|
|
11
|
+
notify: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The refused scopes safe to NAME back to the block — the un-grantable subset
|
|
14
|
+
* filtered to the known vocabulary, sorted + deduped. CAN legitimately be
|
|
15
|
+
* EMPTY while `notify` is true.
|
|
16
|
+
*/
|
|
17
|
+
scopes: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Decide what a `REQUEST_CONSENT` that CANNOT be granted should produce.
|
|
21
|
+
*
|
|
22
|
+
* 🔴 THIS MIRRORS THE REAL HOST — `resolveUngrantableConsentNotice` in
|
|
23
|
+
* civitai/civitai's `src/components/AppBlocks/pageBlockHostLogic.ts` (#3733).
|
|
24
|
+
* Both dev hosts route through this one function so `pnpm dev` cannot disagree
|
|
25
|
+
* with production about WHEN the refusal fires or WHAT it names; a dev host that
|
|
26
|
+
* quietly diverges here is how the original bug survived — the developer-visible
|
|
27
|
+
* failure was untestable locally, so nobody exercised it.
|
|
28
|
+
*
|
|
29
|
+
* TWO SETS, NOT ONE, and the split is load-bearing:
|
|
30
|
+
*
|
|
31
|
+
* - `notify` is decided on the un-grantable set BEFORE any vocabulary filter.
|
|
32
|
+
* The un-grantable set is the TRIGGER as well as the payload, so filtering it
|
|
33
|
+
* would make a request for an un-grantable scope the vocabulary doesn't know
|
|
34
|
+
* produce no message at all — silently deleting the refusal in the name of
|
|
35
|
+
* sanitising it. That regression is the reason the host's own first cut was
|
|
36
|
+
* revised, and it is why a test here asserts a garbage-only request STILL
|
|
37
|
+
* notifies.
|
|
38
|
+
* - `scopes` is that set filtered to the known vocabulary, because
|
|
39
|
+
* `rawScopesHint` is whatever the block's own frame posted (markup, junk, a
|
|
40
|
+
* 5 KB string) and the resulting payload is handed to block UI to render.
|
|
41
|
+
*
|
|
42
|
+
* Returns `notify: false` in three cases, and the second is wider than "absent
|
|
43
|
+
* or not an array" — the phrasing the SDK docs used to carry:
|
|
44
|
+
*
|
|
45
|
+
* 1. the hint is absent or not an array;
|
|
46
|
+
* 2. the hint IS an array but holds no non-empty string — `[]`, `['']`,
|
|
47
|
+
* `[1, 2]` all fall here, so a caller that dutifully passes `scopes: []`
|
|
48
|
+
* gets the same silence as one that passes nothing;
|
|
49
|
+
* 3. everything requested is already granted or still grantable via consent.
|
|
50
|
+
*
|
|
51
|
+
* The caller then keeps the silent no-op. Without an explicit requested scope
|
|
52
|
+
* proven un-grantable there is no way to tell "not confirmed yet" from "never",
|
|
53
|
+
* and guessing is what produced the contradictory two-message screen.
|
|
54
|
+
*
|
|
55
|
+
* @param rawScopesHint the block's advisory `REQUEST_CONSENT` `payload.scopes` —
|
|
56
|
+
* UNTRUSTED, arbitrary `unknown`.
|
|
57
|
+
* @param grantedScopes scopes the block's current token already carries.
|
|
58
|
+
* @param grantableScopes scopes this host could still add via a consent
|
|
59
|
+
* round-trip (the host's `missingScopes`). Empty on a host that can grant
|
|
60
|
+
* nothing at all — e.g. `createLiveHost`, which has no consent UI to open.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveUngrantableConsentNotice(rawScopesHint: unknown, grantedScopes: readonly string[], grantableScopes: readonly string[]): UngrantableConsentNotice;
|
|
63
|
+
/**
|
|
64
|
+
* Build the `CONSENT_UNAVAILABLE` payload for a notice produced above.
|
|
65
|
+
*
|
|
66
|
+
* Exists so both dev hosts spell the wire shape ONCE — `reason` is a typed
|
|
67
|
+
* literal, not a string a second call site can typo into a value no consumer
|
|
68
|
+
* branches on.
|
|
69
|
+
*/
|
|
70
|
+
export declare function consentUnavailablePayload(notice: UngrantableConsentNotice): ConsentUnavailablePayload;
|
|
71
|
+
//# sourceMappingURL=consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/internal/consent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAkBzE,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,2EAA2E;AAC3E,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,eAAe,EAAE,SAAS,MAAM,EAAE,GACjC,wBAAwB,CAc1B;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,wBAAwB,GAC/B,yBAAyB,CAE3B"}
|