@xenosystem/blocks 0.13.14 → 0.13.16
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/dist/trust/index.d.ts +121 -17
- package/dist/trust/index.js +339 -198
- package/package.json +3 -3
package/dist/trust/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PanelModule, PanelManifest } from '@xenosystem/block-sdk';
|
|
1
|
+
import { PanelModule, PanelManifest, BlockDeclaration } from '@xenosystem/block-sdk';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -750,31 +750,135 @@ declare const CONSENT_PANEL_ID = "xeno.core.consent";
|
|
|
750
750
|
declare const consentManifest: PanelManifest;
|
|
751
751
|
|
|
752
752
|
/**
|
|
753
|
-
* The Consent panel
|
|
753
|
+
* The Consent panel AS A DECLARATION — the seventeenth declared block: one elicitation at a time,
|
|
754
|
+
* a PERMISSION (scopes + how long) or a QUESTION (options and/or a typed answer), never in bulk.
|
|
755
|
+
*
|
|
756
|
+
* Everything drawn is data: the header (risk and kind badges, the subject, the waiting count), the
|
|
757
|
+
* request (title, detail, its facts as `KeyValue`s), the permission's scope rows with a `Toggle`
|
|
758
|
+
* each and the duration control, or the question's option rows and the answer field with its
|
|
759
|
+
* length counter, Deny / Allow or Cancel / Submit, the status bar with the expiry. Every rule the
|
|
760
|
+
* code view carried survives: a question has no "deny" — refusing is a CANCELLATION, and the two
|
|
761
|
+
* are different outcomes for the host; no auto-focus on Allow, so a stray Enter grants nothing;
|
|
762
|
+
* the button's `disabled` is the SAME predicate `submit()` enforces. No runtime-bound unit.
|
|
763
|
+
*/
|
|
764
|
+
|
|
765
|
+
type Tone = 'neutral' | 'warning' | 'error';
|
|
766
|
+
interface ConsentViewFact {
|
|
767
|
+
key: string;
|
|
768
|
+
value: string;
|
|
769
|
+
}
|
|
770
|
+
interface ConsentViewScope {
|
|
771
|
+
id: string;
|
|
772
|
+
label: string;
|
|
773
|
+
detail?: string; /** a two-line row needs its height — the unit's default row clips the detail */
|
|
774
|
+
height?: number;
|
|
775
|
+
risk?: string;
|
|
776
|
+
riskTone: Tone;
|
|
777
|
+
granted: boolean;
|
|
778
|
+
grantable: boolean;
|
|
779
|
+
toggleLabel: string;
|
|
780
|
+
selected: boolean;
|
|
781
|
+
}
|
|
782
|
+
interface ConsentViewOption {
|
|
783
|
+
id: string;
|
|
784
|
+
label: string;
|
|
785
|
+
detail?: string;
|
|
786
|
+
height?: number;
|
|
787
|
+
risk?: string;
|
|
788
|
+
riskTone: Tone;
|
|
789
|
+
toggleLabel: string;
|
|
790
|
+
selected: boolean;
|
|
791
|
+
}
|
|
792
|
+
interface ConsentViewModel {
|
|
793
|
+
idle: boolean;
|
|
794
|
+
emptyHint: string;
|
|
795
|
+
active: boolean;
|
|
796
|
+
riskLabel: string;
|
|
797
|
+
riskTone: Tone;
|
|
798
|
+
kindLabel: string;
|
|
799
|
+
subject?: string;
|
|
800
|
+
waiting?: string;
|
|
801
|
+
title: string;
|
|
802
|
+
detail?: string;
|
|
803
|
+
facts: ConsentViewFact[];
|
|
804
|
+
permission: boolean;
|
|
805
|
+
scopes: ConsentViewScope[];
|
|
806
|
+
durations: {
|
|
807
|
+
value: string;
|
|
808
|
+
label: string;
|
|
809
|
+
}[];
|
|
810
|
+
duration: string;
|
|
811
|
+
unrememberable: boolean;
|
|
812
|
+
allowDisabled: boolean;
|
|
813
|
+
question: boolean;
|
|
814
|
+
hasOptions: boolean;
|
|
815
|
+
options: ConsentViewOption[];
|
|
816
|
+
wantsText: boolean;
|
|
817
|
+
textLabel?: string;
|
|
818
|
+
multiline: boolean;
|
|
819
|
+
placeholder: string;
|
|
820
|
+
draft: string;
|
|
821
|
+
hasCounter: boolean;
|
|
822
|
+
counter: string;
|
|
823
|
+
overLimit: boolean;
|
|
824
|
+
submitLabel: string;
|
|
825
|
+
submitDisabled: boolean;
|
|
826
|
+
pendingLabel: string;
|
|
827
|
+
expiryLabel?: string;
|
|
828
|
+
}
|
|
829
|
+
type ConsentUiIntent = {
|
|
830
|
+
kind: 'scope';
|
|
831
|
+
id: string;
|
|
832
|
+
on: boolean;
|
|
833
|
+
} | {
|
|
834
|
+
kind: 'duration';
|
|
835
|
+
duration: XenoConsentDuration;
|
|
836
|
+
} | {
|
|
837
|
+
kind: 'option';
|
|
838
|
+
id: string;
|
|
839
|
+
on: boolean;
|
|
840
|
+
} | {
|
|
841
|
+
kind: 'text';
|
|
842
|
+
value: string;
|
|
843
|
+
} | {
|
|
844
|
+
kind: 'allow';
|
|
845
|
+
} | {
|
|
846
|
+
kind: 'deny';
|
|
847
|
+
} | {
|
|
848
|
+
kind: 'submit';
|
|
849
|
+
} | {
|
|
850
|
+
kind: 'dismiss';
|
|
851
|
+
};
|
|
852
|
+
interface ConsentViewOptions {
|
|
853
|
+
showQueueCount?: boolean;
|
|
854
|
+
emptyHint?: string;
|
|
855
|
+
}
|
|
856
|
+
/** Derive the view from the live controller — the runtime calls this on every draw. */
|
|
857
|
+
declare function consentViewState(c: ConsentController, options?: ConsentViewOptions): ConsentViewModel;
|
|
858
|
+
declare function applyConsentUi(c: ConsentController, intent: ConsentUiIntent): void;
|
|
859
|
+
declare const consentViewManifest: PanelManifest;
|
|
860
|
+
declare const BEHAVIOURS: {
|
|
861
|
+
'trust/consentPanelView': (inputs: Record<string, unknown>) => ConsentViewModel;
|
|
862
|
+
};
|
|
863
|
+
declare const CONSENT_RUNTIME_UNITS: readonly [];
|
|
864
|
+
declare const CONSENT_DECLARATION: BlockDeclaration;
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* The Consent panel view — the CODE VIEW of `CONSENT_DECLARATION`, drawing the same
|
|
868
|
+
* `ConsentViewModel` byte-identical (the equivalence suite holds the two together). No runtime-bound
|
|
869
|
+
* unit; every intent goes through `applyConsentUi`.
|
|
754
870
|
*
|
|
755
871
|
* Composes `@xenosystem/components/chrome`; the host must ensure `@xenosystem/workbench/primitives.css` is
|
|
756
872
|
* present.
|
|
757
873
|
*
|
|
758
|
-
* Two deliberate absences: **no "Allow all"** (bulk approval is how consent fatigue becomes a
|
|
759
|
-
* security hole) and **no auto-focus on Allow** (a stray Enter must not grant anything).
|
|
760
|
-
*
|
|
761
|
-
* 🔴 **A third absence, added with the question kinds: nothing here submits on its own.** The
|
|
762
|
-
* question forms carry no auto-submit, no debounce-then-send, and no Enter-to-answer on the
|
|
763
|
-
* single-line field. The emitted answer is always the product of a click the user made, which is
|
|
764
|
-
* the view's half of the controller's *"no value without a user action"* invariant — the guard
|
|
765
|
-
* lives in `submit()`, but a view that fired it on a keystroke would satisfy the guard while
|
|
766
|
-
* defeating the point.
|
|
767
|
-
*
|
|
768
874
|
* @module
|
|
769
875
|
*/
|
|
770
876
|
|
|
771
877
|
/** Props for {@link ConsentPanelView}. */
|
|
772
|
-
interface ConsentPanelViewProps {
|
|
878
|
+
interface ConsentPanelViewProps extends ConsentViewOptions {
|
|
773
879
|
controller: ConsentController;
|
|
774
|
-
showQueueCount?: boolean;
|
|
775
|
-
emptyHint?: string;
|
|
776
880
|
}
|
|
777
881
|
/** The Consent panel view. */
|
|
778
|
-
declare function ConsentPanelView({ controller, showQueueCount, emptyHint
|
|
882
|
+
declare function ConsentPanelView({ controller, showQueueCount, emptyHint }: ConsentPanelViewProps): ReactNode;
|
|
779
883
|
|
|
780
|
-
export { CONSENT_PANEL_ID, ConsentController, type ConsentControllerOptions, type ConsentHostBridge, type ConsentPanelState, ConsentPanelView, type ConsentPanelViewProps, type ConsentRenderContext, type ConsentViewState, type CreateConsentPanelOptions, ELICITATION_RESULT_SCHEMA, ELICITATION_SCHEMA, type XenoChoiceAnswer, type XenoChoiceElicitation, type XenoConsentDecision, type XenoConsentDuration, type XenoConsentKind, type XenoConsentRequest, type XenoConsentRisk, type XenoConsentScope, type XenoElicitation, type XenoElicitationAnswer, type XenoElicitationAsk, type XenoElicitationBase, type XenoElicitationCancelled, type XenoElicitationOption, type XenoElicitationResult, type XenoPathAnswer, type XenoPathElicitation, type XenoQuestionElicitation, type XenoTextAnswer, type XenoTextElicitation, allowedDurations, autoCancel, autoDeny, consentManifest, consentPanel, createConsentPanel, effectiveRisk, elicitationAsk, elicitationOptions, findOption, isConsentRequest, isElicitation, isElicitationAnswer, isElicitationCancelled, isExpired, isPermissionElicitation, maxTextLength, selectableScopes };
|
|
884
|
+
export { BEHAVIOURS as CONSENT_BEHAVIOURS, CONSENT_DECLARATION, CONSENT_PANEL_ID, CONSENT_RUNTIME_UNITS, ConsentController, type ConsentControllerOptions, type ConsentHostBridge, type ConsentPanelState, ConsentPanelView, type ConsentPanelViewProps, type ConsentRenderContext, type ConsentUiIntent, type ConsentViewFact, type ConsentViewModel, type ConsentViewOption, type ConsentViewOptions, type ConsentViewScope, type ConsentViewState, type CreateConsentPanelOptions, ELICITATION_RESULT_SCHEMA, ELICITATION_SCHEMA, type XenoChoiceAnswer, type XenoChoiceElicitation, type XenoConsentDecision, type XenoConsentDuration, type XenoConsentKind, type XenoConsentRequest, type XenoConsentRisk, type XenoConsentScope, type XenoElicitation, type XenoElicitationAnswer, type XenoElicitationAsk, type XenoElicitationBase, type XenoElicitationCancelled, type XenoElicitationOption, type XenoElicitationResult, type XenoPathAnswer, type XenoPathElicitation, type XenoQuestionElicitation, type XenoTextAnswer, type XenoTextElicitation, allowedDurations, applyConsentUi, autoCancel, autoDeny, consentManifest, consentPanel, consentViewManifest, consentViewState, createConsentPanel, effectiveRisk, elicitationAsk, elicitationOptions, findOption, isConsentRequest, isElicitation, isElicitationAnswer, isElicitationCancelled, isExpired, isPermissionElicitation, maxTextLength, selectableScopes };
|
package/dist/trust/index.js
CHANGED
|
@@ -661,234 +661,369 @@ var consentManifest = {
|
|
|
661
661
|
import { useSyncExternalStore } from "react";
|
|
662
662
|
import {
|
|
663
663
|
Badge,
|
|
664
|
+
Column,
|
|
664
665
|
EmptyState,
|
|
666
|
+
Input,
|
|
667
|
+
KeyValue,
|
|
665
668
|
Row,
|
|
666
669
|
RowList,
|
|
667
670
|
ScrollArea,
|
|
668
671
|
SegmentedControl,
|
|
672
|
+
Stack,
|
|
669
673
|
StatusBar,
|
|
674
|
+
Text,
|
|
675
|
+
TextArea,
|
|
670
676
|
TextButton,
|
|
671
677
|
Toggle,
|
|
672
678
|
Toolbar,
|
|
673
679
|
ToolbarGroup
|
|
674
680
|
} from "@xenosystem/components/chrome";
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
medium: "warning",
|
|
679
|
-
high: "error"
|
|
680
|
-
};
|
|
681
|
+
|
|
682
|
+
// src/trust/consent/declaration.ts
|
|
683
|
+
var RISK_TONE = { low: "neutral", medium: "warning", high: "error" };
|
|
681
684
|
var DURATION_LABEL = { once: "Once", session: "Session", always: "Always" };
|
|
682
|
-
var
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
color: "inherit",
|
|
690
|
-
// 🔴 Text entry never takes the global focus ring: `outline-offset` draws it OUTSIDE the field,
|
|
691
|
-
// so on dark chrome it reads as a stray stroke over the container and the control looks broken.
|
|
692
|
-
outline: "none",
|
|
693
|
-
resize: "none"
|
|
694
|
-
};
|
|
695
|
-
var SUBMIT_LABEL = {
|
|
696
|
-
text: "Submit",
|
|
697
|
-
path: "Use this path",
|
|
698
|
-
choice: "Confirm"
|
|
699
|
-
};
|
|
700
|
-
function ConsentPanelView({
|
|
701
|
-
controller,
|
|
702
|
-
showQueueCount = true,
|
|
703
|
-
emptyHint
|
|
704
|
-
}) {
|
|
705
|
-
const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
706
|
-
const request = state.current;
|
|
685
|
+
var SUBMIT_LABEL = { text: "Submit", path: "Use this path", choice: "Confirm" };
|
|
686
|
+
function consentViewState(c, options = {}) {
|
|
687
|
+
const s = c.getState();
|
|
688
|
+
const request = s.current;
|
|
689
|
+
const showQueueCount = options.showQueueCount ?? true;
|
|
690
|
+
const emptyHint = options.emptyHint ?? "Requests needing your approval appear here.";
|
|
691
|
+
const base = { idle: !request, emptyHint, active: !!request };
|
|
707
692
|
if (!request) {
|
|
708
|
-
return
|
|
709
|
-
EmptyState,
|
|
710
|
-
{
|
|
711
|
-
title: "Nothing pending",
|
|
712
|
-
hint: emptyHint ?? "Requests needing your approval appear here."
|
|
713
|
-
}
|
|
714
|
-
);
|
|
693
|
+
return { ...base, riskLabel: "", riskTone: "neutral", kindLabel: "", title: "", facts: [], permission: false, scopes: [], durations: [], duration: "once", unrememberable: false, allowDisabled: true, question: false, hasOptions: false, options: [], wantsText: false, multiline: false, placeholder: "", draft: "", hasCounter: false, counter: "", overLimit: false, submitLabel: "Submit", submitDisabled: true, pendingLabel: `${s.pending} pending` };
|
|
715
694
|
}
|
|
716
695
|
const risk = effectiveRisk(request);
|
|
717
696
|
const ask = elicitationAsk(request);
|
|
718
697
|
const permission = isPermissionElicitation(request) ? request : null;
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
698
|
+
const opts = permission ? [] : elicitationOptions(request);
|
|
699
|
+
const chosen = opts.find((o) => o.id === s.selectedOptionId);
|
|
700
|
+
const max = permission ? null : maxTextLength(request);
|
|
701
|
+
const extra = request;
|
|
702
|
+
const wantsText = !permission && (ask !== "choice" || chosen?.requiresText === true);
|
|
703
|
+
return {
|
|
704
|
+
...base,
|
|
705
|
+
riskLabel: `${risk} risk`,
|
|
706
|
+
riskTone: RISK_TONE[risk],
|
|
707
|
+
kindLabel: permission ? permission.kind : ask,
|
|
708
|
+
subject: request.subject,
|
|
709
|
+
waiting: showQueueCount && s.queued.length > 0 ? `+${s.queued.length} waiting` : void 0,
|
|
710
|
+
title: request.title,
|
|
711
|
+
detail: request.detail,
|
|
712
|
+
facts: request.fields ? Object.entries(request.fields).map(([key, value]) => ({ key, value: String(value) })) : [],
|
|
713
|
+
permission: !!permission,
|
|
714
|
+
scopes: permission ? permission.scopes.map((scope) => ({
|
|
715
|
+
id: scope.id,
|
|
716
|
+
label: scope.label,
|
|
717
|
+
detail: scope.detail,
|
|
718
|
+
height: scope.detail ? 36 : void 0,
|
|
719
|
+
risk: scope.risk && scope.risk !== risk ? scope.risk : void 0,
|
|
720
|
+
riskTone: scope.risk ? RISK_TONE[scope.risk] : "neutral",
|
|
721
|
+
granted: scope.alreadyGranted === true,
|
|
722
|
+
grantable: scope.alreadyGranted !== true,
|
|
723
|
+
toggleLabel: `Grant ${scope.label}`,
|
|
724
|
+
selected: s.selectedScopeIds.includes(scope.id)
|
|
725
|
+
})) : [],
|
|
726
|
+
durations: permission ? allowedDurations(permission).map((d) => ({ value: d, label: DURATION_LABEL[d] })) : [],
|
|
727
|
+
duration: s.duration,
|
|
728
|
+
unrememberable: permission?.remember === "forbidden",
|
|
729
|
+
allowDisabled: !!permission && permission.scopes.some((sc) => !sc.alreadyGranted) && s.selectedScopeIds.length === 0,
|
|
730
|
+
question: !permission,
|
|
731
|
+
hasOptions: opts.length > 0,
|
|
732
|
+
options: opts.map((option) => ({
|
|
733
|
+
id: option.id,
|
|
734
|
+
label: option.label,
|
|
735
|
+
detail: option.detail,
|
|
736
|
+
height: option.detail ? 36 : void 0,
|
|
737
|
+
risk: option.risk && option.risk !== risk ? option.risk : void 0,
|
|
738
|
+
riskTone: option.risk ? RISK_TONE[option.risk] : "neutral",
|
|
739
|
+
toggleLabel: `Choose ${option.label}`,
|
|
740
|
+
selected: s.selectedOptionId === option.id
|
|
741
|
+
})),
|
|
742
|
+
wantsText,
|
|
743
|
+
textLabel: extra.textLabel,
|
|
744
|
+
multiline: ask === "text" && extra.multiline === true,
|
|
745
|
+
placeholder: extra.placeholder ?? (ask === "path" ? "Type or paste a path\u2026" : "Type your answer\u2026"),
|
|
746
|
+
draft: s.draftText,
|
|
747
|
+
hasCounter: max !== null,
|
|
748
|
+
counter: max !== null ? `${s.draftText.length} / ${max}` : "",
|
|
749
|
+
overLimit: max !== null && s.draftText.length > max,
|
|
750
|
+
submitLabel: SUBMIT_LABEL[ask] ?? "Submit",
|
|
751
|
+
submitDisabled: !s.canSubmit,
|
|
752
|
+
pendingLabel: `${s.pending} pending`,
|
|
753
|
+
expiryLabel: s.expiresInMs !== null ? `expires in ${Math.ceil(s.expiresInMs / 1e3)}s \u2014 ${permission ? "denies" : "cancels"}` : void 0
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
function applyConsentUi(c, intent) {
|
|
757
|
+
switch (intent.kind) {
|
|
758
|
+
case "scope":
|
|
759
|
+
c.toggleScope(intent.id, intent.on);
|
|
760
|
+
break;
|
|
761
|
+
case "duration":
|
|
762
|
+
c.setDuration(intent.duration);
|
|
763
|
+
break;
|
|
764
|
+
case "option":
|
|
765
|
+
c.selectOption(intent.on ? intent.id : null);
|
|
766
|
+
break;
|
|
767
|
+
case "text":
|
|
768
|
+
c.setDraftText(intent.value);
|
|
769
|
+
break;
|
|
770
|
+
case "allow":
|
|
771
|
+
c.allow();
|
|
772
|
+
break;
|
|
773
|
+
case "deny":
|
|
774
|
+
c.deny();
|
|
775
|
+
break;
|
|
776
|
+
case "submit":
|
|
777
|
+
c.submit();
|
|
778
|
+
break;
|
|
779
|
+
case "dismiss":
|
|
780
|
+
c.dismiss();
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
var consentViewManifest = {
|
|
785
|
+
id: consentManifest.id,
|
|
786
|
+
version: "1.0.0",
|
|
787
|
+
title: "Consent",
|
|
788
|
+
category: "trust",
|
|
789
|
+
layout: { slot: "side" },
|
|
790
|
+
inputs: [{ id: "view", type: "object", label: "View state", description: "The ConsentViewModel the runtime derives from the controller on every draw." }],
|
|
791
|
+
outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
|
|
792
|
+
commands: []
|
|
793
|
+
};
|
|
794
|
+
var EMPTY = { idle: true, emptyHint: "Requests needing your approval appear here.", active: false, riskLabel: "", riskTone: "neutral", kindLabel: "", title: "", facts: [], permission: false, scopes: [], durations: [], duration: "once", unrememberable: false, allowDisabled: true, question: false, hasOptions: false, options: [], wantsText: false, multiline: false, placeholder: "", draft: "", hasCounter: false, counter: "", overLimit: false, submitLabel: "Submit", submitDisabled: true, pendingLabel: "0 pending" };
|
|
795
|
+
var BEHAVIOURS = {
|
|
796
|
+
"trust/consentPanelView": (inputs) => inputs.view ?? EMPTY
|
|
797
|
+
};
|
|
798
|
+
var CONSENT_RUNTIME_UNITS = [];
|
|
799
|
+
var text = (b) => ({ component: "text", props: { text: b } });
|
|
800
|
+
var ui = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
|
|
801
|
+
var twoLine = {
|
|
802
|
+
component: "chrome/Stack",
|
|
803
|
+
props: { gap: { value: 1 }, pad: { value: "none" } },
|
|
804
|
+
children: [{ component: "chrome/Text", children: [text({ item: "label" })] }, { component: "chrome/Text", when: { item: "detail" }, props: { role: { value: "meta" } }, children: [text({ item: "detail" })] }]
|
|
805
|
+
};
|
|
806
|
+
var riskMeta = { node: { component: "chrome/Badge", when: { item: "risk" }, props: { tone: { item: "riskTone" } }, children: [text({ item: "risk" })] } };
|
|
807
|
+
var CONSENT_DECLARATION = {
|
|
808
|
+
format: "xeno.block@1",
|
|
809
|
+
manifest: consentViewManifest,
|
|
810
|
+
behaviour: "trust/consentPanelView",
|
|
811
|
+
composition: {
|
|
812
|
+
component: "fragment",
|
|
813
|
+
children: [
|
|
814
|
+
{ component: "chrome/EmptyState", when: { input: "view.idle" }, props: { title: { value: "Nothing pending" }, hint: { input: "view.emptyHint" } } },
|
|
722
815
|
{
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
/* @__PURE__ */ jsx("code", { style: { userSelect: "all", wordBreak: "break-all" }, children: value })
|
|
741
|
-
] }, key)) : null
|
|
742
|
-
] }),
|
|
743
|
-
permission ? /* @__PURE__ */ jsx(RowList, { children: permission.scopes.map((scope) => /* @__PURE__ */ jsx(
|
|
744
|
-
Row,
|
|
745
|
-
{
|
|
746
|
-
noIcon: true,
|
|
747
|
-
label: /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column", gap: 1, minWidth: 0 }, children: [
|
|
748
|
-
/* @__PURE__ */ jsx("span", { children: scope.label }),
|
|
749
|
-
scope.detail ? /* @__PURE__ */ jsx("span", { style: { fontSize: 10, opacity: 0.6 }, children: scope.detail }) : null
|
|
750
|
-
] }),
|
|
751
|
-
meta: scope.risk && scope.risk !== risk ? /* @__PURE__ */ jsx(Badge, { tone: RISK_TONE[scope.risk], children: scope.risk }) : null,
|
|
752
|
-
trailing: scope.alreadyGranted ? (
|
|
753
|
-
// Shown for context, not as a choice — hiding it would make the new ask look
|
|
754
|
-
// bigger than it is.
|
|
755
|
-
/* @__PURE__ */ jsx(Badge, { title: "Already granted", children: "granted" })
|
|
756
|
-
) : /* @__PURE__ */ jsx(
|
|
757
|
-
Toggle,
|
|
758
|
-
{
|
|
759
|
-
size: "sm",
|
|
760
|
-
label: `Grant ${scope.label}`,
|
|
761
|
-
checked: state.selectedScopeIds.includes(scope.id),
|
|
762
|
-
onChange: (next) => controller.toggleScope(scope.id, next)
|
|
816
|
+
component: "chrome/Column",
|
|
817
|
+
when: { input: "view.active" },
|
|
818
|
+
children: [
|
|
819
|
+
{
|
|
820
|
+
component: "chrome/Toolbar",
|
|
821
|
+
props: {
|
|
822
|
+
left: {
|
|
823
|
+
node: {
|
|
824
|
+
component: "fragment",
|
|
825
|
+
children: [
|
|
826
|
+
{ component: "chrome/Badge", props: { tone: { input: "view.riskTone" } }, children: [text({ input: "view.riskLabel" })] },
|
|
827
|
+
{ component: "chrome/Badge", children: [text({ input: "view.kindLabel" })] },
|
|
828
|
+
{ component: "chrome/Text", when: { input: "view.subject" }, children: [text({ input: "view.subject" })] }
|
|
829
|
+
]
|
|
830
|
+
}
|
|
831
|
+
},
|
|
832
|
+
right: { node: { component: "chrome/ToolbarGroup", when: { input: "view.waiting" }, props: { end: { value: true } }, children: [{ component: "chrome/Badge", props: { title: { value: "Answered one at a time \u2014 never in bulk." } }, children: [text({ input: "view.waiting" })] }] } }
|
|
763
833
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
component: "chrome/ScrollArea",
|
|
837
|
+
children: [
|
|
838
|
+
{
|
|
839
|
+
component: "chrome/Stack",
|
|
840
|
+
props: { gap: { value: 6 }, pad: { value: "gutter" } },
|
|
841
|
+
children: [
|
|
842
|
+
{ component: "chrome/Text", props: { role: { value: "title" } }, children: [text({ input: "view.title" })] },
|
|
843
|
+
{ component: "chrome/Text", when: { input: "view.detail" }, children: [text({ input: "view.detail" })] },
|
|
844
|
+
{ component: "chrome/KeyValue", each: { input: "view.facts", key: "key" }, props: { name: { item: "key" }, value: { item: "value" } } }
|
|
845
|
+
]
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
component: "chrome/RowList",
|
|
849
|
+
when: { input: "view.permission" },
|
|
850
|
+
children: [
|
|
851
|
+
{
|
|
852
|
+
component: "chrome/Row",
|
|
853
|
+
each: { input: "view.scopes", key: "id" },
|
|
854
|
+
props: {
|
|
855
|
+
noIcon: { value: true },
|
|
856
|
+
height: { item: "height" },
|
|
857
|
+
label: { node: twoLine },
|
|
858
|
+
meta: riskMeta,
|
|
859
|
+
trailing: {
|
|
860
|
+
node: {
|
|
861
|
+
component: "fragment",
|
|
862
|
+
children: [
|
|
863
|
+
{ component: "chrome/Badge", when: { item: "granted" }, props: { title: { value: "Already granted" } }, children: [text({ value: "granted" })] },
|
|
864
|
+
{ component: "chrome/Toggle", when: { item: "grantable" }, props: { size: { value: "sm" }, label: { item: "toggleLabel" }, checked: { item: "selected" } }, on: { onChange: ui("scope", { id: { item: "id" }, on: { arg: "" } }) } }
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
]
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
component: "chrome/Stack",
|
|
874
|
+
when: { input: "view.question" },
|
|
875
|
+
props: { gap: { value: 6 }, pad: { value: "inset" } },
|
|
876
|
+
children: [
|
|
877
|
+
{
|
|
878
|
+
component: "chrome/RowList",
|
|
879
|
+
when: { input: "view.hasOptions" },
|
|
880
|
+
children: [
|
|
881
|
+
{
|
|
882
|
+
component: "chrome/Row",
|
|
883
|
+
each: { input: "view.options", key: "id" },
|
|
884
|
+
props: { noIcon: { value: true }, height: { item: "height" }, label: { node: twoLine }, meta: riskMeta, trailing: { node: { component: "chrome/Toggle", props: { size: { value: "sm" }, label: { item: "toggleLabel" }, checked: { item: "selected" } }, on: { onChange: ui("option", { id: { item: "id" }, on: { arg: "" } }) } } } }
|
|
885
|
+
}
|
|
886
|
+
]
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
component: "chrome/Stack",
|
|
890
|
+
when: { input: "view.wantsText" },
|
|
891
|
+
props: { gap: { value: 3 }, pad: { value: "none" } },
|
|
892
|
+
children: [
|
|
893
|
+
{ component: "chrome/Text", when: { input: "view.textLabel" }, props: { role: { value: "meta" } }, children: [text({ input: "view.textLabel" })] },
|
|
894
|
+
{ component: "chrome/TextArea", when: { input: "view.multiline" }, props: { value: { input: "view.draft" }, placeholder: { input: "view.placeholder" }, rows: { value: 3 }, label: { value: "Answer" } }, on: { onChange: ui("text", { value: { arg: "" } }) } },
|
|
895
|
+
{ component: "chrome/Input", when: { not: { input: "view.multiline" } }, props: { value: { input: "view.draft" }, placeholder: { input: "view.placeholder" }, autoComplete: { value: "off" }, label: { value: "Answer" } }, on: { onChange: ui("text", { value: { arg: "" } }) } },
|
|
896
|
+
{ component: "chrome/Text", when: { input: "view.hasCounter" }, props: { role: { value: "caption" } }, children: [text({ input: "view.counter" })] },
|
|
897
|
+
{ component: "chrome/Badge", when: { input: "view.overLimit" }, props: { tone: { value: "error" } }, children: [text({ value: "too long" })] }
|
|
898
|
+
]
|
|
899
|
+
}
|
|
900
|
+
]
|
|
901
|
+
}
|
|
902
|
+
]
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
component: "chrome/Toolbar",
|
|
906
|
+
when: { input: "view.permission" },
|
|
907
|
+
props: {
|
|
908
|
+
divided: { value: false },
|
|
909
|
+
// Duration is IN the decision, not buried in a settings page.
|
|
910
|
+
left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "How long" }, options: { input: "view.durations" }, value: { input: "view.duration" } }, on: { onChange: ui("duration", { duration: { arg: "" } }) } } },
|
|
911
|
+
right: { node: { component: "chrome/Text", when: { input: "view.unrememberable" }, props: { role: { value: "caption" } }, children: [text({ value: "This grant cannot be remembered." })] } }
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
component: "chrome/Toolbar",
|
|
916
|
+
props: {
|
|
917
|
+
divided: { value: false },
|
|
918
|
+
right: {
|
|
919
|
+
node: {
|
|
920
|
+
component: "chrome/ToolbarGroup",
|
|
921
|
+
props: { end: { value: true } },
|
|
922
|
+
children: [
|
|
923
|
+
{ component: "chrome/TextButton", when: { input: "view.permission" }, on: { onClick: ui("deny") }, children: [text({ value: "Deny" })] },
|
|
924
|
+
// No auto-focus: a stray Enter must not grant anything.
|
|
925
|
+
{ component: "chrome/TextButton", when: { input: "view.permission" }, props: { strong: { value: true }, disabled: { input: "view.allowDisabled" } }, on: { onClick: ui("allow") }, children: [text({ value: "Allow" })] },
|
|
926
|
+
// A question has no "deny" — refusing to answer is a CANCELLATION.
|
|
927
|
+
{ component: "chrome/TextButton", when: { input: "view.question" }, on: { onClick: ui("dismiss") }, children: [text({ value: "Cancel" })] },
|
|
928
|
+
{ component: "chrome/TextButton", when: { input: "view.question" }, props: { strong: { value: true }, disabled: { input: "view.submitDisabled" } }, on: { onClick: ui("submit") }, children: [text({ input: "view.submitLabel" })] }
|
|
929
|
+
]
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
{ component: "chrome/StatusBar", props: { left: { input: "view.pendingLabel" }, right: { input: "view.expiryLabel" } } }
|
|
935
|
+
]
|
|
936
|
+
}
|
|
937
|
+
]
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
// src/trust/consent/react/ConsentPanelView.tsx
|
|
942
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
943
|
+
var TwoLine = ({ label, detail }) => /* @__PURE__ */ jsxs(Stack, { gap: 1, pad: "none", children: [
|
|
944
|
+
/* @__PURE__ */ jsx(Text, { children: label }),
|
|
945
|
+
detail ? /* @__PURE__ */ jsx(Text, { role: "meta", children: detail }) : null
|
|
946
|
+
] });
|
|
947
|
+
function ConsentPanelView({ controller, showQueueCount, emptyHint }) {
|
|
948
|
+
useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
949
|
+
const view = consentViewState(controller, { showQueueCount, emptyHint });
|
|
950
|
+
const ui2 = (intent) => applyConsentUi(controller, intent);
|
|
951
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
952
|
+
view.idle ? /* @__PURE__ */ jsx(EmptyState, { title: "Nothing pending", hint: view.emptyHint }) : null,
|
|
953
|
+
view.active ? /* @__PURE__ */ jsxs(Column, { children: [
|
|
770
954
|
/* @__PURE__ */ jsx(
|
|
771
|
-
|
|
955
|
+
Toolbar,
|
|
772
956
|
{
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
}))
|
|
779
|
-
value: state.duration,
|
|
780
|
-
onChange: (d) => controller.setDuration(d)
|
|
957
|
+
left: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
958
|
+
/* @__PURE__ */ jsx(Badge, { tone: view.riskTone, children: view.riskLabel }),
|
|
959
|
+
/* @__PURE__ */ jsx(Badge, { children: view.kindLabel }),
|
|
960
|
+
view.subject ? /* @__PURE__ */ jsx(Text, { children: view.subject }) : null
|
|
961
|
+
] }),
|
|
962
|
+
right: view.waiting ? /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx(Badge, { title: "Answered one at a time \u2014 never in bulk.", children: view.waiting }) }) : null
|
|
781
963
|
}
|
|
782
964
|
),
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
divided: false,
|
|
789
|
-
right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: permission ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
790
|
-
/* @__PURE__ */ jsx(TextButton, { onClick: () => controller.deny(), children: "Deny" }),
|
|
791
|
-
/* @__PURE__ */ jsx(
|
|
792
|
-
TextButton,
|
|
793
|
-
{
|
|
794
|
-
strong: true,
|
|
795
|
-
disabled: permission.scopes.some((s) => !s.alreadyGranted) && state.selectedScopeIds.length === 0,
|
|
796
|
-
onClick: () => controller.allow(),
|
|
797
|
-
children: "Allow"
|
|
798
|
-
}
|
|
799
|
-
)
|
|
800
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
801
|
-
/* @__PURE__ */ jsx(TextButton, { onClick: () => controller.dismiss(), children: "Cancel" }),
|
|
802
|
-
/* @__PURE__ */ jsx(
|
|
803
|
-
TextButton,
|
|
804
|
-
{
|
|
805
|
-
strong: true,
|
|
806
|
-
disabled: !state.canSubmit,
|
|
807
|
-
onClick: () => controller.submit(),
|
|
808
|
-
children: SUBMIT_LABEL[ask] ?? "Submit"
|
|
809
|
-
}
|
|
810
|
-
)
|
|
811
|
-
] }) })
|
|
812
|
-
}
|
|
813
|
-
),
|
|
814
|
-
/* @__PURE__ */ jsx(
|
|
815
|
-
StatusBar,
|
|
816
|
-
{
|
|
817
|
-
left: `${state.pending} pending`,
|
|
818
|
-
right: state.expiresInMs !== null ? `expires in ${Math.ceil(state.expiresInMs / 1e3)}s \u2014 ${permission ? "denies" : "cancels"}` : void 0
|
|
819
|
-
}
|
|
820
|
-
)
|
|
821
|
-
] });
|
|
822
|
-
}
|
|
823
|
-
function QuestionForm({ controller, request, state, risk }) {
|
|
824
|
-
const ask = elicitationAsk(request);
|
|
825
|
-
const options = elicitationOptions(request);
|
|
826
|
-
const max = maxTextLength(request);
|
|
827
|
-
const chosen = options.find((o) => o.id === state.selectedOptionId);
|
|
828
|
-
const multiline = ask === "text" && request.multiline === true;
|
|
829
|
-
const placeholder = request.placeholder ?? (ask === "path" ? "Type or paste a path\u2026" : "Type your answer\u2026");
|
|
830
|
-
const wantsText = ask !== "choice" || chosen?.requiresText === true;
|
|
831
|
-
const textLabel = request.textLabel;
|
|
832
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "0 8px 8px", display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
833
|
-
options.length > 0 ? /* @__PURE__ */ jsx(RowList, { children: options.map((option) => /* @__PURE__ */ jsx(
|
|
834
|
-
Row,
|
|
835
|
-
{
|
|
836
|
-
noIcon: true,
|
|
837
|
-
label: /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column", gap: 1, minWidth: 0 }, children: [
|
|
838
|
-
/* @__PURE__ */ jsx("span", { children: option.label }),
|
|
839
|
-
option.detail ? /* @__PURE__ */ jsx("span", { style: { fontSize: 10, opacity: 0.6 }, children: option.detail }) : null
|
|
965
|
+
/* @__PURE__ */ jsxs(ScrollArea, { children: [
|
|
966
|
+
/* @__PURE__ */ jsxs(Stack, { gap: 6, pad: "gutter", children: [
|
|
967
|
+
/* @__PURE__ */ jsx(Text, { role: "title", children: view.title }),
|
|
968
|
+
view.detail ? /* @__PURE__ */ jsx(Text, { children: view.detail }) : null,
|
|
969
|
+
view.facts.map((f) => /* @__PURE__ */ jsx(KeyValue, { name: f.key, value: f.value }, f.key))
|
|
840
970
|
] }),
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
Toggle,
|
|
971
|
+
view.permission ? /* @__PURE__ */ jsx(RowList, { children: view.scopes.map((scope) => /* @__PURE__ */ jsx(
|
|
972
|
+
Row,
|
|
844
973
|
{
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
974
|
+
noIcon: true,
|
|
975
|
+
height: scope.height,
|
|
976
|
+
label: /* @__PURE__ */ jsx(TwoLine, { label: scope.label, detail: scope.detail }),
|
|
977
|
+
meta: scope.risk ? /* @__PURE__ */ jsx(Badge, { tone: scope.riskTone, children: scope.risk }) : null,
|
|
978
|
+
trailing: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
979
|
+
scope.granted ? /* @__PURE__ */ jsx(Badge, { title: "Already granted", children: "granted" }) : null,
|
|
980
|
+
scope.grantable ? /* @__PURE__ */ jsx(Toggle, { size: "sm", label: scope.toggleLabel, checked: scope.selected, onChange: (on) => ui2({ kind: "scope", id: scope.id, on }) }) : null
|
|
981
|
+
] })
|
|
982
|
+
},
|
|
983
|
+
scope.id
|
|
984
|
+
)) }) : null,
|
|
985
|
+
view.question ? /* @__PURE__ */ jsxs(Stack, { gap: 6, pad: "inset", children: [
|
|
986
|
+
view.hasOptions ? /* @__PURE__ */ jsx(RowList, { children: view.options.map((option) => /* @__PURE__ */ jsx(
|
|
987
|
+
Row,
|
|
988
|
+
{
|
|
989
|
+
noIcon: true,
|
|
990
|
+
height: option.height,
|
|
991
|
+
label: /* @__PURE__ */ jsx(TwoLine, { label: option.label, detail: option.detail }),
|
|
992
|
+
meta: option.risk ? /* @__PURE__ */ jsx(Badge, { tone: option.riskTone, children: option.risk }) : null,
|
|
993
|
+
trailing: /* @__PURE__ */ jsx(Toggle, { size: "sm", label: option.toggleLabel, checked: option.selected, onChange: (on) => ui2({ kind: "option", id: option.id, on }) })
|
|
994
|
+
},
|
|
995
|
+
option.id
|
|
996
|
+
)) }) : null,
|
|
997
|
+
view.wantsText ? /* @__PURE__ */ jsxs(Stack, { gap: 3, pad: "none", children: [
|
|
998
|
+
view.textLabel ? /* @__PURE__ */ jsx(Text, { role: "meta", children: view.textLabel }) : null,
|
|
999
|
+
view.multiline ? /* @__PURE__ */ jsx(TextArea, { value: view.draft, placeholder: view.placeholder, rows: 3, label: "Answer", onChange: (value) => ui2({ kind: "text", value }) }) : null,
|
|
1000
|
+
!view.multiline ? /* @__PURE__ */ jsx(Input, { value: view.draft, placeholder: view.placeholder, autoComplete: "off", label: "Answer", onChange: (value) => ui2({ kind: "text", value }) }) : null,
|
|
1001
|
+
view.hasCounter ? /* @__PURE__ */ jsx(Text, { role: "caption", children: view.counter }) : null,
|
|
1002
|
+
view.overLimit ? /* @__PURE__ */ jsx(Badge, { tone: "error", children: "too long" }) : null
|
|
1003
|
+
] }) : null
|
|
1004
|
+
] }) : null
|
|
1005
|
+
] }),
|
|
1006
|
+
view.permission ? /* @__PURE__ */ jsx(
|
|
1007
|
+
Toolbar,
|
|
858
1008
|
{
|
|
859
|
-
|
|
860
|
-
onChange: (
|
|
861
|
-
|
|
862
|
-
rows: 3,
|
|
863
|
-
spellCheck: false,
|
|
864
|
-
style: FIELD_STYLE
|
|
1009
|
+
divided: false,
|
|
1010
|
+
left: /* @__PURE__ */ jsx(SegmentedControl, { size: "sm", label: "How long", options: view.durations, value: view.duration, onChange: (duration) => ui2({ kind: "duration", duration }) }),
|
|
1011
|
+
right: view.unrememberable ? /* @__PURE__ */ jsx(Text, { role: "caption", children: "This grant cannot be remembered." }) : null
|
|
865
1012
|
}
|
|
866
|
-
) :
|
|
867
|
-
|
|
1013
|
+
) : null,
|
|
1014
|
+
/* @__PURE__ */ jsx(
|
|
1015
|
+
Toolbar,
|
|
868
1016
|
{
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1017
|
+
divided: false,
|
|
1018
|
+
right: /* @__PURE__ */ jsxs(ToolbarGroup, { end: true, children: [
|
|
1019
|
+
view.permission ? /* @__PURE__ */ jsx(TextButton, { onClick: () => ui2({ kind: "deny" }), children: "Deny" }) : null,
|
|
1020
|
+
view.permission ? /* @__PURE__ */ jsx(TextButton, { strong: true, disabled: view.allowDisabled, onClick: () => ui2({ kind: "allow" }), children: "Allow" }) : null,
|
|
1021
|
+
view.question ? /* @__PURE__ */ jsx(TextButton, { onClick: () => ui2({ kind: "dismiss" }), children: "Cancel" }) : null,
|
|
1022
|
+
view.question ? /* @__PURE__ */ jsx(TextButton, { strong: true, disabled: view.submitDisabled, onClick: () => ui2({ kind: "submit" }), children: view.submitLabel }) : null
|
|
1023
|
+
] })
|
|
876
1024
|
}
|
|
877
1025
|
),
|
|
878
|
-
|
|
879
|
-
"span",
|
|
880
|
-
{
|
|
881
|
-
style: {
|
|
882
|
-
fontSize: 9,
|
|
883
|
-
opacity: 0.6,
|
|
884
|
-
alignSelf: "flex-end",
|
|
885
|
-
// Over the limit the answer is REFUSED, not truncated — so the counter has to say
|
|
886
|
-
// so rather than implying the extra characters are merely ignored.
|
|
887
|
-
color: state.draftText.length > max ? "var(--xeno-danger)" : void 0
|
|
888
|
-
},
|
|
889
|
-
children: `${state.draftText.length} / ${max}`
|
|
890
|
-
}
|
|
891
|
-
) : null
|
|
1026
|
+
/* @__PURE__ */ jsx(StatusBar, { left: view.pendingLabel, right: view.expiryLabel })
|
|
892
1027
|
] }) : null
|
|
893
1028
|
] });
|
|
894
1029
|
}
|
|
@@ -979,16 +1114,22 @@ function createConsentPanel(options = {}) {
|
|
|
979
1114
|
}
|
|
980
1115
|
var consentPanel = createConsentPanel();
|
|
981
1116
|
export {
|
|
1117
|
+
BEHAVIOURS as CONSENT_BEHAVIOURS,
|
|
1118
|
+
CONSENT_DECLARATION,
|
|
982
1119
|
CONSENT_PANEL_ID,
|
|
1120
|
+
CONSENT_RUNTIME_UNITS,
|
|
983
1121
|
ConsentController,
|
|
984
1122
|
ConsentPanelView,
|
|
985
1123
|
ELICITATION_RESULT_SCHEMA,
|
|
986
1124
|
ELICITATION_SCHEMA,
|
|
987
1125
|
allowedDurations,
|
|
1126
|
+
applyConsentUi,
|
|
988
1127
|
autoCancel,
|
|
989
1128
|
autoDeny,
|
|
990
1129
|
consentManifest,
|
|
991
1130
|
consentPanel,
|
|
1131
|
+
consentViewManifest,
|
|
1132
|
+
consentViewState,
|
|
992
1133
|
createConsentPanel,
|
|
993
1134
|
effectiveRisk,
|
|
994
1135
|
elicitationAsk,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenosystem/blocks",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.16",
|
|
4
4
|
"description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"@duckdb/duckdb-wasm": ">=1.28.0",
|
|
66
66
|
"@xenosystem/block-sdk": ">=0.3.4 <1",
|
|
67
|
-
"@xenosystem/components": ">=0.
|
|
67
|
+
"@xenosystem/components": ">=0.25.0 <1",
|
|
68
68
|
"@xenosystem/data-core": "^0.1.0",
|
|
69
69
|
"@xenosystem/elements": ">=0.0.1",
|
|
70
70
|
"@xenosystem/elements-react": ">=0.0.1",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@types/react": "^19.0.0",
|
|
82
82
|
"@types/react-dom": "^19.0.0",
|
|
83
83
|
"@xenosystem/block-sdk": "^0.3.4",
|
|
84
|
-
"@xenosystem/components": "^0.
|
|
84
|
+
"@xenosystem/components": "^0.25.0",
|
|
85
85
|
"@xenosystem/data-core": "^0.1.0",
|
|
86
86
|
"@xenosystem/elements": "0.0.1",
|
|
87
87
|
"@xenosystem/elements-react": "0.0.1",
|