@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/cjs/client.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var client_exports = {};
22
22
  __export(client_exports, {
23
23
  NeusClient: () => NeusClient,
24
+ PORTABLE_PROOF_SIGNER_HEADER: () => PORTABLE_PROOF_SIGNER_HEADER,
24
25
  constructVerificationMessage: () => constructVerificationMessage
25
26
  });
26
27
  module.exports = __toCommonJS(client_exports);
@@ -129,6 +130,7 @@ var ConfigurationError = class extends SDKError {
129
130
  };
130
131
 
131
132
  // utils.js
133
+ var PORTABLE_PROOF_SIGNER_HEADER = "Portable Proof Verification Request";
132
134
  var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
133
135
  function encodeBase58Bytes(input) {
134
136
  let source;
@@ -143,8 +145,7 @@ function encodeBase58Bytes(input) {
143
145
  } else {
144
146
  throw new SDKError("Unsupported non-EVM signature byte format", "INVALID_SIGNATURE_FORMAT");
145
147
  }
146
- if (source.length === 0)
147
- return "";
148
+ if (source.length === 0) return "";
148
149
  let zeroes = 0;
149
150
  while (zeroes < source.length && source[zeroes] === 0) {
150
151
  zeroes++;
@@ -178,16 +179,28 @@ function deterministicStringify(obj) {
178
179
  return JSON.stringify(obj);
179
180
  }
180
181
  if (typeof obj !== "object") {
182
+ if (typeof obj === "string") return JSON.stringify(obj.normalize("NFC"));
181
183
  return JSON.stringify(obj);
182
184
  }
183
185
  if (Array.isArray(obj)) {
184
- return "[" + obj.map((item) => deterministicStringify(item)).join(",") + "]";
186
+ return `[${obj.map((item) => item === void 0 ? "null" : deterministicStringify(item)).join(",")}]`;
185
187
  }
186
- const sortedKeys = Object.keys(obj).sort();
188
+ const sortedKeys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
187
189
  const pairs = sortedKeys.map(
188
- (key) => JSON.stringify(key) + ":" + deterministicStringify(obj[key])
190
+ (key) => `${JSON.stringify(key)}:${deterministicStringify(obj[key])}`
189
191
  );
190
- return "{" + pairs.join(",") + "}";
192
+ return `{${pairs.join(",")}}`;
193
+ }
194
+ function chainLineForPortableProofSigner(chain, chainId) {
195
+ if (typeof chain === "string" && chain.length > 0) {
196
+ const m = chain.match(/^eip155:(\d+)$/);
197
+ if (m) return Number(m[1]);
198
+ return chain;
199
+ }
200
+ if (typeof chainId === "number" && Number.isFinite(chainId) && chainId > 0) {
201
+ return chainId;
202
+ }
203
+ throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
191
204
  }
192
205
  function constructVerificationMessage({ walletAddress, signedTimestamp, data, verifierIds, chainId, chain }) {
193
206
  if (!walletAddress || typeof walletAddress !== "string") {
@@ -202,28 +215,28 @@ function constructVerificationMessage({ walletAddress, signedTimestamp, data, ve
202
215
  if (!Array.isArray(verifierIds) || verifierIds.length === 0) {
203
216
  throw new SDKError("verifierIds is required and must be a non-empty array", "INVALID_VERIFIER_IDS");
204
217
  }
205
- const chainContext = typeof chain === "string" && chain.length > 0 ? chain : chainId;
206
- if (!chainContext) {
218
+ if ((typeof chain !== "string" || !chain.length) && !(typeof chainId === "number" && chainId > 0)) {
207
219
  throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
208
220
  }
209
- if (chainContext === chainId && typeof chainId !== "number") {
210
- throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
211
- }
212
- if (chainContext === chain && (typeof chain !== "string" || !chain.includes(":"))) {
221
+ if (typeof chain === "string" && chain.length > 0 && !chain.includes(":")) {
213
222
  throw new SDKError('chain must be a "namespace:reference" string', "INVALID_CHAIN");
214
223
  }
224
+ if ((!chain || !chain.length) && typeof chainId !== "number") {
225
+ throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
226
+ }
227
+ const chainLine = chainLineForPortableProofSigner(chain, chainId);
215
228
  const namespace = typeof chain === "string" && chain.includes(":") ? chain.split(":")[0] : "eip155";
216
229
  const normalizedWalletAddress = namespace === "eip155" ? walletAddress.toLowerCase() : walletAddress;
217
230
  const dataString = deterministicStringify(data);
218
231
  const messageComponents = [
219
- "NEUS Verification Request",
232
+ PORTABLE_PROOF_SIGNER_HEADER,
220
233
  `Wallet: ${normalizedWalletAddress}`,
221
- `Chain: ${chainContext}`,
234
+ `Chain: ${chainLine}`,
222
235
  `Verifiers: ${verifierIds.join(",")}`,
223
236
  `Data: ${dataString}`,
224
237
  `Timestamp: ${signedTimestamp}`
225
238
  ];
226
- return messageComponents.join("\n");
239
+ return messageComponents.join("\n").normalize("NFC");
227
240
  }
228
241
  function validateWalletAddress(address) {
229
242
  if (!address || typeof address !== "string") {
@@ -232,17 +245,13 @@ function validateWalletAddress(address) {
232
245
  return /^0x[a-fA-F0-9]{40}$/.test(address);
233
246
  }
234
247
  function validateUniversalAddress(address, chain) {
235
- if (!address || typeof address !== "string")
236
- return false;
248
+ if (!address || typeof address !== "string") return false;
237
249
  const value = address.trim();
238
- if (!value)
239
- return false;
250
+ if (!value) return false;
240
251
  const chainRef = typeof chain === "string" ? chain.trim().toLowerCase() : "";
241
252
  const namespace = chainRef.includes(":") ? chainRef.split(":")[0] : "";
242
- if (validateWalletAddress(value))
243
- return true;
244
- if (namespace === "eip155")
245
- return false;
253
+ if (validateWalletAddress(value)) return true;
254
+ if (namespace === "eip155") return false;
246
255
  if (namespace === "solana") {
247
256
  return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(value);
248
257
  }
@@ -271,34 +280,27 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
271
280
  const chainStr = typeof chain === "string" && chain.trim().length > 0 ? chain.trim() : "eip155";
272
281
  const namespace = chainStr.includes(":") ? chainStr.split(":")[0] || "eip155" : "eip155";
273
282
  const resolveAddress = async () => {
274
- if (typeof walletAddress === "string" && walletAddress.trim().length > 0)
275
- return walletAddress;
283
+ if (typeof walletAddress === "string" && walletAddress.trim().length > 0) return walletAddress;
276
284
  if (namespace === "solana") {
277
285
  if (resolvedProvider?.publicKey && typeof resolvedProvider.publicKey.toBase58 === "function") {
278
286
  const pk = resolvedProvider.publicKey.toBase58();
279
- if (typeof pk === "string" && pk)
280
- return pk;
287
+ if (typeof pk === "string" && pk) return pk;
281
288
  }
282
289
  if (typeof resolvedProvider.getAddress === "function") {
283
290
  const addr = await resolvedProvider.getAddress().catch(() => null);
284
- if (typeof addr === "string" && addr)
285
- return addr;
291
+ if (typeof addr === "string" && addr) return addr;
286
292
  }
287
- if (typeof resolvedProvider.address === "string" && resolvedProvider.address)
288
- return resolvedProvider.address;
293
+ if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
289
294
  return null;
290
295
  }
291
- if (typeof resolvedProvider.address === "string" && resolvedProvider.address)
292
- return resolvedProvider.address;
293
- if (typeof resolvedProvider.getAddress === "function")
294
- return await resolvedProvider.getAddress();
296
+ if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
297
+ if (typeof resolvedProvider.getAddress === "function") return resolvedProvider.getAddress();
295
298
  if (typeof resolvedProvider.request === "function") {
296
299
  let accounts = await resolvedProvider.request({ method: "eth_accounts" }).catch(() => []);
297
300
  if (!Array.isArray(accounts) || accounts.length === 0) {
298
301
  accounts = await resolvedProvider.request({ method: "eth_requestAccounts" }).catch(() => []);
299
302
  }
300
- if (Array.isArray(accounts) && accounts[0])
301
- return accounts[0];
303
+ if (Array.isArray(accounts) && accounts[0]) return accounts[0];
302
304
  }
303
305
  return null;
304
306
  };
@@ -306,16 +308,11 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
306
308
  if (typeof resolvedProvider.signMessage === "function") {
307
309
  const encoded = typeof msg === "string" ? new TextEncoder().encode(msg) : msg;
308
310
  const result = await resolvedProvider.signMessage(encoded);
309
- if (typeof result === "string" && result)
310
- return result;
311
- if (result instanceof Uint8Array)
312
- return encodeBase58Bytes(result);
313
- if (result instanceof ArrayBuffer)
314
- return encodeBase58Bytes(new Uint8Array(result));
315
- if (ArrayBuffer.isView(result))
316
- return encodeBase58Bytes(result);
317
- if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result))
318
- return encodeBase58Bytes(result);
311
+ if (typeof result === "string" && result) return result;
312
+ if (result instanceof Uint8Array) return encodeBase58Bytes(result);
313
+ if (result instanceof ArrayBuffer) return encodeBase58Bytes(new Uint8Array(result));
314
+ if (ArrayBuffer.isView(result)) return encodeBase58Bytes(result);
315
+ if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result)) return encodeBase58Bytes(result);
319
316
  }
320
317
  throw new SDKError("Non-EVM signing requires provider.signMessage", "SIGNER_UNAVAILABLE");
321
318
  }
@@ -324,16 +321,14 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
324
321
  let firstPersonalSignError = null;
325
322
  try {
326
323
  const sig = await resolvedProvider.request({ method: "personal_sign", params: [msg, address] });
327
- if (typeof sig === "string" && sig)
328
- return sig;
324
+ if (typeof sig === "string" && sig) return sig;
329
325
  } catch (error) {
330
326
  firstPersonalSignError = error;
331
327
  }
332
328
  let secondPersonalSignError = null;
333
329
  try {
334
330
  const sig = await resolvedProvider.request({ method: "personal_sign", params: [address, msg] });
335
- if (typeof sig === "string" && sig)
336
- return sig;
331
+ if (typeof sig === "string" && sig) return sig;
337
332
  } catch (error) {
338
333
  secondPersonalSignError = error;
339
334
  const signatureErrorMessage = String(
@@ -344,16 +339,14 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
344
339
  try {
345
340
  const hexMsg = toHexUtf8(msg);
346
341
  const sig = await resolvedProvider.request({ method: "personal_sign", params: [hexMsg, address] });
347
- if (typeof sig === "string" && sig)
348
- return sig;
342
+ if (typeof sig === "string" && sig) return sig;
349
343
  } catch {
350
344
  }
351
345
  }
352
346
  }
353
347
  try {
354
348
  const sig = await resolvedProvider.request({ method: "eth_sign", params: [address, msg] });
355
- if (typeof sig === "string" && sig)
356
- return sig;
349
+ if (typeof sig === "string" && sig) return sig;
357
350
  } catch {
358
351
  }
359
352
  if (secondPersonalSignError || firstPersonalSignError) {
@@ -366,13 +359,12 @@ async function signMessage({ provider, message, walletAddress, chain } = {}) {
366
359
  }
367
360
  if (typeof resolvedProvider.signMessage === "function") {
368
361
  const result = await resolvedProvider.signMessage(msg);
369
- if (typeof result === "string" && result)
370
- return result;
362
+ if (typeof result === "string" && result) return result;
371
363
  }
372
364
  throw new SDKError("Unable to sign message with provided wallet/provider", "SIGNER_UNAVAILABLE");
373
365
  }
374
366
  var NEUS_CONSTANTS = {
375
- // Hub chain (where all verifications occur)
367
+ /** Default EVM chain id for NEUS protocol signing context (`HUB_CHAIN_ID` name kept for compatibility). */
376
368
  HUB_CHAIN_ID: 84532,
377
369
  // Supported target chains for cross-chain propagation
378
370
  TESTNET_CHAINS: [
@@ -402,28 +394,28 @@ var NEUS_CONSTANTS = {
402
394
  };
403
395
 
404
396
  // client.js
405
- var FALLBACK_PUBLIC_VERIFIERS = [
406
- "ownership-basic",
407
- "ownership-pseudonym",
408
- "ownership-dns-txt",
409
- "ownership-social",
410
- "ownership-org-oauth",
411
- "contract-ownership",
412
- "nft-ownership",
413
- "token-holding",
414
- "wallet-link",
415
- "wallet-risk",
416
- "proof-of-human",
417
- "agent-identity",
418
- "agent-delegation",
419
- "ai-content-moderation"
420
- ];
421
- var INTERACTIVE_VERIFIERS = /* @__PURE__ */ new Set([
422
- "ownership-social",
423
- "ownership-org-oauth",
424
- "proof-of-human"
425
- ]);
397
+ var FALLBACK_PUBLIC_VERIFIER_CATALOG = {
398
+ "ownership-basic": { supportsDirectApi: true },
399
+ "ownership-pseudonym": { supportsDirectApi: true },
400
+ "ownership-dns-txt": { supportsDirectApi: true },
401
+ "ownership-social": { supportsDirectApi: false },
402
+ "ownership-org-oauth": { supportsDirectApi: false },
403
+ "contract-ownership": { supportsDirectApi: true },
404
+ "nft-ownership": { supportsDirectApi: true },
405
+ "token-holding": { supportsDirectApi: true },
406
+ "wallet-link": { supportsDirectApi: true },
407
+ "wallet-risk": { supportsDirectApi: true },
408
+ "proof-of-human": { supportsDirectApi: false },
409
+ "agent-identity": { supportsDirectApi: true },
410
+ "agent-delegation": { supportsDirectApi: true },
411
+ "ai-content-moderation": { supportsDirectApi: true }
412
+ };
426
413
  var EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
414
+ var WALLET_LINK_RELATIONSHIP_TYPES = /* @__PURE__ */ new Set(["primary", "personal", "org", "affiliate", "agent", "linked"]);
415
+ function normalizeWalletLinkRelationshipType(value) {
416
+ const normalized = String(value || "").trim().toLowerCase();
417
+ return WALLET_LINK_RELATIONSHIP_TYPES.has(normalized) ? normalized : "linked";
418
+ }
427
419
  var validateVerifierData = (verifierId, data) => {
428
420
  if (!data || typeof data !== "object") {
429
421
  return { valid: false, error: "Data object is required" };
@@ -641,7 +633,10 @@ var validateVerifierData = (verifierId, data) => {
641
633
  const maxBytes = 50 * 1024;
642
634
  const bytes = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(data.content).length : String(data.content).length;
643
635
  if (bytes > maxBytes) {
644
- return { valid: false, error: `content exceeds ${maxBytes} bytes limit for ai-content-moderation verifier (text)` };
636
+ return {
637
+ valid: false,
638
+ error: `content exceeds ${maxBytes} bytes limit for ai-content-moderation verifier (text)`
639
+ };
645
640
  }
646
641
  } catch {
647
642
  }
@@ -700,20 +695,15 @@ var NeusClient = class {
700
695
  if (typeof this.config.appId === "string" && this.config.appId.trim().length > 0) {
701
696
  this.defaultHeaders["X-Neus-App"] = this.config.appId.trim();
702
697
  }
703
- if (typeof this.config.sponsorGrant === "string" && this.config.sponsorGrant.trim().length > 0) {
704
- this.defaultHeaders["X-Sponsor-Grant"] = this.config.sponsorGrant.trim();
705
- }
706
698
  if (typeof this.config.paymentSignature === "string" && this.config.paymentSignature.trim().length > 0) {
707
699
  this.defaultHeaders["PAYMENT-SIGNATURE"] = this.config.paymentSignature.trim();
708
700
  }
709
701
  if (this.config.extraHeaders && typeof this.config.extraHeaders === "object") {
710
702
  for (const [k, v] of Object.entries(this.config.extraHeaders)) {
711
- if (!k || v === void 0 || v === null)
712
- continue;
703
+ if (!k || v === void 0 || v === null) continue;
713
704
  const key = String(k).trim();
714
705
  const value = String(v).trim();
715
- if (!key || !value)
716
- continue;
706
+ if (!key || !value) continue;
717
707
  this.defaultHeaders[key] = value;
718
708
  }
719
709
  }
@@ -726,14 +716,12 @@ var NeusClient = class {
726
716
  }
727
717
  _getHubChainId() {
728
718
  const configured = Number(this.config?.hubChainId);
729
- if (Number.isFinite(configured) && configured > 0)
730
- return Math.floor(configured);
719
+ if (Number.isFinite(configured) && configured > 0) return Math.floor(configured);
731
720
  return NEUS_CONSTANTS.HUB_CHAIN_ID;
732
721
  }
733
722
  _normalizeIdentity(value) {
734
723
  let raw = String(value || "").trim();
735
- if (!raw)
736
- return "";
724
+ if (!raw) return "";
737
725
  const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
738
726
  if (didMatch && didMatch[3]) {
739
727
  raw = String(didMatch[3]).trim();
@@ -741,8 +729,7 @@ var NeusClient = class {
741
729
  return EVM_ADDRESS_RE.test(raw) ? raw.toLowerCase() : raw;
742
730
  }
743
731
  _inferChainForAddress(address, explicitChain) {
744
- if (typeof explicitChain === "string" && explicitChain.includes(":"))
745
- return explicitChain.trim();
732
+ if (typeof explicitChain === "string" && explicitChain.includes(":")) return explicitChain.trim();
746
733
  const raw = String(address || "").trim();
747
734
  const didMatch = raw.match(/^did:pkh:([^:]+):([^:]+):(.+)$/i);
748
735
  if (didMatch && didMatch[1] && didMatch[2]) {
@@ -781,8 +768,7 @@ var NeusClient = class {
781
768
  throw new ConfigurationError("Invalid wallet provider");
782
769
  }
783
770
  _getDefaultBrowserWallet() {
784
- if (typeof window === "undefined")
785
- return null;
771
+ if (typeof window === "undefined") return null;
786
772
  return window.ethereum || window.solana || window.phantom && window.phantom.solana || null;
787
773
  }
788
774
  async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
@@ -840,80 +826,134 @@ var NeusClient = class {
840
826
  signatureMethod: params.signatureMethod
841
827
  });
842
828
  }
843
- // ============================================================================
844
- // CORE VERIFICATION METHODS
845
- // ============================================================================
829
+ async createWalletLinkData(params = {}) {
830
+ const normalizedPrimary = this._normalizeIdentity(params.primaryWalletAddress);
831
+ const normalizedSecondary = this._normalizeIdentity(params.secondaryWalletAddress);
832
+ if (!EVM_ADDRESS_RE.test(normalizedPrimary)) {
833
+ throw new ValidationError("wallet-link requires a valid primaryWalletAddress");
834
+ }
835
+ if (!EVM_ADDRESS_RE.test(normalizedSecondary)) {
836
+ throw new ValidationError("wallet-link requires a valid secondaryWalletAddress");
837
+ }
838
+ if (normalizedPrimary === normalizedSecondary) {
839
+ throw new ValidationError("wallet-link secondaryWalletAddress must differ from primaryWalletAddress");
840
+ }
841
+ const providerWallet = params.wallet || this._getDefaultBrowserWallet();
842
+ const { signerWalletAddress, provider } = await this._resolveWalletSigner(providerWallet);
843
+ const normalizedSigner = this._normalizeIdentity(signerWalletAddress);
844
+ if (!EVM_ADDRESS_RE.test(normalizedSigner)) {
845
+ throw new ValidationError("wallet-link requires an EVM wallet/provider for the secondary wallet");
846
+ }
847
+ if (normalizedSigner !== normalizedSecondary) {
848
+ throw new ValidationError("wallet-link wallet/provider must be connected to secondaryWalletAddress");
849
+ }
850
+ const resolvedChain = (() => {
851
+ const raw = String(params.chain || "").trim();
852
+ if (!raw) return `eip155:${this._getHubChainId()}`;
853
+ if (!/^eip155:\d+$/.test(raw)) {
854
+ throw new ValidationError("wallet-link requires chain in the form eip155:<chainId>");
855
+ }
856
+ return raw;
857
+ })();
858
+ const signedTimestamp = Number.isFinite(Number(params.signedTimestamp)) && Number(params.signedTimestamp) > 0 ? Number(params.signedTimestamp) : Date.now();
859
+ const linkData = {
860
+ primaryAccountId: `${resolvedChain}:${normalizedPrimary}`,
861
+ secondaryAccountId: `${resolvedChain}:${normalizedSecondary}`,
862
+ primaryWalletAddress: normalizedPrimary,
863
+ secondaryWalletAddress: normalizedSecondary
864
+ };
865
+ const message = constructVerificationMessage({
866
+ walletAddress: normalizedSecondary,
867
+ signedTimestamp,
868
+ data: linkData,
869
+ verifierIds: ["wallet-link"],
870
+ chain: resolvedChain
871
+ });
872
+ let signature;
873
+ try {
874
+ signature = await signMessage({
875
+ provider,
876
+ message,
877
+ walletAddress: signerWalletAddress
878
+ });
879
+ } catch (error) {
880
+ if (error?.code === 4001) {
881
+ throw new ValidationError("User rejected wallet-link signature request");
882
+ }
883
+ throw new ValidationError(`Failed to sign wallet-link message: ${error?.message || String(error)}`);
884
+ }
885
+ const label = String(params.label || "").trim().slice(0, 64);
886
+ return {
887
+ primaryWalletAddress: normalizedPrimary,
888
+ secondaryWalletAddress: normalizedSecondary,
889
+ signature,
890
+ chain: resolvedChain,
891
+ signatureMethod: "eip191",
892
+ signedTimestamp,
893
+ relationshipType: normalizeWalletLinkRelationshipType(params.relationshipType),
894
+ ...label ? { label } : {}
895
+ };
896
+ }
846
897
  /**
847
- * VERIFY - Standard verification (auto or manual)
848
- *
849
- * Create proofs with complete control over the verification process.
850
- * If signature and walletAddress are omitted but verifier/content are provided,
851
- * this method performs the wallet flow inline (no aliases, no secondary methods).
852
- *
898
+ * Create a verification proof.
899
+ *
900
+ * Supports two paths:
901
+ * - **Auto:** Supply `verifier`, `content`, and/or `data` with an optional
902
+ * `wallet` provider. The SDK performs signing in the client.
903
+ * - **Manual:** Supply pre-signed `verifierIds`, `data`, `walletAddress`,
904
+ * `signature`, and `signedTimestamp`.
905
+ *
853
906
  * @param {Object} params - Verification parameters
907
+ * @param {string} [params.verifier] - Verifier ID (auto path, e.g. 'ownership-basic')
908
+ * @param {string} [params.content] - Content to verify (auto path)
909
+ * @param {Object} [params.data] - Structured verification data
910
+ * @param {Object} [params.wallet] - Wallet provider (auto path)
911
+ * @param {Object} [params.options] - Additional options
854
912
  * @param {Array<string>} [params.verifierIds] - Array of verifier IDs (manual path)
855
- * @param {Object} [params.data] - Verification data object (manual path)
856
913
  * @param {string} [params.walletAddress] - Wallet address that signed the request (manual path)
857
914
  * @param {string} [params.signature] - EIP-191 signature (manual path)
858
915
  * @param {number} [params.signedTimestamp] - Unix timestamp when signature was created (manual path)
859
- * @param {number} [params.chainId] - Chain ID for verification context (optional, managed by protocol)
860
- * @param {Object} [params.options] - Additional options
861
- * @param {string} [params.verifier] - Verifier ID (auto path)
862
- * @param {string} [params.content] - Content/description (auto path)
863
- * @param {Object} [params.wallet] - Optional injected wallet/provider (auto path)
864
- * @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
865
- *
916
+ * @param {number} [params.chainId] - EVM signing-context hint; when omitted, resolved to the NEUS protocol primary chain for signing
917
+ * @returns {Promise<Object>} Verification result with proofId
918
+ *
866
919
  * @example
920
+ * // Auto path
921
+ * const proof = await client.verify({
922
+ * verifier: 'ownership-basic',
923
+ * content: 'Hello World',
924
+ * wallet: window.ethereum
925
+ * });
926
+ *
927
+ * @example
928
+ * // Manual path
867
929
  * const proof = await client.verify({
868
930
  * verifierIds: ['ownership-basic'],
869
- * data: {
870
- * content: "My content",
871
- * owner: walletAddress, // or ownerAddress for nft-ownership/token-holding
872
- * reference: { type: 'other', id: 'my-unique-identifier' }
873
- * },
931
+ * data: { content: "My content", owner: walletAddress },
874
932
  * walletAddress: '0x...',
875
933
  * signature: '0x...',
876
934
  * signedTimestamp: Date.now(),
877
935
  * options: { targetChains: [421614, 11155111] }
878
936
  * });
879
937
  */
880
- /**
881
- * Create a verification proof
882
- *
883
- * @param {Object} params - Verification parameters
884
- * @param {string} [params.verifier] - Verifier ID (e.g., 'ownership-basic')
885
- * @param {string} [params.content] - Content to verify
886
- * @param {Object} [params.data] - Structured verification data
887
- * @param {Object} [params.wallet] - Wallet provider
888
- * @param {Object} [params.options] - Additional options
889
- * @returns {Promise<Object>} Verification result with proofId (qHash is a deprecated alias)
890
- *
891
- * @example
892
- * // Simple ownership proof
893
- * const proof = await client.verify({
894
- * verifier: 'ownership-basic',
895
- * content: 'Hello World',
896
- * wallet: window.ethereum
897
- * });
898
- */
899
938
  async verify(params) {
900
939
  if ((!params?.signature || !params?.walletAddress) && (params?.verifier || params?.content || params?.data)) {
901
940
  const { content, verifier = "ownership-basic", data: data2 = null, wallet = null, options: options2 = {} } = params;
902
941
  if (verifier === "ownership-basic" && !data2 && (!content || typeof content !== "string")) {
903
942
  throw new ValidationError("content is required and must be a string (or use data param with owner + reference)");
904
943
  }
905
- let validVerifiers = FALLBACK_PUBLIC_VERIFIERS;
944
+ let verifierCatalog = FALLBACK_PUBLIC_VERIFIER_CATALOG;
906
945
  try {
907
- const discovered = await this.getVerifiers();
908
- if (Array.isArray(discovered) && discovered.length > 0) {
909
- validVerifiers = discovered;
946
+ const discovered = await this.getVerifierCatalog();
947
+ if (discovered && discovered.metadata && Object.keys(discovered.metadata).length > 0) {
948
+ verifierCatalog = discovered.metadata;
910
949
  }
911
950
  } catch {
912
951
  }
952
+ const validVerifiers = Object.keys(verifierCatalog);
913
953
  if (!validVerifiers.includes(verifier)) {
914
954
  throw new ValidationError(`Invalid verifier '${verifier}'. Must be one of: ${validVerifiers.join(", ")}.`);
915
955
  }
916
- if (INTERACTIVE_VERIFIERS.has(verifier)) {
956
+ if (verifierCatalog?.[verifier]?.supportsDirectApi === false) {
917
957
  const hostedCheckoutUrl = options2?.hostedCheckoutUrl || "https://neus.network/verify";
918
958
  throw new ValidationError(
919
959
  `${verifier} requires hosted interactive checkout. Use VerifyGate or redirect to ${hostedCheckoutUrl}.`
@@ -1054,7 +1094,10 @@ var NeusClient = class {
1054
1094
  ...data2?.agentLabel && { agentLabel: data2.agentLabel },
1055
1095
  ...data2?.agentType && { agentType: data2.agentType },
1056
1096
  ...data2?.description && { description: data2.description },
1057
- ...data2?.capabilities && { capabilities: data2.capabilities }
1097
+ ...data2?.capabilities && { capabilities: data2.capabilities },
1098
+ ...data2?.instructions && { instructions: data2.instructions },
1099
+ ...data2?.skills && { skills: data2.skills },
1100
+ ...data2?.services && { services: data2.services }
1058
1101
  };
1059
1102
  } else if (verifier === "agent-delegation") {
1060
1103
  if (!data2?.agentWallet) {
@@ -1067,7 +1110,11 @@ var NeusClient = class {
1067
1110
  ...data2?.scope && { scope: data2.scope },
1068
1111
  ...data2?.permissions && { permissions: data2.permissions },
1069
1112
  ...data2?.maxSpend && { maxSpend: data2.maxSpend },
1070
- ...data2?.expiresAt && { expiresAt: data2.expiresAt }
1113
+ ...data2?.allowedPaymentTypes && { allowedPaymentTypes: data2.allowedPaymentTypes },
1114
+ ...data2?.receiptDisclosure && { receiptDisclosure: data2.receiptDisclosure },
1115
+ ...data2?.expiresAt && { expiresAt: data2.expiresAt },
1116
+ ...data2?.instructions && { instructions: data2.instructions },
1117
+ ...data2?.skills && { skills: data2.skills }
1071
1118
  };
1072
1119
  } else if (verifier === "ai-content-moderation") {
1073
1120
  if (!data2?.content) {
@@ -1127,31 +1174,24 @@ var NeusClient = class {
1127
1174
  const enc = new TextEncoder();
1128
1175
  const bytes = enc.encode(s);
1129
1176
  let hex = "0x";
1130
- for (let i = 0; i < bytes.length; i++)
1131
- hex += bytes[i].toString(16).padStart(2, "0");
1177
+ for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
1132
1178
  return hex;
1133
1179
  } catch {
1134
1180
  let hex = "0x";
1135
- for (let i = 0; i < s.length; i++)
1136
- hex += s.charCodeAt(i).toString(16).padStart(2, "0");
1181
+ for (let i = 0; i < s.length; i++) hex += s.charCodeAt(i).toString(16).padStart(2, "0");
1137
1182
  return hex;
1138
1183
  }
1139
1184
  };
1140
1185
  const isFarcasterWallet = (() => {
1141
- if (typeof window === "undefined")
1142
- return false;
1186
+ if (typeof window === "undefined") return false;
1143
1187
  try {
1144
1188
  const w = window;
1145
1189
  const fc = w.farcaster;
1146
- if (!fc || !fc.context)
1147
- return false;
1190
+ if (!fc || !fc.context) return false;
1148
1191
  const fcProvider = fc.provider || fc.walletProvider || fc.context && fc.context.walletProvider;
1149
- if (fcProvider === provider)
1150
- return true;
1151
- if (w.mini && w.mini.wallet === provider && fc && fc.context)
1152
- return true;
1153
- if (w.ethereum === provider && fc && fc.context)
1154
- return true;
1192
+ if (fcProvider === provider) return true;
1193
+ if (w.mini && w.mini.wallet === provider && fc && fc.context) return true;
1194
+ if (w.ethereum === provider && fc && fc.context) return true;
1155
1195
  } catch {
1156
1196
  }
1157
1197
  return false;
@@ -1170,7 +1210,8 @@ var NeusClient = class {
1170
1210
  const msg = String(e && (e.message || e.reason) || e || "").toLowerCase();
1171
1211
  const errCode = e && (e.code || e.error && e.error.code) || null;
1172
1212
  const needsHex = /byte|bytes|invalid byte sequence|encoding|non-hex/i.test(msg);
1173
- const methodUnsupported = /method.*not.*supported|unsupported|not implemented|method not found|unknown method|does not support/i.test(msg) || errCode === -32601 || errCode === 4200 || msg.includes("personal_sign") && msg.includes("not") || msg.includes("request method") && msg.includes("not supported");
1213
+ const unsupportedRe = /method.*not.*supported|unsupported|not implemented|method not found|unknown method|does not support/i;
1214
+ const methodUnsupported = unsupportedRe.test(msg) || errCode === -32601 || errCode === 4200 || msg.includes("personal_sign") && msg.includes("not") || msg.includes("request method") && msg.includes("not supported");
1174
1215
  if (methodUnsupported) {
1175
1216
  this._log("personal_sign not supported; attempting eth_sign fallback");
1176
1217
  try {
@@ -1179,28 +1220,23 @@ var NeusClient = class {
1179
1220
  const prefix = `Ethereum Signed Message:
1180
1221
  ${bytes.length}`;
1181
1222
  const full = new Uint8Array(prefix.length + bytes.length);
1182
- for (let i = 0; i < prefix.length; i++)
1183
- full[i] = prefix.charCodeAt(i);
1223
+ for (let i = 0; i < prefix.length; i++) full[i] = prefix.charCodeAt(i);
1184
1224
  full.set(bytes, prefix.length);
1185
1225
  let payloadHex = "0x";
1186
- for (let i = 0; i < full.length; i++)
1187
- payloadHex += full[i].toString(16).padStart(2, "0");
1226
+ for (let i = 0; i < full.length; i++) payloadHex += full[i].toString(16).padStart(2, "0");
1188
1227
  try {
1189
- if (typeof window !== "undefined")
1190
- window.__NEUS_ALLOW_ETH_SIGN__ = true;
1228
+ if (typeof window !== "undefined") window.__NEUS_ALLOW_ETH_SIGN__ = true;
1191
1229
  } catch {
1192
1230
  }
1193
1231
  signature2 = await provider.request({ method: "eth_sign", params: [walletAddress2, payloadHex], neusAllowEthSign: true });
1194
1232
  try {
1195
- if (typeof window !== "undefined")
1196
- delete window.__NEUS_ALLOW_ETH_SIGN__;
1233
+ if (typeof window !== "undefined") delete window.__NEUS_ALLOW_ETH_SIGN__;
1197
1234
  } catch {
1198
1235
  }
1199
1236
  } catch (fallbackErr) {
1200
1237
  this._log("eth_sign fallback failed", { message: fallbackErr?.message || String(fallbackErr) });
1201
1238
  try {
1202
- if (typeof window !== "undefined")
1203
- delete window.__NEUS_ALLOW_ETH_SIGN__;
1239
+ if (typeof window !== "undefined") delete window.__NEUS_ALLOW_ETH_SIGN__;
1204
1240
  } catch {
1205
1241
  }
1206
1242
  throw e;
@@ -1242,8 +1278,7 @@ ${bytes.length}`;
1242
1278
  } = params;
1243
1279
  const resolvedChainId = chainId || (chain ? null : NEUS_CONSTANTS.HUB_CHAIN_ID);
1244
1280
  const normalizeVerifierId = (id) => {
1245
- if (typeof id !== "string")
1246
- return id;
1281
+ if (typeof id !== "string") return id;
1247
1282
  const match = id.match(/^(.*)@\d+$/);
1248
1283
  return match ? match[1] : id;
1249
1284
  };
@@ -1278,10 +1313,9 @@ ${bytes.length}`;
1278
1313
  // Privacy and storage options (defaults)
1279
1314
  privacyLevel: options?.privacyLevel || "private",
1280
1315
  publicDisplay: options?.publicDisplay || false,
1281
- storeOriginalContent: options?.storeOriginalContent || false
1316
+ storeOriginalContent: typeof options?.storeOriginalContent === "boolean" ? options.storeOriginalContent : true
1282
1317
  };
1283
- if (typeof options?.enableIpfs === "boolean")
1284
- optionsPayload.enableIpfs = options.enableIpfs;
1318
+ if (typeof options?.enableIpfs === "boolean") optionsPayload.enableIpfs = options.enableIpfs;
1285
1319
  const requestData = {
1286
1320
  verifierIds: normalizedVerifierIds,
1287
1321
  data,
@@ -1299,41 +1333,37 @@ ${bytes.length}`;
1299
1333
  }
1300
1334
  return this._formatResponse(response);
1301
1335
  }
1302
- // ============================================================================
1303
- // STATUS AND UTILITY METHODS
1304
- // ============================================================================
1305
1336
  /**
1306
- * Get verification status
1337
+ * Get proof record by proof receipt id.
1307
1338
  *
1308
- * @param {string} proofId - Proof ID (standard). `qHash` is a deprecated alias (same value).
1309
- * @returns {Promise<Object>} Verification status and data
1339
+ * @param {string} proofId - Proof receipt ID (0x + 64 hex).
1340
+ * @returns {Promise<Object>} Proof record and verification state
1310
1341
  *
1311
1342
  * @example
1312
- * const result = await client.getStatus('0x...');
1343
+ * const result = await client.getProof('0x...');
1313
1344
  * console.log('Status:', result.status);
1314
1345
  */
1315
- async getStatus(proofId) {
1346
+ async getProof(proofId) {
1316
1347
  if (!proofId || typeof proofId !== "string") {
1317
1348
  throw new ValidationError("proofId is required");
1318
1349
  }
1319
- const response = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`);
1350
+ const response = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`);
1320
1351
  if (!response.success) {
1321
- throw new ApiError(`Failed to get status: ${response.error?.message || "Unknown error"}`, response.error);
1352
+ throw new ApiError(`Failed to get proof: ${response.error?.message || "Unknown error"}`, response.error);
1322
1353
  }
1323
1354
  return this._formatResponse(response);
1324
1355
  }
1325
1356
  /**
1326
- * Get private proof status with wallet signature
1357
+ * Get private proof record with wallet signature
1327
1358
  *
1328
- * @param {string} proofId - Proof ID (standard). `qHash` is a deprecated alias (same value).
1359
+ * @param {string} proofId - Proof receipt ID.
1329
1360
  * @param {Object} wallet - Wallet provider (window.ethereum or ethers Wallet)
1330
- * @returns {Promise<Object>} Private verification status and data
1361
+ * @returns {Promise<Object>} Private proof record and verification state
1331
1362
  *
1332
1363
  * @example
1333
- * // Access private proof
1334
- * const privateData = await client.getPrivateStatus(proofId, window.ethereum);
1364
+ * const privateData = await client.getPrivateProof(proofId, window.ethereum);
1335
1365
  */
1336
- async getPrivateStatus(proofId, wallet = null) {
1366
+ async getPrivateProof(proofId, wallet = null) {
1337
1367
  if (!proofId || typeof proofId !== "string") {
1338
1368
  throw new ValidationError("proofId is required");
1339
1369
  }
@@ -1347,7 +1377,7 @@ ${bytes.length}`;
1347
1377
  ...typeof auth.chain === "string" && auth.chain.trim() ? { "x-chain": auth.chain.trim() } : {},
1348
1378
  ...typeof auth.signatureMethod === "string" && auth.signatureMethod.trim() ? { "x-signature-method": auth.signatureMethod.trim() } : {}
1349
1379
  };
1350
- const response2 = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`, null, headers);
1380
+ const response2 = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`, null, headers);
1351
1381
  if (!response2.success) {
1352
1382
  throw new ApiError(
1353
1383
  `Failed to access private proof: ${response2.error?.message || "Unauthorized"}`,
@@ -1386,7 +1416,7 @@ ${bytes.length}`;
1386
1416
  }
1387
1417
  throw new ValidationError(`Failed to sign message: ${error.message}`);
1388
1418
  }
1389
- const response = await this._makeRequest("GET", `/api/v1/verification/status/${proofId}`, null, {
1419
+ const response = await this._makeRequest("GET", `/api/v1/proofs/${proofId}`, null, {
1390
1420
  "x-wallet-address": walletAddress,
1391
1421
  "x-signature": signature,
1392
1422
  "x-signed-timestamp": signedTimestamp.toString(),
@@ -1419,25 +1449,37 @@ ${bytes.length}`;
1419
1449
  * @returns {Promise<string[]>} Array of verifier IDs
1420
1450
  */
1421
1451
  async getVerifiers() {
1452
+ const catalog = await this.getVerifierCatalog();
1453
+ return Array.isArray(catalog?.data) ? catalog.data : [];
1454
+ }
1455
+ /**
1456
+ * Get the public verifier catalog with per-verifier capabilities.
1457
+ * @returns {Promise<{data: string[], metadata: Record<string, { supportsDirectApi?: boolean }>, meta?: object}>}
1458
+ */
1459
+ async getVerifierCatalog() {
1422
1460
  const response = await this._makeRequest("GET", "/api/v1/verification/verifiers");
1423
1461
  if (!response.success) {
1424
1462
  throw new ApiError(`Failed to get verifiers: ${response.error?.message || "Unknown error"}`, response.error);
1425
1463
  }
1426
- return Array.isArray(response.data) ? response.data : [];
1464
+ return {
1465
+ data: Array.isArray(response.data) ? response.data : [],
1466
+ metadata: response.metadata && typeof response.metadata === "object" && !Array.isArray(response.metadata) ? response.metadata : {},
1467
+ meta: response.meta && typeof response.meta === "object" && !Array.isArray(response.meta) ? response.meta : {}
1468
+ };
1427
1469
  }
1428
1470
  /**
1429
1471
  * POLL PROOF STATUS - Wait for verification completion
1430
- *
1472
+ *
1431
1473
  * Polls the verification status until it reaches a terminal state (completed or failed).
1432
1474
  * Useful for providing real-time feedback to users during verification.
1433
- *
1434
- * @param {string} proofId - Proof ID to poll (standard). `qHash` is a deprecated alias (same value).
1475
+ *
1476
+ * @param {string} proofId - Proof ID to poll.
1435
1477
  * @param {Object} [options] - Polling options
1436
1478
  * @param {number} [options.interval=5000] - Polling interval in ms
1437
1479
  * @param {number} [options.timeout=120000] - Total timeout in ms
1438
1480
  * @param {Function} [options.onProgress] - Progress callback function
1439
1481
  * @returns {Promise<Object>} Final verification status
1440
- *
1482
+ *
1441
1483
  * @example
1442
1484
  * const finalStatus = await client.pollProofStatus(proofId, {
1443
1485
  * interval: 3000,
@@ -1463,7 +1505,7 @@ ${bytes.length}`;
1463
1505
  let consecutiveRateLimits = 0;
1464
1506
  while (Date.now() - startTime < timeout) {
1465
1507
  try {
1466
- const status = await this.getStatus(proofId);
1508
+ const status = await this.getProof(proofId);
1467
1509
  consecutiveRateLimits = 0;
1468
1510
  if (onProgress && typeof onProgress === "function") {
1469
1511
  onProgress(status.data || status);
@@ -1496,7 +1538,7 @@ ${bytes.length}`;
1496
1538
  }
1497
1539
  /**
1498
1540
  * DETECT CHAIN ID - Get current wallet chain
1499
- *
1541
+ *
1500
1542
  * @returns {Promise<number>} Current chain ID
1501
1543
  */
1502
1544
  async detectChainId() {
@@ -1527,7 +1569,6 @@ ${bytes.length}`;
1527
1569
  const message = constructVerificationMessage({
1528
1570
  walletAddress: address,
1529
1571
  signedTimestamp,
1530
- // Keep wire payload key `qHash` for backwards compatibility.
1531
1572
  data: { action: "revoke_proof", qHash: proofId },
1532
1573
  verifierIds: ["ownership-basic"],
1533
1574
  ...signerIsEvm ? { chainId: this._getHubChainId() } : { chain }
@@ -1546,9 +1587,8 @@ ${bytes.length}`;
1546
1587
  }
1547
1588
  throw new ValidationError(`Failed to sign revocation: ${error.message}`);
1548
1589
  }
1549
- const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/${proofId}/revoke-self`, {
1590
+ const res = await fetch(`${this.config.apiUrl}/api/v1/proofs/revoke-self/${proofId}`, {
1550
1591
  method: "POST",
1551
- // SECURITY: Do not put proof signatures into Authorization headers.
1552
1592
  headers: { "Content-Type": "application/json" },
1553
1593
  body: JSON.stringify({
1554
1594
  walletAddress: address,
@@ -1563,18 +1603,16 @@ ${bytes.length}`;
1563
1603
  }
1564
1604
  return true;
1565
1605
  }
1566
- // ============================================================================
1567
- // PROOFS & GATING METHODS
1568
- // ============================================================================
1569
1606
  /**
1570
1607
  * GET PROOFS BY WALLET - Fetch proofs for a wallet address
1571
- *
1608
+ *
1572
1609
  * @param {string} walletAddress - Wallet identity (EVM/Solana/DID)
1573
1610
  * @param {Object} [options] - Filter options
1574
1611
  * @param {number} [options.limit] - Max results (default: 50; higher limits require owner access)
1575
1612
  * @param {number} [options.offset] - Pagination offset (default: 0)
1613
+ * @param {string} [options.qHash] - Filter to single proof by qHash
1576
1614
  * @returns {Promise<Object>} Proofs result
1577
- *
1615
+ *
1578
1616
  * @example
1579
1617
  * const result = await client.getProofsByWallet('0x...', {
1580
1618
  * limit: 50,
@@ -1588,14 +1626,13 @@ ${bytes.length}`;
1588
1626
  const id = walletAddress.trim();
1589
1627
  const pathId = /^0x[a-fA-F0-9]{40}$/i.test(id) ? id.toLowerCase() : id;
1590
1628
  const qs = [];
1591
- if (options.limit)
1592
- qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1593
- if (options.offset)
1594
- qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1629
+ if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1630
+ if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1631
+ if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1595
1632
  const query = qs.length ? `?${qs.join("&")}` : "";
1596
1633
  const response = await this._makeRequest(
1597
1634
  "GET",
1598
- `/api/v1/proofs/byWallet/${encodeURIComponent(pathId)}${query}`
1635
+ `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`
1599
1636
  );
1600
1637
  if (!response.success) {
1601
1638
  throw new ApiError(`Failed to get proofs: ${response.error?.message || "Unknown error"}`, response.error);
@@ -1618,6 +1655,7 @@ ${bytes.length}`;
1618
1655
  * @param {Object} [options]
1619
1656
  * @param {number} [options.limit] - Max results (server enforces caps)
1620
1657
  * @param {number} [options.offset] - Pagination offset
1658
+ * @param {string} [options.qHash] - Filter to single proof by qHash
1621
1659
  * @param {Object} [wallet] - Optional injected wallet/provider (MetaMask/ethers Wallet)
1622
1660
  */
1623
1661
  async getPrivateProofsByWallet(walletAddress, options = {}, wallet = null) {
@@ -1668,12 +1706,11 @@ ${bytes.length}`;
1668
1706
  throw new ValidationError(`Failed to sign message: ${error.message}`);
1669
1707
  }
1670
1708
  const qs = [];
1671
- if (options.limit)
1672
- qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1673
- if (options.offset)
1674
- qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1709
+ if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1710
+ if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1711
+ if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1675
1712
  const query = qs.length ? `?${qs.join("&")}` : "";
1676
- const response = await this._makeRequest("GET", `/api/v1/proofs/byWallet/${encodeURIComponent(pathId)}${query}`, null, {
1713
+ const response = await this._makeRequest("GET", `/api/v1/proofs/by-wallet/${encodeURIComponent(pathId)}${query}`, null, {
1677
1714
  "x-wallet-address": signerWalletAddress,
1678
1715
  "x-signature": signature,
1679
1716
  "x-signed-timestamp": signedTimestamp.toString(),
@@ -1692,16 +1729,16 @@ ${bytes.length}`;
1692
1729
  };
1693
1730
  }
1694
1731
  /**
1695
- * GATE CHECK (API) - Minimal eligibility check
1732
+ * Gate check (HTTP API) minimal eligibility response.
1696
1733
  *
1697
1734
  * Calls the gate endpoint and returns a **minimal** yes/no response.
1698
- * By default this checks **public + discoverable** proofs only.
1735
+ * By default this checks **public + unlisted** proofs.
1699
1736
  *
1700
1737
  * When `includePrivate=true`, this can perform owner-signed private checks
1701
1738
  * (no full proof payloads returned) by providing a wallet/provider.
1702
1739
  *
1703
- * Prefer this over `checkGate()` for integrations that want the
1704
- * smallest, most stable surface area (and do NOT need full proof payloads).
1740
+ * Prefer this over `checkGate()` when you need the smallest, most stable
1741
+ * response shape and do not need full proof payloads.
1705
1742
  *
1706
1743
  * @param {Object} params - Gate check query params
1707
1744
  * @param {string} params.address - Wallet identity to check (EVM/Solana/DID)
@@ -1724,25 +1761,20 @@ ${bytes.length}`;
1724
1761
  const qs = new URLSearchParams();
1725
1762
  qs.set("address", address);
1726
1763
  const setIfPresent = (key, value) => {
1727
- if (value === void 0 || value === null)
1728
- return;
1764
+ if (value === void 0 || value === null) return;
1729
1765
  const str = typeof value === "string" ? value : String(value);
1730
- if (str.length === 0)
1731
- return;
1766
+ if (str.length === 0) return;
1732
1767
  qs.set(key, str);
1733
1768
  };
1734
1769
  const setBoolIfPresent = (key, value) => {
1735
- if (value === void 0 || value === null)
1736
- return;
1770
+ if (value === void 0 || value === null) return;
1737
1771
  qs.set(key, value ? "true" : "false");
1738
1772
  };
1739
1773
  const setCsvIfPresent = (key, value) => {
1740
- if (value === void 0 || value === null)
1741
- return;
1774
+ if (value === void 0 || value === null) return;
1742
1775
  if (Array.isArray(value)) {
1743
1776
  const items = value.map((v) => String(v).trim()).filter(Boolean);
1744
- if (items.length)
1745
- qs.set(key, items.join(","));
1777
+ if (items.length) qs.set(key, items.join(","));
1746
1778
  return;
1747
1779
  }
1748
1780
  setIfPresent(key, value);
@@ -1768,6 +1800,8 @@ ${bytes.length}`;
1768
1800
  setIfPresent("domain", params.domain);
1769
1801
  setIfPresent("minBalance", params.minBalance);
1770
1802
  setIfPresent("provider", params.provider);
1803
+ setIfPresent("handle", params.handle);
1804
+ setIfPresent("namespace", params.namespace);
1771
1805
  setIfPresent("ownerAddress", params.ownerAddress);
1772
1806
  setIfPresent("riskLevel", params.riskLevel);
1773
1807
  setBoolIfPresent("sanctioned", params.sanctioned);
@@ -1815,11 +1849,17 @@ ${bytes.length}`;
1815
1849
  return response;
1816
1850
  }
1817
1851
  /**
1818
- * CHECK GATE - Evaluate requirements against existing proofs
1819
- *
1852
+ * CHECK GATE Local preview against proofs you already have in memory or from `getProofsByWallet`.
1853
+ *
1854
+ * **Not authoritative for access control.** For production allow/deny, use {@link NeusClient#gateCheck}
1855
+ * (`GET /api/v1/proofs/check`), which applies the same rules as the NEUS API. This method is useful for
1856
+ * UI previews, offline-ish flows, or when you already fetched proofs and want a quick match without
1857
+ * another round trip — but it can disagree with the server (e.g. `contentHash` matching uses a local
1858
+ * approximation when proof data only has inline `content`; the API uses the standard server-side hash).
1859
+ *
1820
1860
  * Gate-first verification: checks if wallet has valid proofs satisfying requirements.
1821
1861
  * Returns which requirements are missing/expired.
1822
- *
1862
+ *
1823
1863
  * @param {Object} params - Gate check parameters
1824
1864
  * @param {string} params.walletAddress - Target wallet
1825
1865
  * @param {Array<Object>} params.requirements - Array of gate requirements
@@ -1837,7 +1877,7 @@ ${bytes.length}`;
1837
1877
  * Note: contentHash matching uses approximation in SDK; for exact SHA-256 matching, use backend API
1838
1878
  * @param {Array} [params.proofs] - Pre-fetched proofs (skip API call)
1839
1879
  * @returns {Promise<Object>} Gate result with satisfied, missing, existing
1840
- *
1880
+ *
1841
1881
  * @example
1842
1882
  * // Basic gate check
1843
1883
  * const result = await client.checkGate({
@@ -1870,20 +1910,20 @@ ${bytes.length}`;
1870
1910
  const verifier = verifiedVerifiers.find(
1871
1911
  (v) => v.verifierId === verifierId && v.verified === true
1872
1912
  );
1873
- if (!verifier)
1874
- return false;
1875
- if (proof.revokedAt)
1876
- return false;
1913
+ if (!verifier) return false;
1914
+ if (proof.revokedAt) return false;
1877
1915
  if (maxAgeMs) {
1878
1916
  const proofTimestamp = proof.createdAt || proof.signedTimestamp || 0;
1879
1917
  const proofAge = now - proofTimestamp;
1880
- if (proofAge > maxAgeMs)
1881
- return false;
1918
+ if (proofAge > maxAgeMs) return false;
1882
1919
  }
1883
1920
  if (match && typeof match === "object") {
1884
1921
  const data = verifier.data || {};
1885
1922
  const input = data.input || {};
1886
- for (const [key, expected] of Object.entries(match)) {
1923
+ const matchObj = Array.isArray(match) ? Object.fromEntries(
1924
+ match.filter((m) => m && m.path && String(m.value ?? "").trim() !== "").map((m) => [String(m.path).trim(), m.value])
1925
+ ) : match;
1926
+ for (const [key, expected] of Object.entries(matchObj)) {
1887
1927
  let actualValue = null;
1888
1928
  if (key.includes(".")) {
1889
1929
  const parts = key.split(".");
@@ -1908,6 +1948,7 @@ ${bytes.length}`;
1908
1948
  actualValue = data.reference?.id || data.content;
1909
1949
  }
1910
1950
  if (actualValue === void 0) {
1951
+ const claims = data.claims || {};
1911
1952
  if (key === "contractAddress") {
1912
1953
  actualValue = input.contractAddress || data.contractAddress;
1913
1954
  } else if (key === "tokenId") {
@@ -1926,6 +1967,22 @@ ${bytes.length}`;
1926
1967
  actualValue = data.verificationMethod;
1927
1968
  } else if (key === "domain") {
1928
1969
  actualValue = data.domain;
1970
+ } else if (key === "handle") {
1971
+ actualValue = data.handle || data.pseudonymId;
1972
+ } else if (key === "namespace") {
1973
+ actualValue = data.namespace !== void 0 && data.namespace !== null && data.namespace !== "" ? data.namespace : "neus";
1974
+ } else if (key === "claims.sanctions_passed") {
1975
+ actualValue = claims.sanctions_passed ?? claims.sanctionsPassed;
1976
+ } else if (key === "claims.age_min") {
1977
+ actualValue = claims.age_min ?? claims.ageMin;
1978
+ } else if (key === "neusPersonhoodId") {
1979
+ actualValue = data.neusPersonhoodId;
1980
+ } else if (key === "riskLevel") {
1981
+ actualValue = data.riskLevel;
1982
+ } else if (key === "sanctioned") {
1983
+ actualValue = data.sanctioned;
1984
+ } else if (key === "poisoned") {
1985
+ actualValue = data.poisoned;
1929
1986
  }
1930
1987
  }
1931
1988
  if (key === "contentHash" && actualValue === void 0 && data.content) {
@@ -1937,7 +1994,7 @@ ${bytes.length}`;
1937
1994
  hash = (hash << 5) - hash + char;
1938
1995
  hash = hash & hash;
1939
1996
  }
1940
- actualValue = "0x" + Math.abs(hash).toString(16).padStart(64, "0").substring(0, 66);
1997
+ actualValue = `0x${Math.abs(hash).toString(16).padStart(64, "0").substring(0, 66)}`;
1941
1998
  } catch {
1942
1999
  actualValue = String(data.content);
1943
2000
  }
@@ -1947,11 +2004,16 @@ ${bytes.length}`;
1947
2004
  if (actualValue === void 0 || actualValue === null) {
1948
2005
  return false;
1949
2006
  }
2007
+ if (typeof actualValue === "boolean" || key && (key.includes("sanctions") || key.includes("sanctioned") || key.includes("poisoned"))) {
2008
+ const bActual = Boolean(actualValue);
2009
+ const bExpected = expected === true || expected === "true" || String(expected).toLowerCase() === "true";
2010
+ if (bActual !== bExpected) return false;
2011
+ continue;
2012
+ }
1950
2013
  if (key === "chainId" || key === "tokenId" && (typeof actualValue === "number" || !isNaN(Number(actualValue)))) {
1951
2014
  normalizedActual = Number(actualValue);
1952
2015
  normalizedExpected = Number(expected);
1953
- if (isNaN(normalizedActual) || isNaN(normalizedExpected))
1954
- return false;
2016
+ if (isNaN(normalizedActual) || isNaN(normalizedExpected)) return false;
1955
2017
  } else if (typeof actualValue === "string" && (actualValue.startsWith("0x") || actualValue.length > 20)) {
1956
2018
  normalizedActual = actualValue.toLowerCase();
1957
2019
  normalizedExpected = typeof expected === "string" ? String(expected).toLowerCase() : expected;
@@ -1980,13 +2042,6 @@ ${bytes.length}`;
1980
2042
  allProofs: proofs
1981
2043
  };
1982
2044
  }
1983
- // ============================================================================
1984
- // PRIVATE UTILITY METHODS
1985
- // ============================================================================
1986
- /**
1987
- * Get connected wallet address
1988
- * @private
1989
- */
1990
2045
  async _getWalletAddress() {
1991
2046
  if (typeof window === "undefined" || !window.ethereum) {
1992
2047
  throw new ConfigurationError("No Web3 wallet detected");
@@ -1997,10 +2052,6 @@ ${bytes.length}`;
1997
2052
  }
1998
2053
  return accounts[0];
1999
2054
  }
2000
- /**
2001
- * Make HTTP request to API
2002
- * @private
2003
- */
2004
2055
  async _makeRequest(method, endpoint, data = null, headersOverride = null) {
2005
2056
  const url = `${this.baseUrl}${endpoint}`;
2006
2057
  const controller = new AbortController();
@@ -2038,10 +2089,6 @@ ${bytes.length}`;
2038
2089
  throw new NetworkError(`Network error: ${error.message}`);
2039
2090
  }
2040
2091
  }
2041
- /**
2042
- * Format API response for consistent structure
2043
- * @private
2044
- */
2045
2092
  _formatResponse(response) {
2046
2093
  const proofId = response?.data?.proofId || response?.proofId || response?.data?.resource?.proofId || response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || response?.data?.id;
2047
2094
  const qHash = response?.data?.qHash || response?.qHash || response?.data?.resource?.qHash || proofId || response?.data?.id;
@@ -2056,13 +2103,9 @@ ${bytes.length}`;
2056
2103
  data: response.data,
2057
2104
  message: response.message,
2058
2105
  timestamp: Date.now(),
2059
- statusUrl: finalProofId ? `${this.baseUrl}/api/v1/verification/status/${finalProofId}` : null
2106
+ proofUrl: finalProofId ? `${this.baseUrl}/api/v1/proofs/${finalProofId}` : null
2060
2107
  };
2061
2108
  }
2062
- /**
2063
- * Check if status is terminal (completed or failed)
2064
- * @private
2065
- */
2066
2109
  _isTerminalStatus(status) {
2067
2110
  const terminalStates = [
2068
2111
  "verified",
@@ -2093,5 +2136,6 @@ ${bytes.length}`;
2093
2136
  // Annotate the CommonJS export names for ESM import in node:
2094
2137
  0 && (module.exports = {
2095
2138
  NeusClient,
2139
+ PORTABLE_PROOF_SIGNER_HEADER,
2096
2140
  constructVerificationMessage
2097
2141
  });