@decentrys/ui-sdk 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/README.md +198 -24
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @decentrys/ui-sdk
2
2
 
3
- Drop-in React components for rendering Decentrys risk assessments.
3
+ **Drop-in React components that render a Decentrys assessment — built so a new project can never be shown as dangerous for being new.**
4
4
 
5
5
  ## Install
6
6
 
@@ -8,44 +8,218 @@ Drop-in React components for rendering Decentrys risk assessments.
8
8
  npm install @decentrys/ui-sdk @decentrys/protect
9
9
  ```
10
10
 
11
- React 18 or 19, as a peer dependency never bundled.
11
+ React 18 or 19, as a peer dependency alongside `react-dom`. Never bundled — two
12
+ copies of React in one app is a real breakage. No styling dependency, no font
13
+ fetch, no network calls of its own.
12
14
 
13
- ## Use
15
+ ## Quick start
14
16
 
15
17
  ```tsx
16
- import { TransactionRiskBanner, DECENTRYS_UI_CSS } from '@decentrys/ui-sdk';
18
+ import { useEffect, useState } from 'react';
19
+ import { Decentrys, type ProtectResult, type TransactionRequest } from '@decentrys/protect';
20
+ import { DecentrysUiProvider, TransactionRiskBanner, RiskDetailsModal } from '@decentrys/ui-sdk';
21
+
22
+ const decentrys = new Decentrys({ apiKey: 'dk_pub_live_...' });
23
+
24
+ export function SigningScreen({ tx, onSign, onCancel }: {
25
+ tx: TransactionRequest;
26
+ onSign: () => void;
27
+ onCancel: () => void;
28
+ }) {
29
+ const [result, setResult] = useState<ProtectResult | null>(null);
30
+ const [detailsOpen, setDetailsOpen] = useState(false);
31
+
32
+ useEffect(() => {
33
+ let live = true;
34
+ decentrys.assessTransaction(tx).then((r) => { if (live) setResult(r); });
35
+ return () => { live = false; };
36
+ }, [tx]);
37
+
38
+ if (!result) return null;
39
+
40
+ return (
41
+ <DecentrysUiProvider theme={{ surface: '#0b0d10', text: '#e8ebef', radius: '12px' }}>
42
+ <TransactionRiskBanner
43
+ result={result}
44
+ onViewDetails={() => setDetailsOpen(true)}
45
+ actions={
46
+ <>
47
+ {/* Your buttons, your policy. This package never disables them. */}
48
+ <button onClick={onSign}>Confirm</button>
49
+ <button onClick={onCancel}>Cancel</button>
50
+ </>
51
+ }
52
+ />
53
+ <RiskDetailsModal result={result} open={detailsOpen} onClose={() => setDetailsOpen(false)} />
54
+ </DecentrysUiProvider>
55
+ );
56
+ }
57
+ ```
58
+
59
+ `DecentrysUiProvider` sets theme and copy once for everything beneath it and
60
+ emits the stylesheet a single time. Without a provider every component emits
61
+ its own — so a single `<AddressRiskBadge>` dropped into a page still renders
62
+ correctly.
63
+
64
+ Placing the CSS yourself instead — in a `<head>`, a bundled stylesheet or a
65
+ shadow root — is `<DecentrysUiProvider injectStyles={false}>`, or export the
66
+ string directly:
17
67
 
68
+ ```tsx
69
+ import { DECENTRYS_UI_CSS } from '@decentrys/ui-sdk';
18
70
  <style>{DECENTRYS_UI_CSS}</style>
