@neus/sdk 1.0.5 → 1.0.7

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/utils.js CHANGED
@@ -1,11 +1,5 @@
1
- /**
2
- * NEUS SDK Utilities
3
- * Core utility functions for proof creation and verification
4
- */
5
-
6
1
  import { SDKError, ApiError, ValidationError } from './errors.js';
7
2
 
8
- /** CAIP-380 six-line signer message — line 1 (fixed context label). */
9
3
  export const PORTABLE_PROOF_SIGNER_HEADER = 'Portable Proof Verification Request';
10
4
 
11
5
  const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
@@ -59,11 +53,6 @@ function encodeBase58Bytes(input) {
59
53
  return out;
60
54
  }
61
55
 
62
- /**
63
- * Deterministic JSON stringification for consistent serialization
64
- * @param {Object} obj - Object to stringify
65
- * @returns {string} Deterministic JSON string
66
- */
67
56
  function deterministicStringify(obj) {
68
57
  if (obj === null || obj === undefined) {
69
58
  return JSON.stringify(obj);
@@ -86,9 +75,6 @@ function deterministicStringify(obj) {
86
75
  return `{${ pairs.join(',') }}`;
87
76
  }
88
77
 
89
- /**
90
- * CAIP-380 EVM: line3 is decimal chainId. Non-EVM: CAIP-2 chain string.
91
- */
92
78
  function chainLineForPortableProofSigner(chain, chainId) {
93
79
  if (typeof chain === 'string' && chain.length > 0) {
94
80
  const m = chain.match(/^eip155:(\d+)$/);
@@ -101,19 +87,7 @@ function chainLineForPortableProofSigner(chain, chainId) {
101
87
  throw new SDKError('chainId is required (or provide chain for universal mode)', 'INVALID_CHAIN_CONTEXT');
102
88
  }
103
89
 
104
- /**
105
- * Construct verification message for wallet signing
106
- *
107
- * @param {Object} params - Message parameters
108
- * @param {string} params.walletAddress - Wallet address
109
- * @param {number} params.signedTimestamp - Unix timestamp
110
- * @param {Object} params.data - Verification data
111
- * @param {Array<string>} params.verifierIds - Array of verifier IDs
112
- * @param {number} params.chainId - Chain ID
113
- * @returns {string} Message for signing
114
- */
115
90
  export function constructVerificationMessage({ walletAddress, signedTimestamp, data, verifierIds, chainId, chain }) {
116
- // Input validation for critical parameters
117
91
  if (!walletAddress || typeof walletAddress !== 'string') {
118
92
  throw new SDKError('walletAddress is required and must be a string', 'INVALID_WALLET_ADDRESS');
119
93
  }
@@ -139,7 +113,6 @@ export function constructVerificationMessage({ walletAddress, signedTimestamp, d
139
113
 
140
114
  const chainLine = chainLineForPortableProofSigner(chain, chainId);
141
115
 
142
- // Address normalization: EVM (`eip155`) is lowercased; non-EVM namespaces preserve the original string.
143
116
  const namespace = (typeof chain === 'string' && chain.includes(':')) ? chain.split(':')[0] : 'eip155';
144
117
  const normalizedWalletAddress = namespace === 'eip155' ? walletAddress.toLowerCase() : walletAddress;
145
118
 
@@ -157,29 +130,14 @@ export function constructVerificationMessage({ walletAddress, signedTimestamp, d
157
130
  return messageComponents.join('\n').normalize('NFC');
158
131
  }
159
132
 
160
- /**
161
- * Validate Ethereum wallet address format
162
- *
163
- * @param {string} address - Address to validate
164
- * @returns {boolean} True if valid Ethereum address
165
- */
166
133
  export function validateWalletAddress(address) {
167
134
  if (!address || typeof address !== 'string') {
168
135
  return false;
169
136
  }
170
137
 
171
- // Basic Ethereum address validation
172
138
  return /^0x[a-fA-F0-9]{40}$/.test(address);
173
139
  }
174
140
 
175
- /**
176
- * Validate universal wallet address format.
177
- * Uses chain namespace when provided; otherwise applies conservative multi-chain checks.
178
- *
179
- * @param {string} address - Address to validate
180
- * @param {string} [chain] - Optional CAIP-2 chain reference (namespace:reference)
181
- * @returns {boolean} True if valid universal wallet address
182
- */
183
141
  export function validateUniversalAddress(address, chain) {
184
142
  if (!address || typeof address !== 'string') return false;
185
143
  const value = address.trim();
@@ -204,17 +162,9 @@ export function validateUniversalAddress(address, chain) {
204
162
  return /^[a-z0-9._-]{2,64}$/.test(value);
205
163
  }
206
164
 
207
- // Generic fallback for universal-address style identifiers.
208
165
  return /^[A-Za-z0-9][A-Za-z0-9._:-]{1,127}$/.test(value);
209
166
  }
210
167
 
211
- /**
212
- * Validate timestamp freshness
213
- *
214
- * @param {number} timestamp - Timestamp to validate
215
- * @param {number} maxAgeMs - Maximum age in milliseconds (default: 5 minutes)
216
- * @returns {boolean} True if timestamp is valid and recent
217
- */
218
168
  export function validateTimestamp(timestamp, maxAgeMs = 5 * 60 * 1000) {
219
169
  if (!timestamp || typeof timestamp !== 'number') {
220
170
  return false;
@@ -223,21 +173,10 @@ export function validateTimestamp(timestamp, maxAgeMs = 5 * 60 * 1000) {
223
173
  const now = Date.now();
224
174
  const age = now - timestamp;
225
175
 
226
- // Check if timestamp is in the past and within allowed age
227
176
  return age >= 0 && age <= maxAgeMs;
228
177
  }
229
178
 
230
- /**
231
- * Create formatted verification data object
232
- *
233
- * @param {string} content - Content to verify
234
- * @param {string} owner - Owner wallet address
235
- * @param {Object} reference - Reference object
236
- * @returns {Object} Formatted verification data
237
- */
238
179
  export function createVerificationData(content, owner, reference = null) {
239
- // Small, deterministic reference ID for convenience (NOT a cryptographic hash).
240
- // Integrators that need a stable binding should prefer contentHash or an explicit reference.id.
241
180
  const stableRefId = (value) => {
242
181
  const str = typeof value === 'string' ? value : JSON.stringify(value);
243
182
  let hash = 0;
@@ -253,17 +192,12 @@ export function createVerificationData(content, owner, reference = null) {
253
192
  content,
254
193
  owner: validateWalletAddress(owner) ? owner.toLowerCase() : owner,
255
194
  reference: reference || {
256
- // Must be a valid backend enum value; 'content' is not supported.
257
195
  type: 'other',
258
196
  id: stableRefId(content)
259
197
  }
260
198
  };
261
199
  }
262
200
 
263
- /**
264
- * DERIVE DID FROM ADDRESS AND CHAIN
265
- * did:pkh:<namespace>:<chainId|segment>:<address_lowercase>
266
- */
267
201
  export function deriveDid(address, chainIdOrChain) {
268
202
  if (!address || typeof address !== 'string') {
269
203
  throw new SDKError('deriveDid: address is required', 'INVALID_ARGUMENT');
@@ -284,20 +218,6 @@ export function deriveDid(address, chainIdOrChain) {
284
218
  }
285
219
  }
286
220
 
287
- /**
288
- * Resolve DID from wallet identity via API endpoint
289
- *
290
- * @param {Object} params - DID resolution parameters
291
- * @param {string} params.walletAddress - Wallet address to resolve
292
- * @param {number} [params.chainId] - EVM chain ID
293
- * @param {string} [params.chain] - Universal chain context (namespace:reference)
294
- * @param {Object} [options] - Request options
295
- * @param {string} [options.endpoint='/api/v1/profile/did/resolve'] - DID resolve endpoint
296
- * @param {string} [options.apiUrl] - Absolute API base URL for non-relative endpoints
297
- * @param {RequestCredentials} [options.credentials] - Fetch credentials mode
298
- * @param {Record<string, string>} [options.headers] - Extra request headers
299
- * @returns {Promise<{did: string, data: any, raw: any}>}
300
- */
301
221
  export async function resolveDID(params, options = {}) {
302
222
  const endpointPath = options.endpoint || '/api/v1/profile/did/resolve';
303
223
  const apiUrl = typeof options.apiUrl === 'string' ? options.apiUrl.trim() : '';
@@ -371,17 +291,6 @@ export async function resolveDID(params, options = {}) {
371
291
  }
372
292
  }
373
293
 
374
- /**
375
- * Standardize verification request via backend signer-string endpoint
376
- *
377
- * @param {Object} params - Verification request payload
378
- * @param {Object} [options] - Request options
379
- * @param {string} [options.endpoint='/api/v1/verification/standardize'] - Standardize endpoint
380
- * @param {string} [options.apiUrl] - Absolute API base URL for non-relative endpoints
381
- * @param {RequestCredentials} [options.credentials] - Fetch credentials mode
382
- * @param {Record<string, string>} [options.headers] - Extra request headers
383
- * @returns {Promise<any>}
384
- */
385
294
  export async function standardizeVerificationRequest(params, options = {}) {
386
295
  const endpointPath = options.endpoint || '/api/v1/verification/standardize';
387
296
  const apiUrl = typeof options.apiUrl === 'string' ? options.apiUrl.trim() : '';
@@ -443,13 +352,6 @@ export async function standardizeVerificationRequest(params, options = {}) {
443
352
  }
444
353
  }
445
354
 
446
- /**
447
- * Resolve default ZK Passport configuration values.
448
- * Kept as an SDK utility to preserve existing app integrations.
449
- *
450
- * @param {Object} [overrides] - Caller-provided config overrides
451
- * @returns {Object}
452
- */
453
355
  export function resolveZkPassportConfig(overrides = {}) {
454
356
  const defaults = {
455
357
  provider: 'zkpassport',
@@ -465,29 +367,12 @@ export function resolveZkPassportConfig(overrides = {}) {
465
367
  };
466
368
  }
467
369
 
468
- /**
469
- * Convert a UTF-8 string to `0x`-prefixed hex.
470
- *
471
- * @param {string} value
472
- * @returns {string}
473
- */
474
370
  export function toHexUtf8(value) {
475
371
  const input = typeof value === 'string' ? value : String(value || '');
476
372
  const bytes = new TextEncoder().encode(input);
477
373
  return `0x${Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')}`;
478
374
  }
479
375
 
480
- /**
481
- * Sign an arbitrary message with the provided wallet/provider.
482
- * Supports EIP-1193 wallets and signer-like objects.
483
- *
484
- * @param {Object} params
485
- * @param {Object} [params.provider] - Wallet provider/signer
486
- * @param {string} params.message - Message to sign
487
- * @param {string} [params.walletAddress] - Explicit signer address (recommended)
488
- * @param {string} [params.chain] - Chain context (`namespace:reference`)
489
- * @returns {Promise<string>}
490
- */
491
376
  export async function signMessage({ provider, message, walletAddress, chain } = {}) {
492
377
  const msg = typeof message === 'string' ? message : String(message || '');
493
378
  if (!msg) {
@@ -574,7 +459,7 @@ export async function signMessage({ provider, message, walletAddress, chain } =
574
459
  const sig = await resolvedProvider.request({ method: 'personal_sign', params: [hexMsg, address] });
575
460
  if (typeof sig === 'string' && sig) return sig;
576
461
  } catch {
577
- // Continue to additional fallbacks.
462
+ void 0;
578
463
  }
579
464
  }
580
465
  }
@@ -601,15 +486,9 @@ export async function signMessage({ provider, message, walletAddress, chain } =
601
486
  throw new SDKError('Unable to sign message with provided wallet/provider', 'SIGNER_UNAVAILABLE');
602
487
  }
603
488
 
604
- /**
605
- * Determine if a verification status is terminal (completed or failed)
606
- * @param {string} status - The verification status
607
- * @returns {boolean} Whether the status is terminal
608
- */
609
489
  export function isTerminalStatus(status) {
610
490
  if (!status || typeof status !== 'string') return false;
611
491
 
612
- // Success states
613
492
  const successStates = [
614
493
  'verified',
615
494
  'verified_no_verifiers',
@@ -618,7 +497,6 @@ export function isTerminalStatus(status) {
618
497
  'verified_propagation_failed'
619
498
  ];
620
499
 
621
- // Failure states
622
500
  const failureStates = [
623
501
  'rejected',
624
502
  'rejected_verifier_failure',
@@ -633,11 +511,6 @@ export function isTerminalStatus(status) {
633
511
  return successStates.includes(status) || failureStates.includes(status);
634
512
  }
635
513
 
636
- /**
637
- * Determine if a verification status indicates success
638
- * @param {string} status - The verification status
639
- * @returns {boolean} Whether the status indicates success
640
- */
641
514
  export function isSuccessStatus(status) {
642
515
  if (!status || typeof status !== 'string') return false;
643
516
 
@@ -652,11 +525,6 @@ export function isSuccessStatus(status) {
652
525
  return successStates.includes(status);
653
526
  }
654
527
 
655
- /**
656
- * Determine if a verification status indicates failure
657
- * @param {string} status - The verification status
658
- * @returns {boolean} Whether the status indicates failure
659
- */
660
528
  export function isFailureStatus(status) {
661
529
  if (!status || typeof status !== 'string') return false;
662
530
 
@@ -674,11 +542,6 @@ export function isFailureStatus(status) {
674
542
  return failureStates.includes(status);
675
543
  }
676
544
 
677
- /**
678
- * Format verification status for display
679
- * @param {string} status - Raw status from API
680
- * @returns {Object} Formatted status information
681
- */
682
545
  export function formatVerificationStatus(status) {
683
546
  const statusMap = {
684
547
  'processing_verifiers': {
@@ -781,18 +644,6 @@ export function formatVerificationStatus(status) {
781
644
  };
782
645
  }
783
646
 
784
- /**
785
- * Compute keccak256 content hash (0x-prefixed) for arbitrary input
786
- * Uses ethers (peer dependency) via dynamic import to avoid hard bundling
787
- *
788
- * Note: The NEUS backend uses SHAKE256 (quantum-resistant) for content hashing.
789
- * For content hashes that match the backend, use the /verification/standardize
790
- * endpoint to get the server-computed hash, or provide the content directly and let
791
- * the backend compute the hash.
792
- *
793
- * @param {string|Uint8Array} input - Raw string (UTF-8) or bytes
794
- * @returns {Promise<string>} 0x-prefixed keccak256 hash
795
- */
796
647
  export async function computeContentHash(input) {
797
648
  try {
798
649
  const ethers = await import('ethers');
@@ -803,18 +654,10 @@ export async function computeContentHash(input) {
803
654
  }
804
655
  }
805
656
 
806
- /**
807
- * Create a delay/sleep function
808
- * @param {number} ms - Milliseconds to wait
809
- * @returns {Promise} Promise that resolves after the delay
810
- */
811
657
  export function delay(ms) {
812
658
  return new Promise(resolve => setTimeout(resolve, ms));
813
659
  }
814
660
 
815
- /**
816
- * Status Polling Utility for tracking verification progress
817
- */
818
661
  export class StatusPoller {
819
662
  constructor(client, qHash, options = {}) {
820
663
  this.client = client;
@@ -838,13 +681,11 @@ export class StatusPoller {
838
681
 
839
682
  const response = await this.client.getProof(this.qHash);
840
683
 
841
- // Check if verification is complete using the terminal status utility
842
684
  if (isTerminalStatus(response.status)) {
843
685
  resolve(response);
844
686
  return;
845
687
  }
846
688
 
847
- // Check if we've exceeded max attempts
848
689
  if (this.attempt >= this.options.maxAttempts) {
849
690
  reject(new SDKError(
850
691
  'Verification polling timeout',
@@ -853,7 +694,6 @@ export class StatusPoller {
853
694
  return;
854
695
  }
855
696
 
856
- // Schedule next poll with optional exponential backoff
857
697
  if (this.options.exponentialBackoff) {
858
698
  this.currentInterval = Math.min(
859
699
  this.currentInterval * 1.5,
@@ -889,20 +729,14 @@ export class StatusPoller {
889
729
  }
890
730
  };
891
731
 
892
- // Start polling immediately
893
732
  pollAttempt();
894
733
  });
895
734
  }
896
735
  }
897
736
 
898
- /**
899
- * NEUS Network Constants
900
- */
901
737
  export const NEUS_CONSTANTS = {
902
- /** Default EVM chain id for NEUS protocol signing context (`HUB_CHAIN_ID` name kept for compatibility). */
903
738
  HUB_CHAIN_ID: 84532,
904
739
 
905
- // Supported target chains for cross-chain propagation
906
740
  TESTNET_CHAINS: [
907
741
  11155111, // Ethereum Sepolia
908
742
  11155420, // Optimism Sepolia
@@ -910,15 +744,12 @@ export const NEUS_CONSTANTS = {
910
744
  80002 // Polygon Amoy
911
745
  ],
912
746
 
913
- // API endpoints
914
747
  API_BASE_URL: 'https://api.neus.network',
915
748
  API_VERSION: 'v1',
916
749
 
917
- // Timeouts and limits
918
750
  SIGNATURE_MAX_AGE_MS: 5 * 60 * 1000, // 5 minutes
919
751
  REQUEST_TIMEOUT_MS: 30 * 1000, // 30 seconds
920
752
 
921
- // Default verifier set for quick starts
922
753
  DEFAULT_VERIFIERS: [
923
754
  'ownership-basic',
924
755
  'nft-ownership',
@@ -926,42 +757,18 @@ export const NEUS_CONSTANTS = {
926
757
  ]
927
758
  };
928
759
 
929
- /**
930
- * Additional validation and utility helpers
931
- */
932
-
933
- /**
934
- * Validate qHash format (0x + 64 hex chars)
935
- * @param {string} qHash - The qHash to validate
936
- * @returns {boolean} True if valid qHash format
937
- */
938
760
  export function validateQHash(qHash) {
939
761
  return typeof qHash === 'string' && /^0x[a-fA-F0-9]{64}$/.test(qHash);
940
762
  }
941
763
 
942
- /**
943
- * Format timestamp to human readable string
944
- * @param {number} timestamp - Unix timestamp
945
- * @returns {string} Formatted date string
946
- */
947
764
  export function formatTimestamp(timestamp) {
948
765
  return new Date(timestamp).toLocaleString();
949
766
  }
950
767
 
951
- /**
952
- * Check if a chain ID is supported for cross-chain propagation
953
- * @param {number} chainId - Chain ID to check
954
- * @returns {boolean} True if supported
955
- */
956
768
  export function isSupportedChain(chainId) {
957
769
  return NEUS_CONSTANTS.TESTNET_CHAINS.includes(chainId) || chainId === NEUS_CONSTANTS.HUB_CHAIN_ID;
958
770
  }
959
771
 
960
- /**
961
- * Normalize wallet address to lowercase (EIP-55 agnostic)
962
- * @param {string} address - Wallet address to normalize
963
- * @returns {string} Lowercase address
964
- */
965
772
  export function normalizeAddress(address) {
966
773
  if (!validateWalletAddress(address)) {
967
774
  throw new SDKError('Invalid wallet address format', 'INVALID_ADDRESS');
@@ -969,13 +776,6 @@ export function normalizeAddress(address) {
969
776
  return address.toLowerCase();
970
777
  }
971
778
 
972
- /**
973
- * Validate a verifier payload for basic structural integrity.
974
- * Lightweight validation checks; verifier authors should document complete schemas.
975
- * @param {string} verifierId - Verifier identifier (e.g., 'ownership-basic' or custom)
976
- * @param {any} data - Verifier-specific payload
977
- * @returns {{ valid: boolean, error?: string, missing?: string[], warnings?: string[] }}
978
- */
979
779
  export function validateVerifierPayload(verifierId, data) {
980
780
  const result = { valid: true, missing: [], warnings: [] };
981
781
 
@@ -987,7 +787,6 @@ export function validateVerifierPayload(verifierId, data) {
987
787
  return { valid: false, error: 'data must be a non-null object' };
988
788
  }
989
789
 
990
- // Minimal field hints for built-in verifiers
991
790
  const id = verifierId.replace(/@\d+$/, '');
992
791
  if (id === 'nft-ownership') {
993
792
  ['contractAddress', 'tokenId', 'chainId'].forEach((key) => {
@@ -1004,10 +803,6 @@ export function validateVerifierPayload(verifierId, data) {
1004
803
  result.warnings.push('ownerAddress omitted (defaults to the signed walletAddress)');
1005
804
  }
1006
805
  } else if (id === 'ownership-basic') {
1007
- // ownership-basic requires an owner, and needs at least one binding:
1008
- // - content (inline), or
1009
- // - contentHash (recommended for large content), or
1010
- // - reference.id (reference-only proofs)
1011
806
  if (!('owner' in data)) result.missing.push('owner');
1012
807
  const hasContent = typeof data.content === 'string' && data.content.length > 0;
1013
808
  const hasContentHash = typeof data.contentHash === 'string' && data.contentHash.length > 0;
@@ -1025,18 +820,6 @@ export function validateVerifierPayload(verifierId, data) {
1025
820
  return result;
1026
821
  }
1027
822
 
1028
- /**
1029
- * Build a standard verification request and signing message for manual flows.
1030
- * Returns the message to sign and the request body (sans signature).
1031
- * @param {Object} params
1032
- * @param {string[]} params.verifierIds
1033
- * @param {object} params.data
1034
- * @param {string} params.walletAddress
1035
- * @param {number} [params.chainId=NEUS_CONSTANTS.HUB_CHAIN_ID]
1036
- * @param {object} [params.options]
1037
- * @param {number} [params.signedTimestamp=Date.now()]
1038
- * @returns {{ message: string, request: { verifierIds: string[], data: object, walletAddress: string, signedTimestamp: number, chainId: number, options?: object } }}
1039
- */
1040
823
  export function buildVerificationRequest({
1041
824
  verifierIds,
1042
825
  data,
@@ -1078,12 +861,6 @@ export function buildVerificationRequest({
1078
861
  return { message, request };
1079
862
  }
1080
863
 
1081
- /**
1082
- * Create a retry utility with exponential backoff
1083
- * @param {Function} fn - Function to retry
1084
- * @param {Object} options - Retry options
1085
- * @returns {Promise} Promise that resolves with function result
1086
- */
1087
864
  export async function withRetry(fn, options = {}) {
1088
865
  const {
1089
866
  maxAttempts = 3,
@@ -1114,17 +891,6 @@ export async function withRetry(fn, options = {}) {
1114
891
  throw lastError;
1115
892
  }
1116
893
 
1117
- /**
1118
- * Validate signature components for debugging signature verification issues
1119
- * @param {Object} params - Signature components to validate
1120
- * @param {string} params.walletAddress - Wallet address
1121
- * @param {string} params.signature - EIP-191 signature
1122
- * @param {number} params.signedTimestamp - Unix timestamp
1123
- * @param {Object} params.data - Verification data
1124
- * @param {Array<string>} params.verifierIds - Array of verifier IDs
1125
- * @param {number} params.chainId - Chain ID
1126
- * @returns {Object} Validation result with detailed feedback
1127
- */
1128
894
  export function validateSignatureComponents({ walletAddress, signature, signedTimestamp, data, verifierIds, chainId }) {
1129
895
  const result = {
1130
896
  valid: true,
@@ -1133,7 +899,6 @@ export function validateSignatureComponents({ walletAddress, signature, signedTi
1133
899
  debugInfo: {}
1134
900
  };
1135
901
 
1136
- // Validate wallet address
1137
902
  if (!validateWalletAddress(walletAddress)) {
1138
903
  result.valid = false;
1139
904
  result.errors.push('Invalid wallet address format - must be 0x + 40 hex characters');
@@ -1144,7 +909,6 @@ export function validateSignatureComponents({ walletAddress, signature, signedTi
1144
909
  }
1145
910
  }
1146
911
 
1147
- // Validate signature format
1148
912
  if (!signature || typeof signature !== 'string') {
1149
913
  result.valid = false;
1150
914
  result.errors.push('Signature is required and must be a string');
@@ -1153,7 +917,6 @@ export function validateSignatureComponents({ walletAddress, signature, signedTi
1153
917
  result.errors.push('Invalid signature format - must be 0x + 130 hex characters (65 bytes)');
1154
918
  }
1155
919
 
1156
- // Validate timestamp
1157
920
  if (!validateTimestamp(signedTimestamp)) {
1158
921
  result.valid = false;
1159
922
  result.errors.push('Invalid or expired timestamp - must be within 5 minutes');
@@ -1161,7 +924,6 @@ export function validateSignatureComponents({ walletAddress, signature, signedTi
1161
924
  result.debugInfo.timestampAge = Date.now() - signedTimestamp;
1162
925
  }
1163
926
 
1164
- // Validate data object
1165
927
  if (!data || typeof data !== 'object' || Array.isArray(data)) {
1166
928
  result.valid = false;
1167
929
  result.errors.push('Data must be a non-null object');
@@ -1169,19 +931,16 @@ export function validateSignatureComponents({ walletAddress, signature, signedTi
1169
931
  result.debugInfo.dataString = deterministicStringify(data);
1170
932
  }
1171
933
 
1172
- // Validate verifier IDs
1173
934
  if (!Array.isArray(verifierIds) || verifierIds.length === 0) {
1174
935
  result.valid = false;
1175
936
  result.errors.push('VerifierIds must be a non-empty array');
1176
937
  }
1177
938
 
1178
- // Validate chain ID
1179
939
  if (typeof chainId !== 'number') {
1180
940
  result.valid = false;
1181
941
  result.errors.push('ChainId must be a number');
1182
942
  }
1183
943
 
1184
- // Generate the message that would be signed
1185
944
  if (result.valid || result.errors.length < 3) {
1186
945
  try {
1187
946
  result.debugInfo.messageToSign = constructVerificationMessage({
@@ -1199,13 +958,6 @@ export function validateSignatureComponents({ walletAddress, signature, signedTi
1199
958
  return result;
1200
959
  }
1201
960
 
1202
- /**
1203
- * Convert a non-negative decimal display amount to agent-delegation `maxSpend`
1204
- * (whole-number string in token base units, 1–78 digits).
1205
- * @param {string|number} humanAmount - e.g. "100.50" or 100.5
1206
- * @param {number} decimals - Number of decimal places for the token (e.g. 6 for USDC, 18 for ETH)
1207
- * @returns {string}
1208
- */
1209
961
  export function toAgentDelegationMaxSpend(humanAmount, decimals) {
1210
962
  if (humanAmount === undefined || humanAmount === null) {
1211
963
  throw new ValidationError('humanAmount is required', 'humanAmount', humanAmount);
@@ -1254,24 +1006,8 @@ export function toAgentDelegationMaxSpend(humanAmount, decimals) {
1254
1006
  return out;
1255
1007
  }
1256
1008
 
1257
- /** Default hosted verify base URL */
1258
1009
  export const DEFAULT_HOSTED_VERIFY_URL = 'https://neus.network/verify';
1259
1010
 
1260
- /**
1261
- * Build standardized hosted checkout/verify URL for your app.
1262
- * Single typed entry point to avoid copy-paste errors.
1263
- * @param {Object} opts
1264
- * @param {string} [opts.gateId] - Gate ID for gate-backed checkout
1265
- * @param {string} [opts.returnUrl] - Partner return URL (postMessage/redirect)
1266
- * @param {string[]} [opts.verifiers] - Verifier IDs (comma-joined)
1267
- * @param {string} [opts.preset] - Preset name (e.g. 'human')
1268
- * @param {string} [opts.mode] - 'popup' or null
1269
- * @param {string} [opts.intent] - 'login' for auth-code flow
1270
- * @param {string} [opts.origin] - Allowed parent origin for popup completion
1271
- * @param {string} [opts.oauthProvider] - Optional OAuth provider id to pre-select for social/org verifiers (hosted flow)
1272
- * @param {string} [opts.baseUrl] - Hosted verify URL override
1273
- * @returns {string} Full URL
1274
- */
1275
1011
  export function getHostedCheckoutUrl(opts = {}) {
1276
1012
  const base = typeof opts.baseUrl === 'string' && opts.baseUrl.trim()
1277
1013
  ? opts.baseUrl.replace(/\/+$/, '')
package/widgets/README.md CHANGED
@@ -1,45 +1,45 @@
1
- # NEUS Widgets
2
-
3
- **Proof-aware React components** (VerifyGate, ProofBadge) so your UI can show verified state and gate content **using the same checks your server already trusts** - avoid re-implementing verifier rules only in the browser.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install @neus/sdk react react-dom
9
- ```
10
-
11
- ## VerifyGate
12
-
13
- Create mode defaults to **unlisted public** for gate-friendly reuse. Override `proofOptions` when you need listed public or private.
14
-
15
- ```jsx
16
- import { VerifyGate } from '@neus/sdk/widgets';
17
-
18
- export function Page() {
19
- return (
20
- <VerifyGate
21
- appId="your-app-id"
22
- requiredVerifiers={['nft-ownership']}
23
- verifierData={{
24
- 'nft-ownership': { contractAddress: '0x...', tokenId: '1', chainId: 8453 }
25
- }}
26
- >
27
- <div>Unlocked</div>
28
- </VerifyGate>
29
- );
30
- }
31
- ```
32
-
33
- ## ProofBadge
34
-
35
- ```jsx
36
- import { ProofBadge } from '@neus/sdk/widgets';
37
-
38
- <ProofBadge proofId="0x..." showChains />
39
- ```
40
-
41
- ## Docs
42
-
43
- - [Widgets Overview](https://docs.neus.network/widgets/overview)
44
- - [Verify Component](https://docs.neus.network/widgets/verifygate)
45
- - [Quickstart](https://docs.neus.network/quickstart)
1
+ # NEUS Widgets
2
+
3
+ **Proof-aware React components** (VerifyGate, ProofBadge) so your UI can show verified state and gate content **using the same checks your server already trusts** - avoid re-implementing verifier rules only in the browser.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @neus/sdk react react-dom
9
+ ```
10
+
11
+ ## VerifyGate
12
+
13
+ Create mode defaults to **private**. Override `proofOptions` only when you intentionally need public visibility for link-based or public checks.
14
+
15
+ ```jsx
16
+ import { VerifyGate } from '@neus/sdk/widgets';
17
+
18
+ export function Page() {
19
+ return (
20
+ <VerifyGate
21
+ appId="your-app-id"
22
+ requiredVerifiers={['nft-ownership']}
23
+ verifierData={{
24
+ 'nft-ownership': { contractAddress: '0x...', tokenId: '1', chainId: 8453 }
25
+ }}
26
+ >
27
+ <div>Unlocked</div>
28
+ </VerifyGate>
29
+ );
30
+ }
31
+ ```
32
+
33
+ ## ProofBadge
34
+
35
+ ```jsx
36
+ import { ProofBadge } from '@neus/sdk/widgets';
37
+
38
+ <ProofBadge proofId="0x..." showChains />
39
+ ```
40
+
41
+ ## Docs
42
+
43
+ - [Widgets Overview](https://docs.neus.network/widgets/overview)
44
+ - [Verify Component](https://docs.neus.network/widgets/verifygate)
45
+ - [Quickstart](https://docs.neus.network/quickstart)