@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.
@@ -0,0 +1,601 @@
1
+ "use client";
2
+
3
+ // widgets/verify-gate/VerifyGate.jsx
4
+ import React, { useCallback, useMemo, useState, useEffect } from "react";
5
+ import { NeusClient } from "@neus/sdk/client";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ var THEME = {
8
+ // Primary colors - use CSS variables with fallbacks
9
+ primary: "var(--neus-primary, #98C0EF)",
10
+ primaryHover: "var(--neus-primary-hover,rgb(91, 126, 182))",
11
+ success: "var(--neus-success, #22c55e)",
12
+ error: "var(--neus-error, #ef4444)",
13
+ warning: "var(--neus-warning, #f59e0b)",
14
+ // Background colors
15
+ bgDark: "var(--neus-bg-dark, rgba(2, 6, 23, 0.95))",
16
+ bgCard: "var(--neus-bg-card, rgba(15, 23, 42, 0.8))",
17
+ // Text colors
18
+ textPrimary: "var(--neus-text-primary, #ffffff)",
19
+ textSecondary: "var(--neus-text-secondary, #94a3b8)",
20
+ textMuted: "var(--neus-text-muted, #64748b)",
21
+ // Border colors
22
+ border: "var(--neus-border, rgba(148, 163, 184, 0.2))",
23
+ borderHover: "var(--neus-border-hover, rgba(61, 114, 201, 0.4))"
24
+ };
25
+ var DEFAULT_MAX_AGE_MS_BY_VERIFIER = {
26
+ // point_in_time (recommended: 1 hour)
27
+ "ownership-dns-txt": 60 * 60 * 1e3,
28
+ "contract-ownership": 60 * 60 * 1e3,
29
+ "nft-ownership": 60 * 60 * 1e3,
30
+ "token-holding": 60 * 60 * 1e3,
31
+ "wallet-risk": 60 * 60 * 1e3,
32
+ // expiring (recommended: 7 days)
33
+ "agent-delegation": 7 * 24 * 60 * 60 * 1e3
34
+ };
35
+ var maxAgeMsForVerifier = (verifierId, overrideMs) => {
36
+ if (typeof overrideMs === "number")
37
+ return overrideMs;
38
+ return DEFAULT_MAX_AGE_MS_BY_VERIFIER[verifierId];
39
+ };
40
+ var CREATABLE_VERIFIERS = /* @__PURE__ */ new Set([
41
+ "ownership-basic",
42
+ "ownership-pseudonym",
43
+ "ownership-dns-txt",
44
+ "contract-ownership",
45
+ "nft-ownership",
46
+ "token-holding",
47
+ "wallet-link",
48
+ "wallet-risk",
49
+ "agent-identity",
50
+ "agent-delegation",
51
+ "ai-content-moderation"
52
+ ]);
53
+ var NeusLogo = ({ size = 16 }) => /* @__PURE__ */ jsxs(
54
+ "svg",
55
+ {
56
+ width: size,
57
+ height: size,
58
+ viewBox: "0 0 24 24",
59
+ "aria-hidden": "true",
60
+ focusable: "false",
61
+ style: {
62
+ width: size,
63
+ height: size,
64
+ marginRight: 8,
65
+ verticalAlign: "middle",
66
+ borderRadius: 4,
67
+ flexShrink: 0
68
+ },
69
+ children: [
70
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "2", width: "20", height: "20", rx: "5", fill: "currentColor", opacity: "0.18" }),
71
+ /* @__PURE__ */ jsx(
72
+ "path",
73
+ {
74
+ d: "M7 16V8h2.1l4.9 5.9V8H17v8h-2.1L10 10.1V16H7z",
75
+ fill: "currentColor",
76
+ opacity: "0.9"
77
+ }
78
+ )
79
+ ]
80
+ }
81
+ );
82
+ var Spinner = ({ size = 16 }) => /* @__PURE__ */ jsxs(
83
+ "svg",
84
+ {
85
+ className: "animate-spin",
86
+ width: size,
87
+ height: size,
88
+ viewBox: "0 0 24 24",
89
+ fill: "none",
90
+ style: { marginRight: 8 },
91
+ children: [
92
+ /* @__PURE__ */ jsx(
93
+ "circle",
94
+ {
95
+ className: "opacity-25",
96
+ cx: "12",
97
+ cy: "12",
98
+ r: "10",
99
+ stroke: "currentColor",
100
+ strokeWidth: "3"
101
+ }
102
+ ),
103
+ /* @__PURE__ */ jsx(
104
+ "path",
105
+ {
106
+ className: "opacity-75",
107
+ fill: "currentColor",
108
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
109
+ }
110
+ )
111
+ ]
112
+ }
113
+ );
114
+ function VerifyGate({
115
+ requiredVerifiers = ["ownership-basic"],
116
+ onVerified = void 0,
117
+ apiUrl = void 0,
118
+ style = void 0,
119
+ children = void 0,
120
+ // Verifier configuration
121
+ verifierOptions = void 0,
122
+ verifierData = void 0,
123
+ // Proof creation options (privacy, discoverability, content storage)
124
+ proofOptions = void 0,
125
+ // Display options
126
+ showBrand = true,
127
+ disabled = false,
128
+ buttonText = void 0,
129
+ // Custom button text
130
+ // Private proof access mode
131
+ mode = "create",
132
+ // 'create' or 'access'
133
+ qHash = null,
134
+ // Required when mode='access'
135
+ // Proof strategy for static vs dynamic verification
136
+ // - 'reuse': Always use existing proof if available (best for static facts)
137
+ // - 'fresh': Always create new proof (best for dynamic facts that change)
138
+ // - 'reuse-or-create': Use existing if valid, else create new (default)
139
+ strategy = "reuse-or-create",
140
+ // Gate-first options (used when strategy includes 'reuse')
141
+ checkExisting = true,
142
+ // Check for existing proofs before verification
143
+ maxProofAgeMs = void 0,
144
+ // Optional max age override (ms) for proof reuse
145
+ allowPrivateReuse = true,
146
+ // Allow owner-signed lookups for private proofs (interactive)
147
+ // Callbacks
148
+ onStateChange = void 0,
149
+ onError = void 0
150
+ }) {
151
+ const [state, setState] = useState("idle");
152
+ const [error, setError] = useState(null);
153
+ const [notice, setNotice] = useState(null);
154
+ const [isProcessing, setIsProcessing] = useState(false);
155
+ const [walletAddress, setWalletAddress] = useState(null);
156
+ const [existingProofs, setExistingProofs] = useState(null);
157
+ const [operation, setOperation] = useState("verify");
158
+ const client = useMemo(() => new NeusClient({ apiUrl }), [apiUrl]);
159
+ const verifierList = useMemo(() => {
160
+ return Array.isArray(requiredVerifiers) && requiredVerifiers.length > 0 ? requiredVerifiers : ["ownership-basic"];
161
+ }, [requiredVerifiers]);
162
+ const primaryVerifier = verifierList[0];
163
+ const shouldCheckExisting = checkExisting && strategy !== "fresh";
164
+ const buildGateRequirements = useCallback(() => {
165
+ return verifierList.map((verifierId) => ({
166
+ verifierId,
167
+ ...maxAgeMsForVerifier(verifierId, maxProofAgeMs) && { maxAgeMs: maxAgeMsForVerifier(verifierId, maxProofAgeMs) }
168
+ }));
169
+ }, [verifierList, maxProofAgeMs]);
170
+ const applySatisfiedGateResult = useCallback((gateResult, address) => {
171
+ if (!gateResult?.satisfied)
172
+ return false;
173
+ setNotice(null);
174
+ setError(null);
175
+ setState("verified");
176
+ setExistingProofs(gateResult);
177
+ const existingProof = gateResult.existing?.[primaryVerifier];
178
+ if (existingProof && onVerified) {
179
+ onVerified({
180
+ qHash: existingProof.qHash,
181
+ address: existingProof.walletAddress || address,
182
+ verifierIds: verifierList,
183
+ verifiedVerifiers: existingProof.verifiedVerifiers || [],
184
+ existing: true,
185
+ proofsByVerifierId: gateResult.existing || {},
186
+ statusUrl: existingProof.qHash ? `${apiUrl || "https://api.neus.network"}/api/v1/verification/status/${existingProof.qHash}` : null
187
+ });
188
+ }
189
+ return true;
190
+ }, [apiUrl, onVerified, primaryVerifier, verifierList]);
191
+ const getOrRequestWalletAddress = useCallback(async () => {
192
+ if (typeof window === "undefined" || !window.ethereum) {
193
+ throw new Error("No wallet provider available");
194
+ }
195
+ let accounts = await window.ethereum.request({ method: "eth_accounts" });
196
+ if (!accounts || accounts.length === 0) {
197
+ await window.ethereum.request({ method: "eth_requestAccounts" });
198
+ accounts = await window.ethereum.request({ method: "eth_accounts" });
199
+ }
200
+ if (!accounts || accounts.length === 0) {
201
+ throw new Error("No wallet accounts available");
202
+ }
203
+ return accounts[0];
204
+ }, []);
205
+ const tryPrivateReuse = useCallback(async (address) => {
206
+ setOperation("reuse");
207
+ setState("signing");
208
+ const result = await client.getPrivateProofsByWallet(
209
+ address,
210
+ { limit: 200, offset: 0 },
211
+ typeof window !== "undefined" ? window.ethereum : null
212
+ );
213
+ const proofs = result?.proofs || [];
214
+ const gateResult = await client.checkGate({
215
+ walletAddress: address,
216
+ requirements: buildGateRequirements(),
217
+ proofs
218
+ });
219
+ setExistingProofs(gateResult);
220
+ return gateResult;
221
+ }, [client, buildGateRequirements]);
222
+ useEffect(() => {
223
+ onStateChange?.(state);
224
+ }, [state, onStateChange]);
225
+ useEffect(() => {
226
+ if (!shouldCheckExisting || mode === "access")
227
+ return;
228
+ const checkExistingProofs = async () => {
229
+ try {
230
+ if (typeof window === "undefined" || !window.ethereum)
231
+ return;
232
+ const accounts = await window.ethereum.request({ method: "eth_accounts" });
233
+ if (!accounts || accounts.length === 0)
234
+ return;
235
+ const address = accounts[0];
236
+ setWalletAddress(address);
237
+ const gateResult = await client.checkGate({
238
+ walletAddress: address,
239
+ requirements: buildGateRequirements()
240
+ });
241
+ setExistingProofs(gateResult);
242
+ applySatisfiedGateResult(gateResult, address);
243
+ } catch (err) {
244
+ }
245
+ };
246
+ checkExistingProofs();
247
+ if (typeof window !== "undefined" && window.ethereum) {
248
+ const handleAccountsChanged = () => {
249
+ setWalletAddress(null);
250
+ setExistingProofs(null);
251
+ if (state === "verified")
252
+ setState("idle");
253
+ checkExistingProofs();
254
+ };
255
+ window.ethereum.on("accountsChanged", handleAccountsChanged);
256
+ return () => window.ethereum.removeListener("accountsChanged", handleAccountsChanged);
257
+ }
258
+ }, [shouldCheckExisting, mode, client, buildGateRequirements, applySatisfiedGateResult, state]);
259
+ const handleClick = useCallback(async () => {
260
+ if (disabled || isProcessing)
261
+ return;
262
+ if (state === "verified" && existingProofs?.satisfied) {
263
+ return;
264
+ }
265
+ setError(null);
266
+ setNotice(null);
267
+ if (shouldCheckExisting && walletAddress) {
268
+ try {
269
+ const gateResult = await client.checkGate({
270
+ walletAddress,
271
+ requirements: buildGateRequirements()
272
+ });
273
+ if (applySatisfiedGateResult(gateResult, walletAddress))
274
+ return;
275
+ } catch (err) {
276
+ }
277
+ }
278
+ try {
279
+ if (mode === "access") {
280
+ setOperation("access");
281
+ setIsProcessing(true);
282
+ setState("signing");
283
+ if (!qHash) {
284
+ throw new Error("qHash is required for access mode");
285
+ }
286
+ setState("verifying");
287
+ const privateData = await client.getPrivateStatus(qHash);
288
+ setState("verified");
289
+ onVerified?.({
290
+ qHash,
291
+ data: privateData.data,
292
+ mode: "access",
293
+ statusUrl: privateData.statusUrl
294
+ });
295
+ } else if (strategy === "reuse") {
296
+ setOperation("reuse");
297
+ if (!allowPrivateReuse) {
298
+ setNotice("No existing proof was found.");
299
+ return;
300
+ }
301
+ setIsProcessing(true);
302
+ const address = walletAddress || await getOrRequestWalletAddress();
303
+ setWalletAddress(address);
304
+ const gateResult = await tryPrivateReuse(address);
305
+ if (applySatisfiedGateResult(gateResult, address))
306
+ return;
307
+ setState("idle");
308
+ setNotice("No matching proof was found. Create a proof to continue.");
309
+ } else {
310
+ setOperation("verify");
311
+ setIsProcessing(true);
312
+ setState("signing");
313
+ const resolvedProofOptions = {
314
+ privacyLevel: "private",
315
+ publicDisplay: false,
316
+ storeOriginalContent: false,
317
+ ...proofOptions && typeof proofOptions === "object" ? proofOptions : {},
318
+ ...verifierOptions && { verifierOptions }
319
+ };
320
+ const buildDataForVerifier = (verifierId) => {
321
+ if (!CREATABLE_VERIFIERS.has(verifierId)) {
322
+ throw new Error(`${verifierId} cannot be created via the wallet flow. It requires deployment configuration.`);
323
+ }
324
+ const explicit = verifierData && verifierData[verifierId];
325
+ if (explicit && typeof explicit === "object")
326
+ return explicit;
327
+ if (verifierId === "ownership-basic") {
328
+ return null;
329
+ }
330
+ if (verifierId === "wallet-risk") {
331
+ return {};
332
+ }
333
+ throw new Error(`${verifierId} requires explicit verifierData`);
334
+ };
335
+ const verifyOne = async (verifierId) => {
336
+ const dataForVerifier = buildDataForVerifier(verifierId);
337
+ const params = verifierId === "ownership-basic" && dataForVerifier === null ? {
338
+ verifier: "ownership-basic",
339
+ content: verifierData?.["ownership-basic"]?.content || `NEUS verification (${verifierId})`,
340
+ options: resolvedProofOptions
341
+ } : {
342
+ verifier: verifierId,
343
+ data: dataForVerifier,
344
+ options: resolvedProofOptions
345
+ };
346
+ setState("signing");
347
+ const created = await client.verify(params);
348
+ setState("verifying");
349
+ const qHashToCheck = created.qHash || created?.data?.qHash;
350
+ const final = await client.pollProofStatus(qHashToCheck, { interval: 3e3, timeout: 6e4 });
351
+ const verifiedVerifiers = final?.data?.verifiedVerifiers || [];
352
+ const verifierResult = verifiedVerifiers.find((v) => v.verifierId === verifierId);
353
+ if (!verifierResult || verifierResult.verified !== true) {
354
+ throw new Error(`Verification failed for ${verifierId}`);
355
+ }
356
+ const hubTx = final?.data?.hubTransaction || {};
357
+ const crosschain = final?.data?.crosschain || {};
358
+ const txHash = hubTx?.txHash || crosschain?.hubTxHash || null;
359
+ return {
360
+ verifierId,
361
+ qHash: final.qHash,
362
+ address: final?.data?.walletAddress,
363
+ txHash,
364
+ verifiedVerifiers,
365
+ statusUrl: final?.statusUrl
366
+ };
367
+ };
368
+ const results = [];
369
+ for (const verifierId of verifierList) {
370
+ results.push(await verifyOne(verifierId));
371
+ }
372
+ setState("verified");
373
+ const last = results[results.length - 1];
374
+ onVerified?.({
375
+ qHash: last?.qHash,
376
+ qHashes: results.map((r) => r.qHash),
377
+ address: last?.address,
378
+ txHash: last?.txHash,
379
+ verifierIds: verifierList,
380
+ verifiedVerifiers: last?.verifiedVerifiers,
381
+ statusUrl: last?.statusUrl,
382
+ results
383
+ });
384
+ }
385
+ } catch (err) {
386
+ const errorMessage = err?.message || (mode === "access" ? "Access failed" : "Verification failed");
387
+ setError(errorMessage);
388
+ setState("error");
389
+ onError?.(err);
390
+ } finally {
391
+ setIsProcessing(false);
392
+ }
393
+ }, [
394
+ disabled,
395
+ isProcessing,
396
+ mode,
397
+ qHash,
398
+ verifierList,
399
+ client,
400
+ verifierOptions,
401
+ verifierData,
402
+ proofOptions,
403
+ onVerified,
404
+ onError,
405
+ shouldCheckExisting,
406
+ walletAddress,
407
+ existingProofs,
408
+ strategy,
409
+ allowPrivateReuse,
410
+ buildGateRequirements,
411
+ applySatisfiedGateResult,
412
+ getOrRequestWalletAddress,
413
+ tryPrivateReuse,
414
+ state
415
+ ]);
416
+ const handleReuseExisting = useCallback(async () => {
417
+ if (disabled || isProcessing)
418
+ return;
419
+ if (mode === "access")
420
+ return;
421
+ if (!allowPrivateReuse)
422
+ return;
423
+ setError(null);
424
+ setNotice(null);
425
+ try {
426
+ setIsProcessing(true);
427
+ const address = walletAddress || await getOrRequestWalletAddress();
428
+ setWalletAddress(address);
429
+ const gateResult = await tryPrivateReuse(address);
430
+ if (applySatisfiedGateResult(gateResult, address))
431
+ return;
432
+ setState("idle");
433
+ setNotice("No matching proof was found. Verify to create a proof.");
434
+ } catch (err) {
435
+ const errorMessage = err?.message || "Unable to access private proofs";
436
+ setError(errorMessage);
437
+ setState("error");
438
+ onError?.(err);
439
+ } finally {
440
+ setIsProcessing(false);
441
+ }
442
+ }, [disabled, isProcessing, mode, allowPrivateReuse, walletAddress, getOrRequestWalletAddress, tryPrivateReuse, applySatisfiedGateResult, onError]);
443
+ const getLabel = () => {
444
+ if (buttonText)
445
+ return buttonText;
446
+ if (mode === "access") {
447
+ return {
448
+ idle: "Sign to view",
449
+ signing: "Waiting for signature...",
450
+ verifying: "Accessing...",
451
+ verified: "Access granted",
452
+ error: "Retry"
453
+ }[state];
454
+ }
455
+ if (strategy === "reuse") {
456
+ return {
457
+ idle: "Check proofs",
458
+ signing: "Waiting for signature...",
459
+ verifying: "Checking...",
460
+ verified: "Verified",
461
+ error: "Retry"
462
+ }[state];
463
+ }
464
+ return {
465
+ idle: "Verify with NEUS",
466
+ signing: "Waiting for signature...",
467
+ verifying: operation === "reuse" ? "Checking..." : "Verifying...",
468
+ verified: "Verified",
469
+ error: "Retry"
470
+ }[state];
471
+ };
472
+ const buttonBaseStyle = {
473
+ display: "inline-flex",
474
+ alignItems: "center",
475
+ justifyContent: "center",
476
+ gap: "8px",
477
+ padding: "12px 24px",
478
+ borderRadius: "8px",
479
+ border: "none",
480
+ fontWeight: 500,
481
+ fontSize: "14px",
482
+ cursor: disabled || isProcessing ? "not-allowed" : "pointer",
483
+ transition: "all 0.2s ease",
484
+ opacity: disabled || isProcessing ? 0.6 : 1,
485
+ fontFamily: "inherit"
486
+ };
487
+ const getButtonStyle = () => {
488
+ if (state === "verified") {
489
+ return {
490
+ ...buttonBaseStyle,
491
+ background: `rgba(34, 197, 94, 0.15)`,
492
+ color: THEME.success,
493
+ border: `1px solid rgba(34, 197, 94, 0.3)`
494
+ };
495
+ }
496
+ if (state === "error") {
497
+ return {
498
+ ...buttonBaseStyle,
499
+ background: `rgba(239, 68, 68, 0.15)`,
500
+ color: THEME.error,
501
+ border: `1px solid rgba(239, 68, 68, 0.3)`
502
+ };
503
+ }
504
+ if (state === "signing" || state === "verifying") {
505
+ return {
506
+ ...buttonBaseStyle,
507
+ background: `rgba(61, 114, 201, 0.15)`,
508
+ color: "#98c0ef",
509
+ border: `1px solid rgba(61, 114, 201, 0.3)`
510
+ };
511
+ }
512
+ return {
513
+ ...buttonBaseStyle,
514
+ background: THEME.primary,
515
+ color: THEME.textPrimary,
516
+ border: "none",
517
+ boxShadow: "0 4px 14px rgba(61, 114, 201, 0.25)"
518
+ };
519
+ };
520
+ if (children) {
521
+ if (state === "verified") {
522
+ return /* @__PURE__ */ jsx(Fragment, { children });
523
+ }
524
+ return /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "20px", ...style }, children: [
525
+ /* @__PURE__ */ jsxs(
526
+ "button",
527
+ {
528
+ onClick: handleClick,
529
+ disabled: disabled || isProcessing,
530
+ style: getButtonStyle(),
531
+ children: [
532
+ (state === "signing" || state === "verifying" || state.startsWith("zkpassport")) && /* @__PURE__ */ jsx(Spinner, { size: 16 }),
533
+ showBrand && state === "idle" && /* @__PURE__ */ jsx(NeusLogo, { size: 16 }),
534
+ state === "verified" && /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
535
+ /* @__PURE__ */ jsx("span", { children: getLabel() })
536
+ ]
537
+ }
538
+ ),
539
+ notice && /* @__PURE__ */ jsx("div", { style: {
540
+ color: THEME.textSecondary,
541
+ marginTop: "10px",
542
+ fontSize: "13px",
543
+ padding: "8px 12px",
544
+ background: "rgba(148, 163, 184, 0.08)",
545
+ borderRadius: "6px",
546
+ border: "1px solid rgba(148, 163, 184, 0.14)"
547
+ }, children: notice }),
548
+ mode !== "access" && allowPrivateReuse && shouldCheckExisting && strategy !== "reuse" && state === "idle" && /* @__PURE__ */ jsx(
549
+ "button",
550
+ {
551
+ type: "button",
552
+ onClick: handleReuseExisting,
553
+ disabled: disabled || isProcessing,
554
+ style: {
555
+ marginTop: notice ? "10px" : "12px",
556
+ background: "transparent",
557
+ border: "none",
558
+ padding: 0,
559
+ color: THEME.textSecondary,
560
+ fontSize: "12px",
561
+ cursor: disabled || isProcessing ? "not-allowed" : "pointer",
562
+ textDecoration: "underline",
563
+ textUnderlineOffset: "2px",
564
+ opacity: disabled || isProcessing ? 0.6 : 0.9
565
+ },
566
+ children: "Already verified? Sign to reuse existing proofs."
567
+ }
568
+ ),
569
+ error && /* @__PURE__ */ jsx("div", { style: {
570
+ color: THEME.error,
571
+ marginTop: "8px",
572
+ fontSize: "13px",
573
+ padding: "8px 12px",
574
+ background: "rgba(239, 68, 68, 0.1)",
575
+ borderRadius: "6px",
576
+ border: "1px solid rgba(239, 68, 68, 0.2)"
577
+ }, children: error })
578
+ ] });
579
+ }
580
+ return /* @__PURE__ */ jsxs(
581
+ "button",
582
+ {
583
+ onClick: handleClick,
584
+ style: { ...getButtonStyle(), ...style },
585
+ disabled: disabled || isProcessing,
586
+ children: [
587
+ (state === "signing" || state === "verifying" || state.startsWith("zkpassport")) && /* @__PURE__ */ jsx(Spinner, { size: 16 }),
588
+ showBrand && state === "idle" && /* @__PURE__ */ jsx(NeusLogo, { size: 16 }),
589
+ state === "verified" && /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
590
+ /* @__PURE__ */ jsx("span", { children: getLabel() }),
591
+ error && /* @__PURE__ */ jsxs("span", { style: { opacity: 0.8, marginLeft: "8px" }, children: [
592
+ " \u2014 ",
593
+ error
594
+ ] })
595
+ ]
596
+ }
597
+ );
598
+ }
599
+ export {
600
+ VerifyGate
601
+ };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ /**
4
+ * NEUS Widgets (VerifyGate + ProofBadge)
5
+ */
6
+
7
+ export { VerifyGate } from './dist/VerifyGate.js';
8
+ export {
9
+ ProofBadge,
10
+ SimpleProofBadge,
11
+ NeusPillLink,
12
+ VerifiedIcon
13
+ } from './dist/ProofBadge.js';
package/widgets.cjs ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @neus/sdk/widgets is an ESM + React entrypoint.
3
+ *
4
+ * This file exists to provide a clear, deterministic error for CommonJS consumers
5
+ * rather than a cryptic ESM resolution failure.
6
+ */
7
+ 'use strict';
8
+
9
+ throw new Error(
10
+ [
11
+ '@neus/sdk/widgets is ESM-only.',
12
+ '',
13
+ 'Use ESM imports:',
14
+ " import { VerifyGate, ProofBadge } from '@neus/sdk/widgets';",
15
+ '',
16
+ 'Or in CommonJS, use dynamic import:',
17
+ " const { VerifyGate } = await import('@neus/sdk/widgets');"
18
+ ].join('\n')
19
+ );
20
+