@neus/sdk 1.0.0 → 1.0.1
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 +36 -40
- package/README.md +86 -152
- package/SECURITY.md +29 -224
- package/cjs/client.cjs +1686 -0
- package/cjs/errors.cjs +202 -0
- package/cjs/gates.cjs +140 -0
- package/cjs/index.cjs +2315 -0
- package/cjs/utils.cjs +620 -0
- package/client.js +1693 -844
- package/errors.js +223 -228
- package/gates.js +175 -0
- package/index.js +21 -26
- package/package.json +68 -18
- package/types.d.ts +519 -71
- package/utils.js +752 -722
- package/widgets/README.md +53 -0
- package/widgets/index.js +9 -0
- package/widgets/verify-gate/dist/ProofBadge.js +355 -0
- package/widgets/verify-gate/dist/VerifyGate.js +601 -0
- package/widgets/verify-gate/index.js +13 -0
- package/widgets.cjs +20 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# NEUS Widgets (VerifyGate + ProofBadge)
|
|
2
|
+
|
|
3
|
+
React components for NEUS verification and access gating.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @neus/sdk react react-dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## VerifyGate
|
|
12
|
+
|
|
13
|
+
Gate UI behind verification requirements.
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
import { VerifyGate } from '@neus/sdk/widgets';
|
|
17
|
+
|
|
18
|
+
export function Page() {
|
|
19
|
+
return (
|
|
20
|
+
<VerifyGate
|
|
21
|
+
requiredVerifiers={['nft-ownership']}
|
|
22
|
+
verifierData={{
|
|
23
|
+
'nft-ownership': { contractAddress: '0x...', tokenId: '1', chainId: 1 }
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
<div>Unlocked</div>
|
|
27
|
+
</VerifyGate>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Key props
|
|
33
|
+
|
|
34
|
+
- `requiredVerifiers`: `string[]` (default: `['ownership-basic']`)
|
|
35
|
+
- `verifierData`: object keyed by verifier id
|
|
36
|
+
- `strategy`: `'reuse-or-create' | 'reuse' | 'fresh'` (default: `'reuse-or-create'`)
|
|
37
|
+
- `proofOptions`: `{ privacyLevel, publicDisplay, storeOriginalContent, enableIpfs? }` (defaults: private)
|
|
38
|
+
- `mode`: `'create' | 'access'` (default: `'create'`)
|
|
39
|
+
- `qHash`: string (required for `mode="access"`)
|
|
40
|
+
|
|
41
|
+
Notes:
|
|
42
|
+
- Reuse without prompting can only see **public + discoverable** proofs.
|
|
43
|
+
- Reusing private proofs requires an **owner signature** (wallet grants read access).
|
|
44
|
+
|
|
45
|
+
## ProofBadge
|
|
46
|
+
|
|
47
|
+
Display verification status by Proof ID (`qHash`).
|
|
48
|
+
|
|
49
|
+
```jsx
|
|
50
|
+
import { ProofBadge } from '@neus/sdk/widgets';
|
|
51
|
+
|
|
52
|
+
<ProofBadge qHash="0x..." showChains />
|
|
53
|
+
```
|
package/widgets/index.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// widgets/verify-gate/ProofBadge.jsx
|
|
4
|
+
import React, { useEffect, useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var DEFAULT_API_BASE = "https://api.neus.network";
|
|
7
|
+
var NeusLogo = ({ size = 12 }) => /* @__PURE__ */ jsxs(
|
|
8
|
+
"svg",
|
|
9
|
+
{
|
|
10
|
+
width: size,
|
|
11
|
+
height: size,
|
|
12
|
+
viewBox: "0 0 24 24",
|
|
13
|
+
"aria-hidden": "true",
|
|
14
|
+
focusable: "false",
|
|
15
|
+
style: {
|
|
16
|
+
width: size,
|
|
17
|
+
height: size,
|
|
18
|
+
display: "block",
|
|
19
|
+
borderRadius: 2,
|
|
20
|
+
flexShrink: 0
|
|
21
|
+
},
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "2", width: "20", height: "20", rx: "5", fill: "currentColor", opacity: "0.18" }),
|
|
24
|
+
/* @__PURE__ */ jsx(
|
|
25
|
+
"path",
|
|
26
|
+
{
|
|
27
|
+
d: "M7 16V8h2.1l4.9 5.9V8H17v8h-2.1L10 10.1V16H7z",
|
|
28
|
+
fill: "currentColor",
|
|
29
|
+
opacity: "0.9"
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
function ProofBadge({
|
|
36
|
+
qHash,
|
|
37
|
+
size = "sm",
|
|
38
|
+
uiLinkBase = "https://neus.network",
|
|
39
|
+
apiUrl = DEFAULT_API_BASE,
|
|
40
|
+
proof = void 0,
|
|
41
|
+
showChains = false,
|
|
42
|
+
showLabel = true,
|
|
43
|
+
onClick = void 0,
|
|
44
|
+
className = ""
|
|
45
|
+
}) {
|
|
46
|
+
const [status, setStatus] = useState(() => {
|
|
47
|
+
if (proof) {
|
|
48
|
+
const proofStatus = proof.status || "";
|
|
49
|
+
return proofStatus.includes("verified") ? "verified" : proofStatus.includes("pending") || proofStatus.includes("processing") ? "pending" : "failed";
|
|
50
|
+
}
|
|
51
|
+
return qHash ? "pending" : "unknown";
|
|
52
|
+
});
|
|
53
|
+
const [chainCount, setChainCount] = useState(() => {
|
|
54
|
+
if (proof?.crosschain) {
|
|
55
|
+
const total = proof.crosschain.totalChains || 0;
|
|
56
|
+
const relayResults = proof.crosschain.relayResults || {};
|
|
57
|
+
return total > 0 ? total : Object.keys(relayResults).length + (proof.crosschain.hubTxHash ? 1 : 0);
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
});
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!qHash || proof)
|
|
63
|
+
return;
|
|
64
|
+
let cancelled = false;
|
|
65
|
+
async function checkStatus() {
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch(`${apiUrl}/api/v1/verification/status/${qHash}`, {
|
|
68
|
+
headers: { Accept: "application/json" }
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
if (!cancelled)
|
|
72
|
+
setStatus("failed");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const json = await res.json();
|
|
76
|
+
if (cancelled)
|
|
77
|
+
return;
|
|
78
|
+
const proofStatus = json?.data?.status || "";
|
|
79
|
+
const isVerified = proofStatus.toLowerCase().includes("verified");
|
|
80
|
+
const isPending = proofStatus.toLowerCase().includes("processing") || proofStatus.toLowerCase().includes("pending");
|
|
81
|
+
setStatus(isVerified ? "verified" : isPending ? "pending" : "failed");
|
|
82
|
+
if (showChains && json?.data?.crosschain) {
|
|
83
|
+
const cc = json.data.crosschain;
|
|
84
|
+
const total = cc.totalChains || 0;
|
|
85
|
+
const relayResults = cc.relayResults || {};
|
|
86
|
+
const count = total > 0 ? total : Object.keys(relayResults).length + (cc.hubTxHash ? 1 : 0);
|
|
87
|
+
setChainCount(count);
|
|
88
|
+
}
|
|
89
|
+
} catch (_) {
|
|
90
|
+
if (!cancelled)
|
|
91
|
+
setStatus("failed");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
checkStatus();
|
|
95
|
+
return () => {
|
|
96
|
+
cancelled = true;
|
|
97
|
+
};
|
|
98
|
+
}, [qHash, proof, apiUrl, showChains]);
|
|
99
|
+
const href = `${String(uiLinkBase).replace(/\/$/, "")}/proof/${qHash}`;
|
|
100
|
+
const isSm = size === "sm";
|
|
101
|
+
const logoSize = isSm ? 12 : 14;
|
|
102
|
+
const fontSize = isSm ? 10 : 11;
|
|
103
|
+
const gap = isSm ? 4 : 5;
|
|
104
|
+
const padY = isSm ? 2 : 3;
|
|
105
|
+
const padX = isSm ? 6 : 8;
|
|
106
|
+
const label = status === "verified" ? "Verified" : status === "pending" ? "Pending" : status === "unknown" ? "Unknown" : "Unverified";
|
|
107
|
+
const style = {
|
|
108
|
+
display: "inline-flex",
|
|
109
|
+
alignItems: "center",
|
|
110
|
+
gap,
|
|
111
|
+
textDecoration: "none",
|
|
112
|
+
padding: `${padY}px ${padX}px`,
|
|
113
|
+
borderRadius: 9999,
|
|
114
|
+
// rounded-full
|
|
115
|
+
border: "1px solid var(--neus-badge-border, rgba(148, 163, 184, 0.2))",
|
|
116
|
+
background: "var(--neus-badge-bg, rgba(148, 163, 184, 0.06))",
|
|
117
|
+
color: "var(--neus-badge-text, #94a3b8)",
|
|
118
|
+
fontFamily: "var(--neus-badge-font, inherit)",
|
|
119
|
+
fontWeight: 500,
|
|
120
|
+
fontSize,
|
|
121
|
+
whiteSpace: "nowrap",
|
|
122
|
+
lineHeight: 1,
|
|
123
|
+
cursor: "pointer",
|
|
124
|
+
transition: "opacity 0.15s ease"
|
|
125
|
+
};
|
|
126
|
+
const handleClick = (e) => {
|
|
127
|
+
if (onClick) {
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
onClick({ qHash, status, chainCount });
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const title = showChains && chainCount > 0 ? `${label} on ${chainCount} chain${chainCount === 1 ? "" : "s"}` : label;
|
|
133
|
+
return /* @__PURE__ */ jsxs(
|
|
134
|
+
"a",
|
|
135
|
+
{
|
|
136
|
+
href,
|
|
137
|
+
target: "_blank",
|
|
138
|
+
rel: "noreferrer",
|
|
139
|
+
style,
|
|
140
|
+
className,
|
|
141
|
+
"aria-label": title,
|
|
142
|
+
title,
|
|
143
|
+
onClick: handleClick,
|
|
144
|
+
children: [
|
|
145
|
+
/* @__PURE__ */ jsx(NeusLogo, { size: logoSize }),
|
|
146
|
+
showLabel && /* @__PURE__ */ jsx("span", { children: label }),
|
|
147
|
+
showChains && chainCount > 0 && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.7, fontSize: fontSize - 1 }, children: [
|
|
148
|
+
"\xB7 ",
|
|
149
|
+
chainCount
|
|
150
|
+
] })
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
function SimpleProofBadge({
|
|
156
|
+
qHash,
|
|
157
|
+
uiLinkBase = "https://neus.network",
|
|
158
|
+
apiUrl = DEFAULT_API_BASE,
|
|
159
|
+
size = "sm",
|
|
160
|
+
label = "Verified",
|
|
161
|
+
proof = void 0,
|
|
162
|
+
onClick = void 0,
|
|
163
|
+
className = ""
|
|
164
|
+
}) {
|
|
165
|
+
const [status, setStatus] = useState(() => {
|
|
166
|
+
if (proof) {
|
|
167
|
+
const proofStatus = proof.status || "";
|
|
168
|
+
return proofStatus.includes("verified") ? "verified" : "failed";
|
|
169
|
+
}
|
|
170
|
+
return qHash ? "pending" : "unknown";
|
|
171
|
+
});
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (!qHash || proof)
|
|
174
|
+
return;
|
|
175
|
+
let cancelled = false;
|
|
176
|
+
async function checkStatus() {
|
|
177
|
+
try {
|
|
178
|
+
const res = await fetch(`${apiUrl}/api/v1/verification/status/${qHash}`, {
|
|
179
|
+
headers: { Accept: "application/json" }
|
|
180
|
+
});
|
|
181
|
+
if (!res.ok) {
|
|
182
|
+
if (!cancelled)
|
|
183
|
+
setStatus("failed");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const json = await res.json();
|
|
187
|
+
if (cancelled)
|
|
188
|
+
return;
|
|
189
|
+
const isVerified = json?.success === true || json?.data?.status?.toLowerCase()?.includes("verified");
|
|
190
|
+
setStatus(isVerified ? "verified" : "failed");
|
|
191
|
+
} catch (_) {
|
|
192
|
+
if (!cancelled)
|
|
193
|
+
setStatus("failed");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
checkStatus();
|
|
197
|
+
return () => {
|
|
198
|
+
cancelled = true;
|
|
199
|
+
};
|
|
200
|
+
}, [qHash, proof, apiUrl]);
|
|
201
|
+
const href = `${String(uiLinkBase).replace(/\/$/, "")}/proof/${qHash}`;
|
|
202
|
+
const isSm = size === "sm";
|
|
203
|
+
const logoSize = isSm ? 12 : 14;
|
|
204
|
+
const fontSize = isSm ? 10 : 11;
|
|
205
|
+
const style = {
|
|
206
|
+
display: "inline-flex",
|
|
207
|
+
alignItems: "center",
|
|
208
|
+
gap: 4,
|
|
209
|
+
textDecoration: "none",
|
|
210
|
+
padding: "2px 6px",
|
|
211
|
+
borderRadius: 9999,
|
|
212
|
+
// rounded-full
|
|
213
|
+
border: "1px solid var(--neus-badge-border, rgba(148, 163, 184, 0.2))",
|
|
214
|
+
background: "var(--neus-badge-bg, transparent)",
|
|
215
|
+
color: "var(--neus-badge-text, #94a3b8)",
|
|
216
|
+
fontFamily: "var(--neus-badge-font, inherit)",
|
|
217
|
+
fontWeight: 500,
|
|
218
|
+
fontSize,
|
|
219
|
+
whiteSpace: "nowrap",
|
|
220
|
+
lineHeight: 1,
|
|
221
|
+
cursor: "pointer",
|
|
222
|
+
transition: "opacity 0.15s ease"
|
|
223
|
+
};
|
|
224
|
+
const handleClick = (e) => {
|
|
225
|
+
if (onClick) {
|
|
226
|
+
e.preventDefault();
|
|
227
|
+
onClick({ qHash, status });
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const displayLabel = status === "verified" ? label : status === "pending" ? "Pending" : status === "unknown" ? "Unknown" : "Unverified";
|
|
231
|
+
return /* @__PURE__ */ jsxs(
|
|
232
|
+
"a",
|
|
233
|
+
{
|
|
234
|
+
href,
|
|
235
|
+
target: "_blank",
|
|
236
|
+
rel: "noreferrer",
|
|
237
|
+
style,
|
|
238
|
+
className,
|
|
239
|
+
"aria-label": displayLabel,
|
|
240
|
+
title: displayLabel,
|
|
241
|
+
onClick: handleClick,
|
|
242
|
+
children: [
|
|
243
|
+
/* @__PURE__ */ jsx(NeusLogo, { size: logoSize }),
|
|
244
|
+
/* @__PURE__ */ jsx("span", { children: displayLabel })
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
function NeusPillLink({
|
|
250
|
+
qHash,
|
|
251
|
+
uiLinkBase = "https://neus.network",
|
|
252
|
+
label = "View",
|
|
253
|
+
size = "sm",
|
|
254
|
+
onClick = void 0,
|
|
255
|
+
className = ""
|
|
256
|
+
}) {
|
|
257
|
+
const base = String(uiLinkBase).replace(/\/$/, "");
|
|
258
|
+
const href = qHash ? `${base}/proof/${qHash}` : base;
|
|
259
|
+
const isSm = size === "sm";
|
|
260
|
+
const logoSize = isSm ? 12 : 14;
|
|
261
|
+
const fontSize = isSm ? 10 : 11;
|
|
262
|
+
const style = {
|
|
263
|
+
display: "inline-flex",
|
|
264
|
+
alignItems: "center",
|
|
265
|
+
gap: 4,
|
|
266
|
+
textDecoration: "none",
|
|
267
|
+
padding: "2px 6px",
|
|
268
|
+
borderRadius: 9999,
|
|
269
|
+
// rounded-full
|
|
270
|
+
border: "1px solid var(--neus-badge-border, rgba(148, 163, 184, 0.2))",
|
|
271
|
+
background: "var(--neus-badge-bg, transparent)",
|
|
272
|
+
color: "var(--neus-badge-text, #94a3b8)",
|
|
273
|
+
fontFamily: "var(--neus-badge-font, inherit)",
|
|
274
|
+
fontWeight: 500,
|
|
275
|
+
fontSize,
|
|
276
|
+
whiteSpace: "nowrap",
|
|
277
|
+
lineHeight: 1,
|
|
278
|
+
cursor: "pointer",
|
|
279
|
+
transition: "opacity 0.15s ease"
|
|
280
|
+
};
|
|
281
|
+
const handleClick = (e) => {
|
|
282
|
+
if (onClick) {
|
|
283
|
+
e.preventDefault();
|
|
284
|
+
onClick({ qHash });
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
return /* @__PURE__ */ jsxs(
|
|
288
|
+
"a",
|
|
289
|
+
{
|
|
290
|
+
href,
|
|
291
|
+
target: "_blank",
|
|
292
|
+
rel: "noreferrer",
|
|
293
|
+
style,
|
|
294
|
+
className,
|
|
295
|
+
"aria-label": label,
|
|
296
|
+
title: label,
|
|
297
|
+
onClick: handleClick,
|
|
298
|
+
children: [
|
|
299
|
+
/* @__PURE__ */ jsx(NeusLogo, { size: logoSize }),
|
|
300
|
+
/* @__PURE__ */ jsx("span", { children: label })
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
function VerifiedIcon({
|
|
306
|
+
qHash,
|
|
307
|
+
uiLinkBase = "https://neus.network",
|
|
308
|
+
size = 14,
|
|
309
|
+
tooltip = "Proof",
|
|
310
|
+
onClick = void 0,
|
|
311
|
+
className = ""
|
|
312
|
+
}) {
|
|
313
|
+
const href = qHash ? `${String(uiLinkBase).replace(/\/$/, "")}/proof/${qHash}` : void 0;
|
|
314
|
+
const handleClick = (e) => {
|
|
315
|
+
if (onClick) {
|
|
316
|
+
e.preventDefault();
|
|
317
|
+
onClick({ qHash });
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const icon = /* @__PURE__ */ jsx(
|
|
321
|
+
"span",
|
|
322
|
+
{
|
|
323
|
+
title: tooltip,
|
|
324
|
+
className,
|
|
325
|
+
style: {
|
|
326
|
+
display: "inline-flex",
|
|
327
|
+
cursor: href || onClick ? "pointer" : "default",
|
|
328
|
+
opacity: 0.85,
|
|
329
|
+
transition: "opacity 0.15s ease"
|
|
330
|
+
},
|
|
331
|
+
children: /* @__PURE__ */ jsx(NeusLogo, { size })
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
if (href) {
|
|
335
|
+
return /* @__PURE__ */ jsx(
|
|
336
|
+
"a",
|
|
337
|
+
{
|
|
338
|
+
href,
|
|
339
|
+
target: "_blank",
|
|
340
|
+
rel: "noreferrer",
|
|
341
|
+
onClick: handleClick,
|
|
342
|
+
style: { display: "inline-flex", textDecoration: "none" },
|
|
343
|
+
"aria-label": tooltip,
|
|
344
|
+
children: icon
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
return icon;
|
|
349
|
+
}
|
|
350
|
+
export {
|
|
351
|
+
NeusPillLink,
|
|
352
|
+
ProofBadge,
|
|
353
|
+
SimpleProofBadge,
|
|
354
|
+
VerifiedIcon
|
|
355
|
+
};
|