@neus/sdk 1.0.3 → 1.0.5
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/README.md +127 -150
- package/SECURITY.md +33 -29
- package/cjs/client.cjs +308 -264
- package/cjs/index.cjs +403 -310
- package/cjs/utils.cjs +138 -97
- package/cli/neus.mjs +606 -0
- package/client.js +559 -470
- package/errors.js +5 -5
- package/gates.js +18 -18
- package/index.js +79 -75
- package/package.json +16 -10
- package/types.d.ts +138 -59
- package/utils.js +1291 -1180
- package/widgets/README.md +45 -64
- package/widgets/index.js +1 -1
- package/widgets/verify-gate/dist/ProofBadge.js +10 -18
- package/widgets/verify-gate/dist/VerifyGate.js +109 -98
- package/widgets/verify-gate/index.js +5 -5
package/cjs/index.cjs
CHANGED
|
@@ -181,8 +181,7 @@ function encodeBase58Bytes(input) {
|
|
|
181
181
|
} else {
|
|
182
182
|
throw new SDKError("Unsupported non-EVM signature byte format", "INVALID_SIGNATURE_FORMAT");
|
|
183
183
|
}
|
|
184
|
-
if (source.length === 0)
|
|
185
|
-
return "";
|
|
184
|
+
if (source.length === 0) return "";
|
|
186
185
|
let zeroes = 0;
|
|
187
186
|
while (zeroes < source.length && source[zeroes] === 0) {
|
|
188
187
|
zeroes++;
|
|
@@ -216,16 +215,28 @@ function deterministicStringify(obj) {
|
|
|
216
215
|
return JSON.stringify(obj);
|
|
217
216
|
}
|
|
218
217
|
if (typeof obj !== "object") {
|
|
218
|
+
if (typeof obj === "string") return JSON.stringify(obj.normalize("NFC"));
|
|
219
219
|
return JSON.stringify(obj);
|
|
220
220
|
}
|
|
221
221
|
if (Array.isArray(obj)) {
|
|
222
|
-
return
|
|
222
|
+
return `[${obj.map((item) => item === void 0 ? "null" : deterministicStringify(item)).join(",")}]`;
|
|
223
223
|
}
|
|
224
|
-
const sortedKeys = Object.keys(obj).sort();
|
|
224
|
+
const sortedKeys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
225
225
|
const pairs = sortedKeys.map(
|
|
226
|
-
(key) => JSON.stringify(key)
|
|
226
|
+
(key) => `${JSON.stringify(key)}:${deterministicStringify(obj[key])}`
|
|
227
227
|
);
|
|
228
|
-
return
|
|
228
|
+
return `{${pairs.join(",")}}`;
|
|
229
|
+
}
|
|
230
|
+
function chainLineForPortableProofSigner(chain, chainId) {
|
|
231
|
+
if (typeof chain === "string" && chain.length > 0) {
|
|
232
|
+
const m = chain.match(/^eip155:(\d+)$/);
|
|
233
|
+
if (m) return Number(m[1]);
|
|
234
|
+
return chain;
|
|
235
|
+
}
|
|
236
|
+
if (typeof chainId === "number" && Number.isFinite(chainId) && chainId > 0) {
|
|
237
|
+
return chainId;
|
|
238
|
+
}
|
|
239
|
+
throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
|
|
229
240
|
}
|
|
230
241
|
function constructVerificationMessage({ walletAddress, signedTimestamp, data, verifierIds, chainId, chain }) {
|
|
231
242
|
if (!walletAddress || typeof walletAddress !== "string") {
|
|
@@ -240,28 +251,28 @@ function constructVerificationMessage({ walletAddress, signedTimestamp, data, ve
|
|
|
240
251
|
if (!Array.isArray(verifierIds) || verifierIds.length === 0) {
|
|
241
252
|
throw new SDKError("verifierIds is required and must be a non-empty array", "INVALID_VERIFIER_IDS");
|
|
242
253
|
}
|
|
243
|
-
|
|
244
|
-
if (!chainContext) {
|
|
254
|
+
if ((typeof chain !== "string" || !chain.length) && !(typeof chainId === "number" && chainId > 0)) {
|
|
245
255
|
throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
|
|
246
256
|
}
|
|
247
|
-
if (
|
|
248
|
-
throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
|
|
249
|
-
}
|
|
250
|
-
if (chainContext === chain && (typeof chain !== "string" || !chain.includes(":"))) {
|
|
257
|
+
if (typeof chain === "string" && chain.length > 0 && !chain.includes(":")) {
|
|
251
258
|
throw new SDKError('chain must be a "namespace:reference" string', "INVALID_CHAIN");
|
|
252
259
|
}
|
|
260
|
+
if ((!chain || !chain.length) && typeof chainId !== "number") {
|
|
261
|
+
throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
|
|
262
|
+
}
|
|
263
|
+
const chainLine = chainLineForPortableProofSigner(chain, chainId);
|
|
253
264
|
const namespace = typeof chain === "string" && chain.includes(":") ? chain.split(":")[0] : "eip155";
|
|
254
265
|
const normalizedWalletAddress = namespace === "eip155" ? walletAddress.toLowerCase() : walletAddress;
|
|
255
266
|
const dataString = deterministicStringify(data);
|
|
256
267
|
const messageComponents = [
|
|
257
|
-
|
|
268
|
+
PORTABLE_PROOF_SIGNER_HEADER,
|
|
258
269
|
`Wallet: ${normalizedWalletAddress}`,
|
|
259
|
-
`Chain: ${
|
|
270
|
+
`Chain: ${chainLine}`,
|
|
260
271
|
`Verifiers: ${verifierIds.join(",")}`,
|
|
261
272
|
`Data: ${dataString}`,
|
|
262
273
|
`Timestamp: ${signedTimestamp}`
|
|
263
274
|
];
|
|
264
|
-
return messageComponents.join("\n");
|
|
275
|
+
return messageComponents.join("\n").normalize("NFC");
|
|
265
276
|
}
|
|
266
277
|
function validateWalletAddress(address) {
|
|
267
278
|
if (!address || typeof address !== "string") {
|
|
@@ -270,17 +281,13 @@ function validateWalletAddress(address) {
|
|
|
270
281
|
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
271
282
|
}
|
|
272
283
|
function validateUniversalAddress(address, chain) {
|
|
273
|
-
if (!address || typeof address !== "string")
|
|
274
|
-
return false;
|
|
284
|
+
if (!address || typeof address !== "string") return false;
|
|
275
285
|
const value = address.trim();
|
|
276
|
-
if (!value)
|
|
277
|
-
return false;
|
|
286
|
+
if (!value) return false;
|
|
278
287
|
const chainRef = typeof chain === "string" ? chain.trim().toLowerCase() : "";
|
|
279
288
|
const namespace = chainRef.includes(":") ? chainRef.split(":")[0] : "";
|
|
280
|
-
if (validateWalletAddress(value))
|
|
281
|
-
|
|
282
|
-
if (namespace === "eip155")
|
|
283
|
-
return false;
|
|
289
|
+
if (validateWalletAddress(value)) return true;
|
|
290
|
+
if (namespace === "eip155") return false;
|
|
284
291
|
if (namespace === "solana") {
|
|
285
292
|
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(value);
|
|
286
293
|
}
|
|
@@ -342,16 +349,12 @@ async function resolveDID(params, options = {}) {
|
|
|
342
349
|
const endpointPath = options.endpoint || "/api/v1/profile/did/resolve";
|
|
343
350
|
const apiUrl = typeof options.apiUrl === "string" ? options.apiUrl.trim() : "";
|
|
344
351
|
const resolveEndpoint = (path) => {
|
|
345
|
-
if (!path || typeof path !== "string")
|
|
346
|
-
return null;
|
|
352
|
+
if (!path || typeof path !== "string") return null;
|
|
347
353
|
const trimmedPath = path.trim();
|
|
348
|
-
if (!trimmedPath)
|
|
349
|
-
|
|
350
|
-
if (/^https?:\/\//i.test(trimmedPath))
|
|
351
|
-
return trimmedPath;
|
|
354
|
+
if (!trimmedPath) return null;
|
|
355
|
+
if (/^https?:\/\//i.test(trimmedPath)) return trimmedPath;
|
|
352
356
|
if (trimmedPath.startsWith("/")) {
|
|
353
|
-
if (!apiUrl)
|
|
354
|
-
return trimmedPath;
|
|
357
|
+
if (!apiUrl) return trimmedPath;
|
|
355
358
|
try {
|
|
356
359
|
return new URL(trimmedPath, apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`).toString();
|
|
357
360
|
} catch {
|
|
@@ -359,8 +362,7 @@ async function resolveDID(params, options = {}) {
|
|
|
359
362
|
}
|
|
360
363
|
}
|
|
361
364
|
const base = apiUrl || NEUS_CONSTANTS.API_BASE_URL;
|
|
362
|
-
if (!base || typeof base !== "string")
|
|
363
|
-
return null;
|
|
365
|
+
if (!base || typeof base !== "string") return null;
|
|
364
366
|
try {
|
|
365
367
|
return new URL(trimmedPath, base.endsWith("/") ? base : `${base}/`).toString();
|
|
366
368
|
} catch {
|
|
@@ -400,8 +402,7 @@ async function resolveDID(params, options = {}) {
|
|
|
400
402
|
}
|
|
401
403
|
return { did, data: json?.data || null, raw: json };
|
|
402
404
|
} catch (error) {
|
|
403
|
-
if (error instanceof SDKError)
|
|
404
|
-
throw error;
|
|
405
|
+
if (error instanceof SDKError) throw error;
|
|
405
406
|
throw new SDKError(`DID resolution failed: ${error?.message || error}`, "DID_RESOLVE_FAILED");
|
|
406
407
|
}
|
|
407
408
|
}
|
|
@@ -409,16 +410,12 @@ async function standardizeVerificationRequest(params, options = {}) {
|
|
|
409
410
|
const endpointPath = options.endpoint || "/api/v1/verification/standardize";
|
|
410
411
|
const apiUrl = typeof options.apiUrl === "string" ? options.apiUrl.trim() : "";
|
|
411
412
|
const resolveEndpoint = (path) => {
|
|
412
|
-
if (!path || typeof path !== "string")
|
|
413
|
-
return null;
|
|
413
|
+
if (!path || typeof path !== "string") return null;
|
|
414
414
|
const trimmedPath = path.trim();
|
|
415
|
-
if (!trimmedPath)
|
|
416
|
-
|
|
417
|
-
if (/^https?:\/\//i.test(trimmedPath))
|
|
418
|
-
return trimmedPath;
|
|
415
|
+
if (!trimmedPath) return null;
|
|
416
|
+
if (/^https?:\/\//i.test(trimmedPath)) return trimmedPath;
|
|
419
417
|
if (trimmedPath.startsWith("/")) {
|
|
420
|
-
if (!apiUrl)
|
|
421
|
-
return trimmedPath;
|
|
418
|
+
if (!apiUrl) return trimmedPath;
|
|
422
419
|
try {
|
|
423
420
|
return new URL(trimmedPath, apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`).toString();
|
|
424
421
|
} catch {
|
|
@@ -426,8 +423,7 @@ async function standardizeVerificationRequest(params, options = {}) {
|
|
|
426
423
|
}
|
|
427
424
|
}
|
|
428
425
|
const base = apiUrl || NEUS_CONSTANTS.API_BASE_URL;
|
|
429
|
-
if (!base || typeof base !== "string")
|
|
430
|
-
return null;
|
|
426
|
+
if (!base || typeof base !== "string") return null;
|
|
431
427
|
try {
|
|
432
428
|
return new URL(trimmedPath, base.endsWith("/") ? base : `${base}/`).toString();
|
|
433
429
|
} catch {
|
|
@@ -458,8 +454,7 @@ async function standardizeVerificationRequest(params, options = {}) {
|
|
|
458
454
|
}
|
|
459
455
|
return json?.data || json;
|
|
460
456
|
} catch (error) {
|
|
461
|
-
if (error instanceof SDKError)
|
|
462
|
-
throw error;
|
|
457
|
+
if (error instanceof SDKError) throw error;
|
|
463
458
|
throw new SDKError(`Standardize request failed: ${error?.message || error}`, "STANDARDIZE_FAILED");
|
|
464
459
|
}
|
|
465
460
|
}
|
|
@@ -493,34 +488,27 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
|
493
488
|
const chainStr = typeof chain === "string" && chain.trim().length > 0 ? chain.trim() : "eip155";
|
|
494
489
|
const namespace = chainStr.includes(":") ? chainStr.split(":")[0] || "eip155" : "eip155";
|
|
495
490
|
const resolveAddress = async () => {
|
|
496
|
-
if (typeof walletAddress === "string" && walletAddress.trim().length > 0)
|
|
497
|
-
return walletAddress;
|
|
491
|
+
if (typeof walletAddress === "string" && walletAddress.trim().length > 0) return walletAddress;
|
|
498
492
|
if (namespace === "solana") {
|
|
499
493
|
if (resolvedProvider?.publicKey && typeof resolvedProvider.publicKey.toBase58 === "function") {
|
|
500
494
|
const pk = resolvedProvider.publicKey.toBase58();
|
|
501
|
-
if (typeof pk === "string" && pk)
|
|
502
|
-
return pk;
|
|
495
|
+
if (typeof pk === "string" && pk) return pk;
|
|
503
496
|
}
|
|
504
497
|
if (typeof resolvedProvider.getAddress === "function") {
|
|
505
498
|
const addr = await resolvedProvider.getAddress().catch(() => null);
|
|
506
|
-
if (typeof addr === "string" && addr)
|
|
507
|
-
return addr;
|
|
499
|
+
if (typeof addr === "string" && addr) return addr;
|
|
508
500
|
}
|
|
509
|
-
if (typeof resolvedProvider.address === "string" && resolvedProvider.address)
|
|
510
|
-
return resolvedProvider.address;
|
|
501
|
+
if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
|
|
511
502
|
return null;
|
|
512
503
|
}
|
|
513
|
-
if (typeof resolvedProvider.address === "string" && resolvedProvider.address)
|
|
514
|
-
|
|
515
|
-
if (typeof resolvedProvider.getAddress === "function")
|
|
516
|
-
return await resolvedProvider.getAddress();
|
|
504
|
+
if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
|
|
505
|
+
if (typeof resolvedProvider.getAddress === "function") return resolvedProvider.getAddress();
|
|
517
506
|
if (typeof resolvedProvider.request === "function") {
|
|
518
507
|
let accounts = await resolvedProvider.request({ method: "eth_accounts" }).catch(() => []);
|
|
519
508
|
if (!Array.isArray(accounts) || accounts.length === 0) {
|
|
520
509
|
accounts = await resolvedProvider.request({ method: "eth_requestAccounts" }).catch(() => []);
|
|
521
510
|
}
|
|
522
|
-
if (Array.isArray(accounts) && accounts[0])
|
|
523
|
-
return accounts[0];
|
|
511
|
+
if (Array.isArray(accounts) && accounts[0]) return accounts[0];
|
|
524
512
|
}
|
|
525
513
|
return null;
|
|
526
514
|
};
|
|
@@ -528,16 +516,11 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
|
528
516
|
if (typeof resolvedProvider.signMessage === "function") {
|
|
529
517
|
const encoded = typeof msg === "string" ? new TextEncoder().encode(msg) : msg;
|
|
530
518
|
const result = await resolvedProvider.signMessage(encoded);
|
|
531
|
-
if (typeof result === "string" && result)
|
|
532
|
-
|
|
533
|
-
if (result instanceof Uint8Array)
|
|
534
|
-
|
|
535
|
-
if (result
|
|
536
|
-
return encodeBase58Bytes(new Uint8Array(result));
|
|
537
|
-
if (ArrayBuffer.isView(result))
|
|
538
|
-
return encodeBase58Bytes(result);
|
|
539
|
-
if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result))
|
|
540
|
-
return encodeBase58Bytes(result);
|
|
519
|
+
if (typeof result === "string" && result) return result;
|
|
520
|
+
if (result instanceof Uint8Array) return encodeBase58Bytes(result);
|
|
521
|
+
if (result instanceof ArrayBuffer) return encodeBase58Bytes(new Uint8Array(result));
|
|
522
|
+
if (ArrayBuffer.isView(result)) return encodeBase58Bytes(result);
|
|
523
|
+
if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result)) return encodeBase58Bytes(result);
|
|
541
524
|
}
|
|
542
525
|
throw new SDKError("Non-EVM signing requires provider.signMessage", "SIGNER_UNAVAILABLE");
|
|
543
526
|
}
|
|
@@ -546,16 +529,14 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
|
546
529
|
let firstPersonalSignError = null;
|
|
547
530
|
try {
|
|
548
531
|
const sig = await resolvedProvider.request({ method: "personal_sign", params: [msg, address] });
|
|
549
|
-
if (typeof sig === "string" && sig)
|
|
550
|
-
return sig;
|
|
532
|
+
if (typeof sig === "string" && sig) return sig;
|
|
551
533
|
} catch (error) {
|
|
552
534
|
firstPersonalSignError = error;
|
|
553
535
|
}
|
|
554
536
|
let secondPersonalSignError = null;
|
|
555
537
|
try {
|
|
556
538
|
const sig = await resolvedProvider.request({ method: "personal_sign", params: [address, msg] });
|
|
557
|
-
if (typeof sig === "string" && sig)
|
|
558
|
-
return sig;
|
|
539
|
+
if (typeof sig === "string" && sig) return sig;
|
|
559
540
|
} catch (error) {
|
|
560
541
|
secondPersonalSignError = error;
|
|
561
542
|
const signatureErrorMessage = String(
|
|
@@ -566,16 +547,14 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
|
566
547
|
try {
|
|
567
548
|
const hexMsg = toHexUtf8(msg);
|
|
568
549
|
const sig = await resolvedProvider.request({ method: "personal_sign", params: [hexMsg, address] });
|
|
569
|
-
if (typeof sig === "string" && sig)
|
|
570
|
-
return sig;
|
|
550
|
+
if (typeof sig === "string" && sig) return sig;
|
|
571
551
|
} catch {
|
|
572
552
|
}
|
|
573
553
|
}
|
|
574
554
|
}
|
|
575
555
|
try {
|
|
576
556
|
const sig = await resolvedProvider.request({ method: "eth_sign", params: [address, msg] });
|
|
577
|
-
if (typeof sig === "string" && sig)
|
|
578
|
-
return sig;
|
|
557
|
+
if (typeof sig === "string" && sig) return sig;
|
|
579
558
|
} catch {
|
|
580
559
|
}
|
|
581
560
|
if (secondPersonalSignError || firstPersonalSignError) {
|
|
@@ -588,14 +567,12 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
|
|
|
588
567
|
}
|
|
589
568
|
if (typeof resolvedProvider.signMessage === "function") {
|
|
590
569
|
const result = await resolvedProvider.signMessage(msg);
|
|
591
|
-
if (typeof result === "string" && result)
|
|
592
|
-
return result;
|
|
570
|
+
if (typeof result === "string" && result) return result;
|
|
593
571
|
}
|
|
594
572
|
throw new SDKError("Unable to sign message with provided wallet/provider", "SIGNER_UNAVAILABLE");
|
|
595
573
|
}
|
|
596
574
|
function isTerminalStatus(status) {
|
|
597
|
-
if (!status || typeof status !== "string")
|
|
598
|
-
return false;
|
|
575
|
+
if (!status || typeof status !== "string") return false;
|
|
599
576
|
const successStates = [
|
|
600
577
|
"verified",
|
|
601
578
|
"verified_no_verifiers",
|
|
@@ -616,8 +593,7 @@ function isTerminalStatus(status) {
|
|
|
616
593
|
return successStates.includes(status) || failureStates.includes(status);
|
|
617
594
|
}
|
|
618
595
|
function isSuccessStatus(status) {
|
|
619
|
-
if (!status || typeof status !== "string")
|
|
620
|
-
return false;
|
|
596
|
+
if (!status || typeof status !== "string") return false;
|
|
621
597
|
const successStates = [
|
|
622
598
|
"verified",
|
|
623
599
|
"verified_no_verifiers",
|
|
@@ -628,8 +604,7 @@ function isSuccessStatus(status) {
|
|
|
628
604
|
return successStates.includes(status);
|
|
629
605
|
}
|
|
630
606
|
function isFailureStatus(status) {
|
|
631
|
-
if (!status || typeof status !== "string")
|
|
632
|
-
return false;
|
|
607
|
+
if (!status || typeof status !== "string") return false;
|
|
633
608
|
const failureStates = [
|
|
634
609
|
"rejected",
|
|
635
610
|
"rejected_verifier_failure",
|
|
@@ -780,23 +755,20 @@ function validateVerifierPayload(verifierId, data) {
|
|
|
780
755
|
const id = verifierId.replace(/@\d+$/, "");
|
|
781
756
|
if (id === "nft-ownership") {
|
|
782
757
|
["contractAddress", "tokenId", "chainId"].forEach((key) => {
|
|
783
|
-
if (!(key in data))
|
|
784
|
-
result.missing.push(key);
|
|
758
|
+
if (!(key in data)) result.missing.push(key);
|
|
785
759
|
});
|
|
786
760
|
if (!("ownerAddress" in data)) {
|
|
787
761
|
result.warnings.push("ownerAddress omitted (defaults to the signed walletAddress)");
|
|
788
762
|
}
|
|
789
763
|
} else if (id === "token-holding") {
|
|
790
764
|
["contractAddress", "minBalance", "chainId"].forEach((key) => {
|
|
791
|
-
if (!(key in data))
|
|
792
|
-
result.missing.push(key);
|
|
765
|
+
if (!(key in data)) result.missing.push(key);
|
|
793
766
|
});
|
|
794
767
|
if (!("ownerAddress" in data)) {
|
|
795
768
|
result.warnings.push("ownerAddress omitted (defaults to the signed walletAddress)");
|
|
796
769
|
}
|
|
797
770
|
} else if (id === "ownership-basic") {
|
|
798
|
-
if (!("owner" in data))
|
|
799
|
-
result.missing.push("owner");
|
|
771
|
+
if (!("owner" in data)) result.missing.push("owner");
|
|
800
772
|
const hasContent = typeof data.content === "string" && data.content.length > 0;
|
|
801
773
|
const hasContentHash = typeof data.contentHash === "string" && data.contentHash.length > 0;
|
|
802
774
|
const hasRefId = typeof data.reference?.id === "string" && data.reference.id.length > 0;
|
|
@@ -860,8 +832,7 @@ async function withRetry(fn, options = {}) {
|
|
|
860
832
|
return await fn();
|
|
861
833
|
} catch (error) {
|
|
862
834
|
lastError = error;
|
|
863
|
-
if (attempt === maxAttempts)
|
|
864
|
-
break;
|
|
835
|
+
if (attempt === maxAttempts) break;
|
|
865
836
|
const delayMs = Math.min(
|
|
866
837
|
baseDelay * Math.pow(backoffFactor, attempt - 1),
|
|
867
838
|
maxDelay
|
|
@@ -929,11 +900,72 @@ function validateSignatureComponents({ walletAddress, signature, signedTimestamp
|
|
|
929
900
|
}
|
|
930
901
|
return result;
|
|
931
902
|
}
|
|
932
|
-
|
|
903
|
+
function toAgentDelegationMaxSpend(humanAmount, decimals) {
|
|
904
|
+
if (humanAmount === void 0 || humanAmount === null) {
|
|
905
|
+
throw new ValidationError("humanAmount is required", "humanAmount", humanAmount);
|
|
906
|
+
}
|
|
907
|
+
const s0 = String(humanAmount).trim();
|
|
908
|
+
if (!s0) {
|
|
909
|
+
throw new ValidationError("humanAmount must be non-empty", "humanAmount", humanAmount);
|
|
910
|
+
}
|
|
911
|
+
if (s0.startsWith("-") || s0.startsWith("+")) {
|
|
912
|
+
throw new ValidationError("humanAmount must be non-negative", "humanAmount", humanAmount);
|
|
913
|
+
}
|
|
914
|
+
const d = Number(decimals);
|
|
915
|
+
if (!Number.isInteger(d) || d < 0 || d > 78) {
|
|
916
|
+
throw new ValidationError("decimalPlaces must be an integer from 0 to 78", "decimals", decimals);
|
|
917
|
+
}
|
|
918
|
+
if (!/^(?:\d+\.?\d*|\.\d+)$/.test(s0)) {
|
|
919
|
+
throw new ValidationError(
|
|
920
|
+
'humanAmount must be a decimal string (e.g. "100" or "100.50")',
|
|
921
|
+
"humanAmount",
|
|
922
|
+
humanAmount
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
const dot = s0.indexOf(".");
|
|
926
|
+
const intPart = dot === -1 ? s0 : s0.slice(0, dot);
|
|
927
|
+
const fracRaw = dot === -1 ? "" : s0.slice(dot + 1);
|
|
928
|
+
const intNormalized = intPart === "" ? "0" : (() => {
|
|
929
|
+
const s = intPart.replace(/^0+/, "");
|
|
930
|
+
return s === "" ? "0" : s;
|
|
931
|
+
})();
|
|
932
|
+
if (!/^\d+$/.test(intNormalized)) {
|
|
933
|
+
throw new ValidationError("humanAmount has an invalid integer part", "humanAmount", humanAmount);
|
|
934
|
+
}
|
|
935
|
+
if (fracRaw && !/^\d*$/.test(fracRaw)) {
|
|
936
|
+
throw new ValidationError("humanAmount has an invalid fractional part", "humanAmount", humanAmount);
|
|
937
|
+
}
|
|
938
|
+
const fracPadded = `${fracRaw}${"0".repeat(d)}`.slice(0, d);
|
|
939
|
+
const base = BigInt(10) ** BigInt(d);
|
|
940
|
+
const value = BigInt(intNormalized) * base + BigInt(fracPadded || "0");
|
|
941
|
+
const out = value.toString();
|
|
942
|
+
if (out.length > 78) {
|
|
943
|
+
throw new ValidationError("maxSpend exceeds 78-digit limit after conversion", "humanAmount", humanAmount);
|
|
944
|
+
}
|
|
945
|
+
return out;
|
|
946
|
+
}
|
|
947
|
+
function getHostedCheckoutUrl(opts = {}) {
|
|
948
|
+
const base = typeof opts.baseUrl === "string" && opts.baseUrl.trim() ? opts.baseUrl.replace(/\/+$/, "") : DEFAULT_HOSTED_VERIFY_URL;
|
|
949
|
+
const params = new URLSearchParams();
|
|
950
|
+
if (opts.gateId) params.set("gateId", String(opts.gateId));
|
|
951
|
+
if (opts.returnUrl) params.set("returnUrl", String(opts.returnUrl));
|
|
952
|
+
if (Array.isArray(opts.verifiers) && opts.verifiers.length > 0) {
|
|
953
|
+
params.set("verifiers", opts.verifiers.filter(Boolean).join(","));
|
|
954
|
+
}
|
|
955
|
+
if (opts.preset) params.set("preset", String(opts.preset));
|
|
956
|
+
if (opts.mode) params.set("mode", String(opts.mode));
|
|
957
|
+
if (opts.intent) params.set("intent", String(opts.intent));
|
|
958
|
+
if (opts.origin) params.set("origin", String(opts.origin));
|
|
959
|
+
if (opts.oauthProvider) params.set("oauthProvider", String(opts.oauthProvider));
|
|
960
|
+
const qs = params.toString();
|
|
961
|
+
return qs ? `${base}?${qs}` : base;
|
|
962
|
+
}
|
|
963
|
+
var PORTABLE_PROOF_SIGNER_HEADER, BASE58_ALPHABET, StatusPoller, NEUS_CONSTANTS, DEFAULT_HOSTED_VERIFY_URL;
|
|
933
964
|
var init_utils = __esm({
|
|
934
965
|
"utils.js"() {
|
|
935
966
|
"use strict";
|
|
936
967
|
init_errors();
|
|
968
|
+
PORTABLE_PROOF_SIGNER_HEADER = "Portable Proof Verification Request";
|
|
937
969
|
BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
938
970
|
StatusPoller = class {
|
|
939
971
|
constructor(client, qHash, options = {}) {
|
|
@@ -957,7 +989,7 @@ var init_utils = __esm({
|
|
|
957
989
|
const pollAttempt = async () => {
|
|
958
990
|
try {
|
|
959
991
|
this.attempt++;
|
|
960
|
-
const response = await this.client.
|
|
992
|
+
const response = await this.client.getProof(this.qHash);
|
|
961
993
|
if (isTerminalStatus(response.status)) {
|
|
962
994
|
resolve(response);
|
|
963
995
|
return;
|
|
@@ -1002,7 +1034,7 @@ var init_utils = __esm({
|
|
|
1002
1034
|
}
|
|
1003
1035
|
};
|
|
1004
1036
|
NEUS_CONSTANTS = {
|
|
1005
|
-
|
|
1037
|
+
/** Default EVM chain id for NEUS protocol signing context (`HUB_CHAIN_ID` name kept for compatibility). */
|
|
1006
1038
|
HUB_CHAIN_ID: 84532,
|
|
1007
1039
|
// Supported target chains for cross-chain propagation
|
|
1008
1040
|
TESTNET_CHAINS: [
|
|
@@ -1030,6 +1062,7 @@ var init_utils = __esm({
|
|
|
1030
1062
|
"token-holding"
|
|
1031
1063
|
]
|
|
1032
1064
|
};
|
|
1065
|
+
DEFAULT_HOSTED_VERIFY_URL = "https://neus.network/verify";
|
|
1033
1066
|
}
|
|
1034
1067
|
});
|
|
1035
1068
|
|
|
@@ -1037,36 +1070,37 @@ var init_utils = __esm({
|
|
|
1037
1070
|
var client_exports = {};
|
|
1038
1071
|
__export(client_exports, {
|
|
1039
1072
|
NeusClient: () => NeusClient,
|
|
1073
|
+
PORTABLE_PROOF_SIGNER_HEADER: () => PORTABLE_PROOF_SIGNER_HEADER,
|
|
1040
1074
|
constructVerificationMessage: () => constructVerificationMessage
|
|
1041
1075
|
});
|
|
1042
|
-
|
|
1076
|
+
function normalizeWalletLinkRelationshipType(value) {
|
|
1077
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
1078
|
+
return WALLET_LINK_RELATIONSHIP_TYPES.has(normalized) ? normalized : "linked";
|
|
1079
|
+
}
|
|
1080
|
+
var FALLBACK_PUBLIC_VERIFIER_CATALOG, EVM_ADDRESS_RE, WALLET_LINK_RELATIONSHIP_TYPES, validateVerifierData, NeusClient;
|
|
1043
1081
|
var init_client = __esm({
|
|
1044
1082
|
"client.js"() {
|
|
1045
1083
|
"use strict";
|
|
1046
1084
|
init_errors();
|
|
1047
1085
|
init_utils();
|
|
1048
|
-
|
|
1049
|
-
"ownership-basic",
|
|
1050
|
-
"ownership-pseudonym",
|
|
1051
|
-
"ownership-dns-txt",
|
|
1052
|
-
"ownership-social",
|
|
1053
|
-
"ownership-org-oauth",
|
|
1054
|
-
"contract-ownership",
|
|
1055
|
-
"nft-ownership",
|
|
1056
|
-
"token-holding",
|
|
1057
|
-
"wallet-link",
|
|
1058
|
-
"wallet-risk",
|
|
1059
|
-
"proof-of-human",
|
|
1060
|
-
"agent-identity",
|
|
1061
|
-
"agent-delegation",
|
|
1062
|
-
"ai-content-moderation"
|
|
1063
|
-
|
|
1064
|
-
INTERACTIVE_VERIFIERS = /* @__PURE__ */ new Set([
|
|
1065
|
-
"ownership-social",
|
|
1066
|
-
"ownership-org-oauth",
|
|
1067
|
-
"proof-of-human"
|
|
1068
|
-
]);
|
|
1086
|
+
FALLBACK_PUBLIC_VERIFIER_CATALOG = {
|
|
1087
|
+
"ownership-basic": { supportsDirectApi: true },
|
|
1088
|
+
"ownership-pseudonym": { supportsDirectApi: true },
|
|
1089
|
+
"ownership-dns-txt": { supportsDirectApi: true },
|
|
1090
|
+
"ownership-social": { supportsDirectApi: false },
|
|
1091
|
+
"ownership-org-oauth": { supportsDirectApi: false },
|
|
1092
|
+
"contract-ownership": { supportsDirectApi: true },
|
|
1093
|
+
"nft-ownership": { supportsDirectApi: true },
|
|
1094
|
+
"token-holding": { supportsDirectApi: true },
|
|
1095
|
+
"wallet-link": { supportsDirectApi: true },
|
|
1096
|
+
"wallet-risk": { supportsDirectApi: true },
|
|
1097
|
+
"proof-of-human": { supportsDirectApi: false },
|
|
1098
|
+
"agent-identity": { supportsDirectApi: true },
|
|
1099
|
+
"agent-delegation": { supportsDirectApi: true },
|
|
1100
|
+
"ai-content-moderation": { supportsDirectApi: true }
|
|
1101
|
+
};
|
|
1069
1102
|
EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
1103
|
+
WALLET_LINK_RELATIONSHIP_TYPES = /* @__PURE__ */ new Set(["primary", "personal", "org", "affiliate", "agent", "linked"]);
|
|
1070
1104
|
validateVerifierData = (verifierId, data) => {
|
|
1071
1105
|
if (!data || typeof data !== "object") {
|
|
1072
1106
|
return { valid: false, error: "Data object is required" };
|
|
@@ -1284,7 +1318,10 @@ var init_client = __esm({
|
|
|
1284
1318
|
const maxBytes = 50 * 1024;
|
|
1285
1319
|
const bytes = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(data.content).length : String(data.content).length;
|
|
1286
1320
|
if (bytes > maxBytes) {
|
|
1287
|
-
return {
|
|
1321
|
+
return {
|
|
1322
|
+
valid: false,
|
|
1323
|
+
error: `content exceeds ${maxBytes} bytes limit for ai-content-moderation verifier (text)`
|
|
1324
|
+
};
|
|
1288
1325
|
}
|
|
1289
1326
|
} catch {
|
|
1290
1327
|
}
|
|
@@ -1343,20 +1380,15 @@ var init_client = __esm({
|
|
|
1343
1380
|
if (typeof this.config.appId === "string" && this.config.appId.trim().length > 0) {
|
|
1344
1381
|
this.defaultHeaders["X-Neus-App"] = this.config.appId.trim();
|
|
1345
1382
|
}
|
|
1346
|
-
if (typeof this.config.sponsorGrant === "string" && this.config.sponsorGrant.trim().length > 0) {
|
|
1347
|
-
this.defaultHeaders["X-Sponsor-Grant"] = this.config.sponsorGrant.trim();
|
|
1348
|
-
}
|
|
1349
1383
|
if (typeof this.config.paymentSignature === "string" && this.config.paymentSignature.trim().length > 0) {
|
|
1350
1384
|
this.defaultHeaders["PAYMENT-SIGNATURE"] = this.config.paymentSignature.trim();
|
|
1351
1385
|
}
|
|
1352
1386
|
if (this.config.extraHeaders && typeof this.config.extraHeaders === "object") {
|
|
1353
1387
|
for (const [k, v] of Object.entries(this.config.extraHeaders)) {
|
|
1354
|
-
if (!k || v === void 0 || v === null)
|
|
1355
|
-
continue;
|
|
1388
|
+
if (!k || v === void 0 || v === null) continue;
|
|
1356
1389
|
const key = String(k).trim();
|
|
1357
1390
|
const value = String(v).trim();
|
|
1358
|
-
if (!key || !value)
|
|
1359
|
-
continue;
|
|
1391
|
+
if (!key || !value) continue;
|
|
1360
1392
|
this.defaultHeaders[key] = value;
|
|
1361
1393
|
}
|
|
1362
1394
|
}
|
|
@@ -1369,14 +1401,12 @@ var init_client = __esm({
|
|
|
1369
1401
|
}
|
|
1370
1402
|
_getHubChainId() {
|
|
1371
1403
|
const configured = Number(this.config?.hubChainId);
|
|
1372
|
-
if (Number.isFinite(configured) && configured > 0)
|
|
1373
|
-
return Math.floor(configured);
|
|
1404
|
+
if (Number.isFinite(configured) && configured > 0) return Math.floor(configured);
|
|
1374
1405
|
return NEUS_CONSTANTS.HUB_CHAIN_ID;
|
|
1375
1406
|
}
|
|
1376
1407
|
_normalizeIdentity(value) {
|
|
1377
1408
|
let raw = String(value || "").trim();
|
|
1378
|
-
if (!raw)
|
|
1379
|
-
return "";
|
|
1409
|
+
if (!raw) return "";
|
|
1380
1410
|
const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
|
|
1381
1411
|
if (didMatch && didMatch[3]) {
|
|
1382
1412
|
raw = String(didMatch[3]).trim();
|
|
@@ -1384,8 +1414,7 @@ var init_client = __esm({
|
|
|
1384
1414
|
return EVM_ADDRESS_RE.test(raw) ? raw.toLowerCase() : raw;
|
|
1385
1415
|
}
|
|
1386
1416
|
_inferChainForAddress(address, explicitChain) {
|
|
1387
|
-
if (typeof explicitChain === "string" && explicitChain.includes(":"))
|
|
1388
|
-
return explicitChain.trim();
|
|
1417
|
+
if (typeof explicitChain === "string" && explicitChain.includes(":")) return explicitChain.trim();
|
|
1389
1418
|
const raw = String(address || "").trim();
|
|
1390
1419
|
const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
|
|
1391
1420
|
if (didMatch && didMatch[1] && didMatch[2]) {
|
|
@@ -1424,8 +1453,7 @@ var init_client = __esm({
|
|
|
1424
1453
|
throw new ConfigurationError("Invalid wallet provider");
|
|
1425
1454
|
}
|
|
1426
1455
|
_getDefaultBrowserWallet() {
|
|
1427
|
-
if (typeof window === "undefined")
|
|
1428
|
-
return null;
|
|
1456
|
+
if (typeof window === "undefined") return null;
|
|
1429
1457
|
return window.ethereum || window.solana || window.phantom && window.phantom.solana || null;
|
|
1430
1458
|
}
|
|
1431
1459
|
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
@@ -1483,80 +1511,134 @@ var init_client = __esm({
|
|
|
1483
1511
|
signatureMethod: params.signatureMethod
|
|
1484
1512
|
});
|
|
1485
1513
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1514
|
+
async createWalletLinkData(params = {}) {
|
|
1515
|
+
const normalizedPrimary = this._normalizeIdentity(params.primaryWalletAddress);
|
|
1516
|
+
const normalizedSecondary = this._normalizeIdentity(params.secondaryWalletAddress);
|
|
1517
|
+
if (!EVM_ADDRESS_RE.test(normalizedPrimary)) {
|
|
1518
|
+
throw new ValidationError("wallet-link requires a valid primaryWalletAddress");
|
|
1519
|
+
}
|
|
1520
|
+
if (!EVM_ADDRESS_RE.test(normalizedSecondary)) {
|
|
1521
|
+
throw new ValidationError("wallet-link requires a valid secondaryWalletAddress");
|
|
1522
|
+
}
|
|
1523
|
+
if (normalizedPrimary === normalizedSecondary) {
|
|
1524
|
+
throw new ValidationError("wallet-link secondaryWalletAddress must differ from primaryWalletAddress");
|
|
1525
|
+
}
|
|
1526
|
+
const providerWallet = params.wallet || this._getDefaultBrowserWallet();
|
|
1527
|
+
const { signerWalletAddress, provider } = await this._resolveWalletSigner(providerWallet);
|
|
1528
|
+
const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
|
|
1529
|
+
if (!EVM_ADDRESS_RE.test(normalizedSigner)) {
|
|
1530
|
+
throw new ValidationError("wallet-link requires an EVM wallet/provider for the secondary wallet");
|
|
1531
|
+
}
|
|
1532
|
+
if (normalizedSigner !== normalizedSecondary) {
|
|
1533
|
+
throw new ValidationError("wallet-link wallet/provider must be connected to secondaryWalletAddress");
|
|
1534
|
+
}
|
|
1535
|
+
const resolvedChain = (() => {
|
|
1536
|
+
const raw = String(params.chain || "").trim();
|
|
1537
|
+
if (!raw) return `eip155:${this._getHubChainId()}`;
|
|
1538
|
+
if (!/^eip155:\d+$/.test(raw)) {
|
|
1539
|
+
throw new ValidationError("wallet-link requires chain in the form eip155:<chainId>");
|
|
1540
|
+
}
|
|
1541
|
+
return raw;
|
|
1542
|
+
})();
|
|
1543
|
+
const signedTimestamp = Number.isFinite(Number(params.signedTimestamp)) && Number(params.signedTimestamp) > 0 ? Number(params.signedTimestamp) : Date.now();
|
|
1544
|
+
const linkData = {
|
|
1545
|
+
primaryAccountId: `${resolvedChain}:${normalizedPrimary}`,
|
|
1546
|
+
secondaryAccountId: `${resolvedChain}:${normalizedSecondary}`,
|
|
1547
|
+
primaryWalletAddress: normalizedPrimary,
|
|
1548
|
+
secondaryWalletAddress: normalizedSecondary
|
|
1549
|
+
};
|
|
1550
|
+
const message = constructVerificationMessage({
|
|
1551
|
+
walletAddress: normalizedSecondary,
|
|
1552
|
+
signedTimestamp,
|
|
1553
|
+
data: linkData,
|
|
1554
|
+
verifierIds: ["wallet-link"],
|
|
1555
|
+
chain: resolvedChain
|
|
1556
|
+
});
|
|
1557
|
+
let signature;
|
|
1558
|
+
try {
|
|
1559
|
+
signature = await signMessage({
|
|
1560
|
+
provider,
|
|
1561
|
+
message,
|
|
1562
|
+
walletAddress: signerWalletAddress
|
|
1563
|
+
});
|
|
1564
|
+
} catch (error) {
|
|
1565
|
+
if (error?.code === 4001) {
|
|
1566
|
+
throw new ValidationError("User rejected wallet-link signature request");
|
|
1567
|
+
}
|
|
1568
|
+
throw new ValidationError(`Failed to sign wallet-link message: ${error?.message || String(error)}`);
|
|
1569
|
+
}
|
|
1570
|
+
const label = String(params.label || "").trim().slice(0, 64);
|
|
1571
|
+
return {
|
|
1572
|
+
primaryWalletAddress: normalizedPrimary,
|
|
1573
|
+
secondaryWalletAddress: normalizedSecondary,
|
|
1574
|
+
signature,
|
|
1575
|
+
chain: resolvedChain,
|
|
1576
|
+
signatureMethod: "eip191",
|
|
1577
|
+
signedTimestamp,
|
|
1578
|
+
relationshipType: normalizeWalletLinkRelationshipType(params.relationshipType),
|
|
1579
|
+
...label ? { label } : {}
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1489
1582
|
/**
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
1494
|
-
*
|
|
1495
|
-
*
|
|
1583
|
+
* Create a verification proof.
|
|
1584
|
+
*
|
|
1585
|
+
* Supports two paths:
|
|
1586
|
+
* - **Auto:** Supply `verifier`, `content`, and/or `data` with an optional
|
|
1587
|
+
* `wallet` provider. The SDK performs signing in the client.
|
|
1588
|
+
* - **Manual:** Supply pre-signed `verifierIds`, `data`, `walletAddress`,
|
|
1589
|
+
* `signature`, and `signedTimestamp`.
|
|
1590
|
+
*
|
|
1496
1591
|
* @param {Object} params - Verification parameters
|
|
1592
|
+
* @param {string} [params.verifier] - Verifier ID (auto path, e.g. 'ownership-basic')
|
|
1593
|
+
* @param {string} [params.content] - Content to verify (auto path)
|
|
1594
|
+
* @param {Object} [params.data] - Structured verification data
|
|
1595
|
+
* @param {Object} [params.wallet] - Wallet provider (auto path)
|
|
1596
|
+
* @param {Object} [params.options] - Additional options
|
|
1497
1597
|
* @param {Array<string>} [params.verifierIds] - Array of verifier IDs (manual path)
|
|
1498
|
-
* @param {Object} [params.data] - Verification data object (manual path)
|
|
1499
1598
|
* @param {string} [params.walletAddress] - Wallet address that signed the request (manual path)
|
|
1500
1599
|
* @param {string} [params.signature] - EIP-191 signature (manual path)
|
|
1501
1600
|
* @param {number} [params.signedTimestamp] - Unix timestamp when signature was created (manual path)
|
|
1502
|
-
* @param {number} [params.chainId] -
|
|
1503
|
-
* @
|
|
1504
|
-
*
|
|
1505
|
-
* @param {string} [params.content] - Content/description (auto path)
|
|
1506
|
-
* @param {Object} [params.wallet] - Optional injected wallet/provider (auto path)
|
|
1507
|
-
* @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
|
|
1508
|
-
*
|
|
1601
|
+
* @param {number} [params.chainId] - EVM signing-context hint; when omitted, resolved to the NEUS protocol primary chain for signing
|
|
1602
|
+
* @returns {Promise<Object>} Verification result with proofId
|
|
1603
|
+
*
|
|
1509
1604
|
* @example
|
|
1605
|
+
* // Auto path
|
|
1606
|
+
* const proof = await client.verify({
|
|
1607
|
+
* verifier: 'ownership-basic',
|
|
1608
|
+
* content: 'Hello World',
|
|
1609
|
+
* wallet: window.ethereum
|
|
1610
|
+
* });
|
|
1611
|
+
*
|
|
1612
|
+
* @example
|
|
1613
|
+
* // Manual path
|
|
1510
1614
|
* const proof = await client.verify({
|
|
1511
1615
|
* verifierIds: ['ownership-basic'],
|
|
1512
|
-
* data: {
|
|
1513
|
-
* content: "My content",
|
|
1514
|
-
* owner: walletAddress, // or ownerAddress for nft-ownership/token-holding
|
|
1515
|
-
* reference: { type: 'other', id: 'my-unique-identifier' }
|
|
1516
|
-
* },
|
|
1616
|
+
* data: { content: "My content", owner: walletAddress },
|
|
1517
1617
|
* walletAddress: '0x...',
|
|
1518
1618
|
* signature: '0x...',
|
|
1519
1619
|
* signedTimestamp: Date.now(),
|
|
1520
1620
|
* options: { targetChains: [421614, 11155111] }
|
|
1521
1621
|
* });
|
|
1522
1622
|
*/
|
|
1523
|
-
/**
|
|
1524
|
-
* Create a verification proof
|
|
1525
|
-
*
|
|
1526
|
-
* @param {Object} params - Verification parameters
|
|
1527
|
-
* @param {string} [params.verifier] - Verifier ID (e.g., 'ownership-basic')
|
|
1528
|
-
* @param {string} [params.content] - Content to verify
|
|
1529
|
-
* @param {Object} [params.data] - Structured verification data
|
|
1530
|
-
* @param {Object} [params.wallet] - Wallet provider
|
|
1531
|
-
* @param {Object} [params.options] - Additional options
|
|
1532
|
-
* @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
|
|
1533
|
-
*
|
|
1534
|
-
* @example
|
|
1535
|
-
* // Simple ownership proof
|
|
1536
|
-
* const proof = await client.verify({
|
|
1537
|
-
* verifier: 'ownership-basic',
|
|
1538
|
-
* content: 'Hello World',
|
|
1539
|
-
* wallet: window.ethereum
|
|
1540
|
-
* });
|
|
1541
|
-
*/
|
|
1542
1623
|
async verify(params) {
|
|
1543
1624
|
if ((!params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
|
|
1544
1625
|
const { content, verifier = "ownership-basic", data: data2 = null, wallet = null, options: options2 = {} } = params;
|
|
1545
1626
|
if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
|
|
1546
1627
|
throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
|
|
1547
1628
|
}
|
|
1548
|
-
let
|
|
1629
|
+
let verifierCatalog = FALLBACK_PUBLIC_VERIFIER_CATALOG;
|
|
1549
1630
|
try {
|
|
1550
|
-
const discovered = await this.
|
|
1551
|
-
if (
|
|
1552
|
-
|
|
1631
|
+
const discovered = await this.getVerifierCatalog();
|
|
1632
|
+
if (discovered && discovered.metadata && Object.keys(discovered.metadata).length > 0) {
|
|
1633
|
+
verifierCatalog = discovered.metadata;
|
|
1553
1634
|
}
|
|
1554
1635
|
} catch {
|
|
1555
1636
|
}
|
|
1637
|
+
const validVerifiers = Object.keys(verifierCatalog);
|
|
1556
1638
|
if (!validVerifiers.includes(verifier)) {
|
|
1557
1639
|
throw new ValidationError(`Invalid verifier '${verifier}'. Must be one of: ${validVerifiers.join(", ")}.`);
|
|
1558
1640
|
}
|
|
1559
|
-
if (
|
|
1641
|
+
if (verifierCatalog?.[verifier]?.supportsDirectApi === false) {
|
|
1560
1642
|
const hostedCheckoutUrl = options2?.hostedCheckoutUrl || "https://neus.network/verify";
|
|
1561
1643
|
throw new ValidationError(
|
|
1562
1644
|
`${verifier} requires hosted interactive checkout. Use VerifyGate or redirect to ${hostedCheckoutUrl}.`
|
|
@@ -1697,7 +1779,10 @@ var init_client = __esm({
|
|
|
1697
1779
|
...data2?.agentLabel && { agentLabel: data2.agentLabel },
|
|
1698
1780
|
...data2?.agentType && { agentType: data2.agentType },
|
|
1699
1781
|
...data2?.description && { description: data2.description },
|
|
1700
|
-
...data2?.capabilities && { capabilities: data2.capabilities }
|
|
1782
|
+
...data2?.capabilities && { capabilities: data2.capabilities },
|
|
1783
|
+
...data2?.instructions && { instructions: data2.instructions },
|
|
1784
|
+
...data2?.skills && { skills: data2.skills },
|
|
1785
|
+
...data2?.services && { services: data2.services }
|
|
1701
1786
|
};
|
|
1702
1787
|
} else if (verifier === "agent-delegation") {
|
|
1703
1788
|
if (!data2?.agentWallet) {
|
|
@@ -1710,7 +1795,11 @@ var init_client = __esm({
|
|
|
1710
1795
|
...data2?.scope && { scope: data2.scope },
|
|
1711
1796
|
...data2?.permissions && { permissions: data2.permissions },
|
|
1712
1797
|
...data2?.maxSpend && { maxSpend: data2.maxSpend },
|
|
1713
|
-
...data2?.
|
|
1798
|
+
...data2?.allowedPaymentTypes && { allowedPaymentTypes: data2.allowedPaymentTypes },
|
|
1799
|
+
...data2?.receiptDisclosure && { receiptDisclosure: data2.receiptDisclosure },
|
|
1800
|
+
...data2?.expiresAt && { expiresAt: data2.expiresAt },
|
|
1801
|
+
...data2?.instructions && { instructions: data2.instructions },
|
|
1802
|
+
...data2?.skills && { skills: data2.skills }
|
|
1714
1803
|
};
|
|
1715
1804
|
} else if (verifier === "ai-content-moderation") {
|
|
1716
1805
|
if (!data2?.content) {
|
|
@@ -1770,31 +1859,24 @@ var init_client = __esm({
|
|
|
1770
1859
|
const enc = new TextEncoder();
|
|
1771
1860
|
const bytes = enc.encode(s);
|
|
1772
1861
|
let hex = "0x";
|
|
1773
|
-
for (let i = 0; i < bytes.length; i++)
|
|
1774
|
-
hex += bytes[i].toString(16).padStart(2, "0");
|
|
1862
|
+
for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
|
|
1775
1863
|
return hex;
|
|
1776
1864
|
} catch {
|
|
1777
1865
|
let hex = "0x";
|
|
1778
|
-
for (let i = 0; i < s.length; i++)
|
|
1779
|
-
hex += s.charCodeAt(i).toString(16).padStart(2, "0");
|
|
1866
|
+
for (let i = 0; i < s.length; i++) hex += s.charCodeAt(i).toString(16).padStart(2, "0");
|
|
1780
1867
|
return hex;
|
|
1781
1868
|
}
|
|
1782
1869
|
};
|
|
1783
1870
|
const isFarcasterWallet = (() => {
|
|
1784
|
-
if (typeof window === "undefined")
|
|
1785
|
-
return false;
|
|
1871
|
+
if (typeof window === "undefined") return false;
|
|
1786
1872
|
try {
|
|
1787
1873
|
const w = window;
|
|
1788
1874
|
const fc = w.farcaster;
|
|
1789
|
-
if (!fc || !fc.context)
|
|
1790
|
-
return false;
|
|
1875
|
+
if (!fc || !fc.context) return false;
|
|
1791
1876
|
const fcProvider = fc.provider || fc.walletProvider || fc.context && fc.context.walletProvider;
|
|
1792
|
-
if (fcProvider === provider)
|
|
1793
|
-
|
|
1794
|
-
if (w.
|
|
1795
|
-
return true;
|
|
1796
|
-
if (w.ethereum === provider && fc && fc.context)
|
|
1797
|
-
return true;
|
|
1877
|
+
if (fcProvider === provider) return true;
|
|
1878
|
+
if (w.mini && w.mini.wallet === provider && fc && fc.context) return true;
|
|
1879
|
+
if (w.ethereum === provider && fc && fc.context) return true;
|
|
1798
1880
|
} catch {
|
|
1799
1881
|
}
|
|
1800
1882
|
return false;
|
|
@@ -1813,7 +1895,8 @@ var init_client = __esm({
|
|
|
1813
1895
|
const msg = String(e && (e.message || e.reason) || e || "").toLowerCase();
|
|
1814
1896
|
const errCode = e && (e.code || e.error && e.error.code) || null;
|
|
1815
1897
|
const needsHex = /byte|bytes|invalid byte sequence|encoding|non-hex/i.test(msg);
|
|
1816
|
-
const
|
|
1898
|
+
const unsupportedRe = /method.*not.*supported|unsupported|not implemented|method not found|unknown method|does not support/i;
|
|
1899
|
+
const methodUnsupported = unsupportedRe.test(msg) || errCode === -32601 || errCode === 4200 || msg.includes("personal_sign") && msg.includes("not") || msg.includes("request method") && msg.includes("not supported");
|
|
1817
1900
|
if (methodUnsupported) {
|
|
1818
1901
|
this._log("personal_sign not supported; attempting eth_sign fallback");
|
|
1819
1902
|
try {
|
|
@@ -1822,28 +1905,23 @@ var init_client = __esm({
|
|
|
1822
1905
|
const prefix = `Ethereum Signed Message:
|
|
1823
1906
|
${bytes.length}`;
|
|
1824
1907
|
const full = new Uint8Array(prefix.length + bytes.length);
|
|
1825
|
-
for (let i = 0; i < prefix.length; i++)
|
|
1826
|
-
full[i] = prefix.charCodeAt(i);
|
|
1908
|
+
for (let i = 0; i < prefix.length; i++) full[i] = prefix.charCodeAt(i);
|
|
1827
1909
|
full.set(bytes, prefix.length);
|
|
1828
1910
|
let payloadHex = "0x";
|
|
1829
|
-
for (let i = 0; i < full.length; i++)
|
|
1830
|
-
payloadHex += full[i].toString(16).padStart(2, "0");
|
|
1911
|
+
for (let i = 0; i < full.length; i++) payloadHex += full[i].toString(16).padStart(2, "0");
|
|
1831
1912
|
try {
|
|
1832
|
-
if (typeof window !== "undefined")
|
|
1833
|
-
window.__NEUS_ALLOW_ETH_SIGN__ = true;
|
|
1913
|
+
if (typeof window !== "undefined") window.__NEUS_ALLOW_ETH_SIGN__ = true;
|
|
1834
1914
|
} catch {
|
|
1835
1915
|
}
|
|
1836
1916
|
signature2 = await provider.request({ method: "eth_sign", params: [walletAddress2, payloadHex], neusAllowEthSign: true });
|
|
1837
1917
|
try {
|
|
1838
|
-
if (typeof window !== "undefined")
|
|
1839
|
-
delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
1918
|
+
if (typeof window !== "undefined") delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
1840
1919
|
} catch {
|
|
1841
1920
|
}
|
|
1842
1921
|
} catch (fallbackErr) {
|
|
1843
1922
|
this._log("eth_sign fallback failed", { message: fallbackErr?.message || String(fallbackErr) });
|
|
1844
1923
|
try {
|
|
1845
|
-
if (typeof window !== "undefined")
|
|
1846
|
-
delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
1924
|
+
if (typeof window !== "undefined") delete window.__NEUS_ALLOW_ETH_SIGN__;
|
|
1847
1925
|
} catch {
|
|
1848
1926
|
}
|
|
1849
1927
|
throw e;
|
|
@@ -1885,8 +1963,7 @@ ${bytes.length}`;
|
|
|
1885
1963
|
} = params;
|
|
1886
1964
|
const resolvedChainId = chainId || (chain ? null : NEUS_CONSTANTS.HUB_CHAIN_ID);
|
|
1887
1965
|
const normalizeVerifierId = (id) => {
|
|
1888
|
-
if (typeof id !== "string")
|
|
1889
|
-
return id;
|
|
1966
|
+
if (typeof id !== "string") return id;
|
|
1890
1967
|
const match = id.match(/^(.*)@\d+$/);
|
|
1891
1968
|
return match ? match[1] : id;
|
|
1892
1969
|
};
|
|
@@ -1921,10 +1998,9 @@ ${bytes.length}`;
|
|
|
1921
1998
|
// Privacy and storage options (defaults)
|
|
1922
1999
|
privacyLevel: options?.privacyLevel || "private",
|
|
1923
2000
|
publicDisplay: options?.publicDisplay || false,
|
|
1924
|
-
storeOriginalContent: options?.storeOriginalContent
|
|
2001
|
+
storeOriginalContent: typeof options?.storeOriginalContent === "boolean" ? options.storeOriginalContent : true
|
|
1925
2002
|
};
|
|
1926
|
-
if (typeof options?.enableIpfs === "boolean")
|
|
1927
|
-
optionsPayload.enableIpfs = options.enableIpfs;
|
|
2003
|
+
if (typeof options?.enableIpfs === "boolean") optionsPayload.enableIpfs = options.enableIpfs;
|
|
1928
2004
|
const requestData = {
|
|
1929
2005
|
verifierIds: normalizedVerifierIds,
|
|
1930
2006
|
data,
|
|
@@ -1942,41 +2018,37 @@ ${bytes.length}`;
|
|
|
1942
2018
|
}
|
|
1943
2019
|
return this._formatResponse(response);
|
|
1944
2020
|
}
|
|
1945
|
-
// ============================================================================
|
|
1946
|
-
// STATUS AND UTILITY METHODS
|
|
1947
|
-
// ============================================================================
|
|
1948
2021
|
/**
|
|
1949
|
-
* Get
|
|
2022
|
+
* Get proof record by proof receipt id.
|
|
1950
2023
|
*
|
|
1951
|
-
* @param {string} proofId - Proof ID (
|
|
1952
|
-
* @returns {Promise<Object>}
|
|
2024
|
+
* @param {string} proofId - Proof receipt ID (0x + 64 hex).
|
|
2025
|
+
* @returns {Promise<Object>} Proof record and verification state
|
|
1953
2026
|
*
|
|
1954
2027
|
* @example
|
|
1955
|
-
* const result = await client.
|
|
2028
|
+
* const result = await client.getProof('0x...');
|
|
1956
2029
|
* console.log('Status:', result.status);
|
|
1957
2030
|
*/
|
|
1958
|
-
async
|
|
2031
|
+
async getProof(proofId) {
|
|
1959
2032
|
if (!proofId || typeof proofId !== "string") {
|
|
1960
2033
|
throw new ValidationError("proofId is required");
|
|
1961
2034
|
}
|
|
1962
|
-
const response = await this._makeRequest("GET", `/api/v1/
|
|
2035
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`);
|
|
1963
2036
|
if (!response.success) {
|
|
1964
|
-
throw new ApiError(`Failed to get
|
|
2037
|
+
throw new ApiError(`Failed to get proof: ${response.error?.message || "Unknown error"}`, response.error);
|
|
1965
2038
|
}
|
|
1966
2039
|
return this._formatResponse(response);
|
|
1967
2040
|
}
|
|
1968
2041
|
/**
|
|
1969
|
-
* Get private proof
|
|
2042
|
+
* Get private proof record with wallet signature
|
|
1970
2043
|
*
|
|
1971
|
-
* @param {string} proofId - Proof ID
|
|
2044
|
+
* @param {string} proofId - Proof receipt ID.
|
|
1972
2045
|
* @param {Object} wallet - Wallet provider (window.ethereum or ethers Wallet)
|
|
1973
|
-
* @returns {Promise<Object>} Private
|
|
2046
|
+
* @returns {Promise<Object>} Private proof record and verification state
|
|
1974
2047
|
*
|
|
1975
2048
|
* @example
|
|
1976
|
-
*
|
|
1977
|
-
* const privateData = await client.getPrivateStatus(proofId, window.ethereum);
|
|
2049
|
+
* const privateData = await client.getPrivateProof(proofId, window.ethereum);
|
|
1978
2050
|
*/
|
|
1979
|
-
async
|
|
2051
|
+
async getPrivateProof(proofId, wallet = null) {
|
|
1980
2052
|
if (!proofId || typeof proofId !== "string") {
|
|
1981
2053
|
throw new ValidationError("proofId is required");
|
|
1982
2054
|
}
|
|
@@ -1990,7 +2062,7 @@ ${bytes.length}`;
|
|
|
1990
2062
|
...typeof auth.chain === "string" && auth.chain.trim() ? { "x-chain": auth.chain.trim() } : {},
|
|
1991
2063
|
...typeof auth.signatureMethod === "string" && auth.signatureMethod.trim() ? { "x-signature-method": auth.signatureMethod.trim() } : {}
|
|
1992
2064
|
};
|
|
1993
|
-
const response2 = await this._makeRequest("GET", `/api/v1/
|
|
2065
|
+
const response2 = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`, null, headers);
|
|
1994
2066
|
if (!response2.success) {
|
|
1995
2067
|
throw new ApiError(
|
|
1996
2068
|
`Failed to access private proof: ${response2.error?.message || "Unauthorized"}`,
|
|
@@ -2029,7 +2101,7 @@ ${bytes.length}`;
|
|
|
2029
2101
|
}
|
|
2030
2102
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
2031
2103
|
}
|
|
2032
|
-
const response = await this._makeRequest("GET", `/api/v1/
|
|
2104
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`, null, {
|
|
2033
2105
|
"x-wallet-address": walletAddress,
|
|
2034
2106
|
"x-signature": signature,
|
|
2035
2107
|
"x-signed-timestamp": signedTimestamp.toString(),
|
|
@@ -2062,25 +2134,37 @@ ${bytes.length}`;
|
|
|
2062
2134
|
* @returns {Promise<string[]>} Array of verifier IDs
|
|
2063
2135
|
*/
|
|
2064
2136
|
async getVerifiers() {
|
|
2137
|
+
const catalog = await this.getVerifierCatalog();
|
|
2138
|
+
return Array.isArray(catalog?.data) ? catalog.data : [];
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Get the public verifier catalog with per-verifier capabilities.
|
|
2142
|
+
* @returns {Promise<{data: string[], metadata: Record<string, { supportsDirectApi?: boolean }>, meta?: object}>}
|
|
2143
|
+
*/
|
|
2144
|
+
async getVerifierCatalog() {
|
|
2065
2145
|
const response = await this._makeRequest("GET", "/api/v1/verification/verifiers");
|
|
2066
2146
|
if (!response.success) {
|
|
2067
2147
|
throw new ApiError(`Failed to get verifiers: ${response.error?.message || "Unknown error"}`, response.error);
|
|
2068
2148
|
}
|
|
2069
|
-
return
|
|
2149
|
+
return {
|
|
2150
|
+
data: Array.isArray(response.data) ? response.data : [],
|
|
2151
|
+
metadata: response.metadata && typeof response.metadata === "object" && !Array.isArray(response.metadata) ? response.metadata : {},
|
|
2152
|
+
meta: response.meta && typeof response.meta === "object" && !Array.isArray(response.meta) ? response.meta : {}
|
|
2153
|
+
};
|
|
2070
2154
|
}
|
|
2071
2155
|
/**
|
|
2072
2156
|
* POLL PROOF STATUS - Wait for verification completion
|
|
2073
|
-
*
|
|
2157
|
+
*
|
|
2074
2158
|
* Polls the verification status until it reaches a terminal state (completed or failed).
|
|
2075
2159
|
* Useful for providing real-time feedback to users during verification.
|
|
2076
|
-
*
|
|
2077
|
-
* @param {string} proofId - Proof ID to poll
|
|
2160
|
+
*
|
|
2161
|
+
* @param {string} proofId - Proof ID to poll.
|
|
2078
2162
|
* @param {Object} [options] - Polling options
|
|
2079
2163
|
* @param {number} [options.interval=5000] - Polling interval in ms
|
|
2080
2164
|
* @param {number} [options.timeout=120000] - Total timeout in ms
|
|
2081
2165
|
* @param {Function} [options.onProgress] - Progress callback function
|
|
2082
2166
|
* @returns {Promise<Object>} Final verification status
|
|
2083
|
-
*
|
|
2167
|
+
*
|
|
2084
2168
|
* @example
|
|
2085
2169
|
* const finalStatus = await client.pollProofStatus(proofId, {
|
|
2086
2170
|
* interval: 3000,
|
|
@@ -2106,7 +2190,7 @@ ${bytes.length}`;
|
|
|
2106
2190
|
let consecutiveRateLimits = 0;
|
|
2107
2191
|
while (Date.now() - startTime < timeout) {
|
|
2108
2192
|
try {
|
|
2109
|
-
const status = await this.
|
|
2193
|
+
const status = await this.getProof(proofId);
|
|
2110
2194
|
consecutiveRateLimits = 0;
|
|
2111
2195
|
if (onProgress && typeof onProgress === "function") {
|
|
2112
2196
|
onProgress(status.data || status);
|
|
@@ -2139,7 +2223,7 @@ ${bytes.length}`;
|
|
|
2139
2223
|
}
|
|
2140
2224
|
/**
|
|
2141
2225
|
* DETECT CHAIN ID - Get current wallet chain
|
|
2142
|
-
*
|
|
2226
|
+
*
|
|
2143
2227
|
* @returns {Promise<number>} Current chain ID
|
|
2144
2228
|
*/
|
|
2145
2229
|
async detectChainId() {
|
|
@@ -2170,7 +2254,6 @@ ${bytes.length}`;
|
|
|
2170
2254
|
const message = constructVerificationMessage({
|
|
2171
2255
|
walletAddress: address,
|
|
2172
2256
|
signedTimestamp,
|
|
2173
|
-
// Keep wire payload key `qHash` for backwards compatibility.
|
|
2174
2257
|
data: { action: "revoke_proof", qHash: proofId },
|
|
2175
2258
|
verifierIds: ["ownership-basic"],
|
|
2176
2259
|
...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
|
|
@@ -2189,9 +2272,8 @@ ${bytes.length}`;
|
|
|
2189
2272
|
}
|
|
2190
2273
|
throw new ValidationError(`Failed to sign revocation: ${error.message}`);
|
|
2191
2274
|
}
|
|
2192
|
-
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/${proofId}
|
|
2275
|
+
const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/revoke-self/${proofId}`, {
|
|
2193
2276
|
method: "POST",
|
|
2194
|
-
// SECURITY: Do not put proof signatures into Authorization headers.
|
|
2195
2277
|
headers: { "Content-Type": "application/json" },
|
|
2196
2278
|
body: JSON.stringify({
|
|
2197
2279
|
walletAddress: address,
|
|
@@ -2206,18 +2288,16 @@ ${bytes.length}`;
|
|
|
2206
2288
|
}
|
|
2207
2289
|
return true;
|
|
2208
2290
|
}
|
|
2209
|
-
// ============================================================================
|
|
2210
|
-
// PROOFS & GATING METHODS
|
|
2211
|
-
// ============================================================================
|
|
2212
2291
|
/**
|
|
2213
2292
|
* GET PROOFS BY WALLET - Fetch proofs for a wallet address
|
|
2214
|
-
*
|
|
2293
|
+
*
|
|
2215
2294
|
* @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
|
|
2216
2295
|
* @param {Object} [options] - Filter options
|
|
2217
2296
|
* @param {number} [options.limit] - Max results (default: 50; higher limits require owner access)
|
|
2218
2297
|
* @param {number} [options.offset] - Pagination offset (default: 0)
|
|
2298
|
+
* @param {string} [options.qHash] - Filter to single proof by qHash
|
|
2219
2299
|
* @returns {Promise<Object>} Proofs result
|
|
2220
|
-
*
|
|
2300
|
+
*
|
|
2221
2301
|
* @example
|
|
2222
2302
|
* const result = await client.getProofsByWallet('0x...', {
|
|
2223
2303
|
* limit: 50,
|
|
@@ -2231,14 +2311,13 @@ ${bytes.length}`;
|
|
|
2231
2311
|
const id = walletAddress.trim();
|
|
2232
2312
|
const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
|
|
2233
2313
|
const qs = [];
|
|
2234
|
-
if (options.limit)
|
|
2235
|
-
|
|
2236
|
-
if (options.
|
|
2237
|
-
qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
2314
|
+
if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
|
|
2315
|
+
if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
2316
|
+
if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
|
|
2238
2317
|
const query = qs.length ? `?${qs.join("&")}` : "";
|
|
2239
2318
|
const response = await this._makeRequest(
|
|
2240
2319
|
"GET",
|
|
2241
|
-
`/api/v1/proofs/
|
|
2320
|
+
`/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`
|
|
2242
2321
|
);
|
|
2243
2322
|
if (!response.success) {
|
|
2244
2323
|
throw new ApiError(`Failed to get proofs: ${response.error?.message || "Unknown error"}`, response.error);
|
|
@@ -2261,6 +2340,7 @@ ${bytes.length}`;
|
|
|
2261
2340
|
* @param {Object} [options]
|
|
2262
2341
|
* @param {number} [options.limit] - Max results (server enforces caps)
|
|
2263
2342
|
* @param {number} [options.offset] - Pagination offset
|
|
2343
|
+
* @param {string} [options.qHash] - Filter to single proof by qHash
|
|
2264
2344
|
* @param {Object} [wallet] - Optional injected wallet/provider (MetaMask/ethers Wallet)
|
|
2265
2345
|
*/
|
|
2266
2346
|
async getPrivateProofsByWallet(walletAddress, options = {}, wallet = null) {
|
|
@@ -2311,12 +2391,11 @@ ${bytes.length}`;
|
|
|
2311
2391
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
2312
2392
|
}
|
|
2313
2393
|
const qs = [];
|
|
2314
|
-
if (options.limit)
|
|
2315
|
-
|
|
2316
|
-
if (options.
|
|
2317
|
-
qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
2394
|
+
if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
|
|
2395
|
+
if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
|
|
2396
|
+
if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
|
|
2318
2397
|
const query = qs.length ? `?${qs.join("&")}` : "";
|
|
2319
|
-
const response = await this._makeRequest("GET", `/api/v1/proofs/
|
|
2398
|
+
const response = await this._makeRequest("GET", `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`, null, {
|
|
2320
2399
|
"x-wallet-address": signerWalletAddress,
|
|
2321
2400
|
"x-signature": signature,
|
|
2322
2401
|
"x-signed-timestamp": signedTimestamp.toString(),
|
|
@@ -2335,16 +2414,16 @@ ${bytes.length}`;
|
|
|
2335
2414
|
};
|
|
2336
2415
|
}
|
|
2337
2416
|
/**
|
|
2338
|
-
*
|
|
2417
|
+
* Gate check (HTTP API) — minimal eligibility response.
|
|
2339
2418
|
*
|
|
2340
2419
|
* Calls the gate endpoint and returns a **minimal** yes/no response.
|
|
2341
|
-
* By default this checks **public +
|
|
2420
|
+
* By default this checks **public + unlisted** proofs.
|
|
2342
2421
|
*
|
|
2343
2422
|
* When `includePrivate=true`, this can perform owner-signed private checks
|
|
2344
2423
|
* (no full proof payloads returned) by providing a wallet/provider.
|
|
2345
2424
|
*
|
|
2346
|
-
* Prefer this over `checkGate()`
|
|
2347
|
-
*
|
|
2425
|
+
* Prefer this over `checkGate()` when you need the smallest, most stable
|
|
2426
|
+
* response shape and do not need full proof payloads.
|
|
2348
2427
|
*
|
|
2349
2428
|
* @param {Object} params - Gate check query params
|
|
2350
2429
|
* @param {string} params.address - Wallet identity to check (EVM/Solana/DID)
|
|
@@ -2367,25 +2446,20 @@ ${bytes.length}`;
|
|
|
2367
2446
|
const qs = new URLSearchParams();
|
|
2368
2447
|
qs.set("address", address);
|
|
2369
2448
|
const setIfPresent = (key, value) => {
|
|
2370
|
-
if (value === void 0 || value === null)
|
|
2371
|
-
return;
|
|
2449
|
+
if (value === void 0 || value === null) return;
|
|
2372
2450
|
const str = typeof value === "string" ? value : String(value);
|
|
2373
|
-
if (str.length === 0)
|
|
2374
|
-
return;
|
|
2451
|
+
if (str.length === 0) return;
|
|
2375
2452
|
qs.set(key, str);
|
|
2376
2453
|
};
|
|
2377
2454
|
const setBoolIfPresent = (key, value) => {
|
|
2378
|
-
if (value === void 0 || value === null)
|
|
2379
|
-
return;
|
|
2455
|
+
if (value === void 0 || value === null) return;
|
|
2380
2456
|
qs.set(key, value ? "true" : "false");
|
|
2381
2457
|
};
|
|
2382
2458
|
const setCsvIfPresent = (key, value) => {
|
|
2383
|
-
if (value === void 0 || value === null)
|
|
2384
|
-
return;
|
|
2459
|
+
if (value === void 0 || value === null) return;
|
|
2385
2460
|
if (Array.isArray(value)) {
|
|
2386
2461
|
const items = value.map((v) => String(v).trim()).filter(Boolean);
|
|
2387
|
-
if (items.length)
|
|
2388
|
-
qs.set(key, items.join(","));
|
|
2462
|
+
if (items.length) qs.set(key, items.join(","));
|
|
2389
2463
|
return;
|
|
2390
2464
|
}
|
|
2391
2465
|
setIfPresent(key, value);
|
|
@@ -2411,6 +2485,8 @@ ${bytes.length}`;
|
|
|
2411
2485
|
setIfPresent("domain", params.domain);
|
|
2412
2486
|
setIfPresent("minBalance", params.minBalance);
|
|
2413
2487
|
setIfPresent("provider", params.provider);
|
|
2488
|
+
setIfPresent("handle", params.handle);
|
|
2489
|
+
setIfPresent("namespace", params.namespace);
|
|
2414
2490
|
setIfPresent("ownerAddress", params.ownerAddress);
|
|
2415
2491
|
setIfPresent("riskLevel", params.riskLevel);
|
|
2416
2492
|
setBoolIfPresent("sanctioned", params.sanctioned);
|
|
@@ -2458,11 +2534,17 @@ ${bytes.length}`;
|
|
|
2458
2534
|
return response;
|
|
2459
2535
|
}
|
|
2460
2536
|
/**
|
|
2461
|
-
* CHECK GATE
|
|
2462
|
-
*
|
|
2537
|
+
* CHECK GATE — Local preview against proofs you already have in memory or from `getProofsByWallet`.
|
|
2538
|
+
*
|
|
2539
|
+
* **Not authoritative for access control.** For production allow/deny, use {@link NeusClient#gateCheck}
|
|
2540
|
+
* (`GET /api/v1/proofs/check`), which applies the same rules as the NEUS API. This method is useful for
|
|
2541
|
+
* UI previews, offline-ish flows, or when you already fetched proofs and want a quick match without
|
|
2542
|
+
* another round trip — but it can disagree with the server (e.g. `contentHash` matching uses a local
|
|
2543
|
+
* approximation when proof data only has inline `content`; the API uses the standard server-side hash).
|
|
2544
|
+
*
|
|
2463
2545
|
* Gate-first verification: checks if wallet has valid proofs satisfying requirements.
|
|
2464
2546
|
* Returns which requirements are missing/expired.
|
|
2465
|
-
*
|
|
2547
|
+
*
|
|
2466
2548
|
* @param {Object} params - Gate check parameters
|
|
2467
2549
|
* @param {string} params.walletAddress - Target wallet
|
|
2468
2550
|
* @param {Array<Object>} params.requirements - Array of gate requirements
|
|
@@ -2480,7 +2562,7 @@ ${bytes.length}`;
|
|
|
2480
2562
|
* Note: contentHash matching uses approximation in SDK; for exact SHA-256 matching, use backend API
|
|
2481
2563
|
* @param {Array} [params.proofs] - Pre-fetched proofs (skip API call)
|
|
2482
2564
|
* @returns {Promise<Object>} Gate result with satisfied, missing, existing
|
|
2483
|
-
*
|
|
2565
|
+
*
|
|
2484
2566
|
* @example
|
|
2485
2567
|
* // Basic gate check
|
|
2486
2568
|
* const result = await client.checkGate({
|
|
@@ -2513,20 +2595,20 @@ ${bytes.length}`;
|
|
|
2513
2595
|
const verifier = verifiedVerifiers.find(
|
|
2514
2596
|
(v) => v.verifierId === verifierId && v.verified === true
|
|
2515
2597
|
);
|
|
2516
|
-
if (!verifier)
|
|
2517
|
-
|
|
2518
|
-
if (proof.revokedAt)
|
|
2519
|
-
return false;
|
|
2598
|
+
if (!verifier) return false;
|
|
2599
|
+
if (proof.revokedAt) return false;
|
|
2520
2600
|
if (maxAgeMs) {
|
|
2521
2601
|
const proofTimestamp = proof.createdAt || proof.signedTimestamp || 0;
|
|
2522
2602
|
const proofAge = now - proofTimestamp;
|
|
2523
|
-
if (proofAge > maxAgeMs)
|
|
2524
|
-
return false;
|
|
2603
|
+
if (proofAge > maxAgeMs) return false;
|
|
2525
2604
|
}
|
|
2526
2605
|
if (match && typeof match === "object") {
|
|
2527
2606
|
const data = verifier.data || {};
|
|
2528
2607
|
const input = data.input || {};
|
|
2529
|
-
|
|
2608
|
+
const matchObj = Array.isArray(match) ? Object.fromEntries(
|
|
2609
|
+
match.filter((m) => m && m.path && String(m.value ?? "").trim() !== "").map((m) => [String(m.path).trim(), m.value])
|
|
2610
|
+
) : match;
|
|
2611
|
+
for (const [key, expected] of Object.entries(matchObj)) {
|
|
2530
2612
|
let actualValue = null;
|
|
2531
2613
|
if (key.includes(".")) {
|
|
2532
2614
|
const parts = key.split(".");
|
|
@@ -2551,6 +2633,7 @@ ${bytes.length}`;
|
|
|
2551
2633
|
actualValue = data.reference?.id || data.content;
|
|
2552
2634
|
}
|
|
2553
2635
|
if (actualValue === void 0) {
|
|
2636
|
+
const claims = data.claims || {};
|
|
2554
2637
|
if (key === "contractAddress") {
|
|
2555
2638
|
actualValue = input.contractAddress || data.contractAddress;
|
|
2556
2639
|
} else if (key === "tokenId") {
|
|
@@ -2569,6 +2652,22 @@ ${bytes.length}`;
|
|
|
2569
2652
|
actualValue = data.verificationMethod;
|
|
2570
2653
|
} else if (key === "domain") {
|
|
2571
2654
|
actualValue = data.domain;
|
|
2655
|
+
} else if (key === "handle") {
|
|
2656
|
+
actualValue = data.handle || data.pseudonymId;
|
|
2657
|
+
} else if (key === "namespace") {
|
|
2658
|
+
actualValue = data.namespace !== void 0 && data.namespace !== null && data.namespace !== "" ? data.namespace : "neus";
|
|
2659
|
+
} else if (key === "claims.sanctions_passed") {
|
|
2660
|
+
actualValue = claims.sanctions_passed ?? claims.sanctionsPassed;
|
|
2661
|
+
} else if (key === "claims.age_min") {
|
|
2662
|
+
actualValue = claims.age_min ?? claims.ageMin;
|
|
2663
|
+
} else if (key === "neusPersonhoodId") {
|
|
2664
|
+
actualValue = data.neusPersonhoodId;
|
|
2665
|
+
} else if (key === "riskLevel") {
|
|
2666
|
+
actualValue = data.riskLevel;
|
|
2667
|
+
} else if (key === "sanctioned") {
|
|
2668
|
+
actualValue = data.sanctioned;
|
|
2669
|
+
} else if (key === "poisoned") {
|
|
2670
|
+
actualValue = data.poisoned;
|
|
2572
2671
|
}
|
|
2573
2672
|
}
|
|
2574
2673
|
if (key === "contentHash" && actualValue === void 0 && data.content) {
|
|
@@ -2580,7 +2679,7 @@ ${bytes.length}`;
|
|
|
2580
2679
|
hash = (hash << 5) - hash + char;
|
|
2581
2680
|
hash = hash & hash;
|
|
2582
2681
|
}
|
|
2583
|
-
actualValue =
|
|
2682
|
+
actualValue = `0x${Math.abs(hash).toString(16).padStart(64, "0").substring(0, 66)}`;
|
|
2584
2683
|
} catch {
|
|
2585
2684
|
actualValue = String(data.content);
|
|
2586
2685
|
}
|
|
@@ -2590,11 +2689,16 @@ ${bytes.length}`;
|
|
|
2590
2689
|
if (actualValue === void 0 || actualValue === null) {
|
|
2591
2690
|
return false;
|
|
2592
2691
|
}
|
|
2692
|
+
if (typeof actualValue === "boolean" || key && (key.includes("sanctions") || key.includes("sanctioned") || key.includes("poisoned"))) {
|
|
2693
|
+
const bActual = Boolean(actualValue);
|
|
2694
|
+
const bExpected = expected === true || expected === "true" || String(expected).toLowerCase() === "true";
|
|
2695
|
+
if (bActual !== bExpected) return false;
|
|
2696
|
+
continue;
|
|
2697
|
+
}
|
|
2593
2698
|
if (key === "chainId" || key === "tokenId" && (typeof actualValue === "number" || !isNaN(Number(actualValue)))) {
|
|
2594
2699
|
normalizedActual = Number(actualValue);
|
|
2595
2700
|
normalizedExpected = Number(expected);
|
|
2596
|
-
if (isNaN(normalizedActual) || isNaN(normalizedExpected))
|
|
2597
|
-
return false;
|
|
2701
|
+
if (isNaN(normalizedActual) || isNaN(normalizedExpected)) return false;
|
|
2598
2702
|
} else if (typeof actualValue === "string" && (actualValue.startsWith("0x") || actualValue.length > 20)) {
|
|
2599
2703
|
normalizedActual = actualValue.toLowerCase();
|
|
2600
2704
|
normalizedExpected = typeof expected === "string" ? String(expected).toLowerCase() : expected;
|
|
@@ -2623,13 +2727,6 @@ ${bytes.length}`;
|
|
|
2623
2727
|
allProofs: proofs
|
|
2624
2728
|
};
|
|
2625
2729
|
}
|
|
2626
|
-
// ============================================================================
|
|
2627
|
-
// PRIVATE UTILITY METHODS
|
|
2628
|
-
// ============================================================================
|
|
2629
|
-
/**
|
|
2630
|
-
* Get connected wallet address
|
|
2631
|
-
* @private
|
|
2632
|
-
*/
|
|
2633
2730
|
async _getWalletAddress() {
|
|
2634
2731
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
2635
2732
|
throw new ConfigurationError("No Web3 wallet detected");
|
|
@@ -2640,10 +2737,6 @@ ${bytes.length}`;
|
|
|
2640
2737
|
}
|
|
2641
2738
|
return accounts[0];
|
|
2642
2739
|
}
|
|
2643
|
-
/**
|
|
2644
|
-
* Make HTTP request to API
|
|
2645
|
-
* @private
|
|
2646
|
-
*/
|
|
2647
2740
|
async _makeRequest(method, endpoint, data = null, headersOverride = null) {
|
|
2648
2741
|
const url = `${this.baseUrl}${endpoint}`;
|
|
2649
2742
|
const controller = new AbortController();
|
|
@@ -2681,10 +2774,6 @@ ${bytes.length}`;
|
|
|
2681
2774
|
throw new NetworkError(`Network error: ${error.message}`);
|
|
2682
2775
|
}
|
|
2683
2776
|
}
|
|
2684
|
-
/**
|
|
2685
|
-
* Format API response for consistent structure
|
|
2686
|
-
* @private
|
|
2687
|
-
*/
|
|
2688
2777
|
_formatResponse(response) {
|
|
2689
2778
|
const proofId = response?.data?.proofId || response?.proofId || response?.data?.resource?.proofId || response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || response?.data?.id;
|
|
2690
2779
|
const qHash = response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || proofId || response?.data?.id;
|
|
@@ -2699,13 +2788,9 @@ ${bytes.length}`;
|
|
|
2699
2788
|
data: response.data,
|
|
2700
2789
|
message: response.message,
|
|
2701
2790
|
timestamp: Date.now(),
|
|
2702
|
-
|
|
2791
|
+
proofUrl: finalProofId ? `${this.baseUrl}/api/v1/proofs/${finalProofId}` : null
|
|
2703
2792
|
};
|
|
2704
2793
|
}
|
|
2705
|
-
/**
|
|
2706
|
-
* Check if status is terminal (completed or failed)
|
|
2707
|
-
* @private
|
|
2708
|
-
*/
|
|
2709
2794
|
_isTerminalStatus(status) {
|
|
2710
2795
|
const terminalStates = [
|
|
2711
2796
|
"verified",
|
|
@@ -2737,12 +2822,13 @@ ${bytes.length}`;
|
|
|
2737
2822
|
});
|
|
2738
2823
|
|
|
2739
2824
|
// index.js
|
|
2740
|
-
var
|
|
2741
|
-
__export(
|
|
2825
|
+
var index_exports = {};
|
|
2826
|
+
__export(index_exports, {
|
|
2742
2827
|
ApiError: () => ApiError,
|
|
2743
2828
|
AuthenticationError: () => AuthenticationError,
|
|
2744
2829
|
ConfigurationError: () => ConfigurationError,
|
|
2745
2830
|
DAY: () => DAY,
|
|
2831
|
+
DEFAULT_HOSTED_VERIFY_URL: () => DEFAULT_HOSTED_VERIFY_URL,
|
|
2746
2832
|
GATE_AGENT_DELEGATION: () => GATE_AGENT_DELEGATION,
|
|
2747
2833
|
GATE_AGENT_IDENTITY: () => GATE_AGENT_IDENTITY,
|
|
2748
2834
|
GATE_CONTENT_MODERATION: () => GATE_CONTENT_MODERATION,
|
|
@@ -2758,6 +2844,7 @@ __export(sdk_exports, {
|
|
|
2758
2844
|
NEUS_CONSTANTS: () => NEUS_CONSTANTS,
|
|
2759
2845
|
NetworkError: () => NetworkError,
|
|
2760
2846
|
NeusClient: () => NeusClient,
|
|
2847
|
+
PORTABLE_PROOF_SIGNER_HEADER: () => PORTABLE_PROOF_SIGNER_HEADER,
|
|
2761
2848
|
SDKError: () => SDKError,
|
|
2762
2849
|
StatusPoller: () => StatusPoller,
|
|
2763
2850
|
ValidationError: () => ValidationError,
|
|
@@ -2770,11 +2857,12 @@ __export(sdk_exports, {
|
|
|
2770
2857
|
constructVerificationMessage: () => constructVerificationMessage,
|
|
2771
2858
|
createGate: () => createGate,
|
|
2772
2859
|
createVerificationData: () => createVerificationData,
|
|
2773
|
-
default: () =>
|
|
2860
|
+
default: () => index_default,
|
|
2774
2861
|
delay: () => delay,
|
|
2775
2862
|
deriveDid: () => deriveDid,
|
|
2776
2863
|
formatTimestamp: () => formatTimestamp,
|
|
2777
2864
|
formatVerificationStatus: () => formatVerificationStatus,
|
|
2865
|
+
getHostedCheckoutUrl: () => getHostedCheckoutUrl,
|
|
2778
2866
|
isFailureStatus: () => isFailureStatus,
|
|
2779
2867
|
isSuccessStatus: () => isSuccessStatus,
|
|
2780
2868
|
isSupportedChain: () => isSupportedChain,
|
|
@@ -2784,6 +2872,7 @@ __export(sdk_exports, {
|
|
|
2784
2872
|
resolveZkPassportConfig: () => resolveZkPassportConfig,
|
|
2785
2873
|
signMessage: () => signMessage,
|
|
2786
2874
|
standardizeVerificationRequest: () => standardizeVerificationRequest,
|
|
2875
|
+
toAgentDelegationMaxSpend: () => toAgentDelegationMaxSpend,
|
|
2787
2876
|
toHexUtf8: () => toHexUtf8,
|
|
2788
2877
|
validateQHash: () => validateQHash,
|
|
2789
2878
|
validateSignatureComponents: () => validateSignatureComponents,
|
|
@@ -2793,7 +2882,7 @@ __export(sdk_exports, {
|
|
|
2793
2882
|
validateWalletAddress: () => validateWalletAddress,
|
|
2794
2883
|
withRetry: () => withRetry
|
|
2795
2884
|
});
|
|
2796
|
-
module.exports = __toCommonJS(
|
|
2885
|
+
module.exports = __toCommonJS(index_exports);
|
|
2797
2886
|
init_client();
|
|
2798
2887
|
init_utils();
|
|
2799
2888
|
|
|
@@ -2858,7 +2947,7 @@ function combineGates(...gates) {
|
|
|
2858
2947
|
|
|
2859
2948
|
// index.js
|
|
2860
2949
|
init_errors();
|
|
2861
|
-
var
|
|
2950
|
+
var index_default = {
|
|
2862
2951
|
NeusClient: () => Promise.resolve().then(() => (init_client(), client_exports)).then((m) => m.NeusClient),
|
|
2863
2952
|
toString: () => "[neus/sdk]"
|
|
2864
2953
|
};
|
|
@@ -2868,6 +2957,7 @@ var sdk_default = {
|
|
|
2868
2957
|
AuthenticationError,
|
|
2869
2958
|
ConfigurationError,
|
|
2870
2959
|
DAY,
|
|
2960
|
+
DEFAULT_HOSTED_VERIFY_URL,
|
|
2871
2961
|
GATE_AGENT_DELEGATION,
|
|
2872
2962
|
GATE_AGENT_IDENTITY,
|
|
2873
2963
|
GATE_CONTENT_MODERATION,
|
|
@@ -2883,6 +2973,7 @@ var sdk_default = {
|
|
|
2883
2973
|
NEUS_CONSTANTS,
|
|
2884
2974
|
NetworkError,
|
|
2885
2975
|
NeusClient,
|
|
2976
|
+
PORTABLE_PROOF_SIGNER_HEADER,
|
|
2886
2977
|
SDKError,
|
|
2887
2978
|
StatusPoller,
|
|
2888
2979
|
ValidationError,
|
|
@@ -2899,6 +2990,7 @@ var sdk_default = {
|
|
|
2899
2990
|
deriveDid,
|
|
2900
2991
|
formatTimestamp,
|
|
2901
2992
|
formatVerificationStatus,
|
|
2993
|
+
getHostedCheckoutUrl,
|
|
2902
2994
|
isFailureStatus,
|
|
2903
2995
|
isSuccessStatus,
|
|
2904
2996
|
isSupportedChain,
|
|
@@ -2908,6 +3000,7 @@ var sdk_default = {
|
|
|
2908
3000
|
resolveZkPassportConfig,
|
|
2909
3001
|
signMessage,
|
|
2910
3002
|
standardizeVerificationRequest,
|
|
3003
|
+
toAgentDelegationMaxSpend,
|
|
2911
3004
|
toHexUtf8,
|
|
2912
3005
|
validateQHash,
|
|
2913
3006
|
validateSignatureComponents,
|