@decentrys/ui-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/browser/decentrys-ui.js +1733 -0
- package/dist/browser/decentrys-ui.mjs +1681 -0
- package/dist/browser/react-dom-global.d.ts +6 -0
- package/dist/browser/react-dom-global.d.ts.map +1 -0
- package/dist/browser/react-dom-global.js +18 -0
- package/dist/browser/react-dom-global.js.map +1 -0
- package/dist/browser/react-global.d.ts +25 -0
- package/dist/browser/react-global.d.ts.map +1 -0
- package/dist/browser/react-global.js +39 -0
- package/dist/browser/react-global.js.map +1 -0
- package/dist/browser/react-jsx-runtime.d.ts +17 -0
- package/dist/browser/react-jsx-runtime.d.ts.map +1 -0
- package/dist/browser/react-jsx-runtime.js +27 -0
- package/dist/browser/react-jsx-runtime.js.map +1 -0
- package/dist/components/AddressRiskBadge.d.ts +39 -0
- package/dist/components/AddressRiskBadge.d.ts.map +1 -0
- package/dist/components/AddressRiskBadge.js +26 -0
- package/dist/components/AddressRiskBadge.js.map +1 -0
- package/dist/components/ApprovalWarning.d.ts +29 -0
- package/dist/components/ApprovalWarning.d.ts.map +1 -0
- package/dist/components/ApprovalWarning.js +18 -0
- package/dist/components/ApprovalWarning.js.map +1 -0
- package/dist/components/ContractFacts.d.ts +27 -0
- package/dist/components/ContractFacts.d.ts.map +1 -0
- package/dist/components/ContractFacts.js +15 -0
- package/dist/components/ContractFacts.js.map +1 -0
- package/dist/components/RiskDetailsModal.d.ts +35 -0
- package/dist/components/RiskDetailsModal.d.ts.map +1 -0
- package/dist/components/RiskDetailsModal.js +74 -0
- package/dist/components/RiskDetailsModal.js.map +1 -0
- package/dist/components/ThreatSignalList.d.ts +28 -0
- package/dist/components/ThreatSignalList.d.ts.map +1 -0
- package/dist/components/ThreatSignalList.js +28 -0
- package/dist/components/ThreatSignalList.js.map +1 -0
- package/dist/components/TokenSecurityPanel.d.ts +28 -0
- package/dist/components/TokenSecurityPanel.d.ts.map +1 -0
- package/dist/components/TokenSecurityPanel.js +26 -0
- package/dist/components/TokenSecurityPanel.js.map +1 -0
- package/dist/components/TransactionRiskBanner.d.ts +36 -0
- package/dist/components/TransactionRiskBanner.d.ts.map +1 -0
- package/dist/components/TransactionRiskBanner.js +20 -0
- package/dist/components/TransactionRiskBanner.js.map +1 -0
- package/dist/context.d.ts +51 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +47 -0
- package/dist/context.js.map +1 -0
- package/dist/copy.d.ts +72 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +77 -0
- package/dist/copy.js.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +107 -0
- package/dist/index.js.map +1 -0
- package/dist/presentation.d.ts +316 -0
- package/dist/presentation.d.ts.map +1 -0
- package/dist/presentation.js +533 -0
- package/dist/presentation.js.map +1 -0
- package/dist/primitives.d.ts +139 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +150 -0
- package/dist/primitives.js.map +1 -0
- package/dist/styles.d.ts +15 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +285 -0
- package/dist/styles.js.map +1 -0
- package/dist/theme.d.ts +52 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +90 -0
- package/dist/theme.js.map +1 -0
- package/package.json +70 -0
- package/src/browser/react-dom-global.ts +20 -0
- package/src/browser/react-global.ts +42 -0
- package/src/browser/react-jsx-runtime.ts +23 -0
- package/src/components/AddressRiskBadge.tsx +94 -0
- package/src/components/ApprovalWarning.tsx +144 -0
- package/src/components/ContractFacts.tsx +119 -0
- package/src/components/RiskDetailsModal.tsx +229 -0
- package/src/components/ThreatSignalList.tsx +76 -0
- package/src/components/TokenSecurityPanel.tsx +168 -0
- package/src/components/TransactionRiskBanner.tsx +123 -0
- package/src/context.tsx +89 -0
- package/src/copy.test.ts +214 -0
- package/src/copy.ts +151 -0
- package/src/index.ts +84 -0
- package/src/presentation.test.ts +521 -0
- package/src/presentation.ts +846 -0
- package/src/primitives.tsx +384 -0
- package/src/styles.ts +281 -0
- package/src/theme.test.ts +105 -0
- package/src/theme.ts +117 -0
|
@@ -0,0 +1,1733 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var DecentrysUI = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
AddressRiskBadge: () => AddressRiskBadge,
|
|
25
|
+
ApprovalWarning: () => ApprovalWarning,
|
|
26
|
+
Chip: () => Chip,
|
|
27
|
+
ContractFacts: () => ContractFacts,
|
|
28
|
+
DECENTRYS_UI_CSS: () => DECENTRYS_UI_CSS,
|
|
29
|
+
DEFAULT_COPY: () => DEFAULT_COPY,
|
|
30
|
+
DecentrysUiProvider: () => DecentrysUiProvider,
|
|
31
|
+
DecentrysUiStyles: () => DecentrysUiStyles,
|
|
32
|
+
EmptyNote: () => EmptyNote,
|
|
33
|
+
LevelBadge: () => LevelBadge,
|
|
34
|
+
MIN_RAISING_CONFIDENCE: () => MIN_RAISING_CONFIDENCE,
|
|
35
|
+
Mono: () => Mono,
|
|
36
|
+
RISK_LEVEL_LABEL: () => RISK_LEVEL_LABEL,
|
|
37
|
+
RiskDetailsModal: () => RiskDetailsModal,
|
|
38
|
+
ScreenReaderText: () => ScreenReaderText,
|
|
39
|
+
Section: () => Section,
|
|
40
|
+
THEME_TOKENS: () => THEME_TOKENS,
|
|
41
|
+
ThreatSignalList: () => ThreatSignalList,
|
|
42
|
+
TokenSecurityPanel: () => TokenSecurityPanel,
|
|
43
|
+
TransactionRiskBanner: () => TransactionRiskBanner,
|
|
44
|
+
approvalPresentation: () => approvalPresentation,
|
|
45
|
+
assessmentSections: () => assessmentSections,
|
|
46
|
+
availabilityPresentation: () => availabilityPresentation,
|
|
47
|
+
capabilityPresentation: () => capabilityPresentation,
|
|
48
|
+
componentRows: () => componentRows,
|
|
49
|
+
cx: () => cx,
|
|
50
|
+
decisionPresentation: () => decisionPresentation,
|
|
51
|
+
evidencePresentation: () => evidencePresentation,
|
|
52
|
+
factPresentation: () => factPresentation,
|
|
53
|
+
formatConfidence: () => formatConfidence,
|
|
54
|
+
formatTimestamp: () => formatTimestamp,
|
|
55
|
+
formatTokenAmount: () => formatTokenAmount,
|
|
56
|
+
historyPresentation: () => historyPresentation,
|
|
57
|
+
hopPresentation: () => hopPresentation,
|
|
58
|
+
isUnlimitedAllowance: () => isUnlimitedAllowance,
|
|
59
|
+
kindPresentation: () => kindPresentation,
|
|
60
|
+
levelPresentation: () => levelPresentation,
|
|
61
|
+
levelRank: () => levelRank,
|
|
62
|
+
plural: () => plural,
|
|
63
|
+
resolveCopy: () => resolveCopy,
|
|
64
|
+
shortenAddress: () => shortenAddress,
|
|
65
|
+
signalPresentation: () => signalPresentation,
|
|
66
|
+
themeStyle: () => themeStyle,
|
|
67
|
+
toneBgVar: () => toneBgVar,
|
|
68
|
+
toneVar: () => toneVar,
|
|
69
|
+
unknownPresentation: () => unknownPresentation,
|
|
70
|
+
useUiConfig: () => useUiConfig
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// src/browser/react-global.ts
|
|
74
|
+
function resolveReact() {
|
|
75
|
+
const candidate = globalThis.React;
|
|
76
|
+
if (!candidate || typeof candidate.createElement !== "function") {
|
|
77
|
+
throw new Error(
|
|
78
|
+
"DecentrysUI: the script-tag build expects React on the page already (window.React, and window.ReactDOM for the details modal). Load React first, or use the ESM build / the npm package if you have a bundler."
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return candidate;
|
|
82
|
+
}
|
|
83
|
+
var React = resolveReact();
|
|
84
|
+
var react_global_default = React;
|
|
85
|
+
var createContext = React.createContext;
|
|
86
|
+
var useContext = React.useContext;
|
|
87
|
+
var useState = React.useState;
|
|
88
|
+
var useEffect = React.useEffect;
|
|
89
|
+
var useId = React.useId;
|
|
90
|
+
var useRef = React.useRef;
|
|
91
|
+
var createElement = React.createElement;
|
|
92
|
+
var Fragment = React.Fragment;
|
|
93
|
+
|
|
94
|
+
// src/styles.ts
|
|
95
|
+
var DECENTRYS_UI_CSS = `
|
|
96
|
+
.dcy {
|
|
97
|
+
--dcy-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
98
|
+
--dcy-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
|
99
|
+
--dcy-radius: 8px;
|
|
100
|
+
--dcy-gap: 12px;
|
|
101
|
+
|
|
102
|
+
--dcy-surface: #ffffff;
|
|
103
|
+
--dcy-surface-raised: #f5f6f8;
|
|
104
|
+
--dcy-border: #dde1e7;
|
|
105
|
+
--dcy-text: #14171c;
|
|
106
|
+
--dcy-text-muted: #545d6b;
|
|
107
|
+
--dcy-text-faint: #737d8c;
|
|
108
|
+
--dcy-focus: #2f6fed;
|
|
109
|
+
|
|
110
|
+
--dcy-tone-neutral: #545d6b;
|
|
111
|
+
--dcy-tone-neutral-bg: #f2f4f6;
|
|
112
|
+
--dcy-tone-info: #2f5f96;
|
|
113
|
+
--dcy-tone-info-bg: #eef3f9;
|
|
114
|
+
--dcy-tone-caution: #7d6113;
|
|
115
|
+
--dcy-tone-caution-bg: #faf4e4;
|
|
116
|
+
--dcy-tone-elevated: #97500f;
|
|
117
|
+
--dcy-tone-elevated-bg: #fbefe3;
|
|
118
|
+
--dcy-tone-high: #a83c18;
|
|
119
|
+
--dcy-tone-high-bg: #fbece6;
|
|
120
|
+
--dcy-tone-critical: #98211d;
|
|
121
|
+
--dcy-tone-critical-bg: #fbe9e9;
|
|
122
|
+
--dcy-tone-fact: #6a7382;
|
|
123
|
+
--dcy-tone-fact-bg: transparent;
|
|
124
|
+
--dcy-tone-capability: #554d8c;
|
|
125
|
+
--dcy-tone-capability-bg: #f2f1fa;
|
|
126
|
+
--dcy-tone-unknown: #77808f;
|
|
127
|
+
--dcy-tone-unknown-bg: transparent;
|
|
128
|
+
--dcy-tone-inactive: #8d97a4;
|
|
129
|
+
--dcy-tone-inactive-bg: transparent;
|
|
130
|
+
|
|
131
|
+
font-family: var(--dcy-font);
|
|
132
|
+
font-size: 14px;
|
|
133
|
+
line-height: 1.5;
|
|
134
|
+
color: var(--dcy-text);
|
|
135
|
+
box-sizing: border-box;
|
|
136
|
+
}
|
|
137
|
+
.dcy *, .dcy *::before, .dcy *::after { box-sizing: inherit; }
|
|
138
|
+
|
|
139
|
+
@media (prefers-color-scheme: dark) {
|
|
140
|
+
.dcy {
|
|
141
|
+
--dcy-surface: #14171c;
|
|
142
|
+
--dcy-surface-raised: #1c2027;
|
|
143
|
+
--dcy-border: #2c323b;
|
|
144
|
+
--dcy-text: #e8ebef;
|
|
145
|
+
--dcy-text-muted: #a4adba;
|
|
146
|
+
--dcy-text-faint: #808a98;
|
|
147
|
+
--dcy-focus: #7aa5ff;
|
|
148
|
+
|
|
149
|
+
--dcy-tone-neutral: #a4adba;
|
|
150
|
+
--dcy-tone-neutral-bg: #1e232a;
|
|
151
|
+
--dcy-tone-info: #86b0e6;
|
|
152
|
+
--dcy-tone-info-bg: #17202b;
|
|
153
|
+
--dcy-tone-caution: #d8b463;
|
|
154
|
+
--dcy-tone-caution-bg: #241f14;
|
|
155
|
+
--dcy-tone-elevated: #e0a065;
|
|
156
|
+
--dcy-tone-elevated-bg: #261c13;
|
|
157
|
+
--dcy-tone-high: #eb8c68;
|
|
158
|
+
--dcy-tone-high-bg: #271812;
|
|
159
|
+
--dcy-tone-critical: #ef7d78;
|
|
160
|
+
--dcy-tone-critical-bg: #291414;
|
|
161
|
+
--dcy-tone-fact: #97a1ae;
|
|
162
|
+
--dcy-tone-capability: #a79fe0;
|
|
163
|
+
--dcy-tone-capability-bg: #1d1b2a;
|
|
164
|
+
--dcy-tone-unknown: #8b95a3;
|
|
165
|
+
--dcy-tone-inactive: #79828f;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
/*
|
|
171
|
+
* Tone resolution happens here, in the stylesheet, rather than in inline
|
|
172
|
+
* styles on the elements. An inline colour would beat any rule an integrator
|
|
173
|
+
* wrote against these components without \`!important\`, which is not a
|
|
174
|
+
* position to put somebody in who only wanted to match their own palette.
|
|
175
|
+
*/
|
|
176
|
+
[data-dcy-tone="neutral"] { --dcy-tone: var(--dcy-tone-neutral); --dcy-tone-bg: var(--dcy-tone-neutral-bg); }
|
|
177
|
+
[data-dcy-tone="info"] { --dcy-tone: var(--dcy-tone-info); --dcy-tone-bg: var(--dcy-tone-info-bg); }
|
|
178
|
+
[data-dcy-tone="caution"] { --dcy-tone: var(--dcy-tone-caution); --dcy-tone-bg: var(--dcy-tone-caution-bg); }
|
|
179
|
+
[data-dcy-tone="elevated"] { --dcy-tone: var(--dcy-tone-elevated); --dcy-tone-bg: var(--dcy-tone-elevated-bg); }
|
|
180
|
+
[data-dcy-tone="high"] { --dcy-tone: var(--dcy-tone-high); --dcy-tone-bg: var(--dcy-tone-high-bg); }
|
|
181
|
+
[data-dcy-tone="critical"] { --dcy-tone: var(--dcy-tone-critical); --dcy-tone-bg: var(--dcy-tone-critical-bg); }
|
|
182
|
+
[data-dcy-tone="fact"] { --dcy-tone: var(--dcy-tone-fact); --dcy-tone-bg: var(--dcy-tone-fact-bg); }
|
|
183
|
+
[data-dcy-tone="capability"] { --dcy-tone: var(--dcy-tone-capability); --dcy-tone-bg: var(--dcy-tone-capability-bg); }
|
|
184
|
+
[data-dcy-tone="unknown"] { --dcy-tone: var(--dcy-tone-unknown); --dcy-tone-bg: var(--dcy-tone-unknown-bg); }
|
|
185
|
+
[data-dcy-tone="inactive"] { --dcy-tone: var(--dcy-tone-inactive); --dcy-tone-bg: var(--dcy-tone-inactive-bg); }
|
|
186
|
+
|
|
187
|
+
[data-dcy-rule="solid"] { border-left-style: solid; }
|
|
188
|
+
[data-dcy-rule="dashed"] { border-left-style: dashed; }
|
|
189
|
+
[data-dcy-rule="dotted"] { border-left-style: dotted; }
|
|
190
|
+
|
|
191
|
+
.dcy-row[data-dcy-kind="signal"] { border-left-width: 4px; }
|
|
192
|
+
|
|
193
|
+
.dcy :focus-visible {
|
|
194
|
+
outline: 2px solid var(--dcy-focus);
|
|
195
|
+
outline-offset: 2px;
|
|
196
|
+
border-radius: 4px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.dcy-card {
|
|
200
|
+
border: 1px solid var(--dcy-border);
|
|
201
|
+
border-radius: var(--dcy-radius);
|
|
202
|
+
background: var(--dcy-surface);
|
|
203
|
+
padding: var(--dcy-gap);
|
|
204
|
+
display: flex;
|
|
205
|
+
flex-direction: column;
|
|
206
|
+
gap: var(--dcy-gap);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.dcy-head { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
|
|
210
|
+
.dcy-head-main { flex: 1 1 14rem; min-width: 0; }
|
|
211
|
+
.dcy-title { margin: 0; font-size: 14px; font-weight: 600; }
|
|
212
|
+
.dcy-meaning { margin: 4px 0 0; color: var(--dcy-text-muted); font-size: 13px; }
|
|
213
|
+
|
|
214
|
+
.dcy-badge {
|
|
215
|
+
display: inline-flex;
|
|
216
|
+
align-items: center;
|
|
217
|
+
gap: 6px;
|
|
218
|
+
padding: 2px 8px;
|
|
219
|
+
border-radius: 999px;
|
|
220
|
+
border: 1px solid currentColor;
|
|
221
|
+
font-size: 12px;
|
|
222
|
+
font-weight: 600;
|
|
223
|
+
line-height: 1.6;
|
|
224
|
+
white-space: nowrap;
|
|
225
|
+
color: var(--dcy-tone, var(--dcy-text-muted));
|
|
226
|
+
background: var(--dcy-tone-bg, transparent);
|
|
227
|
+
}
|
|
228
|
+
.dcy-glyph {
|
|
229
|
+
font-family: var(--dcy-font-mono);
|
|
230
|
+
font-weight: 700;
|
|
231
|
+
letter-spacing: -0.05em;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.dcy-chip {
|
|
235
|
+
display: inline-block;
|
|
236
|
+
padding: 1px 6px;
|
|
237
|
+
border-radius: 4px;
|
|
238
|
+
border: 1px solid var(--dcy-border);
|
|
239
|
+
background: var(--dcy-surface-raised);
|
|
240
|
+
color: var(--dcy-text-muted);
|
|
241
|
+
font-size: 11px;
|
|
242
|
+
font-weight: 600;
|
|
243
|
+
text-transform: uppercase;
|
|
244
|
+
letter-spacing: 0.04em;
|
|
245
|
+
white-space: nowrap;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.dcy-section { display: flex; flex-direction: column; gap: 8px; }
|
|
249
|
+
.dcy-section-title {
|
|
250
|
+
margin: 0;
|
|
251
|
+
font-size: 11px;
|
|
252
|
+
font-weight: 700;
|
|
253
|
+
text-transform: uppercase;
|
|
254
|
+
letter-spacing: 0.06em;
|
|
255
|
+
color: var(--dcy-text-faint);
|
|
256
|
+
}
|
|
257
|
+
.dcy-note { margin: 0; font-size: 12px; color: var(--dcy-text-muted); }
|
|
258
|
+
.dcy-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
* Kind rows.
|
|
262
|
+
*
|
|
263
|
+
* The left rule's *style* and the row's text label are what separate a fact
|
|
264
|
+
* from a threat signal; the colour is the third carrier, not the only one.
|
|
265
|
+
*/
|
|
266
|
+
.dcy-row {
|
|
267
|
+
display: flex;
|
|
268
|
+
gap: 8px;
|
|
269
|
+
padding: 6px 0 6px 10px;
|
|
270
|
+
border-left-style: solid;
|
|
271
|
+
border-left-width: 2px;
|
|
272
|
+
border-left-color: var(--dcy-tone, var(--dcy-tone-fact));
|
|
273
|
+
}
|
|
274
|
+
.dcy-row-body { min-width: 0; flex: 1 1 auto; }
|
|
275
|
+
.dcy-row-statement { margin: 0; }
|
|
276
|
+
.dcy-row-strong { font-weight: 600; }
|
|
277
|
+
.dcy-row-meta {
|
|
278
|
+
margin: 3px 0 0;
|
|
279
|
+
font-size: 12px;
|
|
280
|
+
color: var(--dcy-text-muted);
|
|
281
|
+
display: flex;
|
|
282
|
+
flex-wrap: wrap;
|
|
283
|
+
gap: 4px 10px;
|
|
284
|
+
}
|
|
285
|
+
.dcy-mono { font-family: var(--dcy-font-mono); font-size: 12px; word-break: break-all; }
|
|
286
|
+
|
|
287
|
+
.dcy-signal {
|
|
288
|
+
border: 1px solid var(--dcy-border);
|
|
289
|
+
border-left-width: 4px;
|
|
290
|
+
border-left-color: var(--dcy-tone, var(--dcy-border));
|
|
291
|
+
border-radius: var(--dcy-radius);
|
|
292
|
+
padding: 10px;
|
|
293
|
+
display: flex;
|
|
294
|
+
flex-direction: column;
|
|
295
|
+
gap: 6px;
|
|
296
|
+
}
|
|
297
|
+
.dcy-signal-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
298
|
+
|
|
299
|
+
.dcy-kv { display: grid; grid-template-columns: minmax(6rem, auto) 1fr; gap: 4px 12px; font-size: 13px; }
|
|
300
|
+
.dcy-kv dt { color: var(--dcy-text-muted); }
|
|
301
|
+
.dcy-kv dd { margin: 0; }
|
|
302
|
+
|
|
303
|
+
.dcy-btn {
|
|
304
|
+
font: inherit;
|
|
305
|
+
font-size: 13px;
|
|
306
|
+
font-weight: 600;
|
|
307
|
+
color: var(--dcy-text);
|
|
308
|
+
background: var(--dcy-surface-raised);
|
|
309
|
+
border: 1px solid var(--dcy-border);
|
|
310
|
+
border-radius: 6px;
|
|
311
|
+
padding: 5px 12px;
|
|
312
|
+
cursor: pointer;
|
|
313
|
+
}
|
|
314
|
+
.dcy-btn:hover { background: var(--dcy-border); }
|
|
315
|
+
.dcy-btn-quiet { background: transparent; border-color: transparent; text-decoration: underline; padding-left: 0; }
|
|
316
|
+
|
|
317
|
+
.dcy-backdrop {
|
|
318
|
+
position: fixed;
|
|
319
|
+
inset: 0;
|
|
320
|
+
background: rgba(8, 10, 14, 0.55);
|
|
321
|
+
display: flex;
|
|
322
|
+
align-items: flex-start;
|
|
323
|
+
justify-content: center;
|
|
324
|
+
padding: 24px 16px;
|
|
325
|
+
overflow: auto;
|
|
326
|
+
z-index: 2147483000;
|
|
327
|
+
}
|
|
328
|
+
.dcy-modal {
|
|
329
|
+
width: min(40rem, 100%);
|
|
330
|
+
max-height: calc(100vh - 48px);
|
|
331
|
+
overflow: auto;
|
|
332
|
+
background: var(--dcy-surface);
|
|
333
|
+
border: 1px solid var(--dcy-border);
|
|
334
|
+
border-radius: var(--dcy-radius);
|
|
335
|
+
padding: 16px;
|
|
336
|
+
display: flex;
|
|
337
|
+
flex-direction: column;
|
|
338
|
+
gap: var(--dcy-gap);
|
|
339
|
+
}
|
|
340
|
+
.dcy-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
341
|
+
|
|
342
|
+
.dcy-inline {
|
|
343
|
+
display: inline-flex;
|
|
344
|
+
align-items: center;
|
|
345
|
+
gap: 6px;
|
|
346
|
+
font-family: var(--dcy-font);
|
|
347
|
+
font-size: 12px;
|
|
348
|
+
}
|
|
349
|
+
.dcy-sr {
|
|
350
|
+
position: absolute;
|
|
351
|
+
width: 1px;
|
|
352
|
+
height: 1px;
|
|
353
|
+
padding: 0;
|
|
354
|
+
margin: -1px;
|
|
355
|
+
overflow: hidden;
|
|
356
|
+
clip: rect(0 0 0 0);
|
|
357
|
+
clip-path: inset(50%);
|
|
358
|
+
white-space: nowrap;
|
|
359
|
+
border: 0;
|
|
360
|
+
}
|
|
361
|
+
.dcy-hr { border: none; border-top: 1px solid var(--dcy-border); margin: 0; }
|
|
362
|
+
`;
|
|
363
|
+
|
|
364
|
+
// src/copy.ts
|
|
365
|
+
var DEFAULT_COPY = {
|
|
366
|
+
factsHeading: "Observed facts",
|
|
367
|
+
capabilitiesHeading: "What this contract can do",
|
|
368
|
+
signalsHeading: "Threat signals",
|
|
369
|
+
unknownsHeading: "Not known",
|
|
370
|
+
evidenceHeading: "Evidence",
|
|
371
|
+
componentsHeading: "Score components",
|
|
372
|
+
historyHeading: "History",
|
|
373
|
+
demotedHeading: "Reported as facts, not as risk",
|
|
374
|
+
factLabel: "Fact",
|
|
375
|
+
capabilityLabel: "Capability",
|
|
376
|
+
signalLabel: "Threat signal",
|
|
377
|
+
unknownLabel: "Unknown",
|
|
378
|
+
notAnAssurance: "An absence of findings is an absence of findings. It is not an assurance about this subject.",
|
|
379
|
+
factsAreNotFindings: "These are directly observed and carry no accusation. None of them raises a risk level on its own.",
|
|
380
|
+
capabilitiesAreNotFindings: "What the code is able to do. A capability is not evidence that it has been or will be used.",
|
|
381
|
+
unknownsAreNotRisk: "Reported as unknown rather than guessed at. An unknown never contributes to a risk level.",
|
|
382
|
+
coverageIsNotRisk: "Coverage measures how much Decentrys knows about this subject. It is reported separately and is never added to a risk total.",
|
|
383
|
+
policyIsYours: "Decentrys reports evidence. What happens next is this application\u2019s decision, not ours.",
|
|
384
|
+
demotedExplanation: "These arrived labelled as risk signals and describe how much is known rather than what was found, so they are shown as facts and cannot raise a risk level.",
|
|
385
|
+
noFacts: "No facts were returned for this subject.",
|
|
386
|
+
noCapabilities: "No security-sensitive capabilities were identified.",
|
|
387
|
+
noSignals: "No threat signals were found. That is an absence of findings, not a finding that there is nothing to find.",
|
|
388
|
+
noUnknowns: "Every attribute checked returned an answer.",
|
|
389
|
+
nothingReturned: "Decentrys returned no facts, capabilities, threat signals or unknowns for this subject.",
|
|
390
|
+
viewDetails: "View details",
|
|
391
|
+
close: "Close",
|
|
392
|
+
detailsTitle: "Assessment details",
|
|
393
|
+
showEvidence: "Show evidence",
|
|
394
|
+
hideEvidence: "Hide evidence",
|
|
395
|
+
confidenceLabel: "Confidence",
|
|
396
|
+
confidenceCaveat: "How well the evidence supports this classification. It is not a measure of how much harm the subject could do.",
|
|
397
|
+
sourceLabel: "Source",
|
|
398
|
+
observedLabel: "Observed",
|
|
399
|
+
grantedByLabel: "Granted by",
|
|
400
|
+
hopsLabel: "Distance",
|
|
401
|
+
statusLabel: "Status",
|
|
402
|
+
analystConfirmed: "Confirmed by a Decentrys analyst against the evidence above.",
|
|
403
|
+
notAnalystConfirmed: "Automated finding. No analyst has confirmed it.",
|
|
404
|
+
cachedNotice: "Served from a local cache rather than a fresh lookup.",
|
|
405
|
+
modelLabel: "Model",
|
|
406
|
+
assessedLabel: "Assessed",
|
|
407
|
+
approvalHeading: "What you are about to grant",
|
|
408
|
+
approvalRevocation: "An allowance stays in place until it is revoked, whether or not the application is used again.",
|
|
409
|
+
spenderLabel: "Spender",
|
|
410
|
+
tokenLabel: "Token"
|
|
411
|
+
};
|
|
412
|
+
function resolveCopy(overrides) {
|
|
413
|
+
return overrides ? { ...DEFAULT_COPY, ...overrides } : DEFAULT_COPY;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/browser/react-jsx-runtime.ts
|
|
417
|
+
var Fragment2 = react_global_default.Fragment;
|
|
418
|
+
function create(type, props, key) {
|
|
419
|
+
if (key === void 0 || key === null) return react_global_default.createElement(type, props);
|
|
420
|
+
return react_global_default.createElement(type, { ...props ?? {}, key });
|
|
421
|
+
}
|
|
422
|
+
var jsx = create;
|
|
423
|
+
var jsxs = create;
|
|
424
|
+
|
|
425
|
+
// src/context.tsx
|
|
426
|
+
var UiContext = createContext(null);
|
|
427
|
+
function DecentrysUiStyles() {
|
|
428
|
+
return /* @__PURE__ */ jsx("style", { "data-decentrys-ui": "", children: DECENTRYS_UI_CSS });
|
|
429
|
+
}
|
|
430
|
+
function DecentrysUiProvider({
|
|
431
|
+
theme,
|
|
432
|
+
copy,
|
|
433
|
+
injectStyles = true,
|
|
434
|
+
children
|
|
435
|
+
}) {
|
|
436
|
+
return /* @__PURE__ */ jsxs(UiContext.Provider, { value: { theme, copy, stylesProvided: true }, children: [
|
|
437
|
+
injectStyles ? /* @__PURE__ */ jsx(DecentrysUiStyles, {}) : null,
|
|
438
|
+
children
|
|
439
|
+
] });
|
|
440
|
+
}
|
|
441
|
+
function useUiConfig(local = {}) {
|
|
442
|
+
const ctx = useContext(UiContext);
|
|
443
|
+
const theme = ctx?.theme || local.theme ? { ...ctx?.theme ?? {}, ...local.theme ?? {} } : void 0;
|
|
444
|
+
return {
|
|
445
|
+
theme,
|
|
446
|
+
copy: resolveCopy({ ...ctx?.copy ?? {}, ...local.copy ?? {} }),
|
|
447
|
+
emitStyles: !ctx?.stylesProvided
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/theme.ts
|
|
452
|
+
var THEME_TOKENS = [
|
|
453
|
+
"font",
|
|
454
|
+
"font-mono",
|
|
455
|
+
"radius",
|
|
456
|
+
"gap",
|
|
457
|
+
"surface",
|
|
458
|
+
"surface-raised",
|
|
459
|
+
"border",
|
|
460
|
+
"text",
|
|
461
|
+
"text-muted",
|
|
462
|
+
"text-faint",
|
|
463
|
+
"focus",
|
|
464
|
+
"tone-neutral",
|
|
465
|
+
"tone-neutral-bg",
|
|
466
|
+
"tone-info",
|
|
467
|
+
"tone-info-bg",
|
|
468
|
+
"tone-caution",
|
|
469
|
+
"tone-caution-bg",
|
|
470
|
+
"tone-elevated",
|
|
471
|
+
"tone-elevated-bg",
|
|
472
|
+
"tone-high",
|
|
473
|
+
"tone-high-bg",
|
|
474
|
+
"tone-critical",
|
|
475
|
+
"tone-critical-bg",
|
|
476
|
+
"tone-fact",
|
|
477
|
+
"tone-fact-bg",
|
|
478
|
+
"tone-capability",
|
|
479
|
+
"tone-capability-bg",
|
|
480
|
+
"tone-unknown",
|
|
481
|
+
"tone-unknown-bg",
|
|
482
|
+
"tone-inactive",
|
|
483
|
+
"tone-inactive-bg"
|
|
484
|
+
];
|
|
485
|
+
function themeStyle(theme, base) {
|
|
486
|
+
if (!theme) return base;
|
|
487
|
+
const style = {};
|
|
488
|
+
for (const [token, value] of Object.entries(theme)) {
|
|
489
|
+
if (typeof value === "string" && value.length > 0) style[`--dcy-${token}`] = value;
|
|
490
|
+
}
|
|
491
|
+
return { ...base ?? {}, ...style };
|
|
492
|
+
}
|
|
493
|
+
function toneVar(tone) {
|
|
494
|
+
return `var(--dcy-tone-${tone})`;
|
|
495
|
+
}
|
|
496
|
+
function toneBgVar(tone) {
|
|
497
|
+
return `var(--dcy-tone-${tone}-bg)`;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// ../protect/dist/browser/decentrys-protect.mjs
|
|
501
|
+
var RISK_LEVEL_MEANING = {
|
|
502
|
+
NO_CRITICAL_RISK_DETECTED: "No known critical threat evidence was identified. This is not an assurance of safety.",
|
|
503
|
+
INFORMATIONAL: "Facts worth knowing before proceeding. Nothing here indicates danger.",
|
|
504
|
+
CAUTION: "A security-sensitive capability or behaviour exists that deserves attention.",
|
|
505
|
+
ELEVATED_RISK: "Several meaningful risk signals are present together.",
|
|
506
|
+
HIGH_RISK: "Strong technical or behavioural evidence of significant danger.",
|
|
507
|
+
CRITICAL_THREAT: "Severe threat supported by concrete evidence.",
|
|
508
|
+
KNOWN_MALICIOUS: "Confirmed malicious infrastructure or behaviour, verified against evidence."
|
|
509
|
+
};
|
|
510
|
+
var HISTORY_STATUS_MEANING = {
|
|
511
|
+
ESTABLISHED: "Substantial on-chain history is available.",
|
|
512
|
+
MODERATE: "Some history is available.",
|
|
513
|
+
LIMITED: "Little history is available yet. This is normal for anything recently deployed and is not a risk finding.",
|
|
514
|
+
NONE: "No history is available. This is not a risk finding."
|
|
515
|
+
};
|
|
516
|
+
var MIN_RAISING_CONFIDENCE = 0.5;
|
|
517
|
+
|
|
518
|
+
// src/presentation.ts
|
|
519
|
+
var RISK_LEVEL_LABEL = {
|
|
520
|
+
NO_CRITICAL_RISK_DETECTED: "No critical risk detected",
|
|
521
|
+
INFORMATIONAL: "Informational",
|
|
522
|
+
CAUTION: "Caution",
|
|
523
|
+
ELEVATED_RISK: "Elevated risk",
|
|
524
|
+
HIGH_RISK: "High risk",
|
|
525
|
+
CRITICAL_THREAT: "Critical threat",
|
|
526
|
+
KNOWN_MALICIOUS: "Known malicious"
|
|
527
|
+
};
|
|
528
|
+
var LEVEL_GLYPH = {
|
|
529
|
+
NO_CRITICAL_RISK_DETECTED: "\xB7",
|
|
530
|
+
INFORMATIONAL: "i",
|
|
531
|
+
CAUTION: "!",
|
|
532
|
+
ELEVATED_RISK: "!!",
|
|
533
|
+
HIGH_RISK: "!!!",
|
|
534
|
+
CRITICAL_THREAT: "!!!!",
|
|
535
|
+
KNOWN_MALICIOUS: "\u2715"
|
|
536
|
+
};
|
|
537
|
+
var LEVEL_TONE = {
|
|
538
|
+
// Neither of these two may look like a warning. Nothing in them indicates
|
|
539
|
+
// danger, and a new project landing on INFORMATIONAL is the common case.
|
|
540
|
+
NO_CRITICAL_RISK_DETECTED: "neutral",
|
|
541
|
+
INFORMATIONAL: "info",
|
|
542
|
+
CAUTION: "caution",
|
|
543
|
+
ELEVATED_RISK: "elevated",
|
|
544
|
+
HIGH_RISK: "high",
|
|
545
|
+
CRITICAL_THREAT: "critical",
|
|
546
|
+
KNOWN_MALICIOUS: "critical"
|
|
547
|
+
};
|
|
548
|
+
var LEVEL_ORDER = [
|
|
549
|
+
"NO_CRITICAL_RISK_DETECTED",
|
|
550
|
+
"INFORMATIONAL",
|
|
551
|
+
"CAUTION",
|
|
552
|
+
"ELEVATED_RISK",
|
|
553
|
+
"HIGH_RISK",
|
|
554
|
+
"CRITICAL_THREAT",
|
|
555
|
+
"KNOWN_MALICIOUS"
|
|
556
|
+
];
|
|
557
|
+
function levelRank(level) {
|
|
558
|
+
return LEVEL_ORDER.indexOf(level);
|
|
559
|
+
}
|
|
560
|
+
function levelPresentation(level, options = {}) {
|
|
561
|
+
const label = options.labels?.[level] ?? RISK_LEVEL_LABEL[level];
|
|
562
|
+
const meaning = RISK_LEVEL_MEANING[level];
|
|
563
|
+
const evidenceBacked = levelRank(level) >= levelRank("ELEVATED_RISK");
|
|
564
|
+
return {
|
|
565
|
+
level,
|
|
566
|
+
label,
|
|
567
|
+
meaning,
|
|
568
|
+
tone: LEVEL_TONE[level],
|
|
569
|
+
glyph: LEVEL_GLYPH[level],
|
|
570
|
+
evidenceBacked,
|
|
571
|
+
accusatory: level === "KNOWN_MALICIOUS",
|
|
572
|
+
liveRegionRole: evidenceBacked ? "alert" : "status",
|
|
573
|
+
ariaLabel: `Decentrys assessment: ${label}. ${meaning}`
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
function kindPresentation(kind, copy) {
|
|
577
|
+
switch (kind) {
|
|
578
|
+
case "fact":
|
|
579
|
+
return { kind, label: copy.factLabel, glyph: "\xB7", tone: "fact", rule: "solid", ruleWidth: "2px" };
|
|
580
|
+
case "capability":
|
|
581
|
+
return { kind, label: copy.capabilityLabel, glyph: "\u25C7", tone: "capability", rule: "dashed", ruleWidth: "2px" };
|
|
582
|
+
case "signal":
|
|
583
|
+
return { kind, label: copy.signalLabel, glyph: "\u25B2", tone: "critical", rule: "solid", ruleWidth: "4px" };
|
|
584
|
+
case "unknown":
|
|
585
|
+
return { kind, label: copy.unknownLabel, glyph: "?", tone: "unknown", rule: "dotted", ruleWidth: "2px" };
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function factPresentation(fact) {
|
|
589
|
+
return {
|
|
590
|
+
kind: "fact",
|
|
591
|
+
statement: fact.statement,
|
|
592
|
+
source: fact.source,
|
|
593
|
+
observedAt: formatTimestamp(fact.observedAt),
|
|
594
|
+
tone: "fact"
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
var CAPABILITY_SEVERITY_LABEL = {
|
|
598
|
+
INFO: "Standard",
|
|
599
|
+
NOTABLE: "Notable",
|
|
600
|
+
SIGNIFICANT: "Significant"
|
|
601
|
+
};
|
|
602
|
+
function capabilityPresentation(capability) {
|
|
603
|
+
return {
|
|
604
|
+
kind: "capability",
|
|
605
|
+
statement: capability.statement,
|
|
606
|
+
severity: capability.severity,
|
|
607
|
+
severityLabel: CAPABILITY_SEVERITY_LABEL[capability.severity],
|
|
608
|
+
grantedBy: capability.grantedBy,
|
|
609
|
+
tone: "capability",
|
|
610
|
+
emphasis: capability.severity === "SIGNIFICANT" ? "strong" : "normal"
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
var SEVERITY_LABEL = {
|
|
614
|
+
LOW: "Low",
|
|
615
|
+
MEDIUM: "Medium",
|
|
616
|
+
HIGH: "High",
|
|
617
|
+
CRITICAL: "Critical"
|
|
618
|
+
};
|
|
619
|
+
var SEVERITY_TONE = {
|
|
620
|
+
LOW: "caution",
|
|
621
|
+
MEDIUM: "elevated",
|
|
622
|
+
HIGH: "high",
|
|
623
|
+
CRITICAL: "critical"
|
|
624
|
+
};
|
|
625
|
+
var SIGNAL_STATUS_LABEL = {
|
|
626
|
+
ACTIVE: "Active",
|
|
627
|
+
STALE: "Stale",
|
|
628
|
+
RESOLVED: "Resolved",
|
|
629
|
+
DISPUTED_FACT: "Disputed",
|
|
630
|
+
REMOVED: "Withdrawn"
|
|
631
|
+
};
|
|
632
|
+
function signalPresentation(signal, copy, options = {}) {
|
|
633
|
+
const subject = options.subjectNoun ?? "address";
|
|
634
|
+
const active = signal.status === "ACTIVE";
|
|
635
|
+
const raising = active && signal.confidence >= MIN_RAISING_CONFIDENCE;
|
|
636
|
+
const statusLabel = SIGNAL_STATUS_LABEL[signal.status];
|
|
637
|
+
const analystConfirmed = signal.evidence.some((e) => e.analystVerified);
|
|
638
|
+
let inertStatement;
|
|
639
|
+
if (!active) {
|
|
640
|
+
inertStatement = `This signal is ${statusLabel.toLowerCase()} and did not affect this assessment.`;
|
|
641
|
+
} else if (!raising) {
|
|
642
|
+
inertStatement = `Reported at ${formatConfidence(signal.confidence)} confidence, which is too low to raise the risk level on its own. It is shown because it was observed, not because it counted.`;
|
|
643
|
+
}
|
|
644
|
+
const hop = hopPresentation(signal.hops, subject);
|
|
645
|
+
return {
|
|
646
|
+
kind: "signal",
|
|
647
|
+
explanation: signal.explanation,
|
|
648
|
+
severity: signal.severity,
|
|
649
|
+
severityLabel: SEVERITY_LABEL[signal.severity],
|
|
650
|
+
tone: raising ? SEVERITY_TONE[signal.severity] : "inactive",
|
|
651
|
+
status: signal.status,
|
|
652
|
+
statusLabel,
|
|
653
|
+
active,
|
|
654
|
+
raising,
|
|
655
|
+
inertStatement,
|
|
656
|
+
hops: signal.hops,
|
|
657
|
+
hopLabel: hop.label,
|
|
658
|
+
hopStatement: hop.statement,
|
|
659
|
+
indirect: hop.indirect,
|
|
660
|
+
confidence: signal.confidence,
|
|
661
|
+
confidenceLabel: formatConfidence(signal.confidence),
|
|
662
|
+
analystConfirmed,
|
|
663
|
+
attribution: analystConfirmed ? copy.analystConfirmed : copy.notAnalystConfirmed,
|
|
664
|
+
evidenceCount: signal.evidence.length,
|
|
665
|
+
ariaLabel: `${copy.signalLabel}, ${SEVERITY_LABEL[signal.severity].toLowerCase()} severity, ${formatConfidence(signal.confidence)} confidence, ${hop.label.toLowerCase()}. ${signal.explanation}`
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
function hopPresentation(hops, subjectNoun = "address") {
|
|
669
|
+
const n = Math.max(0, Math.trunc(hops));
|
|
670
|
+
if (n === 0) {
|
|
671
|
+
return {
|
|
672
|
+
hops: 0,
|
|
673
|
+
label: "Direct",
|
|
674
|
+
statement: `Observed directly on this ${subjectNoun}.`,
|
|
675
|
+
indirect: false
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
if (n === 1) {
|
|
679
|
+
return {
|
|
680
|
+
hops: 1,
|
|
681
|
+
label: "1 hop",
|
|
682
|
+
statement: `Observed one hop away. This is an inference about a counterparty of this ${subjectNoun}, not an observation about the ${subjectNoun} itself.`,
|
|
683
|
+
indirect: true
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
return {
|
|
687
|
+
hops: n,
|
|
688
|
+
label: `${n} hops`,
|
|
689
|
+
statement: `Observed ${n} hops away. This is an inference about a counterparty ${n} steps removed from this ${subjectNoun}, not an observation about the ${subjectNoun} itself.`,
|
|
690
|
+
indirect: true
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function evidencePresentation(evidence, copy) {
|
|
694
|
+
return {
|
|
695
|
+
id: evidence.id,
|
|
696
|
+
type: evidence.type,
|
|
697
|
+
source: evidence.source,
|
|
698
|
+
observedAt: formatTimestamp(evidence.observedAt),
|
|
699
|
+
confidenceLabel: formatConfidence(evidence.confidence),
|
|
700
|
+
analystConfirmed: evidence.analystVerified,
|
|
701
|
+
attribution: evidence.analystVerified ? copy.analystConfirmed : copy.notAnalystConfirmed,
|
|
702
|
+
reference: evidence.txHash ?? evidence.contract ?? evidence.address
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
var UNKNOWN_REASON_LABEL = {
|
|
706
|
+
UNKNOWN: "Not known",
|
|
707
|
+
INSUFFICIENT_DATA: "Not enough data",
|
|
708
|
+
PROVIDER_UNAVAILABLE: "Could not be checked",
|
|
709
|
+
NOT_APPLICABLE: "Not applicable"
|
|
710
|
+
};
|
|
711
|
+
function unknownPresentation(unknown) {
|
|
712
|
+
return {
|
|
713
|
+
kind: "unknown",
|
|
714
|
+
field: unknown.field,
|
|
715
|
+
statement: unknown.statement,
|
|
716
|
+
reasonLabel: UNKNOWN_REASON_LABEL[unknown.reason],
|
|
717
|
+
tone: "unknown"
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
var HISTORY_LABEL = {
|
|
721
|
+
ESTABLISHED: "Established history",
|
|
722
|
+
MODERATE: "Some history",
|
|
723
|
+
LIMITED: "Limited history",
|
|
724
|
+
NONE: "No history"
|
|
725
|
+
};
|
|
726
|
+
function historyPresentation(status) {
|
|
727
|
+
return {
|
|
728
|
+
status,
|
|
729
|
+
label: HISTORY_LABEL[status],
|
|
730
|
+
statement: HISTORY_STATUS_MEANING[status],
|
|
731
|
+
tone: "neutral",
|
|
732
|
+
isWarning: false
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function componentRows(components, copy) {
|
|
736
|
+
return [
|
|
737
|
+
{ key: "technicalRisk", label: "Technical", value: components.technicalRisk, isCoverage: false },
|
|
738
|
+
{ key: "behavioralRisk", label: "Behavioural", value: components.behavioralRisk, isCoverage: false },
|
|
739
|
+
{
|
|
740
|
+
key: "threatIntelligenceRisk",
|
|
741
|
+
label: "Threat intelligence",
|
|
742
|
+
value: components.threatIntelligenceRisk,
|
|
743
|
+
isCoverage: false
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
key: "historyConfidence",
|
|
747
|
+
label: "Coverage",
|
|
748
|
+
value: components.historyConfidence,
|
|
749
|
+
isCoverage: true,
|
|
750
|
+
caveat: copy.coverageIsNotRisk
|
|
751
|
+
}
|
|
752
|
+
];
|
|
753
|
+
}
|
|
754
|
+
function assessmentSections(assessment, copy) {
|
|
755
|
+
const facts = assessment.facts ?? [];
|
|
756
|
+
const capabilities = assessment.capabilities ?? [];
|
|
757
|
+
const signals = assessment.threatSignals ?? [];
|
|
758
|
+
const unknowns = assessment.unknowns ?? [];
|
|
759
|
+
const activeSignals = signals.filter(
|
|
760
|
+
(s) => s.status === "ACTIVE" && s.confidence >= MIN_RAISING_CONFIDENCE
|
|
761
|
+
);
|
|
762
|
+
const inertSignals = signals.filter((s) => !activeSignals.includes(s));
|
|
763
|
+
const isEmpty = facts.length === 0 && capabilities.length === 0 && signals.length === 0 && unknowns.length === 0;
|
|
764
|
+
const parts = [];
|
|
765
|
+
if (facts.length) parts.push(`${facts.length} ${plural(facts.length, "fact")}`);
|
|
766
|
+
if (capabilities.length) {
|
|
767
|
+
parts.push(`${capabilities.length} ${plural(capabilities.length, "capability", "capabilities")}`);
|
|
768
|
+
}
|
|
769
|
+
if (signals.length) parts.push(`${signals.length} ${plural(signals.length, "threat signal")}`);
|
|
770
|
+
if (unknowns.length) parts.push(`${unknowns.length} ${plural(unknowns.length, "unknown")}`);
|
|
771
|
+
return {
|
|
772
|
+
facts,
|
|
773
|
+
capabilities,
|
|
774
|
+
activeSignals,
|
|
775
|
+
inertSignals,
|
|
776
|
+
unknowns,
|
|
777
|
+
isEmpty,
|
|
778
|
+
emptyStatement: isEmpty ? `${copy.nothingReturned} ${copy.notAnAssurance}` : void 0,
|
|
779
|
+
summary: parts.length ? parts.join(" \xB7 ") : copy.nothingReturned
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function availabilityPresentation(assessment) {
|
|
783
|
+
const outage = (assessment.unknowns ?? []).filter((u) => u.reason === "PROVIDER_UNAVAILABLE");
|
|
784
|
+
if (outage.length === 0) return { unavailable: false, tone: "neutral" };
|
|
785
|
+
return {
|
|
786
|
+
unavailable: true,
|
|
787
|
+
statement: outage.map((u) => u.statement).join(" "),
|
|
788
|
+
tone: "neutral"
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
var DECISION_LABEL = {
|
|
792
|
+
allow: "No action requested",
|
|
793
|
+
inform: "For your information",
|
|
794
|
+
warn: "Review before continuing",
|
|
795
|
+
warn_strong: "Review carefully before continuing",
|
|
796
|
+
require_confirmation: "Explicit confirmation requested",
|
|
797
|
+
block: "This application will not continue"
|
|
798
|
+
};
|
|
799
|
+
var DECISION_STATEMENT = {
|
|
800
|
+
allow: "This application\u2019s policy asks for nothing further.",
|
|
801
|
+
inform: "Shown because this application\u2019s policy asks that you see it.",
|
|
802
|
+
warn: "This application\u2019s policy asks you to read the detail before continuing.",
|
|
803
|
+
warn_strong: "This application\u2019s policy asks you to read the detail carefully before continuing.",
|
|
804
|
+
require_confirmation: "This application\u2019s policy asks you to confirm explicitly before continuing.",
|
|
805
|
+
block: "This application\u2019s policy stops here. That decision belongs to this application; Decentrys reports evidence and does not stop anything."
|
|
806
|
+
};
|
|
807
|
+
function decisionPresentation(decision) {
|
|
808
|
+
return {
|
|
809
|
+
action: decision.action,
|
|
810
|
+
label: DECISION_LABEL[decision.action],
|
|
811
|
+
statement: DECISION_STATEMENT[decision.action],
|
|
812
|
+
reason: decision.reason,
|
|
813
|
+
blocksUi: false
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function approvalPresentation(details) {
|
|
817
|
+
const spenderName = details.spenderLabel?.trim() || shortenAddress(details.spender);
|
|
818
|
+
const assetName = details.symbol?.trim() || `tokens at ${shortenAddress(details.token)}`;
|
|
819
|
+
if (details.amount === void 0 || details.amount === null || details.amount === "") {
|
|
820
|
+
return {
|
|
821
|
+
unlimited: false,
|
|
822
|
+
amountKnown: false,
|
|
823
|
+
amountLabel: "Not decoded",
|
|
824
|
+
scopeLabel: "Allowance amount not decoded",
|
|
825
|
+
statement: `The allowance amount could not be decoded, so how much this grants ${spenderName} over your ${assetName} is not known.`,
|
|
826
|
+
spenderName,
|
|
827
|
+
assetName,
|
|
828
|
+
tone: "capability",
|
|
829
|
+
emphasis: "strong"
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
if (isUnlimitedAllowance(details.amount)) {
|
|
833
|
+
return {
|
|
834
|
+
unlimited: true,
|
|
835
|
+
amountKnown: true,
|
|
836
|
+
amountLabel: "Unlimited",
|
|
837
|
+
scopeLabel: "Unlimited allowance",
|
|
838
|
+
statement: `This grants ${spenderName} permission to spend an unlimited amount of your ${assetName}, now and at any time in the future, until it is revoked.`,
|
|
839
|
+
spenderName,
|
|
840
|
+
assetName,
|
|
841
|
+
tone: "capability",
|
|
842
|
+
emphasis: "strong"
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
const baseUnits = details.decimals === void 0;
|
|
846
|
+
const figure = formatTokenAmount(details.amount, details.decimals);
|
|
847
|
+
const amountLabel = baseUnits ? `${figure} base units` : `${figure} ${assetName}`;
|
|
848
|
+
return {
|
|
849
|
+
unlimited: false,
|
|
850
|
+
amountKnown: true,
|
|
851
|
+
amountLabel,
|
|
852
|
+
scopeLabel: "Limited allowance",
|
|
853
|
+
statement: `This grants ${spenderName} permission to spend up to ${figure} ${baseUnits ? `base units of ${assetName}` : assetName}, until it is revoked.`,
|
|
854
|
+
spenderName,
|
|
855
|
+
assetName,
|
|
856
|
+
tone: "capability",
|
|
857
|
+
emphasis: "normal"
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
function isUnlimitedAllowance(amount) {
|
|
861
|
+
if (amount.trim().toLowerCase() === "unlimited") return true;
|
|
862
|
+
try {
|
|
863
|
+
return BigInt(amount) >= 1n << 255n;
|
|
864
|
+
} catch {
|
|
865
|
+
return false;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
function formatConfidence(confidence) {
|
|
869
|
+
const clamped = Math.min(1, Math.max(0, confidence));
|
|
870
|
+
return `${Math.round(clamped * 100)}%`;
|
|
871
|
+
}
|
|
872
|
+
function formatTimestamp(iso) {
|
|
873
|
+
const ms = Date.parse(iso);
|
|
874
|
+
if (Number.isNaN(ms)) return iso;
|
|
875
|
+
return `${new Date(ms).toISOString().slice(0, 16).replace("T", " ")} UTC`;
|
|
876
|
+
}
|
|
877
|
+
function shortenAddress(address, lead = 6, tail = 4) {
|
|
878
|
+
if (address.length <= lead + tail + 1) return address;
|
|
879
|
+
return `${address.slice(0, lead)}\u2026${address.slice(-tail)}`;
|
|
880
|
+
}
|
|
881
|
+
function formatTokenAmount(amount, decimals) {
|
|
882
|
+
let value;
|
|
883
|
+
try {
|
|
884
|
+
value = BigInt(amount);
|
|
885
|
+
} catch {
|
|
886
|
+
return amount;
|
|
887
|
+
}
|
|
888
|
+
if (decimals === void 0 || decimals < 0) return group(value.toString());
|
|
889
|
+
const negative = value < 0n;
|
|
890
|
+
const abs = negative ? -value : value;
|
|
891
|
+
const scale = 10n ** BigInt(decimals);
|
|
892
|
+
const whole = abs / scale;
|
|
893
|
+
const fraction = (abs % scale).toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
894
|
+
const text = fraction ? `${group(whole.toString())}.${fraction}` : group(whole.toString());
|
|
895
|
+
return negative ? `-${text}` : text;
|
|
896
|
+
}
|
|
897
|
+
function group(digits) {
|
|
898
|
+
return digits.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
899
|
+
}
|
|
900
|
+
function plural(count, singular, pluralForm) {
|
|
901
|
+
if (count === 1) return singular;
|
|
902
|
+
return pluralForm ?? `${singular}s`;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// src/primitives.tsx
|
|
906
|
+
function cx(...parts) {
|
|
907
|
+
return parts.filter(Boolean).join(" ");
|
|
908
|
+
}
|
|
909
|
+
function StyleGate({ emit }) {
|
|
910
|
+
return emit ? /* @__PURE__ */ jsx(DecentrysUiStyles, {}) : null;
|
|
911
|
+
}
|
|
912
|
+
function LevelBadge({ level }) {
|
|
913
|
+
return /* @__PURE__ */ jsxs("span", { className: "dcy-badge", "data-dcy-tone": level.tone, "data-dcy-level": level.level, children: [
|
|
914
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-glyph", "aria-hidden": "true", children: level.glyph }),
|
|
915
|
+
/* @__PURE__ */ jsx("span", { children: level.label })
|
|
916
|
+
] });
|
|
917
|
+
}
|
|
918
|
+
function Chip({ children, title }) {
|
|
919
|
+
return /* @__PURE__ */ jsx("span", { className: "dcy-chip", title, children });
|
|
920
|
+
}
|
|
921
|
+
function Mono({ children }) {
|
|
922
|
+
return /* @__PURE__ */ jsx("span", { className: "dcy-mono", children });
|
|
923
|
+
}
|
|
924
|
+
function ScreenReaderText({ children }) {
|
|
925
|
+
return /* @__PURE__ */ jsx("span", { className: "dcy-sr", children });
|
|
926
|
+
}
|
|
927
|
+
function Section({
|
|
928
|
+
title,
|
|
929
|
+
note,
|
|
930
|
+
children
|
|
931
|
+
}) {
|
|
932
|
+
return /* @__PURE__ */ jsxs("section", { className: "dcy-section", children: [
|
|
933
|
+
/* @__PURE__ */ jsx("h4", { className: "dcy-section-title", children: title }),
|
|
934
|
+
note ? /* @__PURE__ */ jsx("p", { className: "dcy-note", children: note }) : null,
|
|
935
|
+
children
|
|
936
|
+
] });
|
|
937
|
+
}
|
|
938
|
+
function EmptyNote({ children }) {
|
|
939
|
+
return /* @__PURE__ */ jsx("p", { className: "dcy-note", "data-dcy-empty": "", children });
|
|
940
|
+
}
|
|
941
|
+
function FactRow({ fact, copy }) {
|
|
942
|
+
const kind = kindPresentation("fact", copy);
|
|
943
|
+
const p = factPresentation(fact);
|
|
944
|
+
return /* @__PURE__ */ jsxs(
|
|
945
|
+
"li",
|
|
946
|
+
{
|
|
947
|
+
className: "dcy-row",
|
|
948
|
+
"data-dcy-kind": "fact",
|
|
949
|
+
"data-dcy-tone": p.tone,
|
|
950
|
+
"data-dcy-rule": kind.rule,
|
|
951
|
+
children: [
|
|
952
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-glyph", "aria-hidden": "true", children: kind.glyph }),
|
|
953
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-row-body", children: [
|
|
954
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-row-statement", children: [
|
|
955
|
+
/* @__PURE__ */ jsx(Chip, { children: kind.label }),
|
|
956
|
+
" ",
|
|
957
|
+
p.statement
|
|
958
|
+
] }),
|
|
959
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-row-meta", children: [
|
|
960
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
961
|
+
copy.sourceLabel,
|
|
962
|
+
": ",
|
|
963
|
+
p.source
|
|
964
|
+
] }),
|
|
965
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
966
|
+
copy.observedLabel,
|
|
967
|
+
": ",
|
|
968
|
+
p.observedAt
|
|
969
|
+
] })
|
|
970
|
+
] })
|
|
971
|
+
] })
|
|
972
|
+
]
|
|
973
|
+
}
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
function CapabilityRow({
|
|
977
|
+
capability,
|
|
978
|
+
copy
|
|
979
|
+
}) {
|
|
980
|
+
const kind = kindPresentation("capability", copy);
|
|
981
|
+
const p = capabilityPresentation(capability);
|
|
982
|
+
return /* @__PURE__ */ jsxs(
|
|
983
|
+
"li",
|
|
984
|
+
{
|
|
985
|
+
className: "dcy-row",
|
|
986
|
+
"data-dcy-kind": "capability",
|
|
987
|
+
"data-dcy-tone": p.tone,
|
|
988
|
+
"data-dcy-rule": kind.rule,
|
|
989
|
+
"data-dcy-severity": p.severity,
|
|
990
|
+
children: [
|
|
991
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-glyph", "aria-hidden": "true", children: kind.glyph }),
|
|
992
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-row-body", children: [
|
|
993
|
+
/* @__PURE__ */ jsxs("p", { className: cx("dcy-row-statement", p.emphasis === "strong" && "dcy-row-strong"), children: [
|
|
994
|
+
/* @__PURE__ */ jsx(Chip, { children: kind.label }),
|
|
995
|
+
" ",
|
|
996
|
+
/* @__PURE__ */ jsx(Chip, { children: p.severityLabel }),
|
|
997
|
+
" ",
|
|
998
|
+
p.statement
|
|
999
|
+
] }),
|
|
1000
|
+
p.grantedBy ? /* @__PURE__ */ jsx("p", { className: "dcy-row-meta", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
1001
|
+
copy.grantedByLabel,
|
|
1002
|
+
": ",
|
|
1003
|
+
/* @__PURE__ */ jsx(Mono, { children: p.grantedBy })
|
|
1004
|
+
] }) }) : null
|
|
1005
|
+
] })
|
|
1006
|
+
]
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
function UnknownRow({
|
|
1011
|
+
unknown,
|
|
1012
|
+
copy
|
|
1013
|
+
}) {
|
|
1014
|
+
const kind = kindPresentation("unknown", copy);
|
|
1015
|
+
const p = unknownPresentation(unknown);
|
|
1016
|
+
return /* @__PURE__ */ jsxs(
|
|
1017
|
+
"li",
|
|
1018
|
+
{
|
|
1019
|
+
className: "dcy-row",
|
|
1020
|
+
"data-dcy-kind": "unknown",
|
|
1021
|
+
"data-dcy-tone": p.tone,
|
|
1022
|
+
"data-dcy-rule": kind.rule,
|
|
1023
|
+
children: [
|
|
1024
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-glyph", "aria-hidden": "true", children: kind.glyph }),
|
|
1025
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-row-body", children: [
|
|
1026
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-row-statement", children: [
|
|
1027
|
+
/* @__PURE__ */ jsx(Chip, { children: kind.label }),
|
|
1028
|
+
" ",
|
|
1029
|
+
p.statement
|
|
1030
|
+
] }),
|
|
1031
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-row-meta", children: [
|
|
1032
|
+
/* @__PURE__ */ jsx("span", { children: p.field }),
|
|
1033
|
+
/* @__PURE__ */ jsx("span", { children: p.reasonLabel })
|
|
1034
|
+
] })
|
|
1035
|
+
] })
|
|
1036
|
+
]
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
function EvidenceList({
|
|
1041
|
+
evidence,
|
|
1042
|
+
copy
|
|
1043
|
+
}) {
|
|
1044
|
+
if (evidence.length === 0) return null;
|
|
1045
|
+
return /* @__PURE__ */ jsxs("div", { className: "dcy-section", children: [
|
|
1046
|
+
/* @__PURE__ */ jsx("h5", { className: "dcy-section-title", children: copy.evidenceHeading }),
|
|
1047
|
+
evidence.map((item) => {
|
|
1048
|
+
const e = evidencePresentation(item, copy);
|
|
1049
|
+
return /* @__PURE__ */ jsxs("dl", { className: "dcy-kv", children: [
|
|
1050
|
+
/* @__PURE__ */ jsx("dt", { children: copy.sourceLabel }),
|
|
1051
|
+
/* @__PURE__ */ jsx("dd", { children: e.source }),
|
|
1052
|
+
/* @__PURE__ */ jsx("dt", { children: "Type" }),
|
|
1053
|
+
/* @__PURE__ */ jsx("dd", { children: e.type }),
|
|
1054
|
+
/* @__PURE__ */ jsx("dt", { children: copy.observedLabel }),
|
|
1055
|
+
/* @__PURE__ */ jsx("dd", { children: e.observedAt }),
|
|
1056
|
+
/* @__PURE__ */ jsx("dt", { children: copy.confidenceLabel }),
|
|
1057
|
+
/* @__PURE__ */ jsx("dd", { children: e.confidenceLabel }),
|
|
1058
|
+
e.reference ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1059
|
+
/* @__PURE__ */ jsx("dt", { children: "Reference" }),
|
|
1060
|
+
/* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Mono, { children: e.reference }) })
|
|
1061
|
+
] }) : null,
|
|
1062
|
+
/* @__PURE__ */ jsx("dt", { children: "Attribution" }),
|
|
1063
|
+
/* @__PURE__ */ jsx("dd", { children: e.attribution }),
|
|
1064
|
+
/* @__PURE__ */ jsx("dt", { children: "Evidence id" }),
|
|
1065
|
+
/* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Mono, { children: e.id }) })
|
|
1066
|
+
] }, e.id);
|
|
1067
|
+
})
|
|
1068
|
+
] });
|
|
1069
|
+
}
|
|
1070
|
+
function SignalCard({
|
|
1071
|
+
signal,
|
|
1072
|
+
copy,
|
|
1073
|
+
subjectNoun,
|
|
1074
|
+
showEvidence = false
|
|
1075
|
+
}) {
|
|
1076
|
+
const kind = kindPresentation("signal", copy);
|
|
1077
|
+
const p = signalPresentation(signal, copy, { subjectNoun });
|
|
1078
|
+
return /* @__PURE__ */ jsxs(
|
|
1079
|
+
"li",
|
|
1080
|
+
{
|
|
1081
|
+
className: "dcy-signal",
|
|
1082
|
+
"data-dcy-kind": "signal",
|
|
1083
|
+
"data-dcy-tone": p.tone,
|
|
1084
|
+
"data-dcy-severity": p.severity,
|
|
1085
|
+
"data-dcy-raising": String(p.raising),
|
|
1086
|
+
"data-dcy-hops": String(p.hops),
|
|
1087
|
+
children: [
|
|
1088
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-signal-head", children: [
|
|
1089
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-glyph", "aria-hidden": "true", children: kind.glyph }),
|
|
1090
|
+
/* @__PURE__ */ jsx(Chip, { children: kind.label }),
|
|
1091
|
+
/* @__PURE__ */ jsxs(Chip, { children: [
|
|
1092
|
+
p.severityLabel,
|
|
1093
|
+
" severity"
|
|
1094
|
+
] }),
|
|
1095
|
+
/* @__PURE__ */ jsxs(Chip, { title: copy.confidenceCaveat, children: [
|
|
1096
|
+
p.confidenceLabel,
|
|
1097
|
+
" ",
|
|
1098
|
+
copy.confidenceLabel.toLowerCase()
|
|
1099
|
+
] }),
|
|
1100
|
+
/* @__PURE__ */ jsx(Chip, { children: p.hopLabel }),
|
|
1101
|
+
p.active ? null : /* @__PURE__ */ jsx(Chip, { children: p.statusLabel })
|
|
1102
|
+
] }),
|
|
1103
|
+
/* @__PURE__ */ jsx("p", { className: "dcy-row-statement dcy-row-strong", children: p.explanation }),
|
|
1104
|
+
/* @__PURE__ */ jsx("p", { className: "dcy-note", children: p.hopStatement }),
|
|
1105
|
+
p.inertStatement ? /* @__PURE__ */ jsx("p", { className: "dcy-note", children: p.inertStatement }) : null,
|
|
1106
|
+
/* @__PURE__ */ jsx("p", { className: "dcy-note", children: p.attribution }),
|
|
1107
|
+
showEvidence ? /* @__PURE__ */ jsx(EvidenceList, { evidence: signal.evidence, copy }) : null
|
|
1108
|
+
]
|
|
1109
|
+
}
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
function SignalList({
|
|
1113
|
+
signals,
|
|
1114
|
+
copy,
|
|
1115
|
+
subjectNoun,
|
|
1116
|
+
showEvidence
|
|
1117
|
+
}) {
|
|
1118
|
+
if (signals.length === 0) return /* @__PURE__ */ jsx(EmptyNote, { children: copy.noSignals });
|
|
1119
|
+
return /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: signals.map((signal, index) => /* @__PURE__ */ jsx(
|
|
1120
|
+
SignalCard,
|
|
1121
|
+
{
|
|
1122
|
+
signal,
|
|
1123
|
+
copy,
|
|
1124
|
+
subjectNoun,
|
|
1125
|
+
showEvidence
|
|
1126
|
+
},
|
|
1127
|
+
`${signal.type}:${signal.createdAt}:${index}`
|
|
1128
|
+
)) });
|
|
1129
|
+
}
|
|
1130
|
+
function HistoryNote({
|
|
1131
|
+
status,
|
|
1132
|
+
copy
|
|
1133
|
+
}) {
|
|
1134
|
+
const h = historyPresentation(status);
|
|
1135
|
+
return /* @__PURE__ */ jsxs("p", { className: "dcy-note", "data-dcy-tone": h.tone, "data-dcy-history": h.status, children: [
|
|
1136
|
+
/* @__PURE__ */ jsx(Chip, { children: h.label }),
|
|
1137
|
+
" ",
|
|
1138
|
+
h.statement
|
|
1139
|
+
] });
|
|
1140
|
+
}
|
|
1141
|
+
function AvailabilityNote({ assessment }) {
|
|
1142
|
+
const a = availabilityPresentation(assessment);
|
|
1143
|
+
if (!a.unavailable) return null;
|
|
1144
|
+
return /* @__PURE__ */ jsx("p", { className: "dcy-note", "data-dcy-tone": a.tone, "data-dcy-unavailable": "", children: a.statement });
|
|
1145
|
+
}
|
|
1146
|
+
function DemotedNote({
|
|
1147
|
+
demotedSignals,
|
|
1148
|
+
copy
|
|
1149
|
+
}) {
|
|
1150
|
+
if (!demotedSignals || demotedSignals.length === 0) return null;
|
|
1151
|
+
return /* @__PURE__ */ jsx(Section, { title: copy.demotedHeading, note: copy.demotedExplanation, children: /* @__PURE__ */ jsx("p", { className: "dcy-row-meta", children: demotedSignals.map((type) => /* @__PURE__ */ jsx(Chip, { children: type }, type)) }) });
|
|
1152
|
+
}
|
|
1153
|
+
function ExplanationList({ explanation }) {
|
|
1154
|
+
if (explanation.length === 0) return null;
|
|
1155
|
+
return /* @__PURE__ */ jsx("ul", { className: "dcy-list", "data-dcy-explanation": "", children: explanation.map((line, index) => /* @__PURE__ */ jsx("li", { className: "dcy-note", children: line }, `${index}:${line.slice(0, 24)}`)) });
|
|
1156
|
+
}
|
|
1157
|
+
function LevelHeader({
|
|
1158
|
+
assessment,
|
|
1159
|
+
copy,
|
|
1160
|
+
levelLabels,
|
|
1161
|
+
children
|
|
1162
|
+
}) {
|
|
1163
|
+
const level = levelPresentation(assessment.riskLevel, { labels: levelLabels });
|
|
1164
|
+
return /* @__PURE__ */ jsxs("div", { className: "dcy-head", children: [
|
|
1165
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-head-main", children: [
|
|
1166
|
+
/* @__PURE__ */ jsx("h3", { className: "dcy-title", children: level.label }),
|
|
1167
|
+
/* @__PURE__ */ jsx("p", { className: "dcy-meaning", children: level.meaning })
|
|
1168
|
+
] }),
|
|
1169
|
+
/* @__PURE__ */ jsx(LevelBadge, { level }),
|
|
1170
|
+
children
|
|
1171
|
+
] });
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// src/components/TransactionRiskBanner.tsx
|
|
1175
|
+
function TransactionRiskBanner({
|
|
1176
|
+
result,
|
|
1177
|
+
subjectNoun = "transaction",
|
|
1178
|
+
actions,
|
|
1179
|
+
onViewDetails,
|
|
1180
|
+
maxExplanationLines = 4,
|
|
1181
|
+
className,
|
|
1182
|
+
style,
|
|
1183
|
+
theme,
|
|
1184
|
+
copy: copyOverrides,
|
|
1185
|
+
levelLabels
|
|
1186
|
+
}) {
|
|
1187
|
+
const { copy, theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy: copyOverrides });
|
|
1188
|
+
const { assessment, decision, cached, demotedSignals } = result;
|
|
1189
|
+
const level = levelPresentation(assessment.riskLevel, { labels: levelLabels });
|
|
1190
|
+
const sections = assessmentSections(assessment, copy);
|
|
1191
|
+
const policy = decisionPresentation(decision);
|
|
1192
|
+
return /* @__PURE__ */ jsxs(
|
|
1193
|
+
"section",
|
|
1194
|
+
{
|
|
1195
|
+
className: cx("dcy", "dcy-card", className),
|
|
1196
|
+
style: themeStyle(mergedTheme, style),
|
|
1197
|
+
"data-dcy-component": "transaction-risk-banner",
|
|
1198
|
+
"data-dcy-level": assessment.riskLevel,
|
|
1199
|
+
"data-dcy-tone": level.tone,
|
|
1200
|
+
role: level.liveRegionRole,
|
|
1201
|
+
"aria-label": level.ariaLabel,
|
|
1202
|
+
children: [
|
|
1203
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1204
|
+
/* @__PURE__ */ jsx(LevelHeader, { assessment, copy, levelLabels }),
|
|
1205
|
+
/* @__PURE__ */ jsx(AvailabilityNote, { assessment }),
|
|
1206
|
+
/* @__PURE__ */ jsx(ExplanationList, { explanation: assessment.explanation.slice(0, maxExplanationLines) }),
|
|
1207
|
+
sections.isEmpty ? /* @__PURE__ */ jsx(EmptyNote, { children: sections.emptyStatement }) : /* @__PURE__ */ jsx("p", { className: "dcy-note", "data-dcy-summary": "", children: sections.summary }),
|
|
1208
|
+
sections.activeSignals.length > 0 ? /* @__PURE__ */ jsx(Section, { title: copy.signalsHeading, children: /* @__PURE__ */ jsx(SignalList, { signals: sections.activeSignals, copy, subjectNoun }) }) : null,
|
|
1209
|
+
sections.inertSignals.length > 0 ? /* @__PURE__ */ jsxs(EmptyNote, { children: [
|
|
1210
|
+
sections.inertSignals.length,
|
|
1211
|
+
" ",
|
|
1212
|
+
plural(sections.inertSignals.length, "further signal was", "further signals were"),
|
|
1213
|
+
" ",
|
|
1214
|
+
"observed and did not affect this assessment. They are listed in full in the details."
|
|
1215
|
+
] }) : null,
|
|
1216
|
+
sections.unknowns.length > 0 ? /* @__PURE__ */ jsx(Section, { title: copy.unknownsHeading, note: copy.unknownsAreNotRisk, children: /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.unknowns.map((unknown) => /* @__PURE__ */ jsx(UnknownRow, { unknown, copy }, unknown.field)) }) }) : null,
|
|
1217
|
+
/* @__PURE__ */ jsx(HistoryNote, { status: assessment.historyStatus, copy }),
|
|
1218
|
+
/* @__PURE__ */ jsx(DemotedNote, { demotedSignals, copy }),
|
|
1219
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-note", "data-dcy-decision": policy.action, children: [
|
|
1220
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-chip", children: policy.label }),
|
|
1221
|
+
" ",
|
|
1222
|
+
policy.statement
|
|
1223
|
+
] }),
|
|
1224
|
+
cached ? /* @__PURE__ */ jsx("p", { className: "dcy-note", children: copy.cachedNotice }) : null,
|
|
1225
|
+
onViewDetails || actions ? /* @__PURE__ */ jsxs("div", { className: "dcy-head", children: [
|
|
1226
|
+
onViewDetails ? /* @__PURE__ */ jsx("button", { type: "button", className: "dcy-btn dcy-btn-quiet", onClick: onViewDetails, children: copy.viewDetails }) : null,
|
|
1227
|
+
actions
|
|
1228
|
+
] }) : null
|
|
1229
|
+
]
|
|
1230
|
+
}
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// src/components/ApprovalWarning.tsx
|
|
1235
|
+
function ApprovalWarning({
|
|
1236
|
+
result,
|
|
1237
|
+
approval,
|
|
1238
|
+
actions,
|
|
1239
|
+
onViewDetails,
|
|
1240
|
+
className,
|
|
1241
|
+
style,
|
|
1242
|
+
theme,
|
|
1243
|
+
copy: copyOverrides,
|
|
1244
|
+
levelLabels
|
|
1245
|
+
}) {
|
|
1246
|
+
const { copy, theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy: copyOverrides });
|
|
1247
|
+
const { assessment, decision, demotedSignals } = result;
|
|
1248
|
+
const level = levelPresentation(assessment.riskLevel, { labels: levelLabels });
|
|
1249
|
+
const scope = approvalPresentation(approval);
|
|
1250
|
+
const sections = assessmentSections(assessment, copy);
|
|
1251
|
+
const policy = decisionPresentation(decision);
|
|
1252
|
+
return /* @__PURE__ */ jsxs(
|
|
1253
|
+
"section",
|
|
1254
|
+
{
|
|
1255
|
+
className: cx("dcy", "dcy-card", className),
|
|
1256
|
+
style: themeStyle(mergedTheme, style),
|
|
1257
|
+
"data-dcy-component": "approval-warning",
|
|
1258
|
+
"data-dcy-level": assessment.riskLevel,
|
|
1259
|
+
"data-dcy-tone": level.tone,
|
|
1260
|
+
"data-dcy-unlimited": String(scope.unlimited),
|
|
1261
|
+
role: level.liveRegionRole,
|
|
1262
|
+
"aria-label": `${scope.scopeLabel}. ${level.ariaLabel}`,
|
|
1263
|
+
children: [
|
|
1264
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1265
|
+
/* @__PURE__ */ jsx(LevelHeader, { assessment, copy, levelLabels }),
|
|
1266
|
+
/* @__PURE__ */ jsx(AvailabilityNote, { assessment }),
|
|
1267
|
+
/* @__PURE__ */ jsxs(Section, { title: copy.approvalHeading, children: [
|
|
1268
|
+
/* @__PURE__ */ jsxs(
|
|
1269
|
+
"div",
|
|
1270
|
+
{
|
|
1271
|
+
className: "dcy-row",
|
|
1272
|
+
"data-dcy-kind": "capability",
|
|
1273
|
+
"data-dcy-tone": scope.tone,
|
|
1274
|
+
"data-dcy-rule": "dashed",
|
|
1275
|
+
children: [
|
|
1276
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-glyph", "aria-hidden": "true", children: "\u25C7" }),
|
|
1277
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-row-body", children: [
|
|
1278
|
+
/* @__PURE__ */ jsxs("p", { className: cx("dcy-row-statement", scope.emphasis === "strong" && "dcy-row-strong"), children: [
|
|
1279
|
+
/* @__PURE__ */ jsx(Chip, { children: scope.scopeLabel }),
|
|
1280
|
+
" ",
|
|
1281
|
+
scope.statement
|
|
1282
|
+
] }),
|
|
1283
|
+
/* @__PURE__ */ jsx("p", { className: "dcy-note", children: copy.approvalRevocation })
|
|
1284
|
+
] })
|
|
1285
|
+
]
|
|
1286
|
+
}
|
|
1287
|
+
),
|
|
1288
|
+
/* @__PURE__ */ jsxs("dl", { className: "dcy-kv", children: [
|
|
1289
|
+
/* @__PURE__ */ jsx("dt", { children: copy.spenderLabel }),
|
|
1290
|
+
/* @__PURE__ */ jsxs("dd", { children: [
|
|
1291
|
+
/* @__PURE__ */ jsx(Mono, { children: approval.spender }),
|
|
1292
|
+
approval.spenderLabel ? ` \u2014 ${approval.spenderLabel}` : null
|
|
1293
|
+
] }),
|
|
1294
|
+
/* @__PURE__ */ jsx("dt", { children: copy.tokenLabel }),
|
|
1295
|
+
/* @__PURE__ */ jsxs("dd", { children: [
|
|
1296
|
+
/* @__PURE__ */ jsx(Mono, { children: approval.token }),
|
|
1297
|
+
approval.symbol ? ` \u2014 ${approval.symbol}` : null
|
|
1298
|
+
] }),
|
|
1299
|
+
/* @__PURE__ */ jsx("dt", { children: "Amount" }),
|
|
1300
|
+
/* @__PURE__ */ jsx("dd", { children: scope.amountLabel })
|
|
1301
|
+
] })
|
|
1302
|
+
] }),
|
|
1303
|
+
/* @__PURE__ */ jsx(Section, { title: copy.signalsHeading, children: /* @__PURE__ */ jsx(
|
|
1304
|
+
SignalList,
|
|
1305
|
+
{
|
|
1306
|
+
signals: [...sections.activeSignals, ...sections.inertSignals],
|
|
1307
|
+
copy,
|
|
1308
|
+
subjectNoun: "spender"
|
|
1309
|
+
}
|
|
1310
|
+
) }),
|
|
1311
|
+
sections.unknowns.length > 0 ? /* @__PURE__ */ jsx(Section, { title: copy.unknownsHeading, note: copy.unknownsAreNotRisk, children: /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.unknowns.map((unknown) => /* @__PURE__ */ jsx(UnknownRow, { unknown, copy }, unknown.field)) }) }) : null,
|
|
1312
|
+
/* @__PURE__ */ jsx(HistoryNote, { status: assessment.historyStatus, copy }),
|
|
1313
|
+
demotedSignals && demotedSignals.length > 0 ? /* @__PURE__ */ jsxs(EmptyNote, { children: [
|
|
1314
|
+
copy.demotedHeading,
|
|
1315
|
+
": ",
|
|
1316
|
+
demotedSignals.join(", "),
|
|
1317
|
+
". ",
|
|
1318
|
+
copy.demotedExplanation
|
|
1319
|
+
] }) : null,
|
|
1320
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-note", "data-dcy-decision": policy.action, children: [
|
|
1321
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-chip", children: policy.label }),
|
|
1322
|
+
" ",
|
|
1323
|
+
policy.statement
|
|
1324
|
+
] }),
|
|
1325
|
+
onViewDetails || actions ? /* @__PURE__ */ jsxs("div", { className: "dcy-head", children: [
|
|
1326
|
+
onViewDetails ? /* @__PURE__ */ jsx("button", { type: "button", className: "dcy-btn dcy-btn-quiet", onClick: onViewDetails, children: copy.viewDetails }) : null,
|
|
1327
|
+
actions
|
|
1328
|
+
] }) : null
|
|
1329
|
+
]
|
|
1330
|
+
}
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// src/components/ContractFacts.tsx
|
|
1335
|
+
function ContractFacts({
|
|
1336
|
+
assessment,
|
|
1337
|
+
demotedSignals,
|
|
1338
|
+
onViewSignals,
|
|
1339
|
+
title,
|
|
1340
|
+
className,
|
|
1341
|
+
style,
|
|
1342
|
+
theme,
|
|
1343
|
+
copy: copyOverrides
|
|
1344
|
+
}) {
|
|
1345
|
+
const { copy, theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy: copyOverrides });
|
|
1346
|
+
const sections = assessmentSections(assessment, copy);
|
|
1347
|
+
const signalCount = sections.activeSignals.length + sections.inertSignals.length;
|
|
1348
|
+
return /* @__PURE__ */ jsxs(
|
|
1349
|
+
"section",
|
|
1350
|
+
{
|
|
1351
|
+
className: cx("dcy", "dcy-card", className),
|
|
1352
|
+
style: themeStyle(mergedTheme, style),
|
|
1353
|
+
"data-dcy-component": "contract-facts",
|
|
1354
|
+
"aria-label": title ?? "Contract facts and capabilities",
|
|
1355
|
+
children: [
|
|
1356
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1357
|
+
title ? /* @__PURE__ */ jsx("h3", { className: "dcy-title", children: title }) : null,
|
|
1358
|
+
/* @__PURE__ */ jsx(AvailabilityNote, { assessment }),
|
|
1359
|
+
/* @__PURE__ */ jsx(Section, { title: copy.capabilitiesHeading, note: copy.capabilitiesAreNotFindings, children: sections.capabilities.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noCapabilities }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.capabilities.map((capability, index) => /* @__PURE__ */ jsx(
|
|
1360
|
+
CapabilityRow,
|
|
1361
|
+
{
|
|
1362
|
+
capability,
|
|
1363
|
+
copy
|
|
1364
|
+
},
|
|
1365
|
+
`${capability.type}:${index}`
|
|
1366
|
+
)) }) }),
|
|
1367
|
+
/* @__PURE__ */ jsx(Section, { title: copy.factsHeading, note: copy.factsAreNotFindings, children: sections.facts.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noFacts }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.facts.map((fact, index) => /* @__PURE__ */ jsx(FactRow, { fact, copy }, `${fact.type}:${index}`)) }) }),
|
|
1368
|
+
/* @__PURE__ */ jsx(Section, { title: copy.unknownsHeading, note: copy.unknownsAreNotRisk, children: sections.unknowns.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noUnknowns }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.unknowns.map((unknown) => /* @__PURE__ */ jsx(UnknownRow, { unknown, copy }, unknown.field)) }) }),
|
|
1369
|
+
/* @__PURE__ */ jsx(HistoryNote, { status: assessment.historyStatus, copy }),
|
|
1370
|
+
/* @__PURE__ */ jsx(DemotedNote, { demotedSignals, copy }),
|
|
1371
|
+
signalCount > 0 ? /* @__PURE__ */ jsxs("p", { className: "dcy-note", "data-dcy-signals-elsewhere": "", children: [
|
|
1372
|
+
signalCount,
|
|
1373
|
+
" ",
|
|
1374
|
+
plural(signalCount, "threat signal is", "threat signals are"),
|
|
1375
|
+
" reported for this subject and ",
|
|
1376
|
+
plural(signalCount, "is", "are"),
|
|
1377
|
+
" shown separately.",
|
|
1378
|
+
onViewSignals ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1379
|
+
" ",
|
|
1380
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "dcy-btn dcy-btn-quiet", onClick: onViewSignals, children: copy.signalsHeading })
|
|
1381
|
+
] }) : null
|
|
1382
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "dcy-note", children: copy.noSignals })
|
|
1383
|
+
]
|
|
1384
|
+
}
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// src/components/ThreatSignalList.tsx
|
|
1389
|
+
function ThreatSignalList({
|
|
1390
|
+
signals,
|
|
1391
|
+
subjectNoun = "address",
|
|
1392
|
+
defaultShowEvidence = false,
|
|
1393
|
+
showEvidenceToggle = true,
|
|
1394
|
+
title,
|
|
1395
|
+
className,
|
|
1396
|
+
style,
|
|
1397
|
+
theme,
|
|
1398
|
+
copy: copyOverrides
|
|
1399
|
+
}) {
|
|
1400
|
+
const { copy, theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy: copyOverrides });
|
|
1401
|
+
const [showEvidence, setShowEvidence] = useState(defaultShowEvidence);
|
|
1402
|
+
const evidenceVisible = showEvidenceToggle ? showEvidence : defaultShowEvidence;
|
|
1403
|
+
return /* @__PURE__ */ jsxs(
|
|
1404
|
+
"section",
|
|
1405
|
+
{
|
|
1406
|
+
className: cx("dcy", "dcy-card", className),
|
|
1407
|
+
style: themeStyle(mergedTheme, style),
|
|
1408
|
+
"data-dcy-component": "threat-signal-list",
|
|
1409
|
+
"data-dcy-signal-count": String(signals.length),
|
|
1410
|
+
"aria-label": title ?? copy.signalsHeading,
|
|
1411
|
+
children: [
|
|
1412
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1413
|
+
/* @__PURE__ */ jsx(Section, { title: title ?? copy.signalsHeading, children: signals.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noSignals }) : /* @__PURE__ */ jsx(
|
|
1414
|
+
SignalList,
|
|
1415
|
+
{
|
|
1416
|
+
signals,
|
|
1417
|
+
copy,
|
|
1418
|
+
subjectNoun,
|
|
1419
|
+
showEvidence: evidenceVisible
|
|
1420
|
+
}
|
|
1421
|
+
) }),
|
|
1422
|
+
signals.length > 0 && showEvidenceToggle ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
1423
|
+
"button",
|
|
1424
|
+
{
|
|
1425
|
+
type: "button",
|
|
1426
|
+
className: "dcy-btn dcy-btn-quiet",
|
|
1427
|
+
"aria-expanded": evidenceVisible,
|
|
1428
|
+
onClick: () => setShowEvidence((value) => !value),
|
|
1429
|
+
children: evidenceVisible ? copy.hideEvidence : copy.showEvidence
|
|
1430
|
+
}
|
|
1431
|
+
) }) : null
|
|
1432
|
+
]
|
|
1433
|
+
}
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
// src/browser/react-dom-global.ts
|
|
1438
|
+
function resolveReactDom() {
|
|
1439
|
+
const candidate = globalThis.ReactDOM;
|
|
1440
|
+
if (!candidate || typeof candidate.createPortal !== "function") {
|
|
1441
|
+
throw new Error(
|
|
1442
|
+
"DecentrysUI: RiskDetailsModal needs ReactDOM on the page (window.ReactDOM) to portal into document.body. Load ReactDOM, or pass portal={false} to render the dialog in place."
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
return candidate;
|
|
1446
|
+
}
|
|
1447
|
+
var createPortal = (...args) => resolveReactDom().createPortal(...args);
|
|
1448
|
+
|
|
1449
|
+
// src/components/RiskDetailsModal.tsx
|
|
1450
|
+
function RiskDetailsModal({
|
|
1451
|
+
result,
|
|
1452
|
+
open,
|
|
1453
|
+
onClose,
|
|
1454
|
+
subjectNoun = "address",
|
|
1455
|
+
portal = true,
|
|
1456
|
+
className,
|
|
1457
|
+
style,
|
|
1458
|
+
theme,
|
|
1459
|
+
copy: copyOverrides,
|
|
1460
|
+
levelLabels
|
|
1461
|
+
}) {
|
|
1462
|
+
const { copy, theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy: copyOverrides });
|
|
1463
|
+
const titleId = useId();
|
|
1464
|
+
const dialogRef = useRef(null);
|
|
1465
|
+
const restoreFocusTo = useRef(null);
|
|
1466
|
+
useEffect(() => {
|
|
1467
|
+
if (!open) return void 0;
|
|
1468
|
+
restoreFocusTo.current = typeof document === "undefined" ? null : document.activeElement;
|
|
1469
|
+
dialogRef.current?.focus();
|
|
1470
|
+
const onKeyDown = (event) => {
|
|
1471
|
+
if (event.key === "Escape") {
|
|
1472
|
+
event.stopPropagation();
|
|
1473
|
+
onClose();
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1476
|
+
document.addEventListener("keydown", onKeyDown);
|
|
1477
|
+
return () => {
|
|
1478
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
1479
|
+
const previous = restoreFocusTo.current;
|
|
1480
|
+
if (previous instanceof HTMLElement) previous.focus();
|
|
1481
|
+
};
|
|
1482
|
+
}, [open, onClose]);
|
|
1483
|
+
if (!open) return null;
|
|
1484
|
+
const { assessment, subject, decision, cached, demotedSignals } = result;
|
|
1485
|
+
const level = levelPresentation(assessment.riskLevel, { labels: levelLabels });
|
|
1486
|
+
const sections = assessmentSections(assessment, copy);
|
|
1487
|
+
const policy = decisionPresentation(decision);
|
|
1488
|
+
const dialog = /* @__PURE__ */ jsxs(
|
|
1489
|
+
"div",
|
|
1490
|
+
{
|
|
1491
|
+
className: cx("dcy", "dcy-backdrop"),
|
|
1492
|
+
style: themeStyle(mergedTheme),
|
|
1493
|
+
"data-dcy-component": "risk-details-modal",
|
|
1494
|
+
onClick: (event) => {
|
|
1495
|
+
if (event.target === event.currentTarget) onClose();
|
|
1496
|
+
},
|
|
1497
|
+
children: [
|
|
1498
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1499
|
+
/* @__PURE__ */ jsxs(
|
|
1500
|
+
"div",
|
|
1501
|
+
{
|
|
1502
|
+
ref: dialogRef,
|
|
1503
|
+
role: "dialog",
|
|
1504
|
+
"aria-modal": "true",
|
|
1505
|
+
"aria-labelledby": titleId,
|
|
1506
|
+
tabIndex: -1,
|
|
1507
|
+
className: cx("dcy-modal", className),
|
|
1508
|
+
style,
|
|
1509
|
+
"data-dcy-level": assessment.riskLevel,
|
|
1510
|
+
"data-dcy-tone": level.tone,
|
|
1511
|
+
children: [
|
|
1512
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-modal-head", children: [
|
|
1513
|
+
/* @__PURE__ */ jsx("h2", { className: "dcy-title", id: titleId, children: copy.detailsTitle }),
|
|
1514
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "dcy-btn", onClick: onClose, children: copy.close })
|
|
1515
|
+
] }),
|
|
1516
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-head", children: [
|
|
1517
|
+
/* @__PURE__ */ jsxs("div", { className: "dcy-head-main", children: [
|
|
1518
|
+
/* @__PURE__ */ jsx("h3", { className: "dcy-title", children: level.label }),
|
|
1519
|
+
/* @__PURE__ */ jsx("p", { className: "dcy-meaning", children: level.meaning })
|
|
1520
|
+
] }),
|
|
1521
|
+
/* @__PURE__ */ jsx(LevelBadge, { level })
|
|
1522
|
+
] }),
|
|
1523
|
+
/* @__PURE__ */ jsxs("dl", { className: "dcy-kv", children: [
|
|
1524
|
+
/* @__PURE__ */ jsx("dt", { children: "Subject" }),
|
|
1525
|
+
/* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Mono, { children: subject.identifier }) }),
|
|
1526
|
+
/* @__PURE__ */ jsx("dt", { children: "Chain" }),
|
|
1527
|
+
/* @__PURE__ */ jsx("dd", { children: subject.chain }),
|
|
1528
|
+
/* @__PURE__ */ jsx("dt", { children: "Kind" }),
|
|
1529
|
+
/* @__PURE__ */ jsx("dd", { children: subject.kind }),
|
|
1530
|
+
/* @__PURE__ */ jsx("dt", { children: copy.confidenceLabel }),
|
|
1531
|
+
/* @__PURE__ */ jsxs("dd", { children: [
|
|
1532
|
+
formatConfidence(assessment.confidence),
|
|
1533
|
+
" \u2014 ",
|
|
1534
|
+
copy.confidenceCaveat
|
|
1535
|
+
] }),
|
|
1536
|
+
/* @__PURE__ */ jsx("dt", { children: copy.modelLabel }),
|
|
1537
|
+
/* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(Mono, { children: assessment.modelVersion }) }),
|
|
1538
|
+
/* @__PURE__ */ jsx("dt", { children: copy.assessedLabel }),
|
|
1539
|
+
/* @__PURE__ */ jsx("dd", { children: formatTimestamp(assessment.assessedAt) })
|
|
1540
|
+
] }),
|
|
1541
|
+
/* @__PURE__ */ jsx(AvailabilityNote, { assessment }),
|
|
1542
|
+
/* @__PURE__ */ jsx(Section, { title: "Why this level", children: /* @__PURE__ */ jsx(ExplanationList, { explanation: assessment.explanation }) }),
|
|
1543
|
+
sections.isEmpty ? /* @__PURE__ */ jsx(EmptyNote, { children: sections.emptyStatement }) : null,
|
|
1544
|
+
/* @__PURE__ */ jsx(Section, { title: copy.signalsHeading, children: /* @__PURE__ */ jsx(
|
|
1545
|
+
SignalList,
|
|
1546
|
+
{
|
|
1547
|
+
signals: [...sections.activeSignals, ...sections.inertSignals],
|
|
1548
|
+
copy,
|
|
1549
|
+
subjectNoun,
|
|
1550
|
+
showEvidence: true
|
|
1551
|
+
}
|
|
1552
|
+
) }),
|
|
1553
|
+
/* @__PURE__ */ jsx(Section, { title: copy.capabilitiesHeading, note: copy.capabilitiesAreNotFindings, children: sections.capabilities.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noCapabilities }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.capabilities.map((capability, index) => /* @__PURE__ */ jsx(CapabilityRow, { capability, copy }, `${capability.type}:${index}`)) }) }),
|
|
1554
|
+
/* @__PURE__ */ jsx(Section, { title: copy.factsHeading, note: copy.factsAreNotFindings, children: sections.facts.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noFacts }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.facts.map((fact, index) => /* @__PURE__ */ jsx(FactRow, { fact, copy }, `${fact.type}:${index}`)) }) }),
|
|
1555
|
+
/* @__PURE__ */ jsx(Section, { title: copy.unknownsHeading, note: copy.unknownsAreNotRisk, children: sections.unknowns.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noUnknowns }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.unknowns.map((unknown) => /* @__PURE__ */ jsx(UnknownRow, { unknown, copy }, unknown.field)) }) }),
|
|
1556
|
+
/* @__PURE__ */ jsx(Section, { title: copy.historyHeading, children: /* @__PURE__ */ jsx(HistoryNote, { status: assessment.historyStatus, copy }) }),
|
|
1557
|
+
/* @__PURE__ */ jsx(Section, { title: copy.componentsHeading, children: /* @__PURE__ */ jsx("dl", { className: "dcy-kv", children: componentRows(assessment.components, copy).map((row) => /* @__PURE__ */ jsx(ComponentEntry, { label: row.label, value: row.value, caveat: row.caveat }, row.key)) }) }),
|
|
1558
|
+
/* @__PURE__ */ jsx(DemotedNote, { demotedSignals, copy }),
|
|
1559
|
+
/* @__PURE__ */ jsx("hr", { className: "dcy-hr" }),
|
|
1560
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-note", "data-dcy-decision": policy.action, children: [
|
|
1561
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-chip", children: policy.label }),
|
|
1562
|
+
" ",
|
|
1563
|
+
policy.statement,
|
|
1564
|
+
" ",
|
|
1565
|
+
copy.policyIsYours
|
|
1566
|
+
] }),
|
|
1567
|
+
cached ? /* @__PURE__ */ jsx("p", { className: "dcy-note", children: copy.cachedNotice }) : null
|
|
1568
|
+
]
|
|
1569
|
+
}
|
|
1570
|
+
)
|
|
1571
|
+
]
|
|
1572
|
+
}
|
|
1573
|
+
);
|
|
1574
|
+
if (portal && typeof document !== "undefined") {
|
|
1575
|
+
return createPortal(dialog, document.body);
|
|
1576
|
+
}
|
|
1577
|
+
return dialog;
|
|
1578
|
+
}
|
|
1579
|
+
function ComponentEntry({
|
|
1580
|
+
label,
|
|
1581
|
+
value,
|
|
1582
|
+
caveat
|
|
1583
|
+
}) {
|
|
1584
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1585
|
+
/* @__PURE__ */ jsx("dt", { children: label }),
|
|
1586
|
+
/* @__PURE__ */ jsxs("dd", { children: [
|
|
1587
|
+
Math.round(value),
|
|
1588
|
+
" / 100",
|
|
1589
|
+
caveat ? /* @__PURE__ */ jsxs("span", { className: "dcy-note", children: [
|
|
1590
|
+
" ",
|
|
1591
|
+
caveat
|
|
1592
|
+
] }) : null
|
|
1593
|
+
] })
|
|
1594
|
+
] });
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
// src/components/TokenSecurityPanel.tsx
|
|
1598
|
+
function TokenSecurityPanel({
|
|
1599
|
+
result,
|
|
1600
|
+
tokenName,
|
|
1601
|
+
tokenSymbol,
|
|
1602
|
+
onViewDetails,
|
|
1603
|
+
showComponents = true,
|
|
1604
|
+
className,
|
|
1605
|
+
style,
|
|
1606
|
+
theme,
|
|
1607
|
+
copy: copyOverrides,
|
|
1608
|
+
levelLabels
|
|
1609
|
+
}) {
|
|
1610
|
+
const { copy, theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy: copyOverrides });
|
|
1611
|
+
const { assessment, subject, decision, cached, demotedSignals } = result;
|
|
1612
|
+
const level = levelPresentation(assessment.riskLevel, { labels: levelLabels });
|
|
1613
|
+
const sections = assessmentSections(assessment, copy);
|
|
1614
|
+
const policy = decisionPresentation(decision);
|
|
1615
|
+
return /* @__PURE__ */ jsxs(
|
|
1616
|
+
"section",
|
|
1617
|
+
{
|
|
1618
|
+
className: cx("dcy", "dcy-card", className),
|
|
1619
|
+
style: themeStyle(mergedTheme, style),
|
|
1620
|
+
"data-dcy-component": "token-security-panel",
|
|
1621
|
+
"data-dcy-level": assessment.riskLevel,
|
|
1622
|
+
"data-dcy-tone": level.tone,
|
|
1623
|
+
"aria-label": level.ariaLabel,
|
|
1624
|
+
children: [
|
|
1625
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1626
|
+
/* @__PURE__ */ jsx(LevelHeader, { assessment, copy, levelLabels }),
|
|
1627
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-note", children: [
|
|
1628
|
+
tokenName || tokenSymbol ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1629
|
+
/* @__PURE__ */ jsx(Chip, { children: tokenSymbol ?? tokenName }),
|
|
1630
|
+
" ",
|
|
1631
|
+
tokenName && tokenSymbol ? `${tokenName} \u2014 ` : null
|
|
1632
|
+
] }) : null,
|
|
1633
|
+
/* @__PURE__ */ jsx(Mono, { children: subject.identifier }),
|
|
1634
|
+
" on ",
|
|
1635
|
+
subject.chain
|
|
1636
|
+
] }),
|
|
1637
|
+
/* @__PURE__ */ jsx(AvailabilityNote, { assessment }),
|
|
1638
|
+
/* @__PURE__ */ jsx(ExplanationList, { explanation: assessment.explanation }),
|
|
1639
|
+
sections.isEmpty ? /* @__PURE__ */ jsx(EmptyNote, { children: sections.emptyStatement }) : null,
|
|
1640
|
+
/* @__PURE__ */ jsx(Section, { title: copy.capabilitiesHeading, note: copy.capabilitiesAreNotFindings, children: sections.capabilities.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noCapabilities }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.capabilities.map((capability, index) => /* @__PURE__ */ jsx(CapabilityRow, { capability, copy }, `${capability.type}:${index}`)) }) }),
|
|
1641
|
+
/* @__PURE__ */ jsx(Section, { title: copy.factsHeading, note: copy.factsAreNotFindings, children: sections.facts.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noFacts }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.facts.map((fact, index) => /* @__PURE__ */ jsx(FactRow, { fact, copy }, `${fact.type}:${index}`)) }) }),
|
|
1642
|
+
/* @__PURE__ */ jsx(Section, { title: copy.signalsHeading, children: /* @__PURE__ */ jsx(
|
|
1643
|
+
SignalList,
|
|
1644
|
+
{
|
|
1645
|
+
signals: [...sections.activeSignals, ...sections.inertSignals],
|
|
1646
|
+
copy,
|
|
1647
|
+
subjectNoun: "token"
|
|
1648
|
+
}
|
|
1649
|
+
) }),
|
|
1650
|
+
/* @__PURE__ */ jsx(Section, { title: copy.unknownsHeading, note: copy.unknownsAreNotRisk, children: sections.unknowns.length === 0 ? /* @__PURE__ */ jsx(EmptyNote, { children: copy.noUnknowns }) : /* @__PURE__ */ jsx("ul", { className: "dcy-list", children: sections.unknowns.map((unknown) => /* @__PURE__ */ jsx(UnknownRow, { unknown, copy }, unknown.field)) }) }),
|
|
1651
|
+
/* @__PURE__ */ jsx(HistoryNote, { status: assessment.historyStatus, copy }),
|
|
1652
|
+
showComponents ? /* @__PURE__ */ jsx(Section, { title: copy.componentsHeading, children: /* @__PURE__ */ jsx("dl", { className: "dcy-kv", children: componentRows(assessment.components, copy).map((row) => /* @__PURE__ */ jsx(ComponentEntry2, { label: row.label, value: row.value, caveat: row.caveat }, row.key)) }) }) : null,
|
|
1653
|
+
/* @__PURE__ */ jsx(DemotedNote, { demotedSignals, copy }),
|
|
1654
|
+
/* @__PURE__ */ jsxs("p", { className: "dcy-note", "data-dcy-decision": policy.action, children: [
|
|
1655
|
+
/* @__PURE__ */ jsx("span", { className: "dcy-chip", children: policy.label }),
|
|
1656
|
+
" ",
|
|
1657
|
+
policy.statement
|
|
1658
|
+
] }),
|
|
1659
|
+
cached ? /* @__PURE__ */ jsx("p", { className: "dcy-note", children: copy.cachedNotice }) : null,
|
|
1660
|
+
onViewDetails ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("button", { type: "button", className: "dcy-btn dcy-btn-quiet", onClick: onViewDetails, children: copy.viewDetails }) }) : null
|
|
1661
|
+
]
|
|
1662
|
+
}
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
function ComponentEntry2({
|
|
1666
|
+
label,
|
|
1667
|
+
value,
|
|
1668
|
+
caveat
|
|
1669
|
+
}) {
|
|
1670
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1671
|
+
/* @__PURE__ */ jsx("dt", { children: label }),
|
|
1672
|
+
/* @__PURE__ */ jsxs("dd", { children: [
|
|
1673
|
+
Math.round(value),
|
|
1674
|
+
" / 100",
|
|
1675
|
+
caveat ? /* @__PURE__ */ jsxs("span", { className: "dcy-note", children: [
|
|
1676
|
+
" ",
|
|
1677
|
+
caveat
|
|
1678
|
+
] }) : null
|
|
1679
|
+
] })
|
|
1680
|
+
] });
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
// src/components/AddressRiskBadge.tsx
|
|
1684
|
+
function AddressRiskBadge(props) {
|
|
1685
|
+
const { assessment, level, address, onSelect, className, style, theme, copy, levelLabels } = props;
|
|
1686
|
+
const { theme: mergedTheme, emitStyles } = useUiConfig({ theme, copy });
|
|
1687
|
+
const resolved = assessment?.riskLevel ?? level;
|
|
1688
|
+
if (!resolved) return null;
|
|
1689
|
+
const presentation = levelPresentation(resolved, { labels: levelLabels });
|
|
1690
|
+
const rootClass = cx("dcy", "dcy-inline", className);
|
|
1691
|
+
const rootStyle = themeStyle(mergedTheme, style);
|
|
1692
|
+
const content = /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1693
|
+
/* @__PURE__ */ jsx(LevelBadge, { level: presentation }),
|
|
1694
|
+
address ? /* @__PURE__ */ jsx(Mono, { children: shortenAddress(address) }) : null,
|
|
1695
|
+
/* @__PURE__ */ jsx(ScreenReaderText, { children: presentation.meaning })
|
|
1696
|
+
] });
|
|
1697
|
+
if (onSelect) {
|
|
1698
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1699
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1700
|
+
/* @__PURE__ */ jsx(
|
|
1701
|
+
"button",
|
|
1702
|
+
{
|
|
1703
|
+
type: "button",
|
|
1704
|
+
className: rootClass,
|
|
1705
|
+
style: rootStyle,
|
|
1706
|
+
title: presentation.meaning,
|
|
1707
|
+
onClick: onSelect,
|
|
1708
|
+
"data-dcy-component": "address-risk-badge",
|
|
1709
|
+
"data-dcy-level": resolved,
|
|
1710
|
+
"data-dcy-tone": presentation.tone,
|
|
1711
|
+
children: content
|
|
1712
|
+
}
|
|
1713
|
+
)
|
|
1714
|
+
] });
|
|
1715
|
+
}
|
|
1716
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1717
|
+
/* @__PURE__ */ jsx(StyleGate, { emit: emitStyles }),
|
|
1718
|
+
/* @__PURE__ */ jsx(
|
|
1719
|
+
"span",
|
|
1720
|
+
{
|
|
1721
|
+
className: rootClass,
|
|
1722
|
+
style: rootStyle,
|
|
1723
|
+
title: presentation.meaning,
|
|
1724
|
+
"data-dcy-component": "address-risk-badge",
|
|
1725
|
+
"data-dcy-level": resolved,
|
|
1726
|
+
"data-dcy-tone": presentation.tone,
|
|
1727
|
+
children: content
|
|
1728
|
+
}
|
|
1729
|
+
)
|
|
1730
|
+
] });
|
|
1731
|
+
}
|
|
1732
|
+
return __toCommonJS(index_exports);
|
|
1733
|
+
})();
|