19
- <TransactionRiskBanner result={result} actions={<YourButtons />} />
20
71
  ```
21
72
 
22
- ## What these components will not do
73
+ ## Components
74
+
75
+ Note which prop each one takes — some want the whole `ProtectResult`, some want
76
+ a piece of it.
77
+
78
+ | Component | Required props | Use it when |
79
+ |---|---|---|
80
+ | `TransactionRiskBanner` | `result` | A user is about to sign. The main one. |
81
+ | `ApprovalWarning` | `result`, `approval` | A token approval — leads with what is being granted, not a score. |
82
+ | `ContractFacts` | `assessment` | Showing what a contract can do (upgrade, mint, pause). |
83
+ | `TokenSecurityPanel` | `result` | A token detail screen. |
84
+ | `ThreatSignalList` | `signals` | You want signals only, in your own layout. |
85
+ | `AddressRiskBadge` | `assessment` **or** `level` | Compact inline badge beside an address. |
86
+ | `RiskDetailsModal` | `result`, `open`, `onClose` | "Why?" — every fact, signal, evidence item and score component. |
87
+
88
+ ```tsx
89
+ // An approval. `approval` describes what is being granted; the SDK does not
90
+ // infer it from the assessment.
91
+ <ApprovalWarning
92
+ result={approvalResult} // from decentrys.screenApproval(...)
93
+ approval={{
94
+ token: '0xa0b8…',
95
+ symbol: 'USDC',
96
+ decimals: 6,
97
+ spender: '0x1111…',
98
+ spenderLabel: '1inch Router',
99
+ amount: 'unlimited', // base units, or the literal 'unlimited'
100
+ }}
101
+ />
102
+ // "This grants 1inch Router permission to spend an unlimited amount of your USDC,
103
+ // now and at any time in the future, until it is revoked."
104
+ //
105
+ // Omit `amount` and it says the allowance could not be decoded — never that it
106
+ // is small. Omit `decimals` and the figure is labelled as base units rather
107
+ // than silently shown 10^18 times too small.
108
+
109
+ <ContractFacts assessment={result.assessment} demotedSignals={result.demotedSignals} />
110
+
111
+ <TokenSecurityPanel result={result} tokenSymbol="USDC" showComponents />
112
+
113
+ <ThreatSignalList signals={result.assessment.threatSignals} />
114
+
115
+ <AddressRiskBadge assessment={result.assessment} address="0x1111…" />
116
+ <AddressRiskBadge level="CAUTION" /> {/* when you only have the level */}
117
+ ```
118
+
119
+ Every component also accepts `className`, `style`, `theme`, `copy` and
120
+ `levelLabels`. `AddressRiskBadge` takes exactly one of `assessment` or `level`,
121
+ enforced by the type rather than a runtime throw — a component that throws
122
+ inside a wallet's render tree takes that wallet's screen down.
123
+
124
+ ## What these will not do
125
+
126
+ **Nothing blocks.** `DecisionPresentation.blocksUi` is typed as the literal
127
+ `false`, including for a `block` policy action. No control here is ever
128
+ rendered `disabled` — the decision belongs to your application, and you wire
129
+ your own buttons through `actions`.
23
130
 
24
- **Nothing blocks.** `blocksUi` is typed as the literal `false`, including for
25
- a `block` policy action. No control in this package is ever rendered disabled —
26
- the decision belongs to your application.
131
+ **`LIMITED` history is never a warning.** `HistoryPresentation` types `tone` as
132
+ the literal `'neutral'` and `isWarning` as the literal `false`, so rendering it
133
+ as an alert doesn't compile. It's the correct, expected state for anything
134
+ recently deployed.
27
135
 
28
- **`LIMITED` history is never a warning.** Its presentation is typed
29
- `tone: 'neutral'` and `isWarning: false` as literal types, so rendering it as
30
- an alert does not compile. It is the correct state for anything recently
31
- deployed.
136
+ **Facts never look like threat signals.** `fact`, `capability` and `unknown`
137
+ are separate tone families from the risk tones, each row carries its kind as a
138
+ word and its own non-colour glyph, and a stale or low-confidence signal that
139
+ did not raise the level is toned `inactive`. Colour is the third carrier of
140
+ meaning, not the first — a colour-blind user still has to be able to tell
141
+ "deployed three days ago" from "attributed to a drainer family".
32
142
 
33
- **Facts never look like threat signals.** Each row carries its kind as a word,
34
- its own rule style and its own glyph. Colour is the third carrier of meaning,
35
- not the first — a colour-blind user still has to be able to tell "deployed
36
- three days ago" from "attributed to a drainer family".
143
+ **Anything above zero hops says so in a sentence**, not just a badge. A hop is
144
+ an inference about a counterparty, and a badge reading "2" tells nobody that.
37
145
 
38
146
  ## Theming
39
147
 
40
- CSS custom properties only. No Tailwind, no CSS-in-JS, no external fetches.
41
- 31 `--dcy-*` tokens with light defaults and a dark-mode block, overridable per
42
- component so your brand palette does not flip on a user's OS setting.
148
+ 31 CSS custom properties. Pass them by their **bare token name** — the
149
+ `--dcy-` prefix is added for you:
150
+
151
+ ```tsx
152
+ <TransactionRiskBanner
153
+ result={result}
154
+ theme={{ surface: '#1a1a2e', radius: '12px', 'tone-caution': '#ab9ff2' }}
155
+ className="my-wallet-card"
156
+ />
157
+ ```
158
+
159
+ The tokens (`THEME_TOKENS` is exported, and `DecentrysTheme` is
160
+ `Partial<Record<ThemeToken, string>>`):
161
+
162
+ - Layout and type — `font`, `font-mono`, `radius`, `gap`
163
+ - Surfaces and text — `surface`, `surface-raised`, `border`, `text`, `text-muted`, `text-faint`, `focus`
164
+ - A foreground and a `-bg` wash for each of ten tones — `tone-neutral`, `tone-info`, `tone-caution`, `tone-elevated`, `tone-high`, `tone-critical`, `tone-fact`, `tone-capability`, `tone-unknown`, `tone-inactive`
165
+
166
+ Inline `theme` is applied on the component's own root, so it beats both the
167
+ defaults and the `prefers-color-scheme` dark block — a fixed brand palette
168
+ doesn't flip on a user's OS setting. Props win over the provider, so one banner
169
+ can be re-themed inside an otherwise uniform tree.
170
+
171
+ Every meaningful element also carries a `data-dcy-*` attribute
172
+ (`data-dcy-level`, `data-dcy-kind`, `data-dcy-tone`) if you'd rather style from
173
+ your own CSS.
174
+
175
+ ## Copy and translation
176
+
177
+ Every string is overridable, on the provider or per component:
178
+
179
+ ```tsx
180
+ <DecentrysUiProvider copy={{ /* Partial<UiCopy> */ }}>
181
+ <TransactionRiskBanner result={result} levelLabels={{ CAUTION: 'Attention' }} />
182
+ ```
183
+
184
+ `DEFAULT_COPY` and `resolveCopy` are exported.
185
+
186
+ ## Building your own presentation
187
+
188
+ The presentation logic is pure, React-free and separately exported, so a
189
+ renderer you write yourself cannot drift from the one here:
190
+
191
+ ```ts
192
+ import {
193
+ levelPresentation, factPresentation, capabilityPresentation, signalPresentation,
194
+ historyPresentation, unknownPresentation, approvalPresentation, assessmentSections,
195
+ componentRows, decisionPresentation, evidencePresentation, availabilityPresentation,
196
+ hopPresentation, formatConfidence, formatTokenAmount, shortenAddress,
197
+ MIN_RAISING_CONFIDENCE, RISK_LEVEL_LABEL,
198
+ } from '@decentrys/ui-sdk';
199
+ ```
200
+
201
+ `MIN_RAISING_CONFIDENCE` is re-exported from `@decentrys/protect` rather than
202
+ copied, so a renderer cannot put a signal in the "did not raise the level" list
203
+ while the classifier was in fact raising it.
204
+
205
+ ## React Native
206
+
207
+ These render React DOM and won't work in RN. The presentation logic above is
208
+ React-free and reusable as-is.
209
+
210
+ ## The rest of the SDK
211
+
212
+ | Package | For |
213
+ |---|---|
214
+ | [`@decentrys/protect`](https://www.npmjs.com/package/@decentrys/protect) | Pre-sign risk assessment for wallets and dapps |
215
+ | [`@decentrys/ui-sdk`](https://www.npmjs.com/package/@decentrys/ui-sdk) | React components that render Protect results |
216
+ | [`@decentrys/sentinel-sdk`](https://www.npmjs.com/package/@decentrys/sentinel-sdk) | Monitoring deployed contracts and treasuries |
217
+ | [`@decentrys/risk-sdk`](https://www.npmjs.com/package/@decentrys/risk-sdk) | Screening for exchanges and custodians |
218
+ | [`@decentrys/dri-sdk`](https://www.npmjs.com/package/@decentrys/dri-sdk) | Fund tracing and recovery intelligence |
219
+ | [`@decentrys/agent`](https://www.npmjs.com/package/@decentrys/agent) | Policy enforcement for autonomous agents |
43
220
 
44
221
  ## Licence
45
222
 
46
223
  MIT © Decentrys Labs
47
224
 
48
- ## Links
49
-
50
- - [decentrys.com](https://decentrys.com) · [SDK overview](https://decentrys.com/sdk) · [Developer API](https://decentrys.com/developers)
51
- - Source: [github.com/teamdecentrys-byte/Decentrys](https://github.com/teamdecentrys-byte/Decentrys)
225
+ [decentrys.com](https://decentrys.com) · [SDK overview](https://decentrys.com/sdk) · [Developer API](https://decentrys.com/developers) · [Source](https://github.com/teamdecentrys-byte/Decentrys)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentrys/ui-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Drop-in React components for rendering Decentrys risk assessments, built so a new project can never be shown as dangerous for being new.",
5
5
  "license": "MIT",
6
6
  "author": "Decentrys Labs",
@@ -49,7 +49,7 @@
49
49
  "README.md"
50
50
  ],
51
51
  "dependencies": {
52
- "@decentrys/protect": "0.1.0"
52
+ "@decentrys/protect": "0.1.2"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "react": ">=18